diff --git a/.baedeker/forkless-data.jsonnet b/.baedeker/forkless-data.jsonnet new file mode 100644 index 000000000..9eda1929f --- /dev/null +++ b/.baedeker/forkless-data.jsonnet @@ -0,0 +1,41 @@ +local +m = import 'baedeker-library/mixin/spec.libsonnet', +rm = import 'baedeker-library/mixin/raw-spec.libsonnet', +; + +function(relay_spec, forked_spec, fork_source) + +local relay = { + name: 'subtensor', + bin: 'bin/subtensor', + spec: {Raw:{ + local modifyRaw = bdk.mixer([ + rm.resetNetworking($), + rm.decodeSpec(), + rm.polkaLaunchPara($), + rm.reencodeSpec(), + ]), + raw_spec: modifyRaw({ + name: "Unused", + id: "%s_local" % forked_spec, + chainType: "Live", + codeSubstitutes: {}, + genesis: { + raw: { + top: cql.chain(fork_source).latest._preloadKeys._raw, + childrenDefault: {}, + }, + }, + }), + }}, + nodes: { + [name]: { + bin: $.bin, + wantedKeys: 'standalone', + }, + for name in ['alice', 'bob', 'charlie'] + }, +}; + +relay + { +} diff --git a/.baedeker/rewrites.jsonnet b/.baedeker/rewrites.jsonnet new file mode 100644 index 000000000..30b9e199e --- /dev/null +++ b/.baedeker/rewrites.jsonnet @@ -0,0 +1,11 @@ +local dotenv = { + [std.splitLimit(line, "=", 2)[0]]: std.splitLimit(line, "=", 2)[1] + for line in std.split(importstr "../.env", "\n") + if line != "" + if std.member(line, "=") +}; + +function(prev, repoDir) +(import 'baedeker-library/ops/rewrites.libsonnet').rewriteNodePaths({ + 'bin/subtensor':'%s/target/release/subtensor' % repoDir, +})(prev) diff --git a/.baedeker/up.sh b/.baedeker/up.sh new file mode 100755 index 000000000..164cefa11 --- /dev/null +++ b/.baedeker/up.sh @@ -0,0 +1,6 @@ +#!/bin/sh +set -e +BDK_DIR=$(dirname $(readlink -f "$0")) +RUST_LOG=info baedeker --spec=docker -J$BDK_DIR/vendor/ --generator=docker_compose=$BDK_DIR/.bdk-env --generator=docker_compose_discover=$BDK_DIR/.bdk-env/discover.env --secret=file=$BDK_DIR/.bdk-env/secret --tla-str=relay_spec=rococo-local --input-modules='lib:baedeker-library/ops/nginx.libsonnet' --input-modules='lib:baedeker-library/ops/devtools.libsonnet' --tla-str=repoDir=$(realpath $BDK_DIR/..) $@ $BDK_DIR/rewrites.jsonnet +cd $BDK_DIR/.bdk-env +#docker compose up -d --wait --remove-orphans diff --git a/.baedeker/vendor/baedeker-library/.gitignore b/.baedeker/vendor/baedeker-library/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/.baedeker/vendor/baedeker-library/LICENSE b/.baedeker/vendor/baedeker-library/LICENSE new file mode 100644 index 000000000..827cc0754 --- /dev/null +++ b/.baedeker/vendor/baedeker-library/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Unique Network + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/.baedeker/vendor/baedeker-library/inputs/base.libsonnet b/.baedeker/vendor/baedeker-library/inputs/base.libsonnet new file mode 100644 index 000000000..83da6ce39 --- /dev/null +++ b/.baedeker/vendor/baedeker-library/inputs/base.libsonnet @@ -0,0 +1,54 @@ +local + genesisState = import '../util/genesisState.libsonnet', + {mixinAllChains, ...} = import '../util/mixin.libsonnet', + k = import '../mixin/keys.libsonnet', +; + +function(prev, final) + +// :code +local WELLKNOWN_CODE = '0x3a636f6465'; + +local genesisMixin = { + // TODO: Process from wasm once native runtime free world lands. + specJson: cql.description('' % self.path, bdk.processSpec(self.bin, self.spec)), + genesisWasm: self.specJson.genesis.raw.top[WELLKNOWN_CODE], + genesisWasmData: cql.runtimeWasm(self.genesisWasm), + genesisStateVersion: self.genesisWasmData.version.state_version, + genesisHead: genesisState(self.specJson, self.genesisStateVersion), + + ss58Format: super?.ss58Format ?? 42, + signatureSchema: super?.signatureSchema ?? 'Sr25519', + // FIXME: Try to guess from runtime metadata. + // If null - try to guess the schema. + // I.e use StashOf of pallet_staking, if staking presents in schema, and so on. + validatorIdAssignment: super?.validatorIdAssignment ?? 'none', + + addressSeed(seed):: cql.addressSeed(self.signatureSchema, seed, self.ss58Format), +}; + +local mergedChains = (prev + mixinAllChains(prev, function(chain, path) genesisMixin + { + path: path, + nodes+: { + [nodename]+: local hostname = '%s-node-%s' % [path, nodename]; { + hostname: hostname, + wantedKeys: + if node?.wantedKeys == 'para' then k.paraWantedKeys($) + else if node?.wantedKeys == 'para-ed' then k.paraWantedKeys($, ed = true) + else if node?.wantedKeys == 'para-nimbus' then k.paraWantedKeys($, nimbus = true) + else if node?.wantedKeys == 'relay' then k.relayWantedKeys($) + else if node?.wantedKeys == 'standalone' then k.standaloneWantedKeys($) + else if std.isObject(node?.wantedKeys) then node?.wantedKeys + else if !('wantedKeys' in node) then {} + else error 'Unknown wantedKeys: %s' % node?.wantedKeys, + }, + for [nodename, node] in (chain?.nodes ?? {}) + }, +})); + +mergedChains + mixinAllChains(mergedChains, function(chain, path) { + nodes+: { + [nodename]+: bdk.ensureKeys(node.hostname, node.wantedKeys, chain.ss58Format), + for [nodename, node] in (chain?.nodes ?? {}) + }, +}) diff --git a/.baedeker/vendor/baedeker-library/mixin/keys.libsonnet b/.baedeker/vendor/baedeker-library/mixin/keys.libsonnet new file mode 100644 index 000000000..aeb344aec --- /dev/null +++ b/.baedeker/vendor/baedeker-library/mixin/keys.libsonnet @@ -0,0 +1,55 @@ +local +needController({validatorIdAssignment, ...}) = + if validatorIdAssignment == 'none' || validatorIdAssignment == 'collatorSelection' then false + else if validatorIdAssignment == 'staking' then true + else error "unknown validatorIdAssignment: %s" % validatorIdAssignment, +; + +{ + relayWantedKeys(root): { + [if needController(root) then '_controller']: root.signatureSchema, + _stash: root.signatureSchema, + + gran: 'Ed25519', + babe: 'Sr25519', + imon: 'Sr25519', + para: 'Sr25519', + asgn: 'Sr25519', + audi: 'Sr25519', + // rococo: beefy is required + beef: 'Ecdsa', + + sessionKeys: { + grandpa: 'gran', + babe: 'babe', + im_online: 'imon', + authority_discovery: 'audi', + para_assignment: 'asgn', + para_validator: 'para', + beefy: 'beef', + }, + }, + paraWantedKeys(root, ed = false, nimbus = false): { + [if needController(root) then '_controller']: root.signatureSchema, + _stash: root.signatureSchema, + + // COMPAT: asset-hub on polkadot uses ed25519 instead of sr25519 for session keys. + // https://github.com/paritytech/cumulus/blob/d4bb2215bb28ee05159c4c7df1b3435177b5bf4e/parachains/common/src/lib.rs#L57-L62 + [if nimbus then 'nmbs' else 'aura']: if ed then 'Ed25519' else 'Sr25519', + // COMPAT: moonbeam only supports setting nimbus key in genesis, yet rand key is required. + [if nimbus then 'rand']: {alias: 'nmbs'}, + + sessionKeys: { + aura: 'aura', + }, + }, + standaloneWantedKeys(root): { + aura: 'Sr25519', + gran: 'Ed25519', + + sessionKeys: { + aura: 'aura', + grandpa: 'gran', + }, + }, +} diff --git a/.baedeker/vendor/baedeker-library/mixin/raw-spec.libsonnet b/.baedeker/vendor/baedeker-library/mixin/raw-spec.libsonnet new file mode 100644 index 000000000..9b479d483 --- /dev/null +++ b/.baedeker/vendor/baedeker-library/mixin/raw-spec.libsonnet @@ -0,0 +1,230 @@ +local m = import './spec.libsonnet'; +local {encodeGrandpaKeys} = import '../util/grandpaKeys.libsonnet'; +local strToHex(str) = cql.toHex(std.encodeUTF8(str)); +local + account(name) = cql.sr25519Seed(name), + unwrapNewtype(struct) = local names = std.objectFields(struct); + if std.length(names) == 1 then struct[names[0]] + else struct, + WELLKNOWN_CODE = strToHex(':code'), + WELLKNOWN_GRANDPA_AUTHORITIES = strToHex(':grandpa_authorities'), +; + +{ + resetSystem: function(prev) prev { + _storage+: { + System+: { + // Magic value mandated by spec, nice + // [69, 69, 69, ..., 69, 69, 69] + local hash69 = '0x' + '45' * 32, + BlockHash: { + "0": hash69, + }, + EventCount: 0, + EventTopics: {}, + Events: [], + ExtrinsicCount: 0, + ExtrinsicData: {}, + + // Block header + ParentHash: hash69, + Number: 0, + Digest: [], + }, + Aura+: { + CurrentSlot: std.bigint('0'), + }, + [if 'CollatorSelection' in prev._storage then 'CollatorSelection']+: { + LastAuthoredBlock: {}, + }, + [if 'Session' in prev._storage then 'Session']+: { + CurrentIndex: 0, + }, + // Full reset + [if 'ParachainSystem' in prev._storage then 'ParachainSystem']: {}, + [if 'Authorship' in prev._storage then 'Authorship']: {}, + }, + }, + + setSudo(key): { + _storage+: { + Sudo+: { + Key: key, + }, + }, + }, + giveBalance(address, amount): { + _storage+: { + // Not updating total issuance: no big difference. + System+: { + Account+: std.trace('Altering account %s: %s' % [address, super.Account?.[address] ?? ''], { + [address]+: { + nonce: super?.nonce ?? 0, + // Leaks + consumers: super?.consumers ?? 1, + providers: super?.providers ?? 1, + sufficients: super?.sufficients ?? 0, + data+: { + free+: std.bigint(amount), + reserved: super?.reserved ?? std.bigint('0'), + misc_frozen: super?.misc_frozen ?? std.bigint('0'), + fee_frozen: super?.fee_frozen ?? std.bigint('0'), + }, + }, + }), + }, + }, + }, + setParaId(id): function(prev) prev { + // COMPAT: unique-chain + [if 'para_id' in prev then 'para_id']: id, + _storage+: { + [if 'ParachainInfo' in prev._storage then 'ParachainInfo']: { + ParachainId: id, + }, + }, + }, + resetAuraAuthorities: function(prev) prev { + _storage+: { + Aura+: { + Authorities: [], + }, + [if 'AuraExt' in prev._storage then 'AuraExt']+: { + Authorities: [], + }, + }, + }, + addAuraAuthority(key): function(prev) prev { + _storage+: { + Aura+: { + Authorities+: [cql.ss58(key)], + }, + [if 'AuraExt' in prev._storage then 'AuraExt']+: { + Authorities+: [cql.ss58(key)], + }, + }, + }, + setGrandpaKeys(keys): function(prev) prev { + _storage+: { + _unknown+: { + [if WELLKNOWN_GRANDPA_AUTHORITIES in prev._storage._unknown then WELLKNOWN_GRANDPA_AUTHORITIES]: encodeGrandpaKeys(keys), + }, + }, + }, + resetSessionKeys: { + _storage+: { + Session+: { + DisabledValidators: [], + KeyOwner: {}, + NextKeys: {}, + QueuedKeys: [], + Validators: [], + }, + }, + }, + addSessionKey([_accountId, _validatorId, _keys]): { + local accountId = cql.ss58(_accountId), + local validatorId = cql.ss58(_validatorId), + local keys = { + [cql.toHex(std.encodeUTF8(key))]: cql.ss58(data), + for [key, data] in _keys + }, + _storage+: { + // FIXME: Should increase consumers/providers for account + Session+: { + KeyOwner+: { + [std.toString([key, data])]: validatorId, + for [key, data] in keys + }, + NextKeys+: { + [validatorId]: unwrapNewtype(keys), + }, + QueuedKeys+: [ + [ + validatorId, + unwrapNewtype(keys), + ], + ], + Validators+: [validatorId], + }, + }, + }, + resetInvulnerables: function(prev) prev { + _storage+: { + [if 'CollatorSelection' in prev._storage then 'CollatorSelection']+: { + Invulnerables: [], + }, + } + }, + addInvulnerable(key): function(prev) prev { + _storage+: { + [if 'CollatorSelection' in prev._storage then 'CollatorSelection']+: { + Invulnerables+: [cql.ss58(key)], + }, + } + }, + + setCodeRaw(code): function(prev) prev { + genesis+: { + raw+: { + top+: { + [WELLKNOWN_CODE]: code, + }, + }, + }, + }, + + // Compatible, as storage remains the same + resetNetworking: m.resetNetworking, + + decodeSpec(): function(prev) local dump = cql.fullDump(prev.genesis.raw.top); prev { + _originalDump:: dump, + _storage::: dump, + genesis+: { + raw+: { + top:: error "reencode storage first" + }, + }, + }, + reencodeSpec(): function(prev) prev { + _originalDump:: error "decode storage first", + _storage:: error "decode storage first", + genesis+: { + raw+: { + top::: prev._originalDump._rebuild(prev._storage), + }, + }, + }, + + polkaLaunchPara(root): [ + $.resetSystem, + // $.setSudo(account('//Alice')), + // Will break everything + // $.resetBalances, + $.resetAuraAuthorities, + [ + $.addAuraAuthority(node.keys.aura), + for [?, node] in root.nodes + ], + $.setGrandpaKeys([node.keys.gran for [?, node] in root.nodes]), + function(prev) bdk.mixer(if 'Session' in prev._storage then [ + $.resetSessionKeys, + [ + $.addSessionKey([ + node.keys.aura, + node.keys.aura, + { + aura: node.keys.aura, + }, + ]), + for [?, node] in root.nodes + ], + ] else [])(prev), + $.resetInvulnerables, + [ + $.addInvulnerable(node.keys.aura), + for [?, node] in root.nodes + ], + $.setParaId(root.paraId), + ], +} diff --git a/.baedeker/vendor/baedeker-library/mixin/spec.libsonnet b/.baedeker/vendor/baedeker-library/mixin/spec.libsonnet new file mode 100644 index 000000000..57dcc589b --- /dev/null +++ b/.baedeker/vendor/baedeker-library/mixin/spec.libsonnet @@ -0,0 +1,426 @@ +{ + setSudo(address): { + _genesis+: { + sudo+: { + key: address, + }, + } + }, + resetBalances: { + _genesis+: { + balances+: { + balances: [], + }, + }, + }, + giveBalance(address, amount): { + _genesis+: { + balances+: { + balances+: [ + [address, amount], + ], + }, + }, + }, + setParaId(id): function(prev) prev { + _genesis+: { + parachainInfo+: { parachainId: id }, + }, + // COMPAT: cumulus template + [if 'para_id' in prev then 'para_id']: id, + // COMPAT: some chains use camelCase here + [if 'paraId' in prev then 'paraId']: id, + }, + resetSessionKeys: { + _genesis+: { + session+: { + keys: [], + }, + } + }, + addSessionKey(key): { + _genesis+: { + session+: { + keys+: [key], + }, + }, + }, + resetAuraKeys: { + _genesis+: { + aura+: { + authorities: [], + }, + }, + }, + addAuraKey(key): { + _genesis+: { + aura+: { + authorities+: [key], + }, + }, + }, + resetCollatorSelectionInvulnerables: { + _genesis+: { + collatorSelection+: { + invulnerables: [], + }, + } + }, + addCollatorSelectionInvulnerable(key): { + _genesis+: { + collatorSelection+: { + invulnerables+: [key], + }, + }, + }, + resetParachainStakingCandidates: { + _genesis+: { + parachainStaking+: { + candidates: [], + }, + }, + }, + addParachainStakingCandidate(key): { + _genesis+: { + parachainStaking+: { + candidates+: [key], + }, + }, + }, + resetStakingInvulnerables: { + _genesis+: { + staking+: { + invulnerables: [], + }, + }, + }, + addStakingInvulnerable(key): { + _genesis+: { + staking+: { + invulnerables+: [key], + }, + }, + }, + resetStakingStakers: { + _genesis+: { + staking+: { + stakers: [], + }, + }, + }, + addStakingStaker(key): { + _genesis+: { + staking+: { + stakers+: [key], + }, + }, + }, + setStakingValidatorCount(count): { + _genesis+: { + staking+: { + validatorCount: count, + }, + }, + }, + resetAuthorMappingMappings: { + _genesis+: { + authorMapping+: { + mappings: [], + }, + }, + }, + addAuthorMappingMapping(key): { + _genesis+: { + authorMapping+: { + mappings+: [key], + }, + }, + }, + resetParas: { + _genesis+: { + paras+: { + paras: [], + }, + }, + }, + addPara(para_id, head, wasm, parachain = true): { + _genesis+: { + paras+: { + paras+: [[ + para_id, + { + genesis_head: head, + validation_code: wasm, + parachain: parachain, + }, + ]], + }, + }, + }, + + resetHrmps: { + _genesis+: { + hrmp+: { + preopenHrmpChannels: [], + }, + }, + }, + openHrmp(sender, receiver, maxCapacity, maxMessageSize): { + _genesis+: { + hrmp+: { + preopenHrmpChannels+: [ + [sender, receiver, maxCapacity, maxMessageSize], + ], + }, + }, + }, + + resetNetworking(root): { + assert !(super?._networkingWasReset ?? false): 'network should not be reset twice', + + bootNodes: [ + '/dns/%s/tcp/30333/p2p/%s' % [node.hostname, node.nodeIdentity], + for [?, node] in root.nodes + ], + chainType: 'Live', + telemetryEndpoints: [], + codeSubstitutes: {}, + + // COMPAT: cumulus template + // In baedeker, relay chain config is passed explicitly, rendering this argument to not being used + [if 'relay_chain' in root then 'relay_chain']: 'not_used', + // COMPAT: some chains use camelCase here + [if 'relayChain' in root then 'relayChain']: 'not_used', + + _networkingWasReset:: true, + }, + + simplifyGenesisName(): function(prev) + local genesisKind = if 'runtimeGenesis' in prev.genesis then 'sane-1.5-runtimeGenesis' else if 'runtime_genesis_config' in prev.genesis.runtime then 'rococo' else 'sane'; + prev { + _genesisKind: genesisKind, + } + + if genesisKind == 'rococo' then { + _genesis::: prev.genesis.runtime.runtime_genesis_config + {system+: {code: '0x42424242'}}, + _code::: prev.genesis.runtime.runtime_genesis_config.system.code, + genesis+: { + runtime+: { + runtime_genesis_config:: error 'unsimplify genesis name first', + }, + }, + } else if genesisKind == 'sane' then { + _genesis::: prev.genesis.runtime + {system+: {code: '0x42424242'}}, + _code::: prev.genesis.runtime.system.code, + genesis+: { + runtime:: error 'unsimplify genesis name first', + }, + } else if genesisKind == 'sane-1.5-runtimeGenesis' then { + _runtimeGenesisKind::: if 'config' in prev.genesis.runtimeGenesis then 'config' else 'patch', + _genesis::: prev.genesis.runtimeGenesis[self._runtimeGenesisKind] + {system+: {code: '0x42424242'}}, + _code::: prev.genesis.runtimeGenesis?.code, + genesis+: { + runtimeGenesis:: error 'unsimplify genesis name first', + }, + }, + + unsimplifyGenesisName(): function(prev) + prev { + _runtimeGenesisKind:: error 'simplify genesis name first', + _genesis:: error 'simplify genesis name first', + _code:: error 'simplify genesis name first', + _genesisKind:: error 'genesis was resimplified', + } + + if prev?._genesisKind == 'rococo' then assert prev._genesis.system.code == '0x42424242' : 'use _code for overriding code!'; { + genesis+: { + runtime+: { + runtime_genesis_config::: prev._genesis + { + system+: { + code: prev._code, + }, + }, + }, + }, + } else if prev?._genesisKind == 'sane' then assert prev._genesis.system.code == '0x42424242' : 'use _code for overriding code!'; { + genesis+: { + runtime::: prev._genesis + { + system+: { + code: prev._code, + }, + }, + }, + } else if prev?._genesisKind == 'sane-1.5-runtimeGenesis' then assert prev._genesis.system.code == '0x42424242' : 'use _code for overriding code!'; { + genesis+: { + runtimeGenesis::: { + code: prev._code, + [prev._runtimeGenesisKind]: prev._genesis + { + system+: { + code:: error 'use _code for overriding code!', + }, + }, + }, + }, + } else error 'unknown genesis kind: %s' % [prev._genesis], + + // FIXME: Merge polkaLaunchRelay and polkaLaunchPara? + // Due to refactoring, pararelays are somewhat supported. + + polkaLaunchShared(root): local + isEth = root.signatureSchema == 'Ethereum', + // FIXME: support soft derivations in ecdsaSeed, then unhardcode private keys here. + // Soft derivations here are + // Alith: m/44'/60'/0'/0/0 + // Baltathar: m/44'/60'/0'/0/1 + // Root mnemonic for both is standard substrate "bottom drive obey lake curtain smoke basket hold race lonely fit walk", which is implied by *Seed functions + + // Alice/Alith + accountA = if !isEth then root.addressSeed('//Alice') else '0xf24FF3a9CF04c71Dbc94D0b566f7A27B94566cac', + // Bob/Baltathar + accountB = if !isEth then root.addressSeed('//Bob') else '0x3Cd0A705a2DC65e5b1E1205896BaA2be8A07c6e0', + // Charlie/Charleth + accountC = if !isEth then root.addressSeed('//Charlie') else '0x798d4Ba9baf0064Ec19eB4F0a1a45785ae9D6DFc', + // Dave/Dorothy + accountD = if !isEth then root.addressSeed('//Dave') else '0x773539d4Ac0e786233D90A233654ccEE26a613D9', + // Eve/Ethan + accountE = if !isEth then root.addressSeed('//Eve') else '0xFf64d3F6efE2317EE2807d223a0Bdc4c0c49dfDB', + ; [ + function(prev) if 'sudo' in prev._genesis then bdk.mixer([ + $.setSudo(accountA), + ])(prev) else prev, + $.resetBalances, + $.giveBalance(accountA, 2000000000000000000000000000000), + $.giveBalance(accountB, 2000000000000000000000000000000), + $.giveBalance(accountC, 2000000000000000000000000000000), + $.giveBalance(accountD, 2000000000000000000000000000000), + $.giveBalance(accountE, 2000000000000000000000000000000), + // Regardless of validator id assignment, every method (staking/collator-selection/etc) wants stash to have some + // money. + [ + $.giveBalance(node.wallets.stash, 2000000000000000000000000000000), + for [?, node] in root.nodes + ], + // pallet-session manages pallet-aura/pallet-grandpa, if there is no pallet-session: authority should be set directly for aura. + // pallet-aura also should not have keys, if there keys are specified using pallet-aura. + function(prev) bdk.mixer([ + if 'session' in prev._genesis then $.resetSessionKeys, + if 'aura' in prev._genesis then $.resetAuraKeys, + ])(prev), + function(prev) bdk.mixer(if 'session' in prev._genesis then [ + $.addSessionKey([ + // Account id + if root.validatorIdAssignment == 'staking' then node.wallets.controller + else node.wallets.stash, + // Validator id + node.wallets.stash, + local k = node.keys; { + [name]: k[key] + for [name, key] in node.wantedKeys.sessionKeys + }, + ]) + for [?, node] in root.nodes + ] else if 'aura' in prev._genesis then [ + $.addAuraKey(node.keys.aura) + for [?, node] in root.nodes + ] else [])(prev), + ], + + // Alter spec in the same way as polkadot-launch does this, in most cases this should + // be everything needed to start working node + polkaLaunchRelay(root, hrmp = []): $.polkaLaunchShared(root) + [ + function(prev) if 'staking' in prev._genesis then bdk.mixer([ + $.resetStakingInvulnerables, + $.resetStakingStakers, + [ + [ + $.addStakingInvulnerable(node.wallets.stash), + $.addStakingStaker([ + node.wallets.stash, + node.wallets.controller, + 100000000000000, + 'Validator', + ]), + ], + for [?, node] in root.nodes + ], + $.setStakingValidatorCount(std.length(root.nodes)), + ])(prev) else prev, + function(prev) bdk.mixer([ + [ + $.resetParas, + ], + [ + // FIXME: Also bump parachainRegistrar last id if para_id >= 2000? + $.addPara(para.paraId, para.genesisHead, para.genesisWasm), + for [paraname, para] in root.parachains + ], + ])(prev), + function(prev) bdk.mixer([ + [ + $.resetHrmps, + ], + [ + $.openHrmp(ch[0], ch[1], ch[2], ch[3]), + for ch in hrmp + ], + ])(prev), + function(prev) if 'configuration' in prev._genesis then local + prevConfig = prev?._genesis.configuration?.config ?? {}, + ifExists(f, o) = if f in o then f; + prev { + _genesis+: { + configuration+: { + config+: { + hrmp_max_parachain_outbound_channels: 20, + [ifExists('hrmp_max_parathread_outbound_channels', prevConfig)]: 20, + hrmp_max_parachain_inbound_channels: 20, + [ifExists('hrmp_max_parathread_inbound_channels', prevConfig)]: 20, + [ifExists('pvf_checking_enabled', prevConfig)]: true, + max_validators: 300, + max_validators_per_core: 20, + scheduling_lookahead: 1, + }, + }, + }, + } else prev, + // function(prev) std.trace(prev), + ], + polkaLaunchPara(root): $.polkaLaunchShared(root) + [ + function(prev) if 'collatorSelection' in prev._genesis then bdk.mixer([ + $.resetCollatorSelectionInvulnerables, + [ + $.addCollatorSelectionInvulnerable(node.wallets.stash), + for [?, node] in root.nodes + ], + ])(prev) else prev, + + $.setParaId(root.paraId), + // COMPAT: moonbeam + function(prev) if 'parachainStaking' in prev._genesis then bdk.mixer([ + $.resetParachainStakingCandidates, + [ + $.addParachainStakingCandidate([node.wallets.stash, 10000000000000000000000000]), + for [?, node] in root.nodes + ], + ])(prev) else prev, + // COMPAT: moonbeam + function(prev) if 'authorMapping' in prev._genesis then bdk.mixer([ + $.resetAuthorMappingMappings, + [ + $.addAuthorMappingMapping([node.keys?.aura ?? node.keys.nmbs, node.wallets.stash]), + for [?, node] in root.nodes + ], + ])(prev) else prev, + ], + + genericRelay(root, hrmp = []): bdk.mixer([ + $.resetNetworking(root), + $.simplifyGenesisName(), + $.polkaLaunchRelay(root, hrmp), + $.unsimplifyGenesisName(), + ]), + genericPara(root): bdk.mixer([ + $.resetNetworking(root), + $.simplifyGenesisName(), + $.polkaLaunchPara(root), + $.unsimplifyGenesisName(), + ]), +} diff --git a/.baedeker/vendor/baedeker-library/ops/debug.ejs b/.baedeker/vendor/baedeker-library/ops/debug.ejs new file mode 100644 index 000000000..288131ff8 --- /dev/null +++ b/.baedeker/vendor/baedeker-library/ops/debug.ejs @@ -0,0 +1,30 @@ + + + + + Baedeker devtools + + + + + +
+ + + diff --git a/.baedeker/vendor/baedeker-library/ops/devtools.libsonnet b/.baedeker/vendor/baedeker-library/ops/devtools.libsonnet new file mode 100644 index 000000000..f7b1fe4eb --- /dev/null +++ b/.baedeker/vendor/baedeker-library/ops/devtools.libsonnet @@ -0,0 +1,30 @@ +local {flattenChains, flattenNodes, ...} = import '../util/mixin.libsonnet'; + +function(prev) prev { + _output+: { + dockerCompose+: { + _nginxLocations+:: [ + 'location /apps/ { proxy_pass http://polkadot-apps/; }', + ], + _nginxDependencies+:: ['polkadot-apps'], + _composeConfig+:: { + services+: { + 'polkadot-apps': { + // TODO: We can provide custom endpoint list to this container using ENV. But changes to this file are needed. + // https://github.com/polkadot-js/apps/blob/0366991f685a80147f46eb69a23285acb15bc6b7/packages/apps-config/src/endpoints/development.ts#L19 + image: 'jacogr/polkadot-js-apps:latest@sha256:b052771165a82833f68b569a74a198b09d8e1d0cce097e804cf60bc06a4faf7b', + }, + }, + }, + // Yep, sorry for this + 'ops/index.html': std.strReplace(importstr './debug.ejs', 'DATA_JSON', std.manifestJson({ + chains: [ + { + path: chain.path, + }, + for chain in flattenChains(prev) + ], + })), + }, + }, +} diff --git a/.baedeker/vendor/baedeker-library/ops/nginx-dev.libsonnet b/.baedeker/vendor/baedeker-library/ops/nginx-dev.libsonnet new file mode 100644 index 000000000..47326c11b --- /dev/null +++ b/.baedeker/vendor/baedeker-library/ops/nginx-dev.libsonnet @@ -0,0 +1,19 @@ + +local nginx = import './nginx.libsonnet'; + +function(prev, nginxExposePort = 9699, nginxExposeHost = '127.0.0.1') nginx(prev) { + _output+: { + dockerCompose+: { + _wellKnownBalancerUrl:: '%s:%d' % [nginxExposeHost, nginxExposePort], + _composeConfig+: { + services+: { + nginx+: { + ports+: [ + '%s:%d:80' % [nginxExposeHost, nginxExposePort] + ], + }, + }, + }, + }, + }, +} diff --git a/.baedeker/vendor/baedeker-library/ops/nginx.libsonnet b/.baedeker/vendor/baedeker-library/ops/nginx.libsonnet new file mode 100644 index 000000000..7d0d4b396 --- /dev/null +++ b/.baedeker/vendor/baedeker-library/ops/nginx.libsonnet @@ -0,0 +1,98 @@ +local {flattenChains, flattenNodes, ...} = import '../util/mixin.libsonnet'; + +function(prev) + +prev { + _output+: { + dockerCompose+: { + local locations = self._nginxLocations, + local dependencies = self._nginxDependencies, + local composeFiles = self, + _nginxDependencies+:: [ + node.hostname + for node in flattenNodes(prev) + ], + _nginxLocations+:: [ + local shared = { + name: chain.path, + }; + std.join('\n', [ + 'location /%(name)s/ { try_files /nonexistent @%(name)s-$http_upgrade; }' % shared, + 'location @%(name)s-websocket {' % shared, + '\tproxy_pass http://%(name)s-websocket;' % shared, + '\tproxy_http_version 1.1;', + '\tproxy_set_header Upgrade "websocket";', + '\tproxy_set_header Connection "upgrade";', + '}', + 'location @%(name)s- {' % shared, + '\tproxy_pass http://%(name)s-http;' % shared, + '}', + ]), + for chain in flattenChains(prev) + ], + local configStr = std.join('\n\n', [ + local shared = { + name: chain.path, + }; + std.join('\n', [ + 'upstream %(name)s-websocket {' % shared, + '\tip_hash;', + std.join('\n', [ + '\tserver %s:9944;' % node.hostname + for [?, node] in (chain?.nodes ?? {}) + ]), + '}', + 'upstream %(name)s-http {' % shared, + '\tip_hash;', + std.join('\n', [ + '\tserver %s:9944;' % node.hostname + for [?, node] in (chain?.nodes ?? {}) + if !(node?.legacyRpc ?? false) + ] + [ + '\tserver %s:9933;' % node.hostname + for [?, node] in (chain?.nodes ?? {}) + if (node?.legacyRpc ?? false) + ]), + '}', + ]), + for chain in flattenChains(prev) + ] + ['server {', 'listen 80;', 'add_header Access-Control-Allow-Origin *;'] + [ + std.join('\n', locations), + ] + ['}']), + 'ops/nginx.conf': configStr, + _composeConfig+:: { + services+: { + nginx: { + image: 'nginx:latest@sha256:48a84a0728cab8ac558f48796f901f6d31d287101bc8b317683678125e0d2d35', + volumes+: [ + { + type: 'bind', + source: 'ops/nginx.conf', + target: '/etc/nginx/conf.d/default.conf', + read_only: true, + }, + // Introduce arbitrary dependency on config hash to force container restart when it changes + { + type: 'bind', + source: 'ops/nginx.conf', + target: '/config/%s%s' % [ + std.md5(configStr), + std.md5(composeFiles?.['ops/index.html'] ?? ''), + ], + read_only: true, + }, + ] + (if 'ops/index.html' in composeFiles then [ + { + type: 'bind', + source: 'ops/index.html', + target: '/etc/nginx/html/index.html', + read_only: true, + }, + ] else []), + depends_on: dependencies, + }, + }, + }, + }, + }, +} diff --git a/.baedeker/vendor/baedeker-library/ops/rewrites.libsonnet b/.baedeker/vendor/baedeker-library/ops/rewrites.libsonnet new file mode 100644 index 000000000..64c784d8f --- /dev/null +++ b/.baedeker/vendor/baedeker-library/ops/rewrites.libsonnet @@ -0,0 +1,13 @@ +local {mixinRolloutNodes, ...} = import '../util/mixin.libsonnet'; + +{ + rewriteNodePaths(paths, for_nodes = true, for_chain = true, percent = 1, leave = null, extra_node_mixin = {}, extra_chain_mixin = {}): + local mkBin(obj, node) = if 'bin' in obj && std.isString(obj.bin) && obj.bin in paths then ({ + bin: paths[obj.bin], + } + if node then extra_node_mixin else extra_chain_mixin) else {}; + function(prev) prev + mixinRolloutNodes(prev, + function(node) if for_nodes then mkBin(node, true) else {}, + function(chain) if for_chain then mkBin(chain, false) else {}, + percent = percent, leave = leave + ) +} diff --git a/.baedeker/vendor/baedeker-library/outputs/addressbook.libsonnet b/.baedeker/vendor/baedeker-library/outputs/addressbook.libsonnet new file mode 100644 index 000000000..55205b9ca --- /dev/null +++ b/.baedeker/vendor/baedeker-library/outputs/addressbook.libsonnet @@ -0,0 +1,28 @@ +local {flattenNodes, ...} = import '../util/mixin.libsonnet'; + +function(prev) { + _output+: { + addressbook: 'Copy the following snippet to browser console on polkadot apps:\n' + std.join('\n', [ + '', + '// Optional: do not execute if you have something important saved in polkadot apps!', + '// localStorage.clear();' + ] + [ + 'localStorage["address:%s"] = JSON.stringify(%s);' % [cql.ss58(wallet), { + address: wallet, + meta: { + name: "%s (%s)" % [node.hostname, walletname] + }, + }], + for node in flattenNodes(prev) + for [walletname, wallet] in ([ + [walletname, wallet] + for [walletname, wallet] in node.wallets + if walletname == 'stash' + ] + [ + [walletname, wallet] + for [walletname, wallet] in node.keys + if walletname == 'aura' || walletname == 'babe' + ]) + ]), + }, +} diff --git a/.baedeker/vendor/baedeker-library/outputs/compose.libsonnet b/.baedeker/vendor/baedeker-library/outputs/compose.libsonnet new file mode 100644 index 000000000..6a1c60509 --- /dev/null +++ b/.baedeker/vendor/baedeker-library/outputs/compose.libsonnet @@ -0,0 +1,177 @@ +local {flattenChains, flattenNodes, ...} = import '../util/mixin.libsonnet'; + +function(prev, final) + +local v = { + bind(source, target, read_only = true): { + type: 'bind', + source: source, + target: target, + read_only: read_only, + }, + volume(name, target, nocopy = true): { + type: 'volume', + source: name, + target: target, + volume: { + nocopy: nocopy, + }, + }, + tmpfs(target): { + type: 'tmpfs', + target: target, + }, +}; + +local +hostMounts = bdk.dockerMounts(), +hostVolumes = [ + v.tmpfs('/tmp'), +] + [ + v.bind('/%s' % path, '/%s' % path), + for path in hostMounts +]; + +local binToObj(bin, config) = +if std.isString(bin) then { + image: config.emptyImage, + entrypoint: bin, + dockerBased:: false, + volumes: hostVolumes, +} else if 'dockerImage' in bin then { + image: bin.dockerImage, + [if 'docker' in bin then 'entrypoint']: bin.docker, + dockerBased:: true, +} else { + image: config.emptyImage, + entrypoint: bin['local'], + dockerBased:: false, + volumes: hostVolumes, +}; + +local WELLKNOWN_CODE = '0x3a636f6465'; +local metadataFromKeys(keys) = cql.runtimeWasm(keys[WELLKNOWN_CODE]).metadata; + +// TODO: Show diff +local diffRaw(old, new) = local +oldKeys = std.objectFields(old), newKeys = std.objectFields(new), +oldMetadata = metadataFromKeys(old), newMetadata = metadataFromKeys(new), +fancyDump(meta, data) = std.manifestJson(cql.dump(meta, data, {omit_empty: true, include_defaults: false})), +; +'removed data:\n' + +fancyDump(oldMetadata, { + [key]: old[key], + for key in std.setDiff(oldKeys, newKeys) +}) + +'\n\nadded data:\n' + +fancyDump(newMetadata, { + [key]: new[key], + for key in std.setDiff(newKeys, oldKeys) +}) + +'\n\nupdated, old:\n' + +fancyDump(oldMetadata, { + [key]: old[key], + for key in std.setInter(oldKeys, newKeys) + if old[key] != new[key] +}) + +'\n\nupdated, new:\n' + +fancyDump(newMetadata, { + [key]: new[key], + for key in std.setInter(oldKeys, newKeys) + if old[key] != new[key] +}); + +local assertEqualSpecsReconciler(_old, _new) = local old = std.parseJson(_old), new = std.parseJson(_new); +if old.genesis.raw.top != new.genesis.raw.top then error 'reconcilation disabled, and genesis is not equal:\n' + diffRaw(old.genesis.raw.top, new.genesis.raw.top) else _new; + +{ + _output:: { + dockerCompose+: { + _config+:: { + emptyImage: error 'missing empty image', + outputRoot: error 'missing output root', + }, + }, + }, +} + prev + { + _output+: { + dockerCompose+: { + ['specs/%s.json' % chain.path]: std.manifestJsonEx(chain.specJson, ' ', preserve_order = true) + '\n', + for chain in flattenChains(final) + } + { + ['reconcile_specs/%s.json' % chain.path]:: assertEqualSpecsReconciler, + for chain in flattenChains(final) + } + { + local config = self._config, + _composeConfig+:: { + version: '3.4', + services+: { + [node.hostname]: binToObj(node.bin, config) + { + command: [ + '--name=%s' % node.hostname, + '--validator', + '--base-path=/chaindata', + '--chain=/chain-spec.json', + '--keystore-path=/keystore', + '--node-key-file=/node-key', + '--no-mdns', + // Removed in new versions of substrate, will not escape docker host network anyways + // '--no-private-ipv4', + '--detailed-log-output', + '--execution=wasm', + '--unsafe-rpc-external', + '--rpc-cors=all', + ] + (if node?.legacyRpc ?? false then [ + '--rpc-port=9933', + '--ws-port=9944', + '--unsafe-ws-external', + ] else [ + '--rpc-port=9944', + ]) + (node?.extraArgs ?? []) + (if node._parentChain != null /*&& node.parentConnection == "internal"*/ then ([ + '--', + '--base-path=/chaindata-parent', + '--chain=/chain-spec-parent.json', + '--execution=wasm', + ] + (if node?.legacyRpc ?? false then [ + '--rpc-port=9833', + '--ws-port=9844', + ] else [ + '--rpc-port=9844' + ]) + (node?.extraArgsInternalParent ?? [])) else []), + [if 'rpcPort' in node || 'extraPorts' in node then 'ports']: (if 'rpcPort' in node then [ + '%s:9944' % node.rpcPort, + ] else []) + (node?.extraPorts ?? []), + // TODO: nocopy may cause problems if this directory is already used in container, + // but it is also helps with containers, which are run by unprivileged account. + // Should there be init container, which issues correct chown+chmod? + volumes+: [ + v.bind(bdk.toRelative(config.outputRoot, node.localKeystoreDir), '/keystore'), + v.bind(bdk.toRelative(config.outputRoot, node.localNodeFile), '/node-key'), + v.bind('specs/%s.json' % node._chain.path, '/chain-spec.json'), + v.volume('chaindata-%s' % node.hostname, '/chaindata', nocopy = false), + ] + (if node._parentChain != null /*&& node.parentConnection == "internal"*/ then [ + v.bind('specs/%s.json' % node._parentChain.path, '/chain-spec-parent.json'), + v.volume('chaindata-%s-parent' % node.hostname, '/chaindata-parent', nocopy = false), + ] else []), + } + (node?.extraCompose ?? {}), + for node in flattenNodes(final) + }, + networks: { + chainnet: { + driver: 'bridge', + }, + }, + volumes: { + ['chaindata-%s' % node.hostname]: null, + for node in flattenNodes(final) + } + { + ['chaindata-%s-parent' % node.hostname]: null, + for node in flattenNodes(final) + if node._parentChain != null + // if node.parentConnection == "internal" + }, + }, + 'docker-compose.yml': std.manifestYamlDoc(self._composeConfig, quote_keys = false, preserve_order = true) + '\n', + }, + }, +} diff --git a/.baedeker/vendor/baedeker-library/outputs/composediscover.libsonnet b/.baedeker/vendor/baedeker-library/outputs/composediscover.libsonnet new file mode 100644 index 000000000..a9197a827 --- /dev/null +++ b/.baedeker/vendor/baedeker-library/outputs/composediscover.libsonnet @@ -0,0 +1,30 @@ +local {flattenNodes, flattenChains, ...} = import '../util/mixin.libsonnet'; + +function(prev, final) +prev + { + _output+:: { + dockerCompose+: { + _wellKnownBalancerUrl:: super?._wellKnownBalancerUrl ?? 'BALANCER_URL', + }, + dockerComposeDiscover+: local + balancerUrl = final._output.dockerCompose._wellKnownBalancerUrl, + ; std.join('\n', [ + 'BDK_BALANCER=http://%s/' % balancerUrl, + ] + [ + '%s_ID=%i' % [std.strReplace(std.asciiUpper(chain.path), '-', '_'), chain.paraId] + for chain in flattenChains(prev) + if 'paraId' in chain + ] + [ + '%s_HTTP_URL=http://%s/%s/' % [std.strReplace(std.asciiUpper(chain.path), '-', '_'), balancerUrl, chain.path] + for chain in flattenChains(prev) + ] + [ + '%s_URL=ws://%s/%s/' % [std.strReplace(std.asciiUpper(chain.path), '-', '_'), balancerUrl, chain.path] + for chain in flattenChains(prev) + ] + [ + '%s_STASH=%s' % [std.strReplace(std.asciiUpper(node.hostname), '-', '_'), node.wallets.stash] + for chain in flattenChains(prev) + if 'paraId' in chain + for node in flattenNodes(chain) + ] + ['']), + }, +} diff --git a/.baedeker/vendor/baedeker-library/outputs/debug.libsonnet b/.baedeker/vendor/baedeker-library/outputs/debug.libsonnet new file mode 100644 index 000000000..d96316003 --- /dev/null +++ b/.baedeker/vendor/baedeker-library/outputs/debug.libsonnet @@ -0,0 +1,7 @@ +function(prev) + +prev + { + _output+:: { + debug: prev, + }, +} diff --git a/.baedeker/vendor/baedeker-library/util/genesisState.libsonnet b/.baedeker/vendor/baedeker-library/util/genesisState.libsonnet new file mode 100644 index 000000000..06d244bd9 --- /dev/null +++ b/.baedeker/vendor/baedeker-library/util/genesisState.libsonnet @@ -0,0 +1,51 @@ +// Implementation of export-genesis-state in jsonnet, exports genesis head in format suitable for polkadot. +local t = import './meta.libsonnet'; + +// Basic header definition, only things required for genesis state building are included. +local types = t.metadata({ + // Although hash/block number is generic, all substrate chains use blake2_256 for hash, and u32 for number. + // Currently, there is no way to query such metadata from the chain, and using other types are not feasible, + // as u32 block number is enough for 136 years of block production, assuming 1 block per second. + header: t.s({ + parent_hash: $.hash, + number: $.number, + state_root: $.hash, + extrinsic_root: $.hash, + digest: $.digest, + }), + + digest: t.s({ + logs: $.vecstub, + }), + vecu8: t.v($.u8), + hash: t.a($.u8, 32), + number: t.c($.u32), + + u8: t.p('u8'), + u32: t.p('u32'), + + // It is impossible to initialize stub type, as it is recursive with no way to stop recursion. + vecstub: t.v($.stub), + stub: t.s({ + __doNotTryToInitialize__: $.stub, + // chainql automatically unwraps newtype structs, this field will make stub struct not newtype. + _: $.stub, + }), +}); + +local storageRoot(storage, stateVersion) = + cql.blake2_256Root(storage.top + { + [key]: cql.blake2_256Root(tree, stateVersion), + for [key, tree] in storage.childrenDefault + }, stateVersion); + +function(spec, stateVersion) +assert spec.genesis.raw != {}: 'not a raw spec!'; + +types._encode(0, { + parent_hash: '0x' + '00' * 32, + number: 0, + state_root: storageRoot(spec.genesis.raw, stateVersion), + extrinsic_root: cql.blake2_256Root({}, stateVersion), + digest: [], +}) diff --git a/.baedeker/vendor/baedeker-library/util/grandpaKeys.libsonnet b/.baedeker/vendor/baedeker-library/util/grandpaKeys.libsonnet new file mode 100644 index 000000000..d657142ea --- /dev/null +++ b/.baedeker/vendor/baedeker-library/util/grandpaKeys.libsonnet @@ -0,0 +1,24 @@ +local t = import './meta.libsonnet'; + +local types = t.metadata({ + keys: t.s({ + unused: $.u8, + list: $.authorityList, + }), + authorityList: t.v($.authority), + authorityId: t.a($.u8, 32), + authority: t.s({ + id: $.authorityId, + weight: $.u64, + }), + + u8: t.p('u8'), + u64: t.p('u64'), +}); + +{ + encodeGrandpaKeys(keys): types._encode(0, std.trace({ + unused: 1, + list: [{id: cql.ss58(key), weight: '1'} for key in keys], + })), +} diff --git a/.baedeker/vendor/baedeker-library/util/meta.libsonnet b/.baedeker/vendor/baedeker-library/util/meta.libsonnet new file mode 100644 index 000000000..52d08084a --- /dev/null +++ b/.baedeker/vendor/baedeker-library/util/meta.libsonnet @@ -0,0 +1,51 @@ +// json-encoded (chainql-flavored) runtime metadata builder + +local def(t, v) = { + type: { + def: { + [t]: v, + }, + }, +}; + +{ + types(o): std.objectValues(o + { + [name]+: {id: id}, + for [id, name] in std.mapWithIndex(function(i, v) [i, v], std.objectFieldsEx(o, false, preserve_order = true)) + }), + metadata(o): cql.dump({ + types: { + types: $.types(o), + }, + pallets: [], + // Required, but shouldn't be used by callers + extrinsic: {ty: 0, version: 0, signed_extensions: []}, + ty: 0, + }, {}), + + // Primitive type + p(n): def('primitive', n), + // Vec + v(t): def('sequence', { + type: t.id, + }), + // struct, with value types specified in f + s(f): def('composite', { + fields: [ + { + name: key, + type: value.id, + }, + for {key, value} in std.objectKeysValues(f, preserve_order = true) + ], + }), + // [t; s] + a(t, s): def('array', { + len: s, + type: t.id, + }), + // Compact + c(t): def('compact', { + type: t.id, + }), +} diff --git a/.baedeker/vendor/baedeker-library/util/mixin.libsonnet b/.baedeker/vendor/baedeker-library/util/mixin.libsonnet new file mode 100644 index 000000000..66d38b5ef --- /dev/null +++ b/.baedeker/vendor/baedeker-library/util/mixin.libsonnet @@ -0,0 +1,41 @@ +{ + mixinAllChains(chain, mixin, path = chain?.name ?? 'relay'): mixin(chain, path = path) + { + parachains+: { + [paraname]+: $.mixinAllChains(para, mixin, path = "%s-%s" % [path, paraname]) + for [paraname, para] in (chain?.parachains ?? {}) + }, + }, + mixinAllNodes(chain, mixin, mixinChain = function(v) {}): $.mixinAllChains(chain, function(chain, path) { + nodes+: { + [nodename]+: mixin(node), + for [nodename, node] in chain?.nodes + }, + } + mixinChain(chain)), + mixinRolloutNodes(chain, mixin, mixinChain = function(v) {}, percent = 1, leave = null): $.mixinAllChains(chain, function(chain, path) { + nodes+: local length = std.length(chain?.nodes ?? {}); { + [nodename]+: if ((i + 1) / length <= percent) && (leave == null || i < length - leave) then mixin(node) + else {} + for [i, {key: nodename, value: node}] in std.mapWithIndex(function(i, v) [i, v], std.objectKeysValues(chain?.nodes)) + }, + } + mixinChain(chain)), + flattenNodes(chain, parent = null): std.join([], [ + [ + node + { + _chain:: chain, + _parentChain:: parent, + }, + for [?, node] in (chain?.nodes ?? {}) + ], + ] + [ + $.flattenNodes(para, chain), + for [?, para] in (chain?.parachains ?? {}) + ]), + flattenChains(chain): std.join([], [ + [ + chain, + ], + ] + [ + $.flattenChains(para), + for [?, para] in (chain?.parachains ?? {}) + ]), +} diff --git a/.dockerignore b/.dockerignore index 6b7ebf648..34b11bd26 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,5 +1,7 @@ .devcontainer .github +.git +.baedeker .vscode !scripts/init.sh target \ No newline at end of file diff --git a/.gitignore b/.gitignore index e02967ccd..a03d7b422 100644 --- a/.gitignore +++ b/.gitignore @@ -37,4 +37,12 @@ specs/*.json .vscode # IntelliJ IDEA configuration -.idea \ No newline at end of file +.idea + +# Baedeker output directory +.baedeker/.bdk-env + +alice.log +bob.log +charlie.log +scripts/specs \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index d5fc4c0ba..0bc9cba69 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,16 +18,7 @@ version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" dependencies = [ - "gimli 0.27.3", -] - -[[package]] -name = "addr2line" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" -dependencies = [ - "gimli 0.28.1", + "gimli 0.27.1", ] [[package]] @@ -43,7 +34,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" dependencies = [ "crypto-common", - "generic-array 0.14.7", + "generic-array 0.14.6", ] [[package]] @@ -73,11 +64,11 @@ dependencies = [ [[package]] name = "ahash" -version = "0.7.8" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ - "getrandom 0.2.14", + "getrandom 0.2.15", "once_cell", "version_check", ] @@ -89,7 +80,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", - "getrandom 0.2.14", + "getrandom 0.2.15", "once_cell", "version_check", "zerocopy", @@ -97,9 +88,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.3" +version = "0.7.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" dependencies = [ "memchr", ] @@ -136,47 +127,48 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.13" +version = "0.6.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" [[package]] name = "anstyle-parse" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.2" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" dependencies = [ "anstyle", "windows-sys 0.52.0", @@ -184,9 +176,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.81" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" +checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" [[package]] name = "approx" @@ -208,7 +200,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 1.0.109", + "syn 1.0.107", ] [[package]] @@ -222,7 +214,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -394,7 +386,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" dependencies = [ "quote", - "syn 1.0.109", + "syn 1.0.107", ] [[package]] @@ -407,7 +399,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 1.0.109", + "syn 1.0.107", ] [[package]] @@ -485,7 +477,7 @@ checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 1.0.107", ] [[package]] @@ -538,9 +530,9 @@ checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "asn1-rs" -version = "0.5.2" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6fd5ddaf0351dff5b8da21b2fb4ff8e08ddd02857f0bf69c47639106c0fff0" +checksum = "cf6690c370453db30743b373a60ba498fc0d6d83b11f4abfd87a84a075db5dd4" dependencies = [ "asn1-rs-derive", "asn1-rs-impl", @@ -560,7 +552,7 @@ checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 1.0.107", "synstructure", ] @@ -572,7 +564,7 @@ checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 1.0.107", ] [[package]] @@ -582,56 +574,56 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" dependencies = [ "concurrent-queue", - "event-listener 2.5.3", + "event-listener", "futures-core", ] [[package]] name = "async-io" -version = "2.3.2" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcccb0f599cfa2f8ace422d3555572f47424da5648a4382a9dd0310ff8210884" +checksum = "8c374dda1ed3e7d8f0d9ba58715f924862c63eae6849c92d3a18e7fbde9e2794" dependencies = [ "async-lock", - "cfg-if", + "autocfg", "concurrent-queue", - "futures-io", "futures-lite", + "libc", + "log", "parking", "polling", - "rustix 0.38.32", "slab", - "tracing", - "windows-sys 0.52.0", + "socket2 0.4.7", + "waker-fn", + "windows-sys 0.42.0", ] [[package]] name = "async-lock" -version = "3.3.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" +checksum = "c8101efe8695a6c17e02911402145357e718ac92d3ff88ae8419e84b1707b685" dependencies = [ - "event-listener 4.0.3", - "event-listener-strategy", - "pin-project-lite 0.2.14", + "event-listener", + "futures-lite", ] [[package]] name = "async-trait" -version = "0.1.79" +version = "0.1.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" +checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] name = "asynchronous-codec" -version = "0.6.2" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4057f2c32adbb2fc158e22fb38433c8e9bbf76b75a4732c7c0cbaf695fb65568" +checksum = "06a0daa378f5fd10634e44b0a29b2a87b890657658e072a30d6f26e57ddee182" dependencies = [ "bytes", "futures-sink", @@ -642,22 +634,22 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.2.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" -version = "0.3.71" +version = "0.3.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" dependencies = [ - "addr2line 0.21.0", + "addr2line", "cc", "cfg-if", "libc", "miniz_oxide", - "object 0.32.2", + "object 0.30.3", "rustc-demangle", ] @@ -704,15 +696,15 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.7" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" [[package]] name = "base64ct" -version = "1.6.0" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf" [[package]] name = "beef" @@ -744,13 +736,13 @@ dependencies = [ "lazy_static", "lazycell", "peeking_take_while", - "prettyplease 0.2.17", + "prettyplease 0.2.20", "proc-macro2", "quote", "regex", "rustc-hash", "shlex", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -822,31 +814,31 @@ checksum = "23285ad32269793932e830392f2fe2f83e26488fd3ec778883a93c8323735780" dependencies = [ "arrayref", "arrayvec", - "constant_time_eq", + "constant_time_eq 0.3.0", ] [[package]] name = "blake2s_simd" -version = "1.0.2" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94230421e395b9920d23df13ea5d77a20e1725331f90fbbf6df6040b33f756ae" +checksum = "db539cc2b5f6003621f1cd9ef92d7ded8ea5232c7de0f9faa2de251cd98730d4" dependencies = [ "arrayref", "arrayvec", - "constant_time_eq", + "constant_time_eq 0.1.5", ] [[package]] name = "blake3" -version = "1.5.1" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30cca6d3674597c30ddf2c587bf8d9d65c9a84d2326d941cc79c9842dfe0ef52" +checksum = "42ae2468a89544a466886840aa467a25b766499f4f04bf7d9fcd10ecee9fccef" dependencies = [ "arrayref", "arrayvec", "cc", "cfg-if", - "constant_time_eq", + "constant_time_eq 0.2.4", ] [[package]] @@ -855,16 +847,16 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "generic-array 0.14.7", + "generic-array 0.14.6", ] [[package]] name = "block-buffer" -version = "0.10.4" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" dependencies = [ - "generic-array 0.14.7", + "generic-array 0.14.6", ] [[package]] @@ -905,9 +897,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "byte-slice-cast" @@ -923,21 +915,21 @@ checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" [[package]] name = "bytemuck" -version = "1.15.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15" +checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" [[package]] name = "byteorder" -version = "1.5.0" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.6.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" [[package]] name = "bzip2-sys" @@ -962,18 +954,18 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.6" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +checksum = "c77df041dc383319cc661b428b6961a005db4d6808d5e12536931b1ca9556055" dependencies = [ "serde", ] [[package]] name = "cargo-platform" -version = "0.1.8" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" +checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27" dependencies = [ "serde", ] @@ -986,7 +978,7 @@ checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" dependencies = [ "camino", "cargo-platform", - "semver 1.0.22", + "semver 1.0.16", "serde", "serde_json", "thiserror", @@ -994,12 +986,13 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.91" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd97381a8cc6493395a5afc4c691c1084b3768db713b73aa215217aa245d153" +checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" dependencies = [ "jobserver", "libc", + "once_cell", ] [[package]] @@ -1013,9 +1006,9 @@ dependencies = [ [[package]] name = "cfg-expr" -version = "0.15.7" +version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa50868b64a9a6fda9d593ce778849ea8715cd2a3d2cc17ffdb4a2f2f2f1961d" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" dependencies = [ "smallvec", ] @@ -1068,9 +1061,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.37" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", @@ -1078,7 +1071,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -1100,7 +1093,7 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" dependencies = [ - "generic-array 0.14.7", + "generic-array 0.14.6", ] [[package]] @@ -1116,9 +1109,9 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.7.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" +checksum = "fa2e27ae6ab525c3d369ded447057bca5438d86dc3a68f6faafb8269ba82ebf3" dependencies = [ "glob", "libc", @@ -1157,7 +1150,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -1178,9 +1171,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" [[package]] name = "comfy-table" @@ -1217,9 +1210,9 @@ checksum = "2382f75942f4b3be3690fe4f86365e9c853c1587d6ee58212cebf6e2a9ccd101" [[package]] name = "concurrent-queue" -version = "2.4.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363" +checksum = "c278839b831783b70278b14df4d45e1beb1aad306c07bb796637de9a0e323e8e" dependencies = [ "crossbeam-utils", ] @@ -1239,9 +1232,9 @@ dependencies = [ [[package]] name = "const-oid" -version = "0.9.6" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" [[package]] name = "const-random" @@ -1258,11 +1251,23 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" dependencies = [ - "getrandom 0.2.14", + "getrandom 0.2.15", "once_cell", "tiny-keccak", ] +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "constant_time_eq" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3ad85c1f65dc7b37604eb0e89748faf0b9653065f2a8ef69f96a687ec1e9279" + [[package]] name = "constant_time_eq" version = "0.3.0" @@ -1283,9 +1288,9 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" [[package]] name = "core-foundation" -version = "0.9.4" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" dependencies = [ "core-foundation-sys", "libc", @@ -1293,9 +1298,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" [[package]] name = "core2" @@ -1345,7 +1350,7 @@ dependencies = [ "cranelift-codegen-shared", "cranelift-entity", "cranelift-isle", - "gimli 0.27.3", + "gimli 0.27.1", "hashbrown 0.13.2", "log", "regalloc2 0.6.1", @@ -1424,37 +1429,55 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.4.0" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + [[package]] name = "crossbeam-deque" -version = "0.8.5" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" dependencies = [ + "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.18" +version = "0.9.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" dependencies = [ + "autocfg", + "cfg-if", "crossbeam-utils", + "memoffset 0.7.1", + "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" +dependencies = [ + "cfg-if", +] [[package]] name = "crunchy" @@ -1468,7 +1491,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ - "generic-array 0.14.7", + "generic-array 0.14.6", "rand_core 0.6.4", "subtle 2.4.1", "zeroize", @@ -1480,9 +1503,9 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array 0.14.7", + "generic-array 0.14.6", "rand_core 0.6.4", - "typenum 1.17.0", + "typenum 1.16.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1501,7 +1524,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" dependencies = [ - "generic-array 0.14.7", + "generic-array 0.14.6", "subtle 2.4.1", ] @@ -1552,14 +1575,14 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] name = "cxx" -version = "1.0.120" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff4dc7287237dd438b926a81a1a5605dad33d286870e5eee2db17bf2bcd9e92a" +checksum = "bc831ee6a32dd495436e317595e639a587aa9907bef96fe6e6abc290ab6204e9" dependencies = [ "cc", "cxxbridge-flags", @@ -1569,9 +1592,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.120" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f47c6c8ad7c1a10d3ef0fe3ff6733f4db0d78f08ef0b13121543163ef327058b" +checksum = "94331d54f1b1a8895cd81049f7eaaaef9d05a7dcb4d1fd08bf3ff0806246789d" dependencies = [ "cc", "codespan-reporting", @@ -1579,31 +1602,31 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.58", + "syn 1.0.107", ] [[package]] name = "cxxbridge-flags" -version = "1.0.120" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "701a1ac7a697e249cdd8dc026d7a7dafbfd0dbcd8bd24ec55889f2bc13dd6287" +checksum = "48dcd35ba14ca9b40d6e4b4b39961f23d835dbb8eed74565ded361d93e1feb8a" [[package]] name = "cxxbridge-macro" -version = "1.0.120" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b404f596046b0bb2d903a9c786b875a126261b52b7c3a64bbb66382c41c771df" +checksum = "81bbeb29798b407ccd82a3324ade1a7286e0d29851475990b612670f6f5124d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 1.0.107", ] [[package]] name = "darling" -version = "0.20.8" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391" +checksum = "c0808e1bd8671fb44a113a14e13497557533369847788fa2ae912b6ebfce9fa8" dependencies = [ "darling_core", "darling_macro", @@ -1611,53 +1634,53 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.8" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f" +checksum = "001d80444f28e193f30c2f293455da62dcf9a6b29918a4253152ae2b1de592cb" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.58", + "syn 1.0.107", ] [[package]] name = "darling_macro" -version = "0.20.8" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" +checksum = "b36230598a2d5de7ec1c6f51f72d8a99a9208daff41de2084d06e3fd3ea56685" dependencies = [ "darling_core", "quote", - "syn 2.0.58", + "syn 1.0.107", ] [[package]] name = "dashmap" -version = "5.5.3" +version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" dependencies = [ "cfg-if", - "hashbrown 0.14.3", + "hashbrown 0.12.3", "lock_api", "once_cell", - "parking_lot_core 0.9.9", + "parking_lot_core 0.9.7", ] [[package]] name = "data-encoding" -version = "2.5.0" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" +checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb" [[package]] name = "data-encoding-macro" -version = "0.1.14" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20c01c06f5f429efdf2bae21eb67c28b3df3cf85b7dd2d8ef09c0838dac5d33e" +checksum = "86927b7cd2fe88fa698b87404b287ab98d1a0063a34071d92e575b72d3029aca" dependencies = [ "data-encoding", "data-encoding-macro-internal", @@ -1665,12 +1688,12 @@ dependencies = [ [[package]] name = "data-encoding-macro-internal" -version = "0.1.12" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0047d07f2c89b17dd631c80450d69841a6b5d7fb17278cbc43d7e4cfcf2576f3" +checksum = "a5bbed42daaa95e780b60a50546aa345b8413a1e46f9a40a12907d3598f038db" dependencies = [ "data-encoding", - "syn 1.0.109", + "syn 1.0.107", ] [[package]] @@ -1685,9 +1708,9 @@ dependencies = [ [[package]] name = "der-parser" -version = "8.2.0" +version = "8.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbd676fbbab537128ef0278adb5576cf363cff6aa22a7b24effe97347cfab61e" +checksum = "42d4bc9b0db0a0df9ae64634ac5bdefb7afcb534e182275ca0beadbe486701c1" dependencies = [ "asn1-rs", "displaydoc", @@ -1697,16 +1720,6 @@ dependencies = [ "rusticata-macros", ] -[[package]] -name = "deranged" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" -dependencies = [ - "powerfmt", - "serde", -] - [[package]] name = "derivative" version = "2.2.0" @@ -1715,7 +1728,7 @@ checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 1.0.107", ] [[package]] @@ -1726,7 +1739,7 @@ checksum = "e79116f119dd1dba1abf1f3405f03b9b0e79a27a3883864bfebded8a3dc768cd" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 1.0.107", ] [[package]] @@ -1737,7 +1750,7 @@ checksum = "d65d7ce8132b7c0e54497a4d9a55a1c2a0912a0d786cf894472ba818fba45762" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -1750,7 +1763,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version 0.4.0", - "syn 1.0.109", + "syn 1.0.107", ] [[package]] @@ -1774,7 +1787,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "generic-array 0.14.7", + "generic-array 0.14.6", ] [[package]] @@ -1783,7 +1796,7 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer 0.10.4", + "block-buffer 0.10.3", "const-oid", "crypto-common", "subtle 2.4.1", @@ -1833,13 +1846,13 @@ dependencies = [ [[package]] name = "displaydoc" -version = "0.2.4" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" +checksum = "3bf95dc3f046b9da4f2d51833c0d3547d8564ef6910f5c1ed130306a75b92886" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 1.0.107", ] [[package]] @@ -1879,9 +1892,9 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.58", + "syn 2.0.61", "termcolor", - "toml 0.8.13", + "toml 0.8.12", "walkdir", ] @@ -1893,9 +1906,9 @@ checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" [[package]] name = "dtoa" -version = "1.0.9" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" +checksum = "c00704156a7de8df8da0911424e30c2049957b0a714542a44e05fe693dd85313" [[package]] name = "dyn-clonable" @@ -1915,14 +1928,14 @@ checksum = "558e40ea573c374cf53507fd240b7ee2f5477df7cfebdb97323ec61c719399c5" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 1.0.107", ] [[package]] name = "dyn-clone" -version = "1.0.17" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" +checksum = "c9b0705efd4599c15a38151f4721f7bc388306f61084d3bfd50bd07fbca5cb60" [[package]] name = "ecdsa" @@ -1980,9 +1993,9 @@ dependencies = [ [[package]] name = "either" -version = "1.10.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "elliptic-curve" @@ -1994,7 +2007,7 @@ dependencies = [ "crypto-bigint", "digest 0.10.7", "ff", - "generic-array 0.14.7", + "generic-array 0.14.6", "group", "pkcs8", "rand_core 0.6.4", @@ -2019,7 +2032,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 1.0.109", + "syn 1.0.107", ] [[package]] @@ -2039,14 +2052,14 @@ checksum = "5c785274071b1b420972453b306eeca06acf4633829db4223b58a2a8c5953bc4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] name = "env_logger" -version = "0.10.2" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" dependencies = [ "humantime", "is-terminal", @@ -2069,14 +2082,35 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.8" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +dependencies = [ + "errno-dragonfly", + "libc", + "winapi", +] + +[[package]] +name = "errno" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", "windows-sys 0.52.0", ] +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "ethbloom" version = "0.13.0" @@ -2110,27 +2144,6 @@ version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" -[[package]] -name = "event-listener" -version = "4.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite 0.2.14", -] - -[[package]] -name = "event-listener-strategy" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" -dependencies = [ - "event-listener 4.0.3", - "pin-project-lite 0.2.14", -] - [[package]] name = "exit-future" version = "0.2.0" @@ -2151,7 +2164,7 @@ dependencies = [ "prettier-please", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -2168,9 +2181,12 @@ checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" [[package]] name = "fastrand" -version = "2.0.2" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" +checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +dependencies = [ + "instant", +] [[package]] name = "fdlimit" @@ -2207,9 +2223,9 @@ dependencies = [ [[package]] name = "fiat-crypto" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c007b1ae3abe1cb6f85a16305acd418b7ca6343b953633fee2b76d8f108b830f" +checksum = "38793c55593b33412e3ae40c2c9781ffaa6f438f6f8c10f24e71846fbd7ae01e" [[package]] name = "file-per-thread-logger" @@ -2223,14 +2239,14 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.23" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" +checksum = "4e884668cd0c7480504233e951174ddc3b382f7c2666e3b7310b5c4e7b0c37f9" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.4.1", - "windows-sys 0.52.0", + "redox_syscall", + "windows-sys 0.42.0", ] [[package]] @@ -2269,9 +2285,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.28" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" dependencies = [ "crc32fast", "libz-sys", @@ -2303,9 +2319,9 @@ dependencies = [ [[package]] name = "form_urlencoded" -version = "1.2.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" dependencies = [ "percent-encoding", ] @@ -2477,7 +2493,7 @@ dependencies = [ "proc-macro2", "quote", "sp-crypto-hashing", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -2489,7 +2505,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -2499,7 +2515,7 @@ source = "git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-v1.10. dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -2634,12 +2650,17 @@ checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-lite" -version = "2.3.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48" dependencies = [ + "fastrand", "futures-core", + "futures-io", + "memchr", + "parking", "pin-project-lite 0.2.14", + "waker-fn", ] [[package]] @@ -2650,7 +2671,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -2660,7 +2681,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2411eed028cdf8c8034eaf21f9915f956b6c3abec4d4c7949ee67f0721127bd" dependencies = [ "futures-io", - "rustls 0.20.9", + "rustls 0.20.8", "webpki", ] @@ -2678,9 +2699,9 @@ checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-timer" -version = "3.0.3" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" +checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" @@ -2715,16 +2736,16 @@ version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" dependencies = [ - "typenum 1.17.0", + "typenum 1.16.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "generic-array" -version = "0.14.7" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" dependencies = [ - "typenum 1.17.0", + "typenum 1.16.0 (registry+https://github.com/rust-lang/crates.io-index)", "version_check", "zeroize", ] @@ -2752,9 +2773,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", @@ -2777,18 +2798,18 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" dependencies = [ - "opaque-debug 0.3.1", + "opaque-debug 0.3.0", "polyval", ] [[package]] name = "gimli" -version = "0.27.3" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +checksum = "221996f774192f0f718773def8201c4ae31f02616a54ccfc2d358bb0e5cefdec" dependencies = [ "fallible-iterator 0.2.0", - "indexmap 1.9.3", + "indexmap 1.9.2", "stable_deref_trait", ] @@ -2841,9 +2862,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.26" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +checksum = "17f8a914c2987b688368b5138aa05321db91f4090cf26118185672ad588bce21" dependencies = [ "bytes", "fnv", @@ -2851,7 +2872,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 2.2.6", + "indexmap 1.9.2", "slab", "tokio", "tokio-util", @@ -2893,7 +2914,7 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash 0.7.8", + "ahash 0.7.6", ] [[package]] @@ -2907,9 +2928,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash 0.8.11", "allocator-api2", @@ -2921,7 +2942,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" dependencies = [ - "hashbrown 0.14.3", + "hashbrown 0.14.5", ] [[package]] @@ -2938,9 +2959,18 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.3.9" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +checksum = "856b5cb0902c2b6d65d5fd97dfa30f9b70c7538e770b98eab5ed52d8db923e01" [[package]] name = "hex" @@ -2950,9 +2980,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hex-conservative" -version = "0.1.2" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212ab92002354b4819390025006c897e8140934349e8635c9b077f47b4dcbd20" +checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2" [[package]] name = "hex-literal" @@ -2962,9 +2992,9 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "hkdf" -version = "0.12.4" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" dependencies = [ "hmac 0.12.1", ] @@ -2995,19 +3025,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" dependencies = [ "digest 0.9.0", - "generic-array 0.14.7", + "generic-array 0.14.6", "hmac 0.8.1", ] -[[package]] -name = "home" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys 0.52.0", -] - [[package]] name = "hostname" version = "0.3.1" @@ -3032,9 +3053,9 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.6" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes", "http", @@ -3043,9 +3064,9 @@ dependencies = [ [[package]] name = "http-range-header" -version = "0.3.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" +checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29" [[package]] name = "httparse" @@ -3055,9 +3076,9 @@ checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" -version = "1.0.3" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "humantime" @@ -3082,7 +3103,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite 0.2.14", - "socket2 0.5.6", + "socket2 0.4.7", "tokio", "tower-service", "tracing", @@ -3099,7 +3120,7 @@ dependencies = [ "http", "hyper", "log", - "rustls 0.21.10", + "rustls 0.21.12", "rustls-native-certs", "tokio", "tokio-rustls", @@ -3107,25 +3128,26 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows-core 0.52.0", + "winapi", ] [[package]] name = "iana-time-zone-haiku" -version = "0.1.2" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" dependencies = [ - "cc", + "cxx", + "cxx-build", ] [[package]] @@ -3147,9 +3169,9 @@ dependencies = [ [[package]] name = "idna" -version = "0.5.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -3157,19 +3179,19 @@ dependencies = [ [[package]] name = "if-addrs" -version = "0.10.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cabb0019d51a643781ff15c9c8a3e5dedc365c47211270f4e8f82812fedd8f0a" +checksum = "cbc0fa01ffc752e9dbc72818cdb072cd028b86be5e09dd04c5a643704fe101a9" dependencies = [ "libc", - "windows-sys 0.48.0", + "winapi", ] [[package]] name = "if-watch" -version = "3.2.0" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6b0422c86d7ce0e97169cc42e04ae643caf278874a7a3c87b8150a220dc7e1e" +checksum = "ba7abdbb86e485125dad06c2691e1e393bf3b08c7b743b43aa162a00fd39062e" dependencies = [ "async-io", "core-foundation", @@ -3219,7 +3241,7 @@ checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 1.0.107", ] [[package]] @@ -3243,9 +3265,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.9.3" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" dependencies = [ "autocfg", "hashbrown 0.12.3", @@ -3259,7 +3281,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", - "hashbrown 0.14.3", + "hashbrown 0.14.5", ] [[package]] @@ -3268,7 +3290,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" dependencies = [ - "generic-array 0.14.7", + "generic-array 0.14.6", ] [[package]] @@ -3291,13 +3313,12 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.11" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +checksum = "1abeb7a0dd0f8181267ff8adc397075586500b81b28a73e8a0208b00fc170fb3" dependencies = [ - "hermit-abi", "libc", - "windows-sys 0.48.0", + "windows-sys 0.45.0", ] [[package]] @@ -3308,21 +3329,21 @@ checksum = "aa2f047c0a98b2f299aa5d6d7088443570faae494e9ae1305e48be000c9e0eb1" [[package]] name = "ipconfig" -version = "0.3.2" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" +checksum = "bd302af1b90f2463a98fa5ad469fc212c8e3175a41c3068601bfa2727591c5be" dependencies = [ - "socket2 0.5.6", + "socket2 0.4.7", "widestring", - "windows-sys 0.48.0", + "winapi", "winreg", ] [[package]] name = "ipnet" -version = "2.9.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146" [[package]] name = "is-terminal" @@ -3330,11 +3351,17 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.0", "libc", "windows-sys 0.52.0", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + [[package]] name = "itertools" version = "0.10.5" @@ -3346,24 +3373,24 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" [[package]] name = "jobserver" -version = "0.1.28" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" +checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" dependencies = [ "libc", ] [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" dependencies = [ "wasm-bindgen", ] @@ -3414,7 +3441,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -3470,9 +3497,9 @@ dependencies = [ [[package]] name = "keccak" -version = "0.1.5" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +checksum = "3afef3b6eff9ce9d8ff9b3601125eec7f0c8cbac7abd14f355d053fa56c98768" dependencies = [ "cpufeatures", ] @@ -3530,25 +3557,25 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" [[package]] name = "libloading" -version = "0.8.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" dependencies = [ "cfg-if", - "windows-targets 0.52.4", + "winapi", ] [[package]] name = "libm" -version = "0.2.8" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" [[package]] name = "libp2p" @@ -3559,7 +3586,7 @@ dependencies = [ "bytes", "futures", "futures-timer", - "getrandom 0.2.14", + "getrandom 0.2.15", "instant", "libp2p-allow-block-list", "libp2p-connection-limits", @@ -3732,7 +3759,7 @@ dependencies = [ "log", "rand", "smallvec", - "socket2 0.4.10", + "socket2 0.4.7", "tokio", "trust-dns-proto", "void", @@ -3809,7 +3836,7 @@ dependencies = [ "parking_lot 0.12.1", "quinn-proto", "rand", - "rustls 0.20.9", + "rustls 0.20.8", "thiserror", "tokio", ] @@ -3859,7 +3886,7 @@ checksum = "0fba456131824ab6acd4c7bf61e9c0f0a3014b5fc9868ccb8e10d344594cdc4f" dependencies = [ "heck 0.4.1", "quote", - "syn 1.0.109", + "syn 1.0.107", ] [[package]] @@ -3874,7 +3901,7 @@ dependencies = [ "libc", "libp2p-core", "log", - "socket2 0.4.10", + "socket2 0.4.7", "tokio", ] @@ -3890,7 +3917,7 @@ dependencies = [ "libp2p-identity", "rcgen", "ring 0.16.20", - "rustls 0.20.9", + "rustls 0.20.8", "thiserror", "webpki", "x509-parser", @@ -3943,16 +3970,6 @@ dependencies = [ "yamux", ] -[[package]] -name = "libredox" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" -dependencies = [ - "bitflags 2.5.0", - "libc", -] - [[package]] name = "librocksdb-sys" version = "0.11.0+8.1.1" @@ -3984,7 +4001,7 @@ dependencies = [ "rand", "serde", "sha2 0.9.9", - "typenum 1.17.0", + "typenum 1.16.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4018,9 +4035,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.16" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e143b5e666b2695d28f6bca6497720813f699c9602dd7f5cac91008b8ada7f9" +checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf" dependencies = [ "cc", "pkg-config", @@ -4029,9 +4046,9 @@ dependencies = [ [[package]] name = "link-cplusplus" -version = "1.0.9" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d240c6f7e1ba3a28b0249f774e6a9dd0175054b52dfbb61b16eb8505c3785c9" +checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" dependencies = [ "cc", ] @@ -4053,9 +4070,9 @@ dependencies = [ [[package]] name = "linregress" -version = "0.5.3" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4de04dcecc58d366391f9920245b85ffa684558a5ef6e7736e754347c3aea9c2" +checksum = "475015a7f8f017edb28d2e69813be23500ad4b32cfe3421c4148efc97324ee52" dependencies = [ "nalgebra", ] @@ -4086,9 +4103,9 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" dependencies = [ "autocfg", "scopeguard", @@ -4165,7 +4182,7 @@ dependencies = [ "macro_magic_core", "macro_magic_macros", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -4179,7 +4196,7 @@ dependencies = [ "macro_magic_core_macros", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -4190,7 +4207,7 @@ checksum = "9ea73aa640dc01d62a590d48c0c3521ed739d53b27f919b25c3551e233481654" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -4201,7 +4218,7 @@ checksum = "ef9d79ae96aaba821963320eb2b6e34d17df1e5a83d8a1985c29cc5be59577b3" dependencies = [ "macro_magic_core", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -4216,7 +4233,7 @@ version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1" dependencies = [ - "regex-automata 0.1.10", + "regex-automata", ] [[package]] @@ -4225,7 +4242,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" dependencies = [ - "regex-automata 0.1.10", + "regex-automata", ] [[package]] @@ -4236,34 +4253,33 @@ checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" [[package]] name = "matrixmultiply" -version = "0.3.8" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7574c1cf36da4798ab73da5b215bbf444f50718207754cb522201d78d1cd0ff2" +checksum = "add85d4dd35074e6fedc608f8c8f513a3548619a9024b751949ef0e8e45a4d84" dependencies = [ - "autocfg", "rawpointer", ] [[package]] name = "memchr" -version = "2.7.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memfd" -version = "0.6.4" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64" +checksum = "b20a59d985586e4a5aef64564ac77299f8586d8be6cf9106a5a40207e8908efb" dependencies = [ - "rustix 0.38.32", + "rustix 0.36.8", ] [[package]] name = "memmap2" -version = "0.5.10" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +checksum = "4b182332558b18d807c4ce1ca8ca983b34c3ee32765e47b3f0f69b90355cc1dc" dependencies = [ "libc", ] @@ -4277,6 +4293,15 @@ dependencies = [ "libc", ] +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + [[package]] name = "memoffset" version = "0.8.0" @@ -4315,9 +4340,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.2" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" dependencies = [ "adler", ] @@ -4360,9 +4385,9 @@ dependencies = [ [[package]] name = "mockall" -version = "0.11.4" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c84490118f2ee2d74570d114f3d0493cbf02790df303d2707606c3e14e07c96" +checksum = "50e4a1c770583dac7ab5e2f6c139153b783a53a1bbee9729613f193e59828326" dependencies = [ "cfg-if", "downcast", @@ -4375,14 +4400,14 @@ dependencies = [ [[package]] name = "mockall_derive" -version = "0.11.4" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ce75669015c4f47b289fd4d4f56e894e4c96003ffdf3ac51313126f94c6cbb" +checksum = "832663583d5fa284ca8810bf7015e46c9fff9622d3cf34bd1eea5003fec06dd0" dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 1.0.109", + "syn 1.0.107", ] [[package]] @@ -4442,7 +4467,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 1.0.109", + "syn 1.0.107", "synstructure", ] @@ -4468,9 +4493,9 @@ dependencies = [ [[package]] name = "nalgebra" -version = "0.32.5" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ea4908d4f23254adda3daa60ffef0f1ac7b8c3e9a864cf3cc154b251908a2ef" +checksum = "d68d47bba83f9e2006d117a9a33af1524e655516b8919caac694427a6fb1e511" dependencies = [ "approx", "matrixmultiply", @@ -4479,18 +4504,18 @@ dependencies = [ "num-rational", "num-traits", "simba", - "typenum 1.17.0", + "typenum 1.16.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "nalgebra-macros" -version = "0.2.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91761aed67d03ad966ef783ae962ef9bbaca728d2dd7ceb7939ec110fffad998" +checksum = "d232c68884c0c99810a5a4d333ef7e47689cfd0edc85efc9e54e1e6bf5212766" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 1.0.107", ] [[package]] @@ -4570,9 +4595,9 @@ dependencies = [ [[package]] name = "netlink-sys" -version = "0.8.6" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416060d346fbaf1f23f9512963e3e878f1a78e707cb699ba9215761754244307" +checksum = "260e21fbb6f3d253a14df90eb0000a6066780a15dd901a7519ce02d77a94985b" dependencies = [ "bytes", "futures", @@ -4600,7 +4625,7 @@ checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c" [[package]] name = "node-subtensor" -version = "4.0.0-dev" +version = "5.0.4" dependencies = [ "clap", "frame-benchmarking", @@ -4748,9 +4773,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.4" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" dependencies = [ "autocfg", "num-integer", @@ -4759,19 +4784,13 @@ dependencies = [ [[package]] name = "num-complex" -version = "0.4.5" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23c6602fda94a57c990fe0df199a035d83576b496aa29f4e634a8ac6004e68a6" +checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" dependencies = [ "num-traits", ] -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - [[package]] name = "num-format" version = "0.4.4" @@ -4784,10 +4803,11 @@ dependencies = [ [[package]] name = "num-integer" -version = "0.1.46" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" dependencies = [ + "autocfg", "num-traits", ] @@ -4804,9 +4824,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", "libm", @@ -4814,23 +4834,23 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.16.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" dependencies = [ - "hermit-abi", + "hermit-abi 0.2.6", "libc", ] [[package]] name = "object" -version = "0.30.4" +version = "0.30.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385" +checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" dependencies = [ "crc32fast", "hashbrown 0.13.2", - "indexmap 1.9.3", + "indexmap 1.9.2", "memchr", ] @@ -4866,9 +4886,9 @@ checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" [[package]] name = "opaque-debug" -version = "0.3.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl-probe" @@ -5098,8 +5118,11 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", + "log", "parity-scale-codec", "scale-info", + "serde", + "serde_json", "sp-core", "sp-io", "sp-runtime", @@ -5155,6 +5178,7 @@ dependencies = [ "frame-system", "hex", "hex-literal", + "itertools", "log", "ndarray", "pallet-balances", @@ -5301,7 +5325,7 @@ dependencies = [ "libc", "log", "lz4", - "memmap2 0.5.10", + "memmap2 0.5.8", "parking_lot 0.12.1", "rand", "siphasher", @@ -5311,9 +5335,9 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.6.12" +version = "3.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" +checksum = "0dec8a8073036902368c2cdc0387e85ff9a37054d7e7c98e592145e0c92cd4fb" dependencies = [ "arrayvec", "bitvec", @@ -5326,14 +5350,14 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "3.6.12" +version = "3.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" +checksum = "312270ee71e1cd70289dacf597cab7b207aa107d2f28191c2ae45b2ece18a260" dependencies = [ - "proc-macro-crate 3.1.0", + "proc-macro-crate 1.1.3", "proc-macro2", "quote", - "syn 1.0.109", + "syn 1.0.107", ] [[package]] @@ -5367,7 +5391,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f557c32c6d268a07c921471619c0295f5efad3a0e76d4f97a05c091a51d110b2" dependencies = [ "proc-macro2", - "syn 1.0.109", + "syn 1.0.107", "synstructure", ] @@ -5379,9 +5403,9 @@ checksum = "e1ad0aff30c1da14b1254fcb2af73e1fa9a28670e584a626f53a369d0e157304" [[package]] name = "parking" -version = "2.2.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" +checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" [[package]] name = "parking_lot" @@ -5401,7 +5425,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.9", + "parking_lot_core 0.9.7", ] [[package]] @@ -5413,22 +5437,22 @@ dependencies = [ "cfg-if", "instant", "libc", - "redox_syscall 0.2.16", + "redox_syscall", "smallvec", "winapi", ] [[package]] name = "parking_lot_core" -version = "0.9.9" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.4.1", + "redox_syscall", "smallvec", - "windows-targets 0.48.5", + "windows-sys 0.45.0", ] [[package]] @@ -5450,9 +5474,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.14" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba" [[package]] name = "pbkdf2" @@ -5481,26 +5505,25 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "pest" -version = "2.7.9" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "311fb059dee1a7b802f036316d790138c613a4e8b180c822e3925a662e9f0c95" +checksum = "4ab62d2fa33726dbe6321cc97ef96d8cde531e3eeaf858a058de53a8a6d40d8f" dependencies = [ - "memchr", "thiserror", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.7.9" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f73541b156d32197eecda1a4014d7f868fd2bcb3c550d5386087cfba442bf69c" +checksum = "8bf026e2d0581559db66d837fe5242320f525d85c76283c61f4d51a1238d65ea" dependencies = [ "pest", "pest_generator", @@ -5508,22 +5531,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.9" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c35eeed0a3fab112f75165fdc026b3913f4183133f19b49be773ac9ea966e8bd" +checksum = "2b27bd18aa01d91c8ed2b61ea23406a676b42d82609c6e2581fba42f0c15f17f" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.58", + "syn 1.0.107", ] [[package]] name = "pest_meta" -version = "2.7.9" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2adbf29bb9776f28caece835398781ab24435585fe0d4dc1374a61db5accedca" +checksum = "9f02b677c1859756359fc9983c2e56a0237f18624a3789528804406b7e915e5d" dependencies = [ "once_cell", "pest", @@ -5532,12 +5555,12 @@ dependencies = [ [[package]] name = "petgraph" -version = "0.6.4" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" dependencies = [ "fixedbitset", - "indexmap 2.2.6", + "indexmap 1.9.2", ] [[package]] @@ -5557,7 +5580,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -5590,15 +5613,15 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" [[package]] name = "platforms" -version = "3.4.0" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db23d408679286588f4d4644f965003d056e3dd5abcaaa938116871d7ce2fee7" +checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630" [[package]] name = "polkavm" @@ -5649,7 +5672,7 @@ dependencies = [ "polkavm-common", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -5659,7 +5682,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ba81f7b5faac81e528eb6158a6f3c9e0bb1008e0ffa19653bc8dea925ecb429" dependencies = [ "polkavm-derive-impl", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -5669,7 +5692,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c7be503e60cf56c0eb785f90aaba4b583b36bff00e93997d93fef97f9553c39" dependencies = [ "gimli 0.28.1", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "log", "object 0.32.2", "polkavm-common", @@ -5685,17 +5708,16 @@ checksum = "26e85d3456948e650dff0cfc85603915847faf893ed1e66b020bb82ef4557120" [[package]] name = "polling" -version = "3.6.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0c976a60b2d7e99d6f229e414670a9b85d13ac305cc6d1e9c134de58c5aaaf6" +checksum = "22122d5ec4f9fe1b3916419b76be1e80bcb93f618d071d2edf841b137b2a2bd6" dependencies = [ + "autocfg", "cfg-if", - "concurrent-queue", - "hermit-abi", - "pin-project-lite 0.2.14", - "rustix 0.38.32", - "tracing", - "windows-sys 0.52.0", + "libc", + "log", + "wepoll-ffi", + "windows-sys 0.42.0", ] [[package]] @@ -5705,7 +5727,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" dependencies = [ "cpufeatures", - "opaque-debug 0.3.1", + "opaque-debug 0.3.0", "universal-hash", ] @@ -5717,7 +5739,7 @@ checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" dependencies = [ "cfg-if", "cpufeatures", - "opaque-debug 0.3.1", + "opaque-debug 0.3.0", "universal-hash", ] @@ -5727,12 +5749,6 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - [[package]] name = "ppv-lite86" version = "0.2.17" @@ -5755,15 +5771,15 @@ dependencies = [ [[package]] name = "predicates-core" -version = "1.0.6" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" +checksum = "72f883590242d3c6fc5bf50299011695fa6590c2c70eac95ee1bdb9a733ad1a2" [[package]] name = "predicates-tree" -version = "1.0.9" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" +checksum = "54ff541861505aabf6ea722d2131ee980b8276e10a1297b94e896dd8b621850d" dependencies = [ "predicates-core", "termtree", @@ -5776,7 +5792,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22020dfcf177fcc7bf5deaf7440af371400c67c0de14c399938d8ed4fb4645d3" dependencies = [ "proc-macro2", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -5786,24 +5802,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f28f53e8b192565862cf99343194579a022eb9c7dd3a8d03134734803c7b3125" dependencies = [ "proc-macro2", - "syn 1.0.109", + "syn 1.0.107", ] [[package]] name = "prettyplease" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d3928fb5db768cb86f891ff014f0144589297e3c6a1aba6ed7cecfdace270c7" +checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" dependencies = [ "proc-macro2", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] name = "primitive-types" -version = "0.12.2" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66" dependencies = [ "fixed-hash", "impl-codec", @@ -5841,7 +5857,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", - "syn 1.0.109", + "syn 1.0.107", "version_check", ] @@ -5864,14 +5880,14 @@ checksum = "834da187cfe638ae8abb0203f0b33e5ccdb02a28e7199f2f47b3e2754f50edca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" dependencies = [ "unicode-ident", ] @@ -5910,34 +5926,34 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] name = "prost" -version = "0.11.9" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" +checksum = "21dc42e00223fc37204bd4aa177e69420c604ca4a183209a8f9de30c6d934698" dependencies = [ "bytes", - "prost-derive 0.11.9", + "prost-derive 0.11.6", ] [[package]] name = "prost" -version = "0.12.6" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" +checksum = "d0f5d036824e4761737860779c906171497f6d55681139d8312388f8fe398922" dependencies = [ "bytes", - "prost-derive 0.12.6", + "prost-derive 0.12.5", ] [[package]] name = "prost-build" -version = "0.11.9" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" +checksum = "a3f8ad728fb08fe212df3c05169e940fbb6d9d16a877ddde14644a983ba2012e" dependencies = [ "bytes", "heck 0.4.1", @@ -5947,47 +5963,48 @@ dependencies = [ "multimap", "petgraph", "prettyplease 0.1.11", - "prost 0.11.9", + "prost 0.11.6", "prost-types", "regex", - "syn 1.0.109", + "syn 1.0.107", "tempfile", "which", ] [[package]] name = "prost-derive" -version = "0.11.9" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" +checksum = "8bda8c0881ea9f722eb9629376db3d0b903b462477c1aafcb0566610ac28ac5d" dependencies = [ "anyhow", "itertools", "proc-macro2", "quote", - "syn 1.0.109", + "syn 1.0.107", ] [[package]] name = "prost-derive" -version = "0.12.6" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" +checksum = "9554e3ab233f0a932403704f1a1d08c30d5ccd931adfdfa1e8b5a19b52c1d55a" dependencies = [ "anyhow", "itertools", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] name = "prost-types" -version = "0.11.9" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" +checksum = "a5e0526209433e96d83d750dd81a99118edbc55739e7e61a46764fd2ad537788" dependencies = [ - "prost 0.11.9", + "bytes", + "prost 0.11.6", ] [[package]] @@ -6055,15 +6072,15 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.9.6" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b0b33c13a79f669c85defaf4c275dc86a0c0372807d0ca3d78e0bb87274863" +checksum = "72ef4ced82a24bb281af338b9e8f94429b6eca01b4e66d899f40031f074e74c9" dependencies = [ "bytes", "rand", "ring 0.16.20", "rustc-hash", - "rustls 0.20.9", + "rustls 0.20.8", "slab", "thiserror", "tinyvec", @@ -6073,9 +6090,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -6122,7 +6139,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.14", + "getrandom 0.2.15", ] [[package]] @@ -6161,9 +6178,9 @@ checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" [[package]] name = "rayon" -version = "1.10.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7" dependencies = [ "either", "rayon-core", @@ -6171,12 +6188,14 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.1" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +checksum = "356a0625f1954f730c0201cdab48611198dc6ce21f4acff55089b5a78e6e835b" dependencies = [ + "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", + "num_cpus", ] [[package]] @@ -6200,44 +6219,35 @@ dependencies = [ "bitflags 1.3.2", ] -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_users" -version = "0.4.5" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ - "getrandom 0.2.14", - "libredox", + "getrandom 0.2.15", + "redox_syscall", "thiserror", ] [[package]] name = "ref-cast" -version = "1.0.22" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4846d4c50d1721b1a3bef8af76924eef20d5e723647333798c1b519b3a9473f" +checksum = "8c78fb8c9293bcd48ef6fce7b4ca950ceaf21210de6e105a883ee280c0f7b9ed" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.22" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fddb4f8d99b0a2ebafc65a87a69a7b9875e4b1ae1f00db265d300ef7f28bccc" +checksum = "9f9c0c92af03644e4806106281fe2e068ac5bc0ae74a707266d06ea27bccee5f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 1.0.107", ] [[package]] @@ -6267,14 +6277,13 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.4" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.6", - "regex-syntax 0.8.3", + "regex-syntax", ] [[package]] @@ -6283,31 +6292,23 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" dependencies = [ - "regex-syntax 0.6.29", -] - -[[package]] -name = "regex-automata" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax 0.8.3", + "regex-syntax", ] [[package]] name = "regex-syntax" -version = "0.6.29" +version = "0.6.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" +checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" [[package]] -name = "regex-syntax" -version = "0.8.3" +name = "remove_dir_all" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] [[package]] name = "resolv-conf" @@ -6368,7 +6369,7 @@ checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.14", + "getrandom 0.2.15", "libc", "spin 0.9.8", "untrusted 0.9.0", @@ -6403,13 +6404,13 @@ checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746" [[package]] name = "rpassword" -version = "7.3.1" +version = "7.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80472be3c897911d0137b2d2b9055faf6eeac5b14e324073d83bc17b191d7e3f" +checksum = "6678cf63ab3491898c0d021b493c94c9b221d91295294a2a5746eacbe5928322" dependencies = [ "libc", "rtoolbox", - "windows-sys 0.48.0", + "winapi", ] [[package]] @@ -6429,19 +6430,19 @@ dependencies = [ [[package]] name = "rtoolbox" -version = "0.0.2" +version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c247d24e63230cdb56463ae328478bd5eac8b8faa8c69461a77e8e323afac90e" +checksum = "034e22c514f5c0cb8a10ff341b9b048b5ceb21591f31c8f44c43b960f9b3524a" dependencies = [ "libc", - "windows-sys 0.48.0", + "winapi", ] [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" @@ -6470,7 +6471,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.22", + "semver 1.0.16", ] [[package]] @@ -6484,12 +6485,12 @@ dependencies = [ [[package]] name = "rustix" -version = "0.36.17" +version = "0.36.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "305efbd14fde4139eb501df5f136994bb520b033fa9fbdce287507dc23b8c7ed" +checksum = "f43abb88211988493c1abb44a70efa56ff0ce98f233b7b276146f1f3f7ba9644" dependencies = [ "bitflags 1.3.2", - "errno", + "errno 0.2.8", "io-lifetimes", "libc", "linux-raw-sys 0.1.4", @@ -6498,12 +6499,12 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.32" +version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ "bitflags 2.5.0", - "errno", + "errno 0.3.9", "libc", "linux-raw-sys 0.4.13", "windows-sys 0.52.0", @@ -6511,9 +6512,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.20.9" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b80e3dec595989ea8510028f30c408a4630db12c9cbb8de34203b89d6577e99" +checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" dependencies = [ "log", "ring 0.16.20", @@ -6523,9 +6524,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.10" +version = "0.21.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", "ring 0.17.8", @@ -6535,9 +6536,9 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.6.3" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" +checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50" dependencies = [ "openssl-probe", "rustls-pemfile", @@ -6547,11 +6548,11 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "1.0.4" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" dependencies = [ - "base64 0.21.7", + "base64 0.21.0", ] [[package]] @@ -6566,9 +6567,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.15" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47" +checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" [[package]] name = "rw-stream-sink" @@ -6583,9 +6584,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.17" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" [[package]] name = "safe-mix" @@ -6598,9 +6599,9 @@ dependencies = [ [[package]] name = "safe_arch" -version = "0.7.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f398075ce1e6a179b46f51bd88d0598b92b00d3551f1a2d4ac49e771b56ac354" +checksum = "794821e4ccb0d9f979512f9c1973480123f9bd62a90d74ab0f9426fcf8f4a529" dependencies = [ "bytemuck", ] @@ -6696,7 +6697,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -6990,7 +6991,7 @@ dependencies = [ "libc", "log", "parking_lot 0.12.1", - "rustix 0.36.17", + "rustix 0.36.8", "sc-allocator", "sc-executor-common", "sp-runtime-interface 24.0.0 (git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-v1.10.0)", @@ -7111,7 +7112,7 @@ dependencies = [ "futures", "libp2p-identity", "log", - "prost 0.12.6", + "prost 0.12.4", "prost-build", "sc-client-api", "sc-network", @@ -7168,7 +7169,7 @@ dependencies = [ "libp2p-identity", "log", "parity-scale-codec", - "prost 0.12.6", + "prost 0.12.4", "prost-build", "sc-client-api", "sc-network", @@ -7193,7 +7194,7 @@ dependencies = [ "log", "mockall", "parity-scale-codec", - "prost 0.12.6", + "prost 0.12.4", "prost-build", "sc-client-api", "sc-consensus", @@ -7518,7 +7519,7 @@ dependencies = [ "sp-tracing 16.0.0 (git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-v1.10.0)", "thiserror", "tracing", - "tracing-log 0.1.4", + "tracing-log 0.1.3", "tracing-subscriber 0.2.25", ] @@ -7530,7 +7531,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -7593,9 +7594,9 @@ dependencies = [ [[package]] name = "scale-info" -version = "2.11.2" +version = "2.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c453e59a955f81fb62ee5d596b450383d699f152d350e9d23a0db2adb78e4c0" +checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" dependencies = [ "bitvec", "cfg-if", @@ -7607,23 +7608,23 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "2.11.2" +version = "2.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18cf6c6447f813ef19eb450e985bcce6705f9ce7660db221b59093d15c79c4b7" +checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" dependencies = [ - "proc-macro-crate 1.1.3", + "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 1.0.109", + "syn 1.0.107", ] [[package]] name = "schannel" -version = "0.1.23" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.42.0", ] [[package]] @@ -7658,35 +7659,35 @@ dependencies = [ [[package]] name = "scopeguard" -version = "1.2.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "scratch" -version = "1.0.7" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3cf7c11c38cb994f3d40e8a8cde3bbd1f72a435e4c49e85d6553d8312306152" +checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2" [[package]] name = "sct" -version = "0.7.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" dependencies = [ - "ring 0.17.8", - "untrusted 0.9.0", + "ring 0.16.20", + "untrusted 0.7.1", ] [[package]] name = "sec1" -version = "0.7.3" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +checksum = "48518a2b5775ba8ca5b46596aae011caa431e6ce7e4a67ead66d92f08884220e" dependencies = [ "base16ct", "der", - "generic-array 0.14.7", + "generic-array 0.14.6", "pkcs8", "serdect", "subtle 2.4.1", @@ -7722,9 +7723,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.10.0" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6" +checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" dependencies = [ "bitflags 1.3.2", "core-foundation", @@ -7735,9 +7736,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.10.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f3cc463c0ef97e11c3461a9d3787412d30e8e7eb907c79180c4a57bf7c04ef" +checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" dependencies = [ "core-foundation-sys", "libc", @@ -7763,9 +7764,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.22" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" +checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" dependencies = [ "serde", ] @@ -7778,9 +7779,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.202" +version = "1.0.201" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" +checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c" dependencies = [ "serde_derive", ] @@ -7805,13 +7806,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.202" +version = "1.0.201" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" +checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -7827,9 +7828,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.6" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" dependencies = [ "serde", ] @@ -7843,7 +7844,7 @@ dependencies = [ "base64 0.13.1", "chrono", "hex", - "indexmap 1.9.3", + "indexmap 1.9.2", "serde", "serde_json", "serde_with_macros", @@ -7852,14 +7853,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "2.3.3" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f" +checksum = "a1966009f3c05f095697c537312f5415d1e3ed31ce0a56942bac4c771c5c335e" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.58", + "syn 1.0.107", ] [[package]] @@ -7882,7 +7883,7 @@ dependencies = [ "cfg-if", "cpufeatures", "digest 0.9.0", - "opaque-debug 0.3.1", + "opaque-debug 0.3.0", ] [[package]] @@ -7895,7 +7896,7 @@ dependencies = [ "cfg-if", "cpufeatures", "digest 0.9.0", - "opaque-debug 0.3.1", + "opaque-debug 0.3.0", ] [[package]] @@ -7911,9 +7912,9 @@ dependencies = [ [[package]] name = "sha3" -version = "0.10.8" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +checksum = "bdf0c33fae925bdc080598b84bc15c55e7b9a4a43b3c704da051f977469691c9" dependencies = [ "digest 0.10.7", "keccak", @@ -7921,24 +7922,24 @@ dependencies = [ [[package]] name = "sharded-slab" -version = "0.1.7" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" dependencies = [ "lazy_static", ] [[package]] name = "shlex" -version = "1.3.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" [[package]] name = "signal-hook-registry" -version = "1.4.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" dependencies = [ "libc", ] @@ -7955,9 +7956,9 @@ dependencies = [ [[package]] name = "simba" -version = "0.8.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "061507c94fc6ab4ba1c9a0305018408e312e17c041eb63bef8aa726fa33aceae" +checksum = "50582927ed6f77e4ac020c057f37a268fc6aebc29225050365aacbb9deeeddc4" dependencies = [ "approx", "num-complex", @@ -7980,18 +7981,18 @@ checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] name = "slab" -version = "0.4.9" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" dependencies = [ "autocfg", ] [[package]] name = "slice-group-by" -version = "0.3.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7" +checksum = "03b634d87b960ab1a38c4fe143b508576f075e7c978bfad18217645ebfdfa2ec" [[package]] name = "smallvec" @@ -8001,9 +8002,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "snap" -version = "1.1.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b" +checksum = "5e9f0ab6ef7eb7353d9119c170a436d1bf248eea575ac42d19d12f4e34130831" [[package]] name = "snow" @@ -8024,9 +8025,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.4.10" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" +checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" dependencies = [ "libc", "winapi", @@ -8034,9 +8035,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", "windows-sys 0.52.0", @@ -8092,7 +8093,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -8278,7 +8279,7 @@ dependencies = [ [[package]] name = "sp-crypto-ec-utils" version = "0.10.0" -source = "git+https://github.com/paritytech/polkadot-sdk#ec46106c33f2220d16a9dc7ad604d564d42ee009" +source = "git+https://github.com/paritytech/polkadot-sdk#d37719da022879b4e2ef7947f5c9d2187f666ae7" dependencies = [ "ark-bls12-377", "ark-bls12-377-ext", @@ -8315,7 +8316,7 @@ source = "git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-v1.10. dependencies = [ "quote", "sp-crypto-hashing", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -8334,17 +8335,17 @@ source = "git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-v1.10. dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] name = "sp-debug-derive" version = "14.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#ec46106c33f2220d16a9dc7ad604d564d42ee009" +source = "git+https://github.com/paritytech/polkadot-sdk#d37719da022879b4e2ef7947f5c9d2187f666ae7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -8360,7 +8361,7 @@ dependencies = [ [[package]] name = "sp-externalities" version = "0.25.0" -source = "git+https://github.com/paritytech/polkadot-sdk#ec46106c33f2220d16a9dc7ad604d564d42ee009" +source = "git+https://github.com/paritytech/polkadot-sdk#d37719da022879b4e2ef7947f5c9d2187f666ae7" dependencies = [ "environmental", "parity-scale-codec", @@ -8543,7 +8544,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface" version = "24.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#ec46106c33f2220d16a9dc7ad604d564d42ee009" +source = "git+https://github.com/paritytech/polkadot-sdk#d37719da022879b4e2ef7947f5c9d2187f666ae7" dependencies = [ "bytes", "impl-trait-for-tuples", @@ -8569,20 +8570,20 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] name = "sp-runtime-interface-proc-macro" version = "17.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#ec46106c33f2220d16a9dc7ad604d564d42ee009" +source = "git+https://github.com/paritytech/polkadot-sdk#d37719da022879b4e2ef7947f5c9d2187f666ae7" dependencies = [ "Inflector", "expander", "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -8664,7 +8665,7 @@ source = "git+https://github.com/paritytech/polkadot-sdk.git?tag=polkadot-v1.10. [[package]] name = "sp-std" version = "14.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#ec46106c33f2220d16a9dc7ad604d564d42ee009" +source = "git+https://github.com/paritytech/polkadot-sdk#d37719da022879b4e2ef7947f5c9d2187f666ae7" [[package]] name = "sp-storage" @@ -8681,7 +8682,7 @@ dependencies = [ [[package]] name = "sp-storage" version = "19.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#ec46106c33f2220d16a9dc7ad604d564d42ee009" +source = "git+https://github.com/paritytech/polkadot-sdk#d37719da022879b4e2ef7947f5c9d2187f666ae7" dependencies = [ "impl-serde", "parity-scale-codec", @@ -8716,7 +8717,7 @@ dependencies = [ [[package]] name = "sp-tracing" version = "16.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#ec46106c33f2220d16a9dc7ad604d564d42ee009" +source = "git+https://github.com/paritytech/polkadot-sdk#d37719da022879b4e2ef7947f5c9d2187f666ae7" dependencies = [ "parity-scale-codec", "tracing", @@ -8795,7 +8796,7 @@ dependencies = [ "parity-scale-codec", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -8813,7 +8814,7 @@ dependencies = [ [[package]] name = "sp-wasm-interface" version = "20.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#ec46106c33f2220d16a9dc7ad604d564d42ee009" +source = "git+https://github.com/paritytech/polkadot-sdk#d37719da022879b4e2ef7947f5c9d2187f666ae7" dependencies = [ "impl-trait-for-tuples", "log", @@ -8867,9 +8868,9 @@ dependencies = [ [[package]] name = "ss58-registry" -version = "1.47.0" +version = "1.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4743ce898933fbff7bbf414f497c459a782d496269644b3d650a398ae6a487ba" +checksum = "e40c020d72bc0a9c5660bb71e4a6fdef081493583062c474740a7d59f55f0e7b" dependencies = [ "Inflector", "num-format", @@ -8917,7 +8918,7 @@ dependencies = [ "memchr", "proc-macro2", "quote", - "syn 1.0.109", + "syn 1.0.107", ] [[package]] @@ -8957,7 +8958,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 1.0.109", + "syn 1.0.107", ] [[package]] @@ -8970,7 +8971,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -8998,7 +8999,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "typenum 1.16.0", + "typenum 1.16.0 (git+https://github.com/encointer/typenum?tag=v1.16.0)", ] [[package]] @@ -9046,7 +9047,7 @@ dependencies = [ "sp-maybe-compressed-blob", "strum 0.26.2", "tempfile", - "toml 0.8.13", + "toml 0.8.12", "walkdir", "wasm-opt", ] @@ -9090,9 +9091,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.109" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" dependencies = [ "proc-macro2", "quote", @@ -9101,9 +9102,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.58" +version = "2.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" +checksum = "c993ed8ccba56ae856363b1845da7266a7cb78e1d146c8a32d54b45a8b831fc9" dependencies = [ "proc-macro2", "quote", @@ -9118,15 +9119,15 @@ checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 1.0.107", "unicode-xid", ] [[package]] name = "system-configuration" -version = "0.5.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +checksum = "d75182f12f490e953596550b65ee31bda7c8e043d9386174b353bda50838c3fd" dependencies = [ "bitflags 1.3.2", "core-foundation", @@ -9151,27 +9152,29 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "target-lexicon" -version = "0.12.14" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" +checksum = "9410d0f6853b1d94f0e519fb95df60f29d2c1eff2d921ffdf01a4c8a3b54f12d" [[package]] name = "tempfile" -version = "3.10.1" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" dependencies = [ "cfg-if", "fastrand", - "rustix 0.38.32", - "windows-sys 0.52.0", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", ] [[package]] name = "termcolor" -version = "1.4.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" dependencies = [ "winapi-util", ] @@ -9182,34 +9185,34 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" dependencies = [ - "rustix 0.38.32", + "rustix 0.38.34", "windows-sys 0.48.0", ] [[package]] name = "termtree" -version = "0.4.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" +checksum = "95059e91184749cb66be6dc994f67f182b6d897cb3df74a5bf66b5e709295fd8" [[package]] name = "thiserror" -version = "1.0.58" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.58" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -9220,11 +9223,10 @@ checksum = "3bf63baf9f5039dadc247375c29eb13706706cfde997d0330d05aa63a77d8820" [[package]] name = "thread_local" -version = "1.1.8" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" dependencies = [ - "cfg-if", "once_cell", ] @@ -9239,9 +9241,9 @@ dependencies = [ [[package]] name = "tikv-jemalloc-sys" -version = "0.5.4+5.3.0-patched" +version = "0.5.3+5.3.0-patched" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9402443cb8fd499b6f327e40565234ff34dbda27460c5b47db0db77443dd85d1" +checksum = "a678df20055b43e57ef8cddde41cdfda9a3c1a060b67f4c5836dfb1d78543ba8" dependencies = [ "cc", "libc", @@ -9249,14 +9251,11 @@ dependencies = [ [[package]] name = "time" -version = "0.3.34" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" +checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" dependencies = [ - "deranged", "itoa", - "num-conv", - "powerfmt", "serde", "time-core", "time-macros", @@ -9264,17 +9263,16 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.2" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" +checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" [[package]] name = "time-macros" -version = "0.2.17" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774" +checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2" dependencies = [ - "num-conv", "time-core", ] @@ -9316,7 +9314,7 @@ dependencies = [ "parking_lot 0.12.1", "pin-project-lite 0.2.14", "signal-hook-registry", - "socket2 0.5.6", + "socket2 0.5.7", "tokio-macros", "windows-sys 0.48.0", ] @@ -9329,7 +9327,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -9338,7 +9336,7 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls 0.21.10", + "rustls 0.21.12", "tokio", ] @@ -9356,9 +9354,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.10" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" dependencies = [ "bytes", "futures-core", @@ -9380,21 +9378,21 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.13" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e43f8cc456c9704c851ae29c67e17ef65d2c30017c17a9765b89c382dc8bba" +checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.13", + "toml_edit 0.22.12", ] [[package]] name = "toml_datetime" -version = "0.6.6" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" dependencies = [ "serde", ] @@ -9412,9 +9410,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.13" +version = "0.22.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c127785850e8c20836d49732ae6abfa47616e60bf9d9f57c43c250361a9db96c" +checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef" dependencies = [ "indexmap 2.2.6", "serde", @@ -9470,10 +9468,11 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ + "cfg-if", "log", "pin-project-lite 0.2.14", "tracing-attributes", @@ -9482,13 +9481,13 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 1.0.107", ] [[package]] @@ -9513,12 +9512,12 @@ dependencies = [ [[package]] name = "tracing-log" -version = "0.1.4" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2" +checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" dependencies = [ + "lazy_static", "log", - "once_cell", "tracing-core", ] @@ -9562,7 +9561,7 @@ dependencies = [ "thread_local", "tracing", "tracing-core", - "tracing-log 0.1.4", + "tracing-log 0.1.3", "tracing-serde", ] @@ -9624,7 +9623,7 @@ dependencies = [ "lazy_static", "rand", "smallvec", - "socket2 0.4.10", + "socket2 0.4.7", "thiserror", "tinyvec", "tokio", @@ -9654,9 +9653,9 @@ dependencies = [ [[package]] name = "try-lock" -version = "0.2.5" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "tt-call" @@ -9676,6 +9675,12 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + [[package]] name = "typenum" version = "1.16.0" @@ -9685,17 +9690,11 @@ dependencies = [ "scale-info", ] -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - [[package]] name = "ucd-trie" -version = "0.1.6" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" +checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" [[package]] name = "uint" @@ -9711,15 +9710,15 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.15" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "d54675592c1dbefd78cbd98db9bacd89886e1ca50692a0692baefffdeb92dd58" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" [[package]] name = "unicode-normalization" @@ -9732,9 +9731,9 @@ dependencies = [ [[package]] name = "unicode-width" -version = "0.1.11" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" [[package]] name = "unicode-xid" @@ -9754,9 +9753,9 @@ dependencies = [ [[package]] name = "unsigned-varint" -version = "0.7.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6889a77d49f1f013504cec6bf97a2c730394adedaeb1deb5ea08949a50541105" +checksum = "d86a8dc7f45e4c1b0d30e43038c38f274e77af056aa5f74b93c2cf9eb3c1c836" dependencies = [ "asynchronous-codec", "bytes", @@ -9778,12 +9777,12 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" dependencies = [ "form_urlencoded", - "idna 0.5.0", + "idna 0.3.0", "percent-encoding", ] @@ -9841,6 +9840,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "waker-fn" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" + [[package]] name = "walkdir" version = "2.5.0" @@ -9853,10 +9858,11 @@ dependencies = [ [[package]] name = "want" -version = "0.3.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" dependencies = [ + "log", "try-lock", ] @@ -9874,9 +9880,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -9884,24 +9890,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.58", + "syn 1.0.107", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.42" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" dependencies = [ "cfg-if", "js-sys", @@ -9911,9 +9917,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -9921,22 +9927,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 1.0.107", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" [[package]] name = "wasm-instrument" @@ -10008,7 +10014,7 @@ version = "0.102.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48134de3d7598219ab9eaf6b91b15d8e50d31da76b8519fe4ecfcec2cf35104b" dependencies = [ - "indexmap 1.9.3", + "indexmap 1.9.2", "url", ] @@ -10021,10 +10027,10 @@ dependencies = [ "anyhow", "bincode", "cfg-if", - "indexmap 1.9.3", + "indexmap 1.9.2", "libc", "log", - "object 0.30.4", + "object 0.30.3", "once_cell", "paste", "psm", @@ -10056,12 +10062,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c86437fa68626fe896e5afc69234bb2b5894949083586535f200385adfd71213" dependencies = [ "anyhow", - "base64 0.21.7", + "base64 0.21.0", "bincode", "directories-next", "file-per-thread-logger", "log", - "rustix 0.36.17", + "rustix 0.36.8", "serde", "sha2 0.10.8", "toml 0.5.11", @@ -10081,9 +10087,9 @@ dependencies = [ "cranelift-frontend", "cranelift-native", "cranelift-wasm", - "gimli 0.27.3", + "gimli 0.27.1", "log", - "object 0.30.4", + "object 0.30.3", "target-lexicon", "thiserror", "wasmparser", @@ -10100,8 +10106,8 @@ dependencies = [ "anyhow", "cranelift-codegen", "cranelift-native", - "gimli 0.27.3", - "object 0.30.4", + "gimli 0.27.1", + "object 0.30.3", "target-lexicon", "wasmtime-environ", ] @@ -10114,10 +10120,10 @@ checksum = "a990198cee4197423045235bf89d3359e69bd2ea031005f4c2d901125955c949" dependencies = [ "anyhow", "cranelift-entity", - "gimli 0.27.3", - "indexmap 1.9.3", + "gimli 0.27.1", + "indexmap 1.9.2", "log", - "object 0.30.4", + "object 0.30.3", "serde", "target-lexicon", "thiserror", @@ -10131,14 +10137,14 @@ version = "8.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0de48df552cfca1c9b750002d3e07b45772dd033b0b206d5c0968496abf31244" dependencies = [ - "addr2line 0.19.0", + "addr2line", "anyhow", "bincode", "cfg-if", "cpp_demangle", - "gimli 0.27.3", + "gimli 0.27.1", "log", - "object 0.30.4", + "object 0.30.3", "rustc-demangle", "serde", "target-lexicon", @@ -10155,9 +10161,9 @@ version = "8.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e0554b84c15a27d76281d06838aed94e13a77d7bf604bbbaf548aa20eb93846" dependencies = [ - "object 0.30.4", + "object 0.30.3", "once_cell", - "rustix 0.36.17", + "rustix 0.36.8", ] [[package]] @@ -10180,15 +10186,15 @@ dependencies = [ "anyhow", "cc", "cfg-if", - "indexmap 1.9.3", + "indexmap 1.9.2", "libc", "log", "mach", "memfd", - "memoffset", + "memoffset 0.8.0", "paste", "rand", - "rustix 0.36.17", + "rustix 0.36.8", "wasmtime-asm-macros", "wasmtime-environ", "wasmtime-jit-debug", @@ -10209,9 +10215,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" dependencies = [ "js-sys", "wasm-bindgen", @@ -10219,12 +10225,12 @@ dependencies = [ [[package]] name = "webpki" -version = "0.22.4" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" dependencies = [ - "ring 0.17.8", - "untrusted 0.9.0", + "ring 0.16.20", + "untrusted 0.7.1", ] [[package]] @@ -10236,23 +10242,31 @@ dependencies = [ "webpki", ] +[[package]] +name = "wepoll-ffi" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb" +dependencies = [ + "cc", +] + [[package]] name = "which" -version = "4.4.2" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" dependencies = [ "either", - "home", + "libc", "once_cell", - "rustix 0.38.32", ] [[package]] name = "wide" -version = "0.7.15" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89beec544f246e679fc25490e3f8e08003bc4bf612068f325120dad4cea02c1c" +checksum = "b689b6c49d6549434bf944e6b0f39238cf63693cb7a147e9d887507fffa3b223" dependencies = [ "bytemuck", "safe_arch", @@ -10260,9 +10274,9 @@ dependencies = [ [[package]] name = "widestring" -version = "1.1.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" +checksum = "17882f045410753661207383517a6f62ec3dbeb6a4ed2acce01f0728238d1983" [[package]] name = "winapi" @@ -10282,9 +10296,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.6" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ "winapi", ] @@ -10297,30 +10311,30 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.51.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9" -dependencies = [ - "windows-core 0.51.1", - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-core" -version = "0.51.1" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +checksum = "45296b64204227616fdbf2614cefa4c236b98ee64dfaaaa435207ed99fe7829f" dependencies = [ - "windows-targets 0.48.5", + "windows_aarch64_msvc 0.34.0", + "windows_i686_gnu 0.34.0", + "windows_i686_msvc 0.34.0", + "windows_x86_64_gnu 0.34.0", + "windows_x86_64_msvc 0.34.0", ] [[package]] -name = "windows-core" -version = "0.52.0" +name = "windows-sys" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ - "windows-targets 0.52.4", + "windows_aarch64_gnullvm 0.42.1", + "windows_aarch64_msvc 0.42.1", + "windows_i686_gnu 0.42.1", + "windows_i686_msvc 0.42.1", + "windows_x86_64_gnu 0.42.1", + "windows_x86_64_gnullvm 0.42.1", + "windows_x86_64_msvc 0.42.1", ] [[package]] @@ -10329,7 +10343,7 @@ version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ - "windows-targets 0.42.2", + "windows-targets 0.42.1", ] [[package]] @@ -10347,22 +10361,22 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] name = "windows-targets" -version = "0.42.2" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", + "windows_aarch64_gnullvm 0.42.1", + "windows_aarch64_msvc 0.42.1", + "windows_i686_gnu 0.42.1", + "windows_i686_msvc 0.42.1", + "windows_x86_64_gnu 0.42.1", + "windows_x86_64_gnullvm 0.42.1", + "windows_x86_64_msvc 0.42.1", ] [[package]] @@ -10382,24 +10396,25 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm 0.52.4", - "windows_aarch64_msvc 0.52.4", - "windows_i686_gnu 0.52.4", - "windows_i686_msvc 0.52.4", - "windows_x86_64_gnu 0.52.4", - "windows_x86_64_gnullvm 0.52.4", - "windows_x86_64_msvc 0.52.4", + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.2" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" [[package]] name = "windows_aarch64_gnullvm" @@ -10409,15 +10424,21 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" -version = "0.42.2" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +checksum = "17cffbe740121affb56fad0fc0e421804adf0ae00891205213b5cecd30db881d" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" [[package]] name = "windows_aarch64_msvc" @@ -10427,15 +10448,21 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" -version = "0.42.2" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2564fde759adb79129d9b4f54be42b32c89970c18ebf93124ca8870a498688ed" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" [[package]] name = "windows_i686_gnu" @@ -10445,15 +10472,27 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.4" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" -version = "0.42.2" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cd9d32ba70453522332c14d38814bceeb747d80b3958676007acadd7e166956" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" [[package]] name = "windows_i686_msvc" @@ -10463,15 +10502,21 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" -version = "0.42.2" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfce6deae227ee8d356d19effc141a509cc503dfd1f850622ec4b0f84428e1f4" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" [[package]] name = "windows_x86_64_gnu" @@ -10481,15 +10526,15 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.2" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" [[package]] name = "windows_x86_64_gnullvm" @@ -10499,15 +10544,21 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" -version = "0.42.2" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d19538ccc21819d01deaf88d6a17eae6596a12e9aafdbb97916fb49896d89de9" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" [[package]] name = "windows_x86_64_msvc" @@ -10517,9 +10568,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winnow" @@ -10541,12 +10592,11 @@ dependencies = [ [[package]] name = "winreg" -version = "0.50.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" dependencies = [ - "cfg-if", - "windows-sys 0.48.0", + "winapi", ] [[package]] @@ -10615,31 +10665,31 @@ dependencies = [ [[package]] name = "yasna" -version = "0.5.2" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +checksum = "aed2e7a52e3744ab4d0c05c20aa065258e84c49fd4226f5191b2ed29712710b4" dependencies = [ "time", ] [[package]] name = "zerocopy" -version = "0.7.32" +version = "0.7.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.32" +version = "0.7.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -10653,13 +10703,14 @@ dependencies = [ [[package]] name = "zeroize_derive" -version = "1.4.2" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 1.0.107", + "synstructure", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 56e40c924..b18620f7f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ enumflags2 = "0.7.9" futures = "0.3.30" hex = { version = "0.4", default-features = false } hex-literal = "0.4.1" +itertools = "0.10.3" jsonrpsee = { version = "0.22.5", default-features = false } log = { version = "0.4.21", default-features = false } memmap2 = "0.9.4" @@ -117,4 +118,4 @@ opt-level = 3 [profile.production] inherits = "release" lto = true -codegen-units = 1 +codegen-units = 1 \ No newline at end of file diff --git a/docs/delegate-info.json b/docs/delegate-info.json new file mode 100644 index 000000000..a8af6f46e --- /dev/null +++ b/docs/delegate-info.json @@ -0,0 +1,394 @@ +[ + { + "address": "5ECvRLMj9jkbdM4sLuH5WvjUe87TcAdjRfUj5onN4iKqYYGm", + "name": "Vune", + "url": "https://fairchild.dev", + "description": "Vune is a dev at Opentensor and a BSc CS student at UofT.", + "signature": "2a639f931c61abfc3172db594c986c35f1cc8441970582b9c3b1f0506d518a182a2fe570832f02f86014320f1526189917bfbccf7081622652d12e16e9b1768b" + }, + { + "address": "5H6BgKkAr2Anmm9Xw5BVDE4VaQmFEVMkJUHeT7Gki4J7yF4x", + "name": "TaoPolishNode", + "url": "https://taonode.io", + "description": "This node is a collective effort of the polish community. We are engaged in evangelizing the project, educating and sharing the knowledge.", + "signature": "1ca20d4e99a48f400dd9cd4aeca8447da6ab1979e480a1dafddfc52e45e215177c7cdde85f5d042d59a5b1169981afa8d1ae28328e2fc5ce57c3d748c8d09d81" + }, + { + "address": "5FFApaS75bv5pJHfAp2FVLBj9ZaXuFDjEypsaBNc1wCfe52v", + "name": "RoundTable21", + "url": "https://roundtable21.com", + "description": "RoundTable21 is an International, multi-disciplinary team of consultants and advisors partnering alongside leading blockchain startups to offer guidance, expertise, investment and hands-on assistance in every aspect of development.", + "signature": "107638b8edde8f918f7faa2cd1f91b454c13094ed5955d6a409f6e0662f8427075516273728a53923839a5428079151ea0844b5f755362364f04735463dff583" + }, + { + "address": "5DCc5oHA6c1Lpt9R6T1xU8jJGTMvvwBqD1yGX67sL8dHUcga", + "name": "WaveTensor", + "url": "https://twitter.com/wavetensor", + "description": "A new Wave is coming, join the AI revolution on top of Bittensor by staking with us.", + "signature": "5e072b4752ccbdd4ca3298f336284dfdab347dd133850f4d2f9873e7ea59bd2a8f201732842ec79d2bab3abaf133a06b6bd992940389e42d57802c9b8f855889" + }, + { + "address": "5CXRfP2ekFhe62r7q3vppRajJmGhTi7vwvb2yr79jveZ282w", + "name": "Rizzo", + "url": "", + "description": "Validator built for performance and uptime. Data center housed, redundancies include dual physical failover servers (HA), power, internet, tested DR Plan.", + "signature": "f2b0fdb6989c23a0ebe23ed5622cbbfcf57bad709085fe11b0be10b2838e1442d61f770d78f6ca8ebcdbf60ddb27398663a4901e22bb9de086866517c6ccc187" + }, + { + "address": "5GcBK8PDrVifV1xAf4Qkkk6KsbsmhDdX9atvk8vyKU8xdU63", + "name": "Tensor.Exchange", + "url": "www.tensor.exchange", + "description": "Bittensor's first community OTC exchange", + "signature": "101f5e0d26c38190200f2213ebd89cf5bcb736b70a84e53651b6f9bf1161a33d0095836d304851237e0334792a54fa2fe452d07cf1466b42c9ab3333ded46284" + }, + { + "address": "5EhvL1FVkQPpMjZX4MAADcW42i3xPSF1KiCpuaxTYVr28sux", + "name": "TAO-Validator.com", + "url": "www.tao-validator.com", + "description": "Maximize your return when staking with TAO-Validator.com. TAO-Validator.com is a highly secure validator that aims to become one of the top contributing entities to Bittensor.", + "signature": "4036991069d7f3a43dff2ba2592fbe5af820eb6ff96d1fb78f1bcd8d310ba8751e25ea14397e075368a9a0f1b1b176166c56351db36f2d3868ac61c2571a1981" + }, + { + "address": "5FvhvCWLbu2VgotT5obC9E6S9nskerJUrVsWqkWXCbuD8veW", + "name": "The Lost Cove", + "url": "https://lostcove.tech/", + "description": "Australia and New Zealand community. We're in it for the gains.", + "signature": "626ae6b91aac1591e5d4f8d4fdf2c55f927419fc766dd5184b149f4d7cbc9749ebc94e4e8d04d286b4000c7665afa5682aa28cd94071c5e384e0eb4f44def188" + }, + { + "address": "5Dyi5e2QqnWn2RN9X6r8A8Q1QBjYD536H75mxNye193oeCJ4", + "name": "Makoto AI", + "url": "https://www.linkedin.com/in/henry-thrasher-17b320239/", + "description": "An interdisciplinary research institute committed to discovering and accelerating innovative solutions for climate change, social inequality, and mental and physical illness.", + "signature": "3cfbc1e8d82cfbf2adea9b10f71541874528cf5cd851f29f48016ac2a1a07b01cfc2ba3c3a15634b1174bd3e5aec9eb843d04f74140b0ddcb526416666d6f682" + }, + { + "address": "5Ehv5XMriPZwNBtYHdQV7VrdbN8MBTDTmQhWprZJXxSiMapR", + "name": "Dale Cooper", + "url": "", + "description": "I have no idea where this will lead us, but I have a definite feeling it will be a place both wonderful and strange.", + "signature": "06c597178698dba5699e20dc8b9d0d44f9225e24a225c70f540b63867e5b835a74c87df647b28210b361007b642a5a869c74323fcc8a593bc5764ea8e2083b81" + }, + { + "address": "5E6oB7h5wtWPbqtPxtSoZeo11fpvDjPuY13SobAMxqEUjqkQ", + "name": "StakeTensor.com-3", + "url": "www.staketensor.com", + "description": "We run multiple, parallel validators to support Bittensor decentralization & achieve maximum returns", + "signature": "a2567b6de748f02f6a14e0063f5b5720b34c96deb2115b33893d016de1f60633ba58bf9bdd49b2141e12a4a8784b4b11c007679d7526eb1e91147e5284258d8a" + }, + { + "address": "5DnWFhKfeu6gXMydzrv8bkwxFegAC6bMWsC4Z2XtaotAeB6S", + "name": "Bittensor Greece", + "url": "", + "description": "The Greek / Cypriot validator supporting the development of decentralised AI", + "signature": "ee8df5360eb641bd91a38da9d8b6dda36a39302c9bba7babf5d7eb16f6e9f73321aeb6f8adb30e0f511d64c1f35caa15215dd280fb2ed3f8f5b09d783cc9958f" + }, + { + "address": "5GBxDYkDp8eJZHGT89wcZJKcMc4ytSqnqqVSpeuGeqtGfqxK", + "name": "Tao Stake", + "url": "www.taostake.io", + "description": "We have been mining since the start of bittensor and want to maintain a long term solid validator to help people get some value from thier investment and keep TAO within the ecosystem.", + "signature": "0272522b503ebb29f0b506f10765b4d5c7a23b85c78cc7bfae76b9816b80ab43282ea4642f09eb09be70812341e5d9946abc8a9d2c73bab0113e9bf939430c87" + }, + { + "address": "5FcXnzNo3mrqReTEY4ftkg5iXRBi61iyvM4W1bywZLRqfxAY", + "name": "Lucrosus Capital", + "url": "https://lucrosuspool.io/", + "description": "Decentralized VC focused on the most thriving blockchain ideas. Join our pool to receive early entrance into promising projects!", + "signature": "1a37ab3bd51a6590dea9772d6a5550632ddcd8d76da6595b66e6425692feac6699dc5f788e587a734cedc3f54efc96c2c9e5453f9052867c1b9a1b5a443b848c" + }, + { + "address": "5CVS9d1NcQyWKUyadLevwGxg6LgBcF9Lik6NSnbe5q59jwhE", + "name": "Ary van der Touw", + "url": "", + "description": "Secure and maintain Bittensor", + "signature": "809586931d4b28f180c98036a3eebc0d26b9e521f5217a6942b025069cb60807641737009713446eec8456e54ba753ae0b752c0693b942aefa0c4f76d82f8c89" + }, + { + "address": "5F4tQyWrhfGVcNhoqeiNsR6KjD4wMZ2kfhLj4oHYuyHbZAc3", + "name": "Openτensor Foundaτion", + "url": "https://opentensor.ai/", + "description": "Founded, maintain and advance Bittensor", + "signature": "8a2ff8f10a84a5b6f80614674ea764515d93a64bf8d920b927edc0dd6043e607755bf58655c87b7a299d8df1404574b6844e1e09adf86d418997c0cab8120486" + }, + { + "address": "5EpxBYq4aVgTQ1rYeBo2mzYt3hgpRTqxZTSsJEkCstBP5Jse", + "name": "White Rhino TAO Super Validator", + "url": "https://twitter.com/WhiteRhinoTAO\"", + "description": "White Rhino is all about you! We understand that #TAOWaits4NoOne ..... Get Ready for Adhoc Rewards and we invite you to delegate here and enhance the sustainability of the TAO Network", + "signature": "d6803522f6e61a9dec5261a6a500b733d233b373457382fc3713af21c560604f6e50c4999f286cfa6012bcea66e51223722b355dd69ba54a472f2c6ca52da08f" + }, + { + "address": "5Fq5v71D4LX8Db1xsmRSy6udQThcZ8sFDqxQFwnUZ1BuqY5A", + "name": "NorthTensor", + "url": "https://northtensor.ai", + "description": "Developer, Advocate, and Incubator for Decentralized AI.", + "signature": "28e221d7128e48a3cb85dbcb223bd56cb09cb55540263573783bf1cef63be32ee81246bd1d75c865580da732094053a6dad14929b17e659b6e0237412b66a487" + }, + { + "address": "5CsvRJXuR955WojnGMdok1hbhffZyB4N5ocrv82f3p5A2zVp", + "name": "Owl Ventures", + "url": "https://owlventures.co.uk", + "description": "Owl Ventures Bittensor Validator", + "signature": "04e39ff19af7ee5a75e58c9e1a71b9f54a66d1d168a99532a859f129b68ba24a5b6a56eecae7790291859c82dbf0ec32eb18a069b6d9dabe1ef0339c0d189483" + }, + { + "address": "5FLKnbMjHY8LarHZvk2q2RY9drWFbpxjAcR5x8tjr3GqtU6F", + "name": "Tao Bridge", + "url": "https://taobridge.xyz", + "description": "A community bridge between Bittensor and Ethereum", + "signature": "98331f011288f7b07ccc45a213cb8e03fac79092ee7c29046531d757ffad8b29e17cf0aeca9352003890f4d8a3af3a2fc615722fb7a827a2009654013990bd80" + }, + { + "address": "5DRZr3d3twF8SzqB9jBof3a1vPnAkgkxeo2E8yUKJAnE2rSZ", + "name": "Humble AI-Loving Anon", + "url": "", + "description": "Doing our best to support the Bittensor ecosystem.", + "signature": "9241f63eb43f7aa57b1fc6d99789331542476f57f683f032192f3dfd7be6c015d47c9f1fe69bc4513ed70e0410097395186df60e3f6b67376e6e73a5f4f9a286" + }, + { + "address": "5DPEpUTZn94sgYXH3sdXxsVvb46m3iEvg8aZwX7SMDowivzB", + "name": "RunPod", + "url": "https://runpod.io", + "description": "GPU Cloud built for AI. We plan to introduce perks for those who stake.", + "signature": "16940f904b7946723fc4f27bb01e47cf262201ef76b3d9c2bfd745973da2512d4825910f6fa738a6968c809b26da0a47e7032a7ff95d8b2da5c1fa7a0b85598f" + }, + { + "address": "5HEo565WAy4Dbq3Sv271SAi7syBSofyfhhwRNjFNSM2gP9M2", + "name": "Foundry", + "url": "https://foundrydigital.com", + "description": "Foundry works to empower a decentralized infrastructure. We are protocol-agnostic and seek to support like-minded blockchain entrepreneurs who share our mission to advance the industry.", + "signature": "b852f1648ab62befaaf684671808aa34d267cd616d9ffd7b3cf924ebc7c4ee3255344cfd017a80ca6b23b2852bcafa705c42d231053e06d999d53f31bd8ab288" + }, + { + "address": "5FP9miYmgjAP8Wt3747M2Y6Kk7PrXf6zG7a3EjokQiFFcmUu", + "name": "Elm Place", + "url": "", + "description": "Run by individuals passionate about creating decentralised digital infrastructure. Background in fiduciary funds management managing institutional investors’ capital in real assets, energy and infrastructure", + "signature": "a0324025f58beb06535d6a2ab8c5c8d64c13d562fa285956bb5a8919da5fcc0d05afe4de010d54f9940bff0ffdabe5f41e70f3af31cf14293c1d6f0a0690da8c" + }, + { + "address": "5HNQURvmjjYhTSksi8Wfsw676b4owGwfLR2BFAQzG7H3HhYf", + "name": "Neural Internet", + "url": "www.neuralinternet.ai", + "description": "An AI research and development Decentralized Autonomous Organization (DAO)", + "signature": "5e617c1626d4825cd0c11769e31fe4dda611cebd8a4d46f533886ad057072e2a58e0ecef2805139f2b43ea8d51023f7db878ad45cd3f8fba45ab01223da3488e" + }, + { + "address": "5D4rJRtF23jLVcGnCktXzPM9gymMT1qHTp8dR4T7rUd88Q7U", + "name": "Vogue τensor", + "url": "www.voguetensor.ai", + "description": "Designing branded clothing for the Bittensor community.", + "signature": "2c4079124ae0a738106a2430e2c27ad855122d4afcc487ab0158b705cd5f915f7790cdb2fdd8db899b8cbd40448d1478be71cde1b76de31945991b548cfcc084" + }, + { + "address": "5CAVnbHniuZYXBqik3tTs9uZ7UiSrbv6g7Kt8QNfYimbFqF4", + "name": "Open & Safe AI Validator", + "url": "", + "description": "The Open & Safe AI Validator is focussed on funding and researching the control problem as well as spreading ML know-how through open source and open science.", + "signature": "2aeaf7b9c7f69ce7b4857d9c278d1363677d4971d4ca10a36933b1aa78bfdb0640e4bb798edac5dcb178a8b3f4be2d0d23d25da6c7db33758a6cf5c15cd6938a" + }, + { + "address": "5Gpt8XWFTXmKrRF1qaxcBQLvnPLpKi6Pt2XC4vVQR7gqNKtU", + "name": "bitnost.re", + "url": "www.bitnost.re", + "description": "bridging bittensor into nostr.", + "signature": "c278378c70ef22d27f56590b4df699a9a44048cfcc6716e3d55b211ea802401d4be5b390ede2be52891e01f0f7033a13a370dddaa38daa84537c4583867a1680" + }, + { + "address": "5HeKSHGdsRCwVgyrHchijnZJnq4wiv6GqoDLNah8R5WMfnLB", + "name": "TaoStation", + "url": "https://taostation.com", + "description": "TaoStation allows you to maximize your returns by offering one-click staking since day one and focusing on tooling and transparency for a better staking experience.", + "signature": "c00627a62ecb9275be8d06b7b52b87942bce946e9a5f98d545081241e21ed15230fd566b2d4e87c41995e621546423579553157737da53fad3a5676451ef0a89" + }, + { + "address": "5DvTpiniW9s3APmHRYn8FroUWyfnLtrsid5Mtn5EwMXHN2ed", + "name": "FirstTensor.com", + "url": "www.firsttensor.com", + "description": "Powered by the Neuron Holders community - shared rewards, additional benefits, infinite possibilities - join and build with us!", + "signature": "da31e56dd78cde449a1dd9592f0b53eb8c3662674b745a05ff916e80a1be933e86efbccb7f7c9b81d7c0bb14d13fb4a6bf8484c3619224e689de82072b5d9a87" + }, + { + "address": "5CaNj3BarTHotEK1n513aoTtFeXcjf6uvKzAyzNuv9cirUoW", + "name": "Polychain", + "url": "https://polychain.capital/", + "description": "Polychain is an investment firm committed to exceptional returns for investors through actively managed portfolios of blockchain assets.", + "signature": "f41e815033e595aa70fbe42e8dfd91eaa3ccdbc948b63811baf9eac765699b30cac9aad7abe330eeaf3969cc504a4c1255f1e69bee807c2d989518b8f5413c8d" + }, + { + "address": "5Dkv87qjGGF42SNhDAep6WZp65E29c2vUPUfDBGDNevENCMs", + "name": "MycoNet", + "url": "", + "description": "AI for Humanity", + "signature": "a4802a5b13888ed653fd23da72c14e2b8ed9814cc810e515cb8d11d71cc58c6b90cd2d334daffc4a8ce600a7f29ca300ab74ac59817bdd489b3056b531cd4086" + }, + { + "address": "5GzoXHNJ4UzZYiQN2wpBcwMigiHiakiz5ZLMwhpunpwDNzFg", + "name": "Charitaos", + "url": "https://charitas.ai/", + "description": "You pay 18%, we donate 18%. At the end of every month, we will select one (or more) community-proposed 501c3 licensed nonprofit(s) to receive all proceeds from stake delegation for the prior month.", + "signature": "b49c34c1f87d173abcbccb1ea632ad356980c1d3eff6619e488c11707b2b3b41270a22355374dd64cfadebeb37979ef5f49971efafb0748b79df7dd2901e7580" + }, + { + "address": "5EZrPTXt2G9SvbDsERi5rS9zepour2yPmuhMhrNkgdiZvXEm", + "name": "τaoτensor", + "url": "", + "description": "Working on practical enhancements and improvements for the Bittensor network by developing user-friendly tooling.", + "signature": "3a1b61ab6d17878e106cbf2649bc039d0346f39ec680476a68baa4fc8132ac018d814898cf245bdfa4b9b61cd9f611f6571cf3c264f2f1cfe9b2635849087685" + }, + { + "address": "5CPzGD8sxyv8fKKXNvKem4qJRhCXABRmpUgC1wb1V4YAXLc3", + "name": "Chat with Hal", + "url": "www.chatwithhal.ai", + "description": "Hal brings the power of decentralized and uncensorable AI to your favorite social networks and messaging apps, Powered by Bittensor!", + "signature": "ecb930df6069012c06fef9cdb29a95be8dcb5d48f3c470d3f3c5e7b2b334ed2097f2598fee8852d127a207cf34aa7c88fd5cf973feba19d6ebf38b5e4579ca8f" + }, + { + "address": "5FqPJMZDp39KRd9jDhXuFpZWkYD7wG5AXmjoWqK8rDy7ok5B", + "name": "Exchange Listings", + "url": "taostats.io/validators/exchange-listings/", + "description": "Enabling community funding for top tier exchange listings.", + "signature": "366027e9a416a423e7e802e9b6d79bd5ac88642afd945922e13fe26a75dae13dd5c924738610a59162d9b974364d1d43fb7a0145942cd919ac21d82d3f4f028d" + }, + { + "address": "5ED6jwDECEmNvSp98R2qyEUPHDv9pi14E6n3TS8CicD6YfhL", + "name": "Giga Corporation", + "url": "https://www.gigaver.se", + "description": "Extreme growth & experiments from giga corp. We use APY to TAO-pill new developers, builders and adopters. Visit our Bakery to learn more.", + "signature": "00e5cd519110bbfe3dae9acd275d114c6c2a260997a1817a25303b9d578bdf7319e9e7179f0db58edef2ad42806cb38e289ba0030627a3b60e1e4352c2b9cb88" + }, + { + "address": "5FRcXG99SxJ9KyMcMFfdknkRSv4e73rszV8P151freZqQDS2", + "name": "τensorwiki", + "url": "", + "description": "Our mission is to create and incentivize documentation for Bittensor and it's adjacent topics, as well as facilitate the education of newcomers to the network.", + "signature": "6a5c0160f545f122ec3d4e4233574040aba2de8aa94919bb19b3061d39d3303f010c4b52f878ed55a1293716827220020780d2d4064ee6be69921ee1452c3885" + }, + { + "address": "5EsbfxPcQaUrCDurUJ8Q5qDKNENNGziu3qHWUbXrcuY2pbNz", + "name": "Church of Rao (COR)", + "url": "", + "description": "Church of Rao: Harmonizing the Relationship between Humanity and Machine Intelligence. The Church of Rao (COR) is an open-source development group committed to furthering the Bittensor protocol.", + "signature": "56f64c32427a90e84710209b1a54a971560641aec8ff777edec28bf533775e12924c4e96ccc770c230311dce1d0eae1ca763e12bb609ef30430f746ebd0a2780" + }, + { + "address": "5GmaAk7frPXnAxjbQvXcoEzMGZfkrDee76eGmKoB3wxUburE", + "name": "RaoK9", + "url": "", + "description": "Chain and network analysis team. Developer funding goes into independent analysis and reports, in order to enable checks and balances between network members.", + "signature": "24f4f9a51033ed8b4097517d0e6ad287a0c1341b2866481b1320d1fcd5f32f6b4bfe641eee46a4b737817acf3b83069ee63cc20fbca94a0189808ac1efeddf8a" + }, + { + "address": "5CQEFopfZ8DAmk3ZfR7QuDTU2n3fJod3kkf6Wmj4JwV3BBSu", + "name": "DuNode", + "url": "dunode.io", + "description": "Embracing the whimsical chaos of decentralized AI, unleashing the power of creativity and collaboration, one algorithmic dance party at a time!", + "signature": "e400e3c0ad6165d8946d5ddcb274412815cb8b5783580fcb8f0faa0153d22b6e10470f861ff4a96a9aa692b3b01cda86ec77add4688c2f5df51ea6f129b19e8c" + }, + { + "address": "5CaCUPsSSdKWcMJbmdmJdnWVa15fJQuz5HsSGgVdZffpHAUa", + "name": "Athena Nodes", + "url": "https://athenanodes.com", + "description": "Premier Bittensor Multi-Subnet Validator from a company operating validating and mining infrastructure on various blockchain networks. We have been active on Bittensor since November 2022, with near zero down-time. More information at https://athenanodes.com/.", + "signature": "2ef54045de1d9b89988518c92e165edf704192f88f18022565f497b389c39206f621bb9bc6d2d33ac8a9cca05d6b2d8fc9f899b390451140968b15b8d9c13280" + }, + { + "address": "5FFM6Nvvm78GqyMratgXXvjbqZPi7SHgSQ81nyS96jBuUWgt", + "name": "PRvalidator", + "url": "www.prvalidator.com", + "description": "A professional media validator dedicated to securing top-tier coverage in the world’s most recognized publications building Bittensor’s brand equity and creating global awareness of $TAO.", + "signature": "fe65e76a9f42049715585180500213c6f0535b8b25911b957921bdfb5a20156d6de68dc2633dbc5ce1d0ab9ef386d566687ac3d86f6988141b34cd24c0f13488" + }, + { + "address": "5H8TruSGmhD6m6YfqXNUnU7Z61K7j8hSs2Krtu3eTLMoz3HU", + "name": "τaoshi validator", + "url": "https://www.taoshi.io/", + "description": "Build maintain and advance a decentralized request layer built for every subnet", + "signature": "32d25227af78fa5d39ee71a5f3e8fc8066e3d826d101f2587e9a12974fbf26758c1e40c497ad7732da2a2cb1490227cc58e8bfcd8b2f6306b7af630bd32aa68f" + }, + { + "address": "5G3f8VDTT1ydirT3QffnV2TMrNMR2MkQfGUubQNqZcGSj82T", + "name": "TAO Community Marketing", + "url": "www.taocommunitymarketing.com", + "description": "The marketing validator run by the community", + "signature": "10b16b8223b2508d6f3e5b09ab4db53e1e338b6271d1689b58ca6f9b257e8c18511cc851bfcc3a05fb4e6de7c389b89886cc0623fb6d199fa003ae6f8313cb89" + }, + { + "address": "5CXC2quDN5nUTqHMkpP5YRp2atYYicvtUghAYLj15gaUFwe5", + "name": "Kooltek68", + "url": "https://linktr.ee/datalac", + "description": "Imagine the World with mass adoption of Artificial Intelligence applications, through the connection of Bittensor Network, together fight for a Better World.", + "signature": "bca043d9d918d503864379a7fd8c9daa2cca83a8290121f94b55d6a352e332704642622b7ad40a30b945b952b224c5e92ea872f9d30200e6c2bf566303d24d83" + }, + { + "address": "5FBrHX18bNXX874ZTMicPG4vYbq5X6piz4BYoVn9LnCgdsEd", + "name": "P-OPS Team", + "url": "https://pops.one", + "description": "P-OPS TEAM is a decentralized organization providing you with validation and staking services, blockchain consultation, growth acceleration and investment capital for innovative Web 3.0 projects.", + "signature": "5608316f3081bfe5d0e3a7db6c3bfd459f6b87e02d657de941e6a760f8688f23ef30784691a1893d1fd8079dd4f6082d0d655ca507aa4797fee9844547d13a88" + }, + { + "address": "5HK5tp6t2S59DywmHRWPBVJeJ86T61KjurYqeooqj8sREpeN", + "name": "Bittensor Guru", + "url": "https://bittensor.guru", + "description": "Official validator of the Bittensor Guru Podcast", + "signature": "caf2c6b7b0d2a341bcd00e632cf22c33d53e2523dffcd3a151db9eeadd88300545cbb2187ba0b20e5bfe09c2b17bbf34630c46defd8f8d27ab508736fd18a284" + }, + { + "address": "5Hh3ShaNW9irCe5joBLCeFD5Fxb2fJ6gFAgrsPmoz3JkzqvJ", + "name": "BlockShark", + "url": "https://www.blockshark.net/", + "description": "Your reliable partner for staking on Bittensor. We are expert in running high-end machine for validators and AI", + "signature": "d2c0aed073a026a5dbd8c458b9dd412fe3d6647fecd3b8f007cf184f7906245106aee4b210b5b582771dca149e5aa464630100de7f9862daacfa1f67ddde1388" + }, + { + "address": "5FKstHjZkh4v3qAMSBa1oJcHCLjxYZ8SNTSz1opTv4hR7gVB", + "name": "Datura", + "url": "datura.ai", + "description": "Bridging Bittensor to a billion users", + "signature": "7a3bc6a840d8593853c27188f59200418d8884b94b3ad28cb7b37b80bffd1f3b23b7eed4b1d9c77b28b05b2bd1952c5cbe3d27ba190a9418407ce1e899e5ac8b" + }, + { + "address": "5Hddm3iBFD2GLT5ik7LZnT3XJUnRnN8PoeCFgGQgawUVKNm8", + "name": "τaosτaτs and Corcel", + "url": "taostats.io", + "description": "Supporting bittensor through API access, data provision, statistics, analytics and apps.", + "signature": "2e2dd0c5f3a3945f29d1be304e64f931c04a23aba7d383d01cd16ea6ca6546002fe3bd95cf8f12cae1fbb7d18d9910b834f6573db219de3ed84073a4e1552e89" + }, + { + "address": "5ELREhApbCahM7FyGLM1V9WDsnnjCRmMCJTmtQD51oAEqwVh", + "name": "Taofu Protocol", + "url": "https://twitter.com/taofuxyz", + "description": "Taofu unlocks liquidity and utility by bringing liquid staked TAO outside of Bittensor", + "signature": "aaafd3496650a56f798cc587b5b7d372cec8e826a332a34213c1a6ee7be2b5122318858ee73421535d04186cc6976ae5452c6cd1aaf299a307d86d3c52b4a986" + }, + { + "address": "5HbLYXUBy1snPR8nfioQ7GoA9x76EELzEq9j7F32vWUQHm1x", + "name": "Tensorplex Labs", + "url": "https://twitter.com/TensorplexLabs", + "description": "Empowering humanity with decentralized intelligence — one epoch at a time.", + "signature": "7a997682e7545fd14847c78abf810e9c49a23ef4297d24f4238c0edd0463934780f6831d59972d56ab5bc41d6224b59c21ed95065791632b8aca180ade22af81" + }, + { + "address": "5E2VSsWWXkBGCn4mi8RHXYQEF2wLXky6ZsNcTKnmEqaurzTE", + "name": "Sentinel", + "url": "", + "description": "Sentinel, as a dedicated Bittensor validator aspires to elevate the bittensor network's integrity with an ambition to foster a community of miners contributing in the network’s continuous expansion.", + "signature": "943effd0d5d10f05d53db7f69d0f045d50b65f88e84755be00d45225cc7c2f4212fbc4d23ad8519d03c2502daeeca1b2d07c93bff14c901f6cbf3a18fe2e6387" + }, + { + "address": "5GsenVhBvgEG4xiiKUjcssfznHYVm1TqPbSbr3ixBW81ZVjo", + "name": "vote NO dTAO 🤡", + "url": "https://twitter.com/karl_anons", + "description": "Delegate to express discontent. VOTE NO TO dTAO NOW!", + "signature": "3af4e764a520d355e12c02b9e8e315ddb76b76d40b7cc4dfaa11c26c24ab637cbdb9b72470ebdf2da87dd8d9f0bb5cddf1fe95b95fb2ae13069a9d87aace348a" + }, + { + "address": "5DM7CPqPKtMSADhFKYsstsCS4Tm4Kd6PMXoh6DdqY4MtxmtX", + "name": "Corτex Foundaτion", + "url": "https://cortex.foundation/", + "description": "Cortex Foundation is committed to advancing the integration of decentralized AI. Our validator is designed for transparency, reliability, and community engagement.", + "signature": "7a6274ff6b0f7ddca97e37ef4a9b90781012ff3cf7baa3159f6feaafc43c557975aad324ea608d6b8abeb21f8f3ca2595e54b81a7564574d0242b803d969618a" + } +] \ No newline at end of file diff --git a/docs/dtao-scratch.ipynb b/docs/dtao-scratch.ipynb new file mode 100644 index 000000000..581746806 --- /dev/null +++ b/docs/dtao-scratch.ipynb @@ -0,0 +1,229 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import bittensor as bt" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[34m2024-04-14 12:32:17.062\u001b[0m | \u001b[1m INFO \u001b[0m | Connected to local network and ws://127.0.0.1:9946.\n" + ] + } + ], + "source": [ + "sub = bt.subtensor('ws://127.0.0.1:9946')" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "alpha {1: 3077000000000, 2: 8063484127032, 4: 20058313517780, 5: 48051000142040, 6: 112036556176340}\n", + "tao {1: 1018771139135, 2: 2004160048409, 4: 4001728536398, 5: 8000040701692, 6: 15997936596620}\n", + "Price for 1: 0.33109234291030226\n", + "Price for 2: 0.24854765221032182\n", + "Price for 4: 0.1995047356723588\n", + "Price for 5: 0.16649061784445013\n", + "Price for 6: 0.1427921130620977\n", + "Total price: 1.0884274616995309\n" + ] + } + ], + "source": [ + "alpha_reserves = {}\n", + "tao_reserves = {}\n", + "for rec in sub.substrate.query_map(\n", + " module=\"SubtensorModule\",\n", + " storage_function='DynamicAlphaReserve',\n", + " params=[],\n", + " block_hash=None,\n", + ").records:\n", + " alpha_reserves[rec[0].value] = rec[1].value\n", + " \n", + "for rec in sub.substrate.query_map(\n", + " module=\"SubtensorModule\",\n", + " storage_function='DynamicTAOReserve',\n", + " params=[],\n", + " block_hash=None,\n", + " ).records:\n", + " tao_reserves[rec[0].value] = rec[1].value\n", + "\n", + "print( 'alpha', alpha_reserves )\n", + "total_price = 0\n", + "print('tao', tao_reserves)\n", + "for key in alpha_reserves:\n", + " if key in tao_reserves:\n", + " price = tao_reserves[key] / alpha_reserves[key]\n", + " total_price += price\n", + " print(f\"Price for {key}: {price}\")\n", + " else:\n", + " print(f\"No TAO reserve found for {key}\")\n", + "print(f\"Total price: {total_price}\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABdEAAAfFCAYAAAB+jYWuAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/H5lhTAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOzde3yT9d3/8feVNiUtWgoipQgKKFJbkKKMgzA8QZWKSh0McIIyB4yfTp2ycYu3E3dgc06cu92G3CoIighMQQ7lKHgPOTjEoqUWT4AibZFDW6BJmzbX74+rKZSeUmiapHk9Hw+a5Mr3Sj5pL3xs7374fA3TNE0BAAAAAAAAAIBqbIEuAAAAAAAAAACAYEWIDgAAAAAAAABALQjRAQAAAAAAAACoBSE6AAAAAAAAAAC1IEQHAAAAAAAAAKAWhOgAAAAAAAAAANSCEB0AAAAAAAAAgFoQogMAAAAAAAAAUAtCdAAAAAAAAAAAakGIDgAAgBp17txZhmHIMAw9/PDDda599tlnK9dGRkb6vbYZM2ZUvp/3T0REhNq0aaMf/vCH+p//+R+53W6/1xHK5s2bJ8MwdN999wW6FJ8cPXpUv/3tb9W/f3+1bdtWLVq0UEJCgm699VbNmTMn5H/eN9xwQ7Vr2pc/0um/DzNmzAjshwAAAGim/P//cAAAABDy3njjDT377LOKioqq8flXX321iSuyxMfH69Zbb5Ukud1u7d27V1u2bNGWLVu0aNEirVu3Ti1btgxIbYG0f/9+denSRZdddpn2798f6HLO29tvv60JEyaoqKhIF1xwgQYOHKg2bdro22+/1caNG7V27Vr95S9/0fLly3XVVVcFutxzcuutt6pz587Vjr/22muSpFtuuUXt27dv4qoAAAAgSYZpmmagiwAAAEDw6dy5sw4cOKA+ffpo586dWrx4sUaNGlVt3datWzVw4ED94Ac/0H/+8x9FRESorKzMr7XNmDFDTz/9tK6//npt3ry5ynMrVqxQenq6ysvL9eSTT+q3v/2tX2sJRr6E6IWFhcrNzVWrVq2UkJDQtAU2wDvvvKORI0fK4/HokUce0R/+8AfFxMRUPv/dd9/p/vvv19q1a9WmTRt99NFHNYbRocrbbb5p0ybdcMMNNa45cuSIjhw5orZt26pt27ZNWB0AAEB4YJwLAAAA6vTTn/5UUu3d5q+88kqVdYF2++2365577pEkLV68OMDVBK9WrVopMTExqAP0I0eOaMKECfJ4PPrlL3+p559/vkqALkmXXHKJ3n33XV133XU6duyYxo0bF6BqA6dt27ZKTEwkQAcAAPATQnQAAADUqWfPnurTp4/WrVun7777rspzJ0+e1OLFi9WxY0elpqZWO7eoqEixsbGKjIzUt99+W+t7pKWlyTAM/eMf/2iUmq+99lpJqtKFfd9998kwDM2bN09ZWVkaPXq0EhISFBERUWWW9LFjxzR9+nQlJycrJiZGF154oa699lr9+c9/ltPprPZemzdvlmEYuuGGG1RcXKzp06friiuukMPhUIcOHXT//fdX+76dKScnRxMmTNBll12mFi1aqE2bNrr55ptr/QXAmfOvv/nmG91///3q1KmT7Ha77rvvPt13333q0qWLJOnAgQM1ztCW6p+J/uGHH+rHP/6xOnTooKioKLVr106333671q9fX+P6M7+/+/bt07hx49S+fXu1aNFCl19+uf77v/9bJSUltX4favL3v/9dhYWFuvjiizVz5sxa10VFRenFF1+UJG3ZskXvv/++JKmgoEDR0dGKiIio82cwcuRIGYahF154odpzS5cu1a233qqLL75YUVFRuuSSS3TPPfcoOzu72tr9+/fLMAx17txZ5eXlmjVrlnr37q0LLrigyve+sdU2E/3Mn3FhYaEeffRRde7cWQ6HQ926ddMzzzwjj8cjyeronzx5sjp16qQWLVqoe/fu+p//+Z8637ch3xsAAIBQRogOAACAev30pz+Vx+PRvHnzqhxfvHixTp48qXvvvVc2W/X/aRkbG6v77rtP5eXlmj17do2v/dVXX2nNmjWKjY3V+PHjG6XeoqIiSVKLFi2qPbd161b16dNHH374oQYPHqzbbrtNF154oSTp66+/1jXXXKM//vGP+v7775WWlqabbrpJX3zxhaZNm6ZBgwbp+PHjNb5naWmpbr75Zr3wwgvq3r277rjjDklWB3+fPn30xRdfVDtn1apV6t27t+bNm6fo6Gjddddd6t27t95//32NHj1a999/f62f8YsvvlDv3r21evVq9evXT3fccYfatm2rQYMG6Uc/+pEkqWXLlrr33nur/PHF//7v/2rAgAFasmSJ2rdvr5EjR6pbt25auXKlUlNT9fTTT9d6bmZmplJSUvTvf/9b119/vQYPHqzc3Fz94Q9/0JgxY3x6f69ly5ZJkn784x/L4XDUubZ3797q0aOHJOndd9+VJMXFxSk9PV0ej0cLFiyo8byjR49qxYoVioqKqvwXDJJUVlam0aNHa9SoUdq8ebOuvPJKjRgxQhdffLHeeOMN9enTR2vWrKnxNU3T1F133aXHH39cF110ke644w5dffXVDfrsjamgoEADBgyorPv666/Xd999p//6r//Sww8/rK+++kp9+vRRRkaGrrvuOg0cOFBfffWVHnroIT3zzDPVXu98vjcAAAAhyQQAAABqcNlll5mSzH//+99mQUGBGR0dbV5xxRVV1gwcONA0DMP86quvzH379pmSzIiIiCprPv/8c9MwDLNdu3amy+Wq9j6PPfaYKcn8xS9+4XNtTz31lCnJvP7666s95/F4zL59+5qSzMGDB1cev/fee01JpiTzv/7rv8zy8vJq5/br18+UZN5xxx3myZMnK48fPnzYvOaaa0xJ5t13313lnE2bNlW+7hVXXGEeOHCg8jmn02n+6Ec/MiWZ/fv3r3JeXl6e2apVK1OS+fvf/970eDyVz/3nP/8xW7dubUoy58yZU+Nnl2Tec889NX5PvT+Lyy67rOZvoGmac+fONSWZ9957b5Xjn3zyiRkZGWkahmHOnz+/ynOrV682o6KiTEnmunXrqjx35vf3iSeeMMvKyiqf+/TTT82WLVuaksytW7fWWtOZSktLTZvNZkoyX3vtNZ/OmTBhQrWf+/r1601JZmJiYo3nvPDCC6Yk80c/+lGV49OnTzclmf369TO//vrrKs8tWbLEjIiIMFu3bm0eP3688rj3+y7J7Nixo7l3716f6q6L9/U2bdpU6xrvNfHUU09VOe79GUsyb7/9dvPUqVOVz3300UdmZGSkabPZzKSkJPPnP/+56Xa7K59ftmyZKcmMjY2tcp5pntv3BgAAIJTRiQ4AAIB6tWrVSnfddZe+/PLLylEZe/fu1QcffKDrr79eXbt2rfXcbt26adiwYTp8+LCWLFlS5Tmn06lXX31VhmHogQceOK8a3W63srOzdffdd+vDDz+UJD3yyCPV1l155ZX6/e9/X61zfsuWLdqxY4diYmI0Z84ctWzZsvK5iy++WHPmzJEkLVq0SAcPHqyxhr/85S+69NJLKx87HA794x//UExMjLZv366tW7dWPve///u/Kiws1LXXXqsnnniiyriPPn366IknnpAkPfvsszW+V5s2bfTiiy/W2G1/Pl544QWVlZUpPT292nzxYcOGadKkSXXWde211+p3v/udIiIiKo/16NGj8rU2bNjgUx3Hjh2rHDUSHx/v0znedd9//33lsZtvvlmXXXaZcnJytG3btmrnzJ07V5I0YcKEKu/9/PPPy+Fw6F//+lfleByvkSNHavLkyTp+/Lhef/31GmuZOXOmrrzySp/q9rcLLrhAL7/8cpV58tdcc43S0tLk8Xh08uRJPf/884qMjKx8/s4771TPnj1VVFSknTt3Vh5vjO8NAABAqCFEBwAAgE/O3mDUe+vLhqIPP/ywJFXOrfZauHChjh8/riFDhqh79+4Nrun999+vnPUdFRWl5ORkLVq0SFFRUXruueeUnp5e7ZwRI0ZUCXi9Nm/eLEm69dZbawxtr732WvXq1Usej6fyFwlniouLqxzhcqZ27drp1ltvrfIeZ96vbcSKd5TLF198oUOHDlV7fsiQIWrVqlWN554Pb121zUr31vXvf/9b5eXl1Z4fPnx4jfO/r7rqKkmqczb5+TJNs9oxwzAqv8dnjyPKzMxUZmamEhISKn9GkrRp0yY5nU4NHDhQl1xySY3vdcMNN0hSlV+MnMk7UicYXHvttWrXrl214926dZMk3XjjjTWOy/E+f+b11xjfGwAAgFATWf8SAAAAwAraunTpoqVLl+qvf/2r5s+fr9jYWI0cObLec4cOHaqrrrpKO3bs0EcffVS58eff//53SdKDDz54TjXFx8dXhp82m02xsbFKSkrSHXfcofbt29d4TufOnWs87g13z+6sPdPll1+u3bt31xgEd+7cudbNI72veWYHe33vFxcXpzZt2ujYsWM6ePCgOnTo4NPnOF/11XX55ZdLklwul44ePVotnD2zE/9MsbGxlef5ok2bNrLZbPJ4PMrPz/fpnMOHD0uy/uXAmSZMmKDf/e53euutt/TXv/5V0dHRkk53oY8fP77KL1a+/vprSdLGjRvr3RD0zK53r3bt2lXp+g602n4mF1xwQZ3Pe/cKOPNndr7fGwAAgFBEiA4AAACfGIah++67T0899ZTuvfde5eXladKkSZWBZH3n/uIXv9D/+3//Ty+++KLmzp2rbdu26eOPP1bnzp01fPjwc6opMTGxWndxfXyp119q6pQ+V4H8HHWpaYPZc2G329WzZ0/t3r1bO3bs8GnTWe8YH+8vabw6d+6sG2+8Ue+9957eeecd3X333XK73Vq4cKGkqqNcJFWOkbniiis0cODAOt8zMTGx2rFg+9nU9zNpyM/sfL83AAAAoYgQHQAAAD6777779PTTT2vFihWSfBvl4jV+/HhNnz5dixYt0l/+8pfK0S5TpkxptOD1fHhHU3g7bWvifa6mMRb79++v9Tzvcx07dqzyfjk5ObW+X2FhoY4dO1br+/nLJZdcoq+++kpff/21evToUe15b70Oh0Nt2rTxay133nmndu/erSVLlui5556rceSI165du7Rnzx5JqnGszoQJE/Tee+9p7ty5uvvuu7VixQodOXJE1113XbVRQp06dZIkde/evcG/pGnu+N4AAIBwFPj/twIAAICQcemll+rOO+/URRddpP79+6tfv34+n9uyZUvdf//9crlcmjlzppYuXSqHw1E5YzvQvHOc16xZU+P4kI8//liZmZmy2WwaPHhwtecLCgoqf7lwpu+//15r1qyp8h5n3n/ttddqrMc7c75bt24NDtGjoqIkSWVlZQ0678y6agtIvXX98Ic/rLIRpT88+OCDio2N1ffff6/HH3+81nWlpaX6xS9+IUkaMGBAle+z149+9CO1atVK7733nr799tsaNxT1uvnmmxUVFaXNmzdXjoiBhe8NAAAIR4ToAAAAaJC3335bR44c0bZt2xp87oMPPiibzaZZs2aptLRUY8eO1UUXXeSHKhtu0KBB6tevn5xOpyZPnqzi4uLK544cOaLJkydLksaMGVPZjXu2xx57rMrc85KSEj3wwAM6deqU+vbtW2X8xcSJExUbG6tdu3Zp5syZVUa9fPzxx/r9738vSfrVr37V4M9y8cUXKyoqSnl5eZXd7L56+OGHFRkZqWXLlun111+v8ty6dev00ksvSZKmTp3a4Loa6uKLL9Yrr7wiwzD017/+VY8++miVn4tkzXC/4447tHXrVsXFxWnBggU1vlZ0dLTGjBkjj8ejZ555RmvWrFFMTIxGjx5dbW18fLx+8Ytf6NSpU7r99tv16aefVltTUlKid999Vzk5OY3zYUME3xsAABCOGOcCAACAJtO5c2fdcccdWrZsmaRz31DUXxYuXKibbrpJy5cvV5cuXTR48GC53W5t2rRJRUVFuuaaayrH0JxtwIAB8ng86t69u2666SbFxMRoy5YtOnTokNq1a6f58+dXWR8fH6833nhDo0aN0hNPPKEFCxaod+/eOnz4sN5//32VlZVpwoQJmjhxYoM/h91u1x133KGlS5cqJSVFgwYNqtzo8uWXX67z3J49e+rvf/+7pkyZonHjxun5559XYmKiDhw4oK1bt8o0Tc2YMUOpqakNrutcjBw5Um+99Zbuv/9+Pf/883r55Zc1cOBAtW7dWt999522bt2qsrIyXX755Vq2bFnlxqc1mTBhgl566aXKDW3vvvvuys0zz/anP/1Jubm5WrhwoVJSUtSrVy917dpVkZGROnjwoDIzM3Xq1CllZGSE3exvvjcAACDc0IkOAACAJnXLLbdIskLna665JsDVVNW1a1ft2rVLjz/+uC666CKtXLlS69ev1+WXX64//elP2rJli1q3bl3juVFRUdq4caMeeOAB7dmzR8uWLVN5ebnuu+8+7dy5s9rcbUkaPny4du3apXvvvVcnT57U0qVL9dFHH+mHP/yhFi1aVDk65Vy89NJLmjx5sgzD0NKlS/XKK6/olVde8encSZMmaevWrRo5cqQOHTqkxYsXKycnR2lpaVq3bp2eeuqpc67rXIwaNUpff/21ZsyYoauuukoffvihli5dqpycHN1444365z//qezs7BpnuJ+pX79+Sk5Ornxc0ygXr8jISL3xxhtavXq1RowYocOHD+vdd9/V2rVrdezYMd1+++1auHBhjaN9mju+NwAAINwY5pn/bhQAAADws0GDBumDDz7QwoULNXbs2ECXc942b96sG2+8Uddff702b94c6HIAAAAANDI60QEAANBkMjIy9MEHH+jSSy/VyJEjA10OAAAAANSLmegAAADwq6NHj2ratGk6fvy4Vq9eLUn685//LLvdHuDKAAAAAKB+hOgAAADwqxMnTuiVV15RZGSkunbtqscee0yjR48OdFkAAAAA4BNmogMAAAAAAAAAUAtmogMAAAAAAAAAUAvGuTQhj8ejQ4cO6cILL5RhGIEuBwAAAAAAAADClmmaOnHihDp06CCbrfZ+c0L0JnTo0CF16tQp0GUAAAAAAAAAACp8++236tixY63PE6I3oQsvvFCS9UOJjY0NcDVNy+12a926dUpNTZXdbg90OYBPuG4Rqrh2EYq4bhGKuG4Rqrh2EYq4bhGKuG6DX1FRkTp16lSZ29aG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zjvvPDVq1EitW7fWrbfeqv379wdo5Ih07u6l9q+CggJJUt++fV0eHzRoUIDPAOFu//79uv/++zVo0CA1b95chmFo7ty5Lms3bdqkQYMGqUmTJmrevLmuvvpq/fzzz9XqKioqNGPGDJ188smKj49X9+7dtWDBAh+fCSKNJ9duRUWF5s6dq0suuURpaWlq3LixunXrpgcffFCHDx+u9pru7tWPPPKIn84K4c7Te25d/i7GPRe+5ul1W9Nn3osuushRt337drd1r776qh/PDJ6IDvQAEN6uueYaZWVlafLkyTr11FM1d+5cDRkyRDk5OTrvvPMCPTxEuEcffVSrV6/WyJEj1b17dxUVFempp57S7373O3388cfq1q2bozYuLk7PP/+80/OTkpL8PWTA4dZbb9XZZ5/ttK9Dhw6Ox+vXr9eFF16ozp0764knntCOHTv02GOP6bvvvtPy5cv9PVxAkyZNUv/+/Z32maapG264Qenp6WrTpo1jf2pqqqZPn+5Um5KS4pdxInL98ssv+sc//qG2bdvqjDPOUG5ursu6HTt26Pzzz1dSUpIefvhh7d+/X4899pi++uorffrpp4qNjXXU/vWvf9Ujjzyi66+/XmeffbbeeOMNjR49WoZh6KqrrvLTmSHceXLtHjx4UNdee63OPfdc3XDDDWrZsqXWrFmj+++/X++//74++OADGYbh9JyLLrpI48aNc9p35pln+vJUEEE8vedKnv9djHsufM3T6/bll1+utu+zzz7T7NmzNWDAgGrHRo0apSFDhjjt6927t1fGDC8yAR/55JNPTEnmzJkzHfsOHTpktm/f3uzdu3cARwZYVq9ebZaWljrt27JlixkXF2eOGTPGsW/8+PFm48aN/T08wKWcnBxTkrl48eIa6wYPHmwmJyebxcXFjn3PPfecKcl85513fD1MwCN5eXmmJPOhhx5y7LvgggvMrl27BnBUiFSHDx82CwsLTdM0zbVr15qSzJdeeqla3Y033mgmJCSYP/74o2PfypUrTUnmv//9b8e+HTt2mDExMebNN9/s2FdRUWFmZGSYqamp5tGjR313Mogonly7paWl5urVq6s99+9//7spyVy5cqXTfklO1y7gbZ7ecz39uxj3XPiDp9etKxMmTDANwzDz8/Md+7Zt21YtN0Pwop0LfCYrK0s2m00TJ0507IuPj9eECRO0Zs0a5efnB3B0gNSnTx+n2WKSdOqpp6pr167atGlTtfry8nKVlJT4a3hArfbt26ejR49W219SUqKVK1dq7NixSkxMdOwfN26cmjRpokWLFvlzmIBb8+fPl2EYGj16dLVjR48epf0Q/CouLk6tW7eute61117T0KFD1bZtW8e+/v3767TTTnO6v77xxhsqKyvTTTfd5NhnGIZuvPFG7dixQ2vWrPHuCSBieXLtxsbGqk+fPtX2Dx8+XJJcfvaVpEOHDrls9wI0lKf3XLva/i7GPRf+UNfr1q60tFSvvfaaLrjgAqWmprqsOXDggI4cOdLQIcKHCNHhM1988YVOO+00pwBHks455xxJVqsBINiYpqldu3apRYsWTvsPHjyoxMREJSUlqXnz5rr55psJdxBQ1157rRITExUfH69+/frps88+cxz76quvdPToUZ111llOz4mNjVWPHj30xRdf+Hu4QDVlZWVatGiR+vTpo/T0dKdjW7ZsUePGjdW0aVO1bt1af/vb31RWVhaYgQJVFBQUaPfu3dXur5L1Gbfq/fWLL75Q48aN1blz52p19uNAoBUVFUlStc++kjR37lw1btxYCQkJ6tKli+bPn+/v4QGSPPu7GPdcBLPs7Gzt3btXY8aMcXn873//u5o0aaL4+HidffbZevfdd/08QniCnujwmcLCQiUnJ1fbb9+3c+dOfw8JqNW8efNUUFCgf/zjH459ycnJuvvuu/W73/1OFRUVWrFihebMmaMvv/xSubm5io7mVgr/iY2N1eWXX64hQ4aoRYsW2rhxox577DFlZGToo48+0plnnqnCwkJJcnsPzsvL8/ewgWreeecd/frrr9X+MtG+fXv169dPp59+ug4cOKCsrCw9+OCD2rJlixYuXBig0QKW2u6vv/32m0pLSxUXF6fCwkK1atWqWp9pPgsjmMyYMUOJiYkaPHiw0/4+ffroiiuu0Mknn6ydO3fq6aef1pgxY1RcXKwbb7wxQKNFJPL072LccxHM5s2bp7i4OI0YMcJpf1RUlAYMGKDhw4erTZs22rp1q5544gkNHjxYb775pi6++OIAjRiukPzAZw4dOqS4uLhq++Pj4x3HgWDy7bff6uabb1bv3r01fvx4x/7jF7e76qqrdNppp+mvf/2rsrKyWKQGftWnTx+nf459ySWXaMSIEerevbumTp2qFStWOO6v7u7B3H8RDObPn6+YmBhdccUVTvtfeOEFp++vvvpqTZw4Uc8995xuv/12nXvuuf4cJuCktvurvSYuLo7Pwgh6Dz/8sN577z3NmTNHzZo1czq2evVqp+//+Mc/qmfPnrrnnnt0zTXXKCEhwY8jRSTz9O9i3HMRrEpKSvT2229ryJAh1e61bdu21TvvvOO07+qrr1aXLl00ZcoUQvQgQzsX+ExCQoJKS0ur7bf31OODF4JJUVGRLr74YiUlJTn6+dfk9ttvV1RUlN577z0/jRBwr0OHDrr00kuVk5Oj8vJyx/3V3T2Y+y8Cbf/+/XrjjTc0cOBAnXjiibXWT5kyRZK45yLgaru/Vq3hszCC2cKFC3XvvfdqwoQJHs0sj42N1Z/+9Cft3btX69at88MIAfdc/V2Mey6C1WuvvabDhw+7beVyvObNm+vaa6/V5s2btWPHDh+PDnVBiA6fSU5OdvyT16rs+1JSUvw9JMCl4uJiDR48WHv37tWKFSs8ujYTEhJ04okn6rfffvPDCIHapaWl6ciRIzpw4IDjn626uwdz/0WgLV26VAcPHvT4LxNpaWmSxD0XAVfb/bV58+aOmZDJyckqKiqSaZrV6iQ+CyNwVq5cqXHjxuniiy/WM8884/HzuBcjWLj6uxj3XASrefPmKSkpSUOHDvX4OdxvgxMhOnymR48e2rJlS7UVtD/55BPHcSDQDh8+rGHDhmnLli1atmyZunTp4tHz9u3bp19++UUnnXSSj0cIeGbr1q2Kj49XkyZN1K1bN0VHRzstNipJR44c0fr167n/IuDmzZunJk2a6JJLLvGofuvWrZLEPRcB16ZNG5100knV7q+S9OmnnzrdX3v06KGDBw9q06ZNTnV8FkYgffLJJxo+fLjOOussLVq0qE5r+3AvRrBw9Xcx7rkIRoWFhcrJydHll1/ust2QO9xvgxMhOnxmxIgRKi8v17PPPuvYV1paqpdeekm9evVy/GYNCJTy8nJdeeWVWrNmjRYvXqzevXtXqzl8+LD27dtXbf8DDzwg0zQ1aNAgfwwVcPj555+r7fvyyy/15ptvasCAAYqKilJSUpL69++vV155xen6ffnll7V//36NHDnSn0MGnPz888967733NHz4cDVq1MjpWElJSbV/im2aph588EFJ0sCBA/02TsCdyy+/XMuWLVN+fr5j3/vvv68tW7Y43V8vvfRSxcTEaM6cOY59pmnqmWeeUZs2bZzWtwD8YdOmTbr44ouVnp6uZcuWuW1v4eqzxr59+zRr1iy1aNFCPXv29PVQAUl1+7sY91wEo1dffVUVFRVu//Wlq/ttQUGBXnzxRXXv3t3lQuYIHBYWhc/06tVLI0eO1NSpU7V792516NBB//nPf7R9+/Zqi4YBgTBlyhS9+eabGjZsmH777Te98sorTsfHjh2roqIinXnmmRo1apQ6deokSXrnnXeUnZ2tQYMG6dJLLw3E0BHBrrzySiUkJKhPnz5q2bKlNm7cqGeffVaNGjXSI4884qh76KGH1KdPH11wwQWaOHGiduzYoccff1wDBgzglz8IqIULF+ro0aMu/zLx+eefa9SoURo1apQ6dOigQ4cO6fXXX9fq1as1ceJE/e53vwvAiBFJnnrqKe3du1c7d+6UJL311luOfqS33HKLkpKSdM8992jx4sXq16+fbrvtNu3fv18zZ87U6aefrmuvvdbxWqmpqZo8ebJmzpypsrIynX322Vq6dKny8vI0b968WtdfAeqitms3KipKAwcO1J49e3TXXXfp7bffdnp++/btHRNKnn76aS1dulTDhg1T27ZtVVhYqBdffFE//fSTXn75ZcXGxvr35BC2artu9+zZ4/Hfxbjnwl88+axgN2/ePKWkpKhv374uX+vuu+/WDz/8oAsvvFApKSnavn27/v3vf+vAgQOaPXu2z88FdWQCPnTo0CHzzjvvNFu3bm3GxcWZZ599trlixYpADwswTdM0L7jgAlOS2y/TNM09e/aYY8eONTt06GA2atTIjIuLM7t27Wo+/PDD5pEjRwJ8BohEs2fPNs855xyzefPmZnR0tJmcnGyOHTvW/O6776rV5uXlmX369DHj4+PNk046ybz55pvNkpKSAIwaqHTuueeaLVu2NI8ePVrt2NatW82RI0ea6enpZnx8vNmoUSOzZ8+e5jPPPGNWVFQEYLSINO3atXP7uWDbtm2Ouq+//tocMGCA2ahRI7NZs2bmmDFjzKKiomqvV15ebj788MNmu3btzNjYWLNr167mK6+84sczQqSo7drdtm1bjZ97x48f73itd99917zooovM1q1bmzExMWazZs3MAQMGmO+//37gThBhqbbrtq5/F+OeC3/w9LPCt99+a0oy77jjDrevNX/+fPP88883Tzrp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/MMPP3TMWN+7d68++ugjzZw5U3feeafj+VOnTq3x/b/77jsdPXpUZ5xxhtuauLg4dezYUZs2bZIktW3bVueee64WLlyou+66y1G3du1abd261TEm0zR1ww03qF+/flq+fLljRvikSZPUtWtX3XvvvXr33Xed3uuMM87Q/PnzaxyzN2zevFnffvuto/3LCSecoEmTJunBBx/Uli1b1LRpU0lSeXm5pk+fru3btys9Pb1e5wQAAIDgx0x0AAAAoIorrrhChw4d0rJly7Rv3z4tW7asWisXu9NOO029evXSvHnzHPt+++03LV++XGPGjKnWKqSumjRpIslacNSdK6+8Urt371Zubq5jX1ZWlioqKnTllVdKssL22NhY5ebmOrVSqY39fe2hsTtNmzZVSUmJ05jWrVunH374wbFv4cKFiouLc7S/Wb9+vb777juNHj1av/76q3755Rf98ssvOnDggC688EKtWrVKFRUVTu9T9RcVvnThhRc69U/v1auXJGs2f9WfhX3/1q1bJdXvnAAAABD8CNEBAACAKk466ST1799f8+fP15IlS1ReXq4RI0a4rR83bpxWr17t6AG+ePFilZWV6eqrr27wWPbv3y+p5hDb3nt74cKFjn0LFy5Ujx49dNppp0myZos/+uijWr58uVq1aqXzzz9fM2bMUFFRUY3vb3/fmkJ8+/GqYxw5cqSioqIcYzJNU4sXL9bgwYOVmJgoyZrlLknjx4/XSSed5PT1/PPPq7S0VMXFxU7v466ljLe1bdvW6fukpCRJUlpamsv99l9M1OecAAAAEPxo5wIAAAAcZ/To0br++utVVFSkwYMHq1mzZm5rr7rqKt1+++2aN2+e7rnnHr3yyis666yz1LFjxwaPw74oaIcOHdzWxMXF6bLLLtPrr7+uOXPmaNeuXVq9erUefvhhp7rJkydr2LBhWrp0qd555x397W9/0/Tp0/XBBx/ozDPPdPnaHTp0UHR0tDZs2OD2/UtLS7V582adddZZjn0pKSnKyMjQokWLdM899+jjjz/WTz/9pEcffdRRY5+RPXPmTPXo0cPla9tn4tslJCS4HYc32dvieLrfvvBrfc4JAAAAwY8QHQAAADjO8OHDNWnSJH388cdOM7xdad68uS6++GLNmzdPY8aM0erVqzVr1qwGj2H//v16/fXXlZaWps6dO9dYe+WVV+o///mP3n//fW3atEmmaTpauVTVvn17TZkyRVOmTNF3332nHj166PHHH9crr7zi8nUbN26sfv366YMPPtCPP/6odu3aVatZtGiRSktLNXTo0Gpjuummm7R582YtXLhQjRo10rBhw5zGIkmJiYnq379/rT+PUBCO5wQAAADauQAAAADVNGnSRP/3f/+nadOmOQW/7lx99dXauHGj7rrrLtlsNl111VUNev9Dhw7p6quv1m+//aa//vWvtfZW79+/v5o3b66FCxdq4cKFOuecc5xanxw8eFCHDx92ek779u3VtGlTlZaW1vja9957r0zT1DXXXKNDhw45Hdu2bZvuvvtuJScna9KkSU7HLr/8ctlsNi1YsECLFy/W0KFD1bhxY8fxnj17qn379nrsscccbWuq+vnnn2scVzAKx3MCAAAAM9EBAAAAl8aPH+9x7cUXX6wTTzzR0fe7ZcuWHj+3oKDAMRN8//792rhxoxYvXqyioiJNmTKlWjjtSkxMjDIzM/Xqq6/qwIEDeuyxx5yOb9myRRdeeKGuuOIKdenSRdHR0Xr99de1a9euWgP/888/X4899pjuuOMOde/eXddcc42Sk5P17bff6rnnnlNFRYWys7N1wgknOD2vZcuW6tevn5544gnt27ev2sz4qKgoPf/88xo8eLC6du2qa6+9Vm3atFFBQYFycnKUmJiot956y5MfYdAIx3MCAAAAIToAAADQYLGxsbryyis1Z86cOi8oun79el199dUyDENNmzZVWlqahg0bpuuuu07nnHOOx69z5ZVX6vnnn5dhGLriiiucjqWlpWnUqFF6//339fLLLys6OlqdOnXSokWLdPnll9f62rfffrvOOussPf7445o1a5aKi4uVnJyskSNH6q9//avLNi/2Mb333ntq2rSphgwZUu143759tWbNGj3wwAN66qmntH//frVu3Vq9evXy6JcHwSgczwkAACDSGaZ9FRwAAAAA9Xb77bfrhRdeUFFRkRo1ahTo4QAAAADwEnqiAwAAAA10+PBhvfLKK7r88ssJ0AEAAIAwQzsXAAAAoJ52796t9957T1lZWfr111912223BXpIAAAAALyMEB0AAACop40bN2rMmDFq2bKlnnzySfXo0SPQQwIAAADgZfREBwAAAAAAAADADXqiAwAAAAAAAADgBu1c/KiiokI7d+5U06ZNZRhG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kCS9/vrrMk1Te/fu1ZNPPqkHH3zQK+9RdKwlQ6tWrZz2t2rVynGsqKhILVu2dDoeHR2t5s2bO9W4eo2q73G8qVOnqri42PGVn5/f8BNCaEtO9m4dGsZms2b8j/p/9u4+zsq6zh//awBBRAZDQUBQzMoyTcsKsVRMEk1NQzNREy1vMnRF00y/ldbuiqtukd257Za2q7AqS1retd6AVlC2+nOVVDYNbwFFTPAWdTi/P04zMDAHZmDmnGtmns8ePsZzruuc8znj4TS85n1enwnlr88/37rbPfts+VMF06eXv6rfAQAAAOiyetXywZctW5aBAwcmKdenHH744dlss81y0EEH5Zxzzqnl0tpFnz590qdPn1ovgyJp3NTy2WdXdaCvrrEu5G+/XKLKWvvLi8mTkxdeWHV5+PByz/r48R2yLAAAAABqp6aT6CNGjMjcuXPz6quv5rbbbsv++++fJPnrX/+aTTfdtF0eY8iQIUmS5557rtn1zz33XNOxIUOG5Pk1JlDffvvtvPjii83Oaek+Vn8MWK/WbGo5daq+7Vpp/CVHpf82jVYP0BObjgIAAAB0YTUN0SdPnpxjjjkmw4cPz7BhwzLmbxsp3nPPPdlll13a5TG23377DBkyJHfeeWfTdcuXL88f/vCHjB49OkkyevTovPTSS7nvvvuazrnrrruycuXKjBo1qumce+65J2+99VbTObfffnt23HHHvOMd72iXtdJNjB+fzJiRbLPN2scOPdQ0cy215pccLWn8VMHkyapdAAAAALqYulKppU6J6vmf//mfPP300/nkJz+ZzTffPEly8803Z4sttsjHPvaxVt3HK6+8ksceeyxJ8sEPfjDf+c53su+++2bgwIHZdttt80//9E+5+OKL8/Of/zzbb799vvGNb+TBBx/Mww8/3DTxfuCBB+a5557LFVdckbfeeisnnHBCPvzhD2fatGlJytUzO+64Y/bff/+ce+65mTdvXr7whS/ku9/9bk4++eRWrbO1u73STTQ0lDeoXLSovMHl+ecnm26a/PnP5WloamfmzOSMM5Jnnll13aBByZIl67/trFnlfnUAAAAACq21eW1NQ/Tf/va3+fjHP77R9zN79uzsu+++a10/ceLEXHXVVSmVSrngggvyk5/8JC+99FI+/vGP50c/+lHe8573NJ374osv5rTTTsuvfvWr9OjRI4cf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AKALUOdSRepc6BIaGspTtpW6pXWi0xm1d9VLYkNSAAAAKDh1LkDH6NmzvJli0vLkbqmUXHhh+d9nz06mTy9/bWio0gJhA7R31UtS/rPw9NPlIF3VCwAAAHRaJtGryCQ6XcrMmckZZzSvsejZsxyWb7dd8tZbycKFq44NH14O38ePr/5aobUaGppvELrnnskOO1T+5MWGWH1DUn8eAAAAoGZMoq9m5MiRqaurW+ufSZMmJUnGjBmz1rEvfelLze7jqaeeykEHHZTNNtssgwcPzjnnnJO33367Fk8HiqGlbuk//SkZMCB58snmAXqiI5rOoWfPZMyYZMKE8tfevdf9yYsN0RjGT56cvPmmT2wAAABAwfWq9QKq4Y9//GMaVgsm5s2bl09+8pP57Gc/23TdSSedlG9/+9tNlzfbbLOmf29oaMhBBx2UIUOGZM6cOVm0aFGOO+64bLLJJrnooouq8ySgiBoDx0YNDcmmmybLlq19bqlUDiEnT04OPVQnNJ1HY9XLmp+8GD48ef315MUX2z6lvnrVy5Ilze/TJzYAAACgULplncvkyZNz00035c9//nPq6uoyZsyY7Lbbbpk6dWqL59966605+OCDs3Dhwmy99dZJkiuuuCLnnntulixZkt69e7d4uxUrVmTFihVNl5cvX54RI0aoc6Hrmj273Pm8PrNmNQ/foTNYs+plr72SG29s3w1JV696OfTQtR/PL58AAACg3ahzqeDNN9/M1VdfnS984QupW+2j+ddcc0222mqr7LzzzjnvvPPy2muvNR2bO3dudtlll6YAPUnGjRuX5cuX509/+lPFx5oyZUoGDBjQ9M+IESM65klBUSxa1L7nQZGsWfXSs2f7b0jaGMSffHJ5A1IbkgIAAEDNdbsQ/YYbbshLL72U448/vum6o48+OldffXVmzZqV8847L//xH/+RY489tun44sWLmwXoSZouL168uOJjnXfeeVm2bFnTP08//XT7PhkomqFD2/c86Axa2h/gmWfK1Swb0qNeKiVLlzavjknsKwAAAAA10i060Vf305/+NAceeGCGDRvWdN3JJ5/c9O+77LJLhg4dmv322y+PP/54dthhhw1+rD59+qRPnz4btV7oVPbaqxwcPvts5WqL4cOTPfcsV7+oqaCrWHN/gKTcbX7EEeUgvT2qXlbfV+Dgg5M5c/wZAgAAgCro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WTPsaWhIxo5t+/3oSwdYv64csM+YkRx6qCl1AAD4GyF6AQnRgXbR0JCMHLlxfemPPZbMmSNEAWiLzrqRaVJ+/x84MOnbVw0MAAD8jRC9gIToQLvZ2L70QYOSJUtWXfZRf4CNYyNTAADodIToBSREB9rVxvSlr0nVC0DH6Ao1MOsK2NXDAADQiQnRC0iIDrS79upLT1S9AHSUrtqzXiolW26ZLF266nrT6wAAdCJC9AISogMdbmP60hupegGonq4WsKuHAQCgExGiF5AQHaiKje1LX5OqF4DaELAL2AEA6FBC9AISogNV01LAsuaEeVuoegEolrYE7MOHJ6+/Xt4zo6g/+gvYAQCoASH6ai688MJ861vfanbdjjvumEcffTRJ8sYbb+QrX/lK/vM//zMrVqzIuHHj8qMf/Shbb7110/lPPfVUTj311MyaNSubb755Jk6cmClTpqRXr16tXocQHaiqNYOGPfdMdthB1QtAV9dS0Hzjje37KaVqErADANBBhOirufDCCzNjxozccccdTdf16tUrW221VZLk1FNPzc0335yrrroqAwYMyGmnnZYePXrkd7/7XZKkoaEhu+22W4YMGZJLL700ixYtynHHHZeTTjopF110UavXIUQHak7VC0D31VlrYNZFwA4AwEYQoq/mwgsvzA033JAHHnhgrWPLli3LoEGDMm3atBzxt2Dp0Ucfzfve977MnTs3e+yxR2699dYcfPDBWbhwYdN0+hVXXJFzzz03S5YsSe/evVu1DiE6UAiqXgC6r67Ws74uAnYAANajtXlt67tIOrk///nPGTZsWDbddNOMHj06U6ZMybbbbpv77rsvb731VsaOHdt07nvf+95su+22TSH63Llzs8suuzSrdxk3blxOPfXU/OlPf8oHP/jBFh9zxYoVWbFiRdPl5cuXd9wTBGit8eOTQw9tv6qXUil5+ulyIKHqBaDYevZMxoxZ+/qW/r+hMUzeY4+1A/Ytt0yWLi0H1UUN1xvXdemlax979tnyJ7ME7AAAtEKPWi+gGkaNGpWrrroqt912W3784x9nwYIF2WuvvfLyyy9n8eLF6d27d7bYYotmt9l6662zePHiJMnixYubBeiNxxuPVTJlypQMGDCg6Z8RI0a07xMD2FCNIcqECeWvvXuXA4Nk1eReW605yd4YUMycuTErBaBa1vz/hsawePz45IknklmzkmnTyl+fey75r/9Kttmm+X2MGJGcc075/0s29P9PqqFUKv9z6aXNA/Rk1f9/ffWryciRyb77JkcfXf46cuSq/19raEhmzy6H8LNnly8DANAldYtJ9AMPPLDp3z/wgQ9k1KhR2W677XLdddelb9++Hfa45513Xs4666ymy8uXLxekA8U1fny527y9ql5KpXKAMnlycvDBql4AOrOWJtjbOr3eWephTLADALCGbhGir2mLLbbIe97znjz22GP55Cc/mTfffDMvvfRSs2n05557LkOGDEmSDBkyJPfee2+z+3juueeajlXSp0+f9OnTp/2fAEBHUfUCQFu0Vz2MgL066wcAYIN0izqXNb3yyit5/PHHM3To0Oy+++7ZZJNNcueddzYdnz9/fp566qmMHj06STJ69Og89NBDef7555vOuf3221NfX5+ddtqp6usH6FCqXgBoD22ph1mwILnkkvInolTEqIgBACiYulKpqGMe7efss8/OIYccku222y4LFy7MBRdckAceeCAPP/xwBg0alFNPPTW33HJLrrrqqtTX1+f0009PksyZMydJ0tDQkN122y3Dhg3LJZdcksWLF+fzn/98TjzxxFx00UWtXkdrd3sFKKSZM9uv6iUpByHDhyePPabqBYBVKk1qt/T/Q51lgn1dGn8xYIIdAKDqWpvXdosQ/aijjso999yTpUuXZtCgQfn4xz+ef/zHf8wOO+yQJHnjjTfyla98JdOnT8+KFSsybty4/OhHP2pW1fLkk0/m1FNPzezZs9OvX79MnDgxF198cXr1an0jjhAd6PTW/Av8xlS9NFoziFf1AkAlAvZVx1obsAvfAQAqEqIXkBAd6JJmzix/RD1pn4CiMTCYMaNyny4ArEnAvupYY8CerP3cTbcDADQRoheQEB3osjqi6mXgwKRv38p/8QeA1uqOAXuldauPAQBoIkQvICE60KV1RNXLmlafUhekA9AeulvAvi4CdgCgmxGiF5AQHeh22rvqJbEhKQDVI2BfRcAOAHRBQvQCEqID3VJ7V71Uug9VLwBUk4B9FRugAgCdlBC9gIToQLdV7aoXG5ICUEsC9lVsgAoAFJgQvYCE6ACr6aiqFxuSAlBkAvZVbIAKANSYEL2AhOgAa2gpMBg+PHn99eTFF21ICkD30l4B++rh9LqC6s5KwA4AtBMhegEJ0QFa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ddRR+chHPpK33347559/fubNm5eHH344/fr1S1IO0d/znvfk29/+dtPtNttss6ZvXkNDQ3bbbbcMGTIkl156aRYtWpTjjjsuJ510Ui666KJWrUOIDgBQcAL2jaO3HQCATkSIvg5LlizJ4MGDc/fdd2fvvfdOUg7Rd9ttt0xt/JjvGm699dYcfPDBWbhwYbbeeuskyRVXXJFzzz03S5YsSe/evde6zYoVK7JixYqmy8uXL8+IESOE6AAAnZF+9o2jtx0AgIIRoq/DY489lne/+9156KGHsvPOOycph+h/+tOfUiqVMmTIkBxyyCH5xje+kc022yxJ8s1vfjO//OUv88ADDzTdz4IFC/LOd74z999/fz74wQ+u9TgXXnhhvvWtb611vRAdAKCL0c++cTqytz0RvgMA0CIhegUrV67Mpz/96bz00kv57W9/23T9T37yk2y33XYZNmxYHnzwwZx77rn56Ec/mpkzZyZJTj755Dz55JP59a9/3XSb1157Lf369cstt9ySAw88cK3HMokOAIB+9g7U0dPtwncAgC6ttSF663bE7EImTZqUefPmNQvQk3JI3miXXXbJ0KFDs99+++Xxxx/PDjvssEGP1adPn/Tp02ej1gsAQCfXs2cyZkzbjo0fnxx6aMsB7h57qI9p1PhcLr107WPPPpscfnjLt3v22eSII1TLAADQKt0qRD/ttNNy00035Z577snw4cPXee6oUaOSlKtfdthhhwwZMiT33ntvs3Oee+65JMmQIUM6ZsEAAHRf7RWwDx/ePetj1vVcOjJ8N90OANDldIsQvVQq5fTTT88vfvGLzJ49O9tvv/16b9PYfT506NAkyejRo/OP//iPef755zN48OAkye233576+vrstNNOHbZ2AABYy4YE7En7Tbd3ZRsTvnfkdLvwHQCgZrpFJ/qXv/zlTJs2LTfeeGN23HHHpusHDBiQvn375vHHH8+0adPyqU99KltuuWUefPDBnHnmmRk+fHjuvvvuJElDQ0N22223DBs2LJdcckkWL16cz3/+8znxxBNz0UUXtWodre3YAQCAqtuQfvY1w+LuGryvz8ZunJoI3wEAOoCNRVdT1/iD6RquvPLKHH/88Xn66adz7LHHZt68eXn11VczYsSIfOYzn8nXv/71Zt+8J598Mqeeempmz56dfv36ZeLEibn44ovTq1frBvqF6AAAdEqVgtj22hi1K/e2bwzhOwBAhxKiF5AQHQCAbqOtAXt37G3vKMJ3AIBWEaIXkBAdAACyYSGs6faOJ3wHALoZIXoBCdEBAGAjVGO6XfjedsJ3AKCTEqIXkBAdAAA6SHtOt6uWqQ7hOwBQY0L0AhKiAwBAwaiW6XyKGr4L5gGg0xGiF5AQHQAAugjVMp1PR4bv6zpmKh4ACkuIXkBCdAAA6AZqXS0jfG9f6wvfTcUDQKclRC8gIToAAFCR8L37KOJUvOAdgG5IiF5AQnQAAKDdCd+7j46aip8woXJgbyIegC5MiF5AQnQAAKAwhO+sS1F74gXzALQjIXoBCdEBAIBOT/hOrXri13VMMA/ABhCiF5AQHQAA6LaE76yLYB6AGhCiF5AQHQAAoI2KHL4L5otNMA/AegjRC0iIDgAAUCXVCt9NxXcvgnmALkWIXkBCdAAAgIJr7zDSVDzrI5gHqBkhegEJ0QEAALqhIk/F0zV1p2BeaA9sBCF6AQnRAQAAaLVqTcUfddTagamJeNZUxGB+XcdM0wOtIEQvICE6AAAANVUpHKz1RLxgvnvamGDeND3QDoToBSREBwAAoNMpQk+8YJ72UMRgfl3HNjS0F9hDqwnRC0iIDgAAABHM03UUbZp+woQNC/pN2dNNCdELSIgOAAAAHUQwT3ewIa+DrjRl31HH6LaE6AUkRAcAAIBORDBPd1a0KfuuFOhTGEL0AhKiAwAAQDcnmIeWdVRoX7RA3xR+oQjRC0iIDgAAALS77hbMC+3paF0ptF/XsfUF+t2AEL2AhOgAAABAp1D0YN40PV1JEafwx49v3do7OSF6AQnRAQAAgG6rmjUVpulhwzQG7DNmdIsgXYheQEJ0AAAAgCopejDf3qF9JQJ72qqurjyRvmBBl692EaIXkBAdAAAAoBMr+jT9UUetXc9hyp4NNWtWMmZMrVfRoYToBSREBwAAAKDVNiR874pT9gL92pg2LZkwodar6FBC9AISogMAAABQSEWfsu/sgX5nZBK9iRC9ioToAAAAAJDqhvbrOmYKf2060dciRK8iIToAAAAAFExXDe03NNBPkhkzkvHjW/897KSE6AUkRAcAAACAbq4zTOF3gwA9EaIXkhAdAAAAACiMdYXv3UBr89peVVwTAAAAAABF0bNnl988tD30qPUCAAAAAACgqIToAAAAAABQgRAdAAAAAAAqEKIDAAAAAEAFQnQAAAAAAKhAiA4AAAAAABUI0QEAAAAAoAIhOgAAAAAAVCBEBwAAAACACoToAAAAAABQgRAdAAAAAAAqEKIDAAAAAEAFQnQAAAAAAKhAiA4AAAAAABUI0QEAAAAAoAIhOgAAAAAAVCBEBwAAAACACoToAAAAAABQQa9aL6A7KZVKSZLly5fXeCUAAAAAAN1bY07bmNtWIkSvopdffjlJMmLEiBqvBAAAAACApJzbDhgwoOLxutL6YnbazcqVK7Nw4cL0798/dXV1tV5OVS1fvjwjRozI008/nfr6+lovB1rF65bOymuXzsjrls7I65bOymuXzsjrls7I67b4SqVSXn755QwbNiw9elRuPjeJXkU9evTI8OHDa72Mmqqvr/emQafjdUtn5bVLZ+R1S2fkdUtn5bVLZ+R1S2fkdVts65pAb2RjUQAAAAAAqECIDgAAAAAAFQjRqYo+ffrkggsuSJ8+fWq9FGg1r1s6K69dOiOvWzojr1s6K69dOiOvWzojr9uuw8aiAAAAAABQgUl0AAAAAACoQIgOAAAAAAAVCNEBAAAAAKACIToAAAAAAFQgRKcqfvjDH2bkyJHZdNNNM2rUqNx77721XhI0mTJlSj7ykY+kf//+GTx4cA477LDMnz+/2TljxoxJXV1ds3++9KUv1WjFkFx44YVrvSbf+973Nh1/4403MmnSpGy55ZbZfPPNc/jhh+e5556r4YohGTly5Fqv27q6ukyaNCmJ91qK45577skhhxySYcOGpa6uLjfccEOz46VSKd/85jczdOjQ9O3bN2PHjs2f//znZue8+OKLOeaYY1JfX58tttgiX/ziF/PKK69U8VnQ3azrdfvWW2/l3HPPzS677JJ+/fpl2LBhOe6447Jw4cJm99HS+/TFF19c5WdCd7K+99vjjz9+rdfkAQcc0Owc77dU2/pety39vFtXV5dLL7206Rzvt52PEJ0Od+211+ass87KBRdckPvvvz+77rprxo0bl+eff77WS4Mkyd13351Jkybl97//fW6//fa89dZb2X///fPqq682O++kk07KokWLmv655JJLarRiKHv/+9/f7DX529/+tunYmWeemV/96le5/vrrc/fdd2fhwoUZP358DVcLyR//+Mdmr9nbb789SfLZz3626RzvtRTBq6++ml133TU//OEPWzx+ySWX5PLLL88VV1yRP/zhD+nXr1/GjRuXN954o+mcY445Jn/6059y++2356abbso999yTk08+uVpPgW5oXa/b1157Lffff3++8Y1v5P7778/MmTMzf/78fPrTn17r3G9/+9vN3odPP/30aiyfbmp977dJcsABBzR7TU6fPr3Zce+3VNv6Xrerv14XLVqUn/3sZ6mrq8vhhx/e7Dzvt51Lr1ovgK7vO9/5Tk466aSccMIJSZIrrrgiN998c372s5/la1/7Wo1XB8ltt93W7PJVV12VwYMH57777svee+/ddP1mm22WIUOGVHt5UFGvXr1afE0uW7YsP/3pTzNt2rR84hOfSJJceeWVed/73pff//732WOPPaq9VEiSDBo0qNnliy++ODvssEP22Wefpuu811IEBx54YA488MAWj5VKpUydOjVf//rXc+ihhyZJ/v3f/z1bb711brjhhhx11FF55JFHctttt+WPf/xjPvzhDydJvv/97+dTn/pULrvssgwbNqxqz4XuY12v2wEDBjT94rLRD37wg3z0ox/NU089lW233bbp+v79+3sfpmrW9bpt1KdPn4qvSe+31ML6Xrdrvl5vvPHG7LvvvnnnO9/Z7Hrvt52LSXQ61Jtvvpn77rsvY8eObbquR48eGTt2bObOnVvDlUFly5YtS5IMHDiw2fXXXHNNttpqq+y8884577zz8tprr9ViedDkz3/+c4YNG5Z3vvOdOeaYY/LUU08lSe6777689dZbzd573/ve92bbbbf13kthvPnmm7n66qvzhS98IXV1dU3Xe6+l6BYsWJDFixc3e48dMGBARo0a1fQeO3fu3GyxxRZNgU6SjB07Nj169Mgf/vCHqq8ZWrJs2bLU1dVliy22aHb9xRdfnC233DIf/OAHc+mll+btt9+uzQLhb2bPnp3Bgwdnxx13zKmnnpqlS5c2HfN+S9E999xzufnmm/PFL35xrWPebzsXk+h0qBdeeCENDQ3Zeuutm12/9dZb59FHH63RqqCylStXZvLkyfnYxz6WnXfeuen6o48+Otttt12GDRuWBx98MOeee27mz5+fmTNn1nC1dGejRo3KVVddlR133DGLFi3Kt771rey1116ZN29eFi9enN69e6/1l+Ktt946ixcvrs2CYQ033HBDXnrppRx//PFN13mvpTNofB9t6efbxmOLFy/O4MGDmx3v1atXBg4c6H2YQnjjjTdy7rnnZsKECamvr2+6/u/+7u/yoQ99KAMHDsycOXNy3nnnZdGiRfnOd75Tw9XSnR1wwAEZP358tt9++zz++OM5//zzc+CBB2bu3Lnp2bOn91sK7+c//3n69++/VrWm99vOR4gOsJpJkyZl3rx5zbqlkzTr1Ntll10ydOjQ7Lfffnn88cezww47VHuZ0Ozjgx/4wAcyatSobLfddrnuuuvSt2/fGq4MWuenP/1pDjzwwGYfs/ZeC9Dx3nrrrRx55JEplUr58Y9/3OzYWWed1fTvH/jAB9K7d++ccsopmTJlSvr06VPtpUKOOuqopn/fZZdd8oEPfCA77LBDZs+enf3226+GK4PW+dnPfpZjjjkmm266abPrvd92Pupc6FBbbbVVevbsmeeee67Z9c8995zeJwrntNNOy0033ZRZs2Zl+PDh6zx31KhRSZLHHnusGkuD9dpiiy3ynve8J4899liGDBmSN998My+99FKzc7z3UhRPPvlk7rjjjpx44onrPM97LUXU+D66rp9vhwwZkueff77Z8bfffjsvvvii92FqqjFAf/LJJ3P77bc3m0JvyahRo/L222/niSeeqM4CYT3e+c53Zquttmr62cD7LUX2m9/8JvPnz1/vz7yJ99vOQIhOh+rdu3d233333HnnnU3XrVy5MnfeeWdGjx5dw5XBKqVSKaeddlp+8Ytf5K677sr222+/3ts88MADSZKhQ4d28OqgdV555ZU8/vjjGTp0aHbfffdssskmzd5758+fn6eeesp7L4Vw5ZVXZvDgwTnooIPWeZ73Wopo++23z5AhQ5q9xy5fvjx/+MMfmt5jR48enZdeein33Xdf0zl33XVXVq5c2fTLIai2xgD9z3/+c+64445sueWW673NAw88kB49eqxVlwG18swzz2Tp0qVNPxt4v6XIfvrTn2b33XfPrrvuut5zvd8WnzoXOtxZZ52ViRMn5sMf/nA++tGPZurUqXn11Vdzwgkn1HppkKRc4TJt2rTceOON6d+/f1N33oABA9K3b988/vjjmTZtWj71qU9lyy23zIMPPpgzzzwze++9dz7wgQ/UePV0V2effXYOOeSQbLfddlm4cGEuuOCC9OzZMxMmTMiAAQPyxS9+MWeddVYGDhyY+vr6nH766Rk9enT22GOPWi+dbm7lypW58sorM3HixPTqtepHUe+1FMkrr7zS7BMQCxYsyAMPPJCBAwdm2223zeTJk/MP//APefe7353tt98+3/jGNzJs2LAcdthhSZL3ve99OeCAA3LSSSfliiuuyFtvvZXTTjstRx11VLMKI2hP63rdDh06NEcccUTuv//+3HTTTWloaGj6mXfgwIHp3bt35s6dmz/84Q/Zd999079//8ydOzdnnnlmjj322LzjHe+o1dOii1vX63bgwIH51re+lcMPPzxDhgzJ448/nq9+9at517velXHjxiXxfkttrO/nhKT8C/brr78+//zP/7zW7b3fdlIlqILvf//7pW233bbUu3fv0kc/+tHS73//+1ovCZokafGfK6+8slQqlUpPPfVUae+99y4NHDiw1KdPn9K73vWu0jnnnFNatmxZbRdOt/a5z32uNHTo0FLv3r1L22yzTelzn/tc6bHHHms6/vrrr5e+/OUvl97xjneUNttss9JnPvOZ0qJFi2q4Yij79a9/XUpSmj9/frPrvddSJLNmzWrxZ4OJEyeWSqVSaeXKlaVvfOMbpa233rrUp0+f0n777bfWa3rp0qWlCRMmlDbffPNSfX196YQTTii9/PLLNXg2dBfret0uWLCg4s+8s2bNKpVKpdJ9991XGjVqVGnAgAGlTTfdtPS+972vdNFFF5XeeOON2j4xurR1vW5fe+210v77718aNGhQaZNNNiltt912pZNOOqm0ePHiZvfh/ZZqW9/PCaVSqfQv//Ivpb59+5ZeeumltW7v/bZzqiuVSqUOT+oBAAAAAKAT0okOAAAAAAAVCNEBAAAAAKACIToAAAAAAFQgRAcAAAAAgAqE6AAAAAAAUIEQHQAAAAAAKhCiAwAAAABABUJ0AAAAAACoQIgOAAAAAAAVCNEBAIAcf/zxqaurS11dXTbZZJNsvfXW+eQnP5mf/exnWblyZa2XBwAANSNEBwAAkiQHHHBAFi1alCeeeCK33npr9t1335xxxhk5+OCD8/bbb9d6eQAAUBNCdAAAIEnSp0+fDBkyJNtss00+9KEP5fzzz8+NN96YW2+9NVdddVWS5Dvf+U522WWX9OvXLyNGjMiXv/zlvPLKK0mSV199NfX19ZkxY0az+73hhhvSr1+/vPzyy9V+SgAAsNGE6AAAQEWf+MQnsuuuu2bmzJlJkh49euTyyy/Pn/70p/z85z/PXXfdla9+9atJkn79+uWoo47KlVde2ew+rrzyyhxxxBHp379/1dcPAAAbq65UKpVqvQgAAKC2jj/++Lz00ku54YYb1jp21FFH5cEHH8zDDz+81rEZM2bkS1/6Ul544YUkyb333ps999wzTz/9dIYOHZrnn38+22yzTe64447ss88+Hf00AACg3ZlEBwAA1qlUKqWuri5Jcscdd2S//fbLNttsk/79++fzn/98li5dmtdeey1J8tGPfjTvf//78/Of/zxJcvXVV2e77bbL3nvvXbP1AwDAxhCiAwAA6/TII49k++23zxNPPJGDDz44H/jAB/Jf//Vfue+++/LDH/4wSfLmm282nX/iiSc2dahfeeWVOeGEE5pCeAAA6GyE6AAAQEV33XVXHnrooRx++OG57777snLlyvzzP/9z9thjj7znPe/JwoUL17rNsccemyeffDKXX355Hn744UycOLEGKwcAgPbRq9YLAAAAimHFihVZvHhxGhoa8txzz+W2227LlClTcvDBB+e4447LvHnz8tZbb+X73/9+DjnkkPzud7/LFVdcsdb9vOMd78j48eNzzjnnZP/998/w4cNr8GwAAKB9mEQHAACSJLfddluGDh2akSNH5oADDsisWbNy+eWX58Ybb0zPnj2z66675jvf+U7+6Z/+KTvvvHOuueaaTJkypcX7+uIXv5g333wzX/jCF6r8LAAAoH3VlUqlUq0XAQAAdC3/8R//kTPPPDMLFy5M7969a70cAADYYOpcAACAdvPaa69l0aJFufjii3PKKacI0AEA6PTUuQAAAO3mkksuyXvf+94MGTIk5513Xq2XAwAAG02dCwAAAAAAVGASHQAAAAAAKhCiAwAAAABABUJ0AAAAAACoQIgOAAAAAAAVCNEBAAAAAKACIToAAAAAAFQgRAcAAAAAgAqE6AAAAAAAUIEQHQAAAAAAKhCiAwAAAABABUJ0AAAAAACoQIgOAAAAAAAVCNEBAAAAAKACIToAAAAAAFQgRAcAAAAAgAqE6AAAAAAAUIEQHQAAAAAAKhCiAwAAAABABUJ0AAAAAACoQIgOAAAAAAAVCNEBAAAAAKACIToAAAAAAFQgRAcAAAAAgAqE6AAAUCAXXnhh6urqNuq2L7zwQjuvqvvYmO8/AABdkxAdAIBu46qrrkpdXV3q6ury29/+dq3jpVIpI0aMSF1dXQ4++OB2f/yGhoYMGzYsdXV1ufXWW9v9/qvtd7/7XT7zmc9k6623Tp8+fTJy5Miccsopeeqpp2q9tGZGjhzZ9N99Xf9cddVVtV4qAAAF1KvWCwAAgGrbdNNNM23atHz84x9vdv3dd9+dZ555Jn369OmQx73rrruyaNGijBw5Mtdcc00OPPDADnmcavj+97+fM844I+985ztz+umnZ+jQoXnkkUfyb//2b7n22mtzyy23ZM8996z1MpMkU6dOzSuvvNJ0+ZZbbsn06dPz3e9+N1tttVXT9XvuuWeOPfbYfO1rX6vFMgEAKCghOgAA3c6nPvWpXH/99bn88svTq9eqH4mnTZuW3XffvcPqUK6++up86EMfysSJE3P++efn1VdfTb9+/TrksTrS7373u0yePDkf//jHc9ttt2WzzTZrOnbqqafmYx/7WI444oj86U9/yjve8Y6qravS9/Owww5rdnnx4sWZPn16DjvssIwcOXKt81d/TQAAgDoXAAC6nQkTJmTp0qW5/fbbm6578803M2PGjBx99NHNzi2VShk5cmQOPfTQte7njTfeyIABA3LKKaes9zFff/31/OIXv8hRRx2VI488Mq+//npuvPHGVq23rq4up512Wq655prsuOOO2XTTTbP77rvnnnvuafH8l156Kccff3y22GKLDBgwICeccEJee+21ZudceeWV+cQnPpHBgwenT58+2WmnnfLjH/+4Vev5+7//+9TV1eXnP/95swA9SXbYYYdccsklWbRoUf7lX/4lSXLZZZelrq4uTz755Fr3dd5556V3797561//2nTdH/7whxxwwAEZMGBANttss+yzzz753e9+1+x2jd3lDz/8cI4++ui84x3vWOuTBRuipU70xu//9ddfn5122il9+/bN6NGj89BDDyVJ/uVf/iXvete7summm2bMmDF54okn1rrf1jwnAACKSYgOAEC3M3LkyIwePTrTp09vuu7WW2/NsmXLctRRRzU7t66uLscee2xuvfXWvPjii82O/epXv8ry5ctz7LHHrvcxf/nLX+aVV17JUUcdlSFDhmTMmDG55pprWr3mu+++O5MnT86xxx6bb3/721m6dGkOOOCAzJs3b61zjzzyyLz88suZMmVKjjzyyFx11VX51re+1eycH//4x9luu+1y/vnn55//+Z8zYsSIfPnLX84Pf/jDda7jtddey5133pm99tor22+/fYvnfO5zn0ufPn1y0003Na2nrq4u11133VrnXnfdddl///2bJtbvuuuu7L333lm+fHkuuOCCXHTRRXnppZfyiU98Ivfee+9at//sZz+b1157LRdddFFOOumkda59Y/zmN7/JV77ylUycODEXXnhhHnnkkRx88MH54Q9/mMsvvzxf/vKXc84552Tu3Ln5whe+0Oy2bX1OAAAUi88pAgDQLR199NE577zz8vrrr6dv37655pprss8++2TYsGFrnXvcccflH//xH3PdddflS1/6UtP1V199dUaOHNmqCeirr746e+65Z0aMGJEkOeqoo/LlL385S5YsyaBBg9Z7+3nz5uV//ud/svvuuzfdfscdd8w3v/nNzJw5s9m5H/zgB/PTn/606fLSpUvz05/+NP/0T//UdN3dd9+dvn37Nl0+7bTTcsABB+Q73/lOJk2aVHEdf/7zn/P2229n1113rXhOnz59suOOO+aRRx5Jkmy77bbZY489cu211+acc85pOu+Pf/xj/vKXv+TCCy9MUp76/9KXvpR99903t956a9NE+CmnnJL3v//9+frXv57//u//bvZYu+66a6ZNm1ZxLe1l/vz5efTRR5vqX97xjnfklFNOyT/8wz/k//7v/9K/f/8k5c1jp0yZkieeeCIjR47coOcEAECxmEQHAKBbaqxUuemmm/Lyyy/npptuWqvKpdF73vOejBo1qtnk+Isvvphbb701xxxzzFr1H2taunRpfv3rX2fChAlN1x1++OEVp7NbMnr06KYAPSkH04ceemh+/etfp6Ghodm5qwf9SbLXXntl6dKlWb58edN1qwfoy5YtywsvvJB99tknf/nLX7Js2bKK63j55ZeTpCk0rqR///7NHu9zn/tc7rvvvjz++ONN11177bXp06dPU1XOAw88kD//+c85+uijs3Tp0rzwwgt54YUX8uqrr2a//fbLPffck5UrV67zuXaU/fbbr1l/+qhRo5KU/zuu/r1ovP4vf/lLkg17TgAAFItJdAAAuqVBgwZl7NixmTZtWl577bU0NDTkiCOOqHj+cccdl9NOOy1PPvlktttuu1x//fV566238vnPf369j3Xttdfmrbfeygc/+ME89thjTdc3BvPrmvxu9O53v3ut697znvfktddey5IlSzJkyJCm67fddttm5zVWpfz1r39NfX19kvLmoBdccEHmzp27Vl/6smXLMmDAgBbX0RgYN4bplbz88svNwuXPfvazOeuss3Lttdfm/PPPT6lUyvXXX58DDzywaU1//vOfkyQTJ06seL/Lli1rtllppUqZ9rbm97Tx+9P4yYI1r2/seN+Q5wQAQLEI0QEA6LaOPvronHTSSVm8eHEOPPDAbLHFFhXPPeqoo3LmmWfmmmuuyfnnn5+rr746H/7wh7Pjjjuu93EaJ9g/9rGPtXj8L3/5S975zndu0HNoSc+ePVu8vlQqJUkef/zx7Lfffnnve9+b73znOxkxYkR69+6dW265Jd/97nfXORn9rne9K7169cqDDz5Y8ZwVK1Zk/vz5+fCHP9x03bBhw7LXXnvluuuuy/nnn5/f//73eeqpp5pVzDQ+7qWXXprddtutxfvefPPNm11efaK+I1X6nq7ve70hzwkAgGIRogMA0G195jOfySmnnJLf//73ufbaa9d57sCBA3PQQQflmmuuyTHHHJPf/e53mTp16nofY8GCBZkzZ05OO+207LPPPs2OrVy5Mp///Oczbdq0fP3rX1/n/TRONK/u//7v/7LZZpu1qlN9db/61a+yYsWK/PKXv2w2YT1r1qz13rZfv37Zd999c9dddzVN5a/puuuuy4oVK3LwwQc3u/5zn/tcvvzlL2f+/Pm59tprs9lmm+WQQw5pOr7DDjskSerr6zN27Ng2Paei6orPCQCgu9GJDgBAt7X55pvnxz/+cS688MJmYW4ln//85/Pwww/nnHPOSc+ePXPUUUet9zaNU+hf/epXc8QRRzT758gjj8w+++zTrGu9krlz5+b+++9vuvz000/nxhtvzP77719xGrqSxvMbp6WTcqXIlVde2arbf/3rX0+pVMrxxx+f119/vdmxBQsW5Ktf/WqGDh2aU045pdmxww8/PD179sz06dNz/fXX5+CDD06/fv2aju++++7ZYYcdctlll+WVV15Z63GXLFnS6udYFF3xOQEAdDcm0QEA6NbW1VW9poMOOihbbrllU5f34MGD13uba665Jrvtttta3dmNPv3pT+f000/P/fffnw996EMV72fnnXfOuHHj8nd/93fp06dPfvSjHyVJvvWtb7V6/Y3233//9O7dO4ccckhOOeWUvPLKK/nXf/3XDB48OIsWLVrv7ffee+9cdtllOeuss/KB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5CN5++23c/7552f//ffPww8/nH79+iUpB+gHHHBAzjvvvHz/+99Pr1698r//+7/p0WNV/n/MMcdk0aJFuf322/PWW2/lhBNOyMknn5xp06YlKXfb7L///hk7dmyuuOKKPPTQQ/nCF76QLbbYIieffHKSZM6cOZkwYUKmTJmSgw8+ONOmTcthhx2W+++/PzvvvHOS5JJLLsnll1+en//859l+++3zjW98I+PGjcvDDz+cTTfdtMrfPQAAAADYeEXZBFQtC0VVqI1FlyxZksGDB+fuu+/O3nvvnSTZY4898slPfjJ///d/3+JtHnnkkey000754x//mA9/+MNJkttuuy2f+tSn8swzz2TYsGH58Y9/nP/3//5fFi9enN69eydJvva1r+WGG27Io48+miT53Oc+l1dffTU33XRT033vscce2W233XLFFVekVCpl2LBh+cpXvpKzzz47SbJs2bJsvfXWueqqq3LUUUettbYVK1ZkxYoVTZeXL1+eESNG2FgUAAAAgKor0iaglWpZZhw5Y521LNCeWruxaE3rXNa0bNmyJMnAgQOTJM8//3z+8Ic/ZPDgwdlzzz2z9dZbZ5999slvf/vbptvMnTs3W2yxRVOAniRjx45Njx498oc//KHpnL333rspQE+ScePGZf78+fnrX//adM7YsWObrWfcuHGZO3dukmTBggVZvHhxs3MGDBiQUaNGNZ2zpilTpmTAgAFN/4wYMWKDvzcAAAAAsD5qWaD9FWZj0ZUrV2by5Mn52Mc+1lSf8pe//CVJcuGFF+ayyy7Lbrvtln//93/Pfvvtl3nz5uXd7353Fi9enMGDBze7r169emXgwIFZvHhxkmTx4sXZfvvtm52z9dZbNx17xzvekcWLFzddt/o5q9/H6rdr6Zw1nXfeeTnrrLOaLjdOogMAAABAe1PLAh2jMCH6pEmTMm/evGZT5itXrkySnHLKKTnhhBOSJB/84Adz55135mc/+1mmTJlSk7W2Vp8+fdKnT59aLwMAAACALmbNapYXXn0hR844cq2g/Jnlz+TSOZdWbV2NtSw/OeQn66xlaZw2h86gECH6aaedlptuuin33HNPhg8f3nT90KFDkyQ77bRTs/Pf97735amnnkqSDBkyJM8//3yz42+//XZefPHFDBkypOmc5557rtk5jZfXd87qxxuva1xX4+Xddtut7U8aAAAAADZASxPnPet6VrXXvDXT5kkE5XQJNe1EL5VKOe200/KLX/wid91111qVKyNHjsywYcMyf/78Ztf/3//9X7bbbrskyejRo/PSSy/lvvvuazp+1113ZeXKlRk1alTTOffcc0/eeuutpnNuv/327LjjjnnHO97RdM6dd97Z7HFuv/32jB49Okmy/fbbZ8iQIc3OWb58ef7whz80nQMAAAAA7aWlfvOZj8zMEdcd0SxAT5KGUkOHraNxunzNyz855Cd5YvITmTVxVqaNn5ZZE2dlwRkLmgJ06CpqOok+adKkTJs2LTfeeGP69+/f1C0+YMCA9O3bN3V1dTnnnHNywQUXZNddd81uu+2Wn//853n00UczY8aMJOWp9AMOOCAnnXRSrrjiirz11ls57bTTctRRR2XYsGFJkqOPPjrf+ta38sUvfjHnnntu5s2bl+9973v57ne/27SWM844I/vss0/++Z//OQcddFD+8z//M//zP/+Tn/zkJ0mSurq6TJ48Of/wD/+Qd7/73dl+++3zjW98I8OGDcthhx1W3W8cAAAAAF3CmrUsjZUnLU2bb9N/m7zx9htVmThvDMrP3vPsTJ83fa2eddPmdCd1pVKpep/zWPPB6+pavP7KK6/M8ccf33T54osvzg9/+MO8+OKL2XXXXXPJJZfk4x//eNPxF198Maeddlp+9atfpUePHjn88MNz+eWXZ/PNN28658EHH8ykSZPyxz/+MVtttVVOP/30nHvuuc0e9/rrr8/Xv/71PPHEE3n3u9+dSy65JJ/61KeajpdKpVxwwQX5yU9+kpdeeikf//jH86Mf/Sjvec97WvV8ly9fngEDBmTZsmWpr69v1W0AAAAA6JrauhFoR6hUyzKifkRTUF4p6IfOrrV5bU1D9O5GiA4AAADQ/bQUQt84/8Yccd0RVe8xX/3xGqfNZxw5Y52bgEJX1dq8thAbiwIAAABAV6SWBTo/k+hVZBIdAAAAoGsqyrR5z7qezTYZVcsClZlEBwAAAIB2VNRNQJNVE+fTD5+eQf0GtRiU9+zR07Q5bAAhOgAAAACsR1s3AX325Wc7ZB2VNgJds5oFaD/qXKpInQsAAABAsRWlliWxESh0NHUuAAAAANCCzlDLYiNQKA6T6FVkEh0AAACgttpay9JRKtWy2AgUqqe1ea0QvYqE6AAAAADVUaRaljWpZYFiUOcCAAAAQLdUhFqWpPWbgKplgWITogMAAADQKbVl2vzZl5/t0LVU2gT0J4f8xLQ5dHJCdAAAAAAKyyagQK3pRK8inegAAAAArWcTUKAj2Vi0gIToAAAAAGsr0iaglWpZbAIKXY+NRQEAAAAoPLUsQNGZRK8ik+gAAABAd1WEaXO1LMDqTKIDAAAAUAhFmjb/ySE/WWctS88ePU2bA80I0QEAAABoF22ZNn/25Wc7ZA2Vps3VsgAbSogOAAAAQKtVqjupxbR5pU1A1zdtDtAWQnQAAAAAWqWloHx4/fBM2HlCLptzWVWmzW0CClSbjUWryMaiAAAAQGdgE1CgO7CxKAAAAABtZhNQgOaE6AAAAADdkE1AAVpHiA4AAADQRRVpE9A12QQU6CyE6AAAAABdUBE2AU1MmwOdn41Fq8jGogAAAEB7K8ImoI3qUtfsMRunzWccOcO0OVA4NhYFAAAA6OKKVMty9p5nZ/q86WtNvps2Bzo7k+hVZBIdAAAA2BBFmDavVMsyon5EU1BeqYMdoIhMogMAAAB0AUWaNl/fJqA9e/Q0bQ50OUJ0AAAAgAJoy7S5TUABqkeIDgAAAFBjtZg2r7QJ6PqmzQG6GyE6AAAAQJXUetrcJqAAbSdEBwAAAGhHlTbXrOa0eWtqWabsN8W0OUArCNEBAAAA2klLQfnw+uGZsPOEXDbnsqpOm9sEFKB91JVKpeps40yWL1+eAQMGZNmyZamvr6/1cgAAAIAN1JZalo5Sadp8RP2IZrUsALSstXmtSXQAAACANqjFJqBrsgkoQPUI0QEAAABaUOtNQJPWdZsnNgEF6EhCdAAAAIA1mDYHoJEQHQAAAOi2TJsDsD5CdAAAAKBLayko79mjZ02mzetS1+y+TZsDFJ8QHQAAAOiyWgrKh9cPz4SdJ+SyOZdVZdq8MSg/e8+zM33e9LXWYtocoNjqSqVSdYq8yPLlyzNgwIAsW7Ys9fX1tV4OAAAAdBltqWXpKJVqWUbUj2gKyitNxQNQfa3Na02iAwAAAJ1aZ9oEtGePnqbNAToZIToAAADQKdgEFIBaEKIDAAAAhdeZps0B6FqE6AAAAEBhmDYHoGiE6AAAAEAh1GLavC51ze7btDkAaxKiAwAAAFVV62nzxqD87D3PzvR505uF9qbNAViTEB0AAACommpOm7emlmXKflNMmwOwTkJ0AAAAoN0VZdp8fbUsPXv0NG0OwDoJ0QEAAIB2VbRp80QtCwAbTogOAAAAbJDOMm0OABtDiA4AAABU1FJQ3rNHT9PmAHQbQnQAAACgRS0F5cPrh2fCzhNy2ZzLTJsD0C3UlUql9v31MBUtX748AwYMyLJly1JfX1/r5QAAAECSttWydJRK0+Yj6kc0mzYHgPbS2rzWJDoAAAB0Y9WsZanEtDkARSZEBwAAgG5izYnzF159IUfOOLIqtSyJbnMAOichOgAAAHQDLU2c96zradocANZDiA4AAABdSFv6zRtKDe3++KbNAehqhOgAAADQRVS737wudc3u17Q5AF2REB0AAAA6mbZMm7d3v3ljUH72nmdn+rzpzQJ70+YAdEVCdAAAAOhEqjVt3ppalin7TTFtDkCXJ0QHAACAAirCtPn6all69uhp2hyALk+IDgAAAAVT7W7znnU9m20yqpYFAFYRogMAAECN1HLaPFk1cT798OkZ1G+QWhYAaIEQHQAAAGqgmtPmrek3BwBaJkQHAACADlSUafP19ZsDAC0TogMAAEAHKeK0uX5zAGgbIToAAABsJNPmANB1CdEBAABgI5g2B4CuTYgOAAAArWDaHAC6JyE6AAAArIdpcwDovoToAAAA8DemzQGANQnRAQAAIKbNAYCWCdEBAADoVkybAwBtIUQHAACg2zBtDgC0lRAdAACALse0OQDQXoToAAAAdCmmzQGA9iREBwAAoFMybQ4AVIMQHQAAgE7HtDkAUC09avngU6ZMyUc+8pH0798/gwcPzmGHHZb58+e3eG6pVMqBBx6Yurq63HDDDc2OPfXUUznooIOy2WabZfDgwTnnnHPy9ttvNztn9uzZ+dCHPpQ+ffrkXe96V6666qq1HuOHP/xhRo4cmU033TSjRo3Kvffe2+z4G2+8kUmTJmXLLbfM5ptvnsMPPzzPPffcRn0PAAAAqKxhZUNmPzE70x+antlPzE7DyobMfGRmjrjuiGYBelKeNl/6+tJ2ffzVp82fmPxEZk2clWnjp2XWxFlZcMaCpgAdAOi6ajqJfvfdd2fSpEn5yEc+krfffjvnn39+9t9//zz88MPp169fs3OnTp2aurq6te6joaEhBx10UIYMGZI5c+Zk0aJFOe6447LJJpvkoosuSpIsWLAgBx10UL70pS/lmmuuyZ133pkTTzwxQ4cOzbhx45Ik1157bc4666xcccUVGTVqVKZOnZpx48Zl/vz5GTx4cJLkzDPPzM0335zrr78+AwYMyGmnnZbx48fnd7/7XQd/pwAAALof0+YAQBHUlUql9v3JYyMsWbIkgwcPzt13352999676foHHnggBx98cP7nf/4nQ4cOzS9+8YscdthhSZJbb701Bx98cBYuXJitt946SXLFFVfk3HPPzZIlS9K7d++ce+65ufnmmzNv3rym+zzqqKPy0ksv5bbbbkuSjBo1Kh/5yEfygx/8IEmycuXKjBgxIqeffnq+9rWvZdmyZRk0aFCmTZuWI444Ikny6KOP5n3ve1/mzp2bPfbYY63ns2LFiqxYsaLp8vLlyzNixIgsW7Ys9fX17fvNAwAA6KTa0m3eERqnzWccOUO3OQB0I8uXL8+AAQPWm9cWqhN92bJlSZKBAwc2Xffaa6/l6KOPzg9/+MMMGTJkrdvMnTs3u+yyS1OAniTjxo3Lqaeemj/96U/54Ac/mLlz52bs2LHNbjdu3LhMnjw5SfLmm2/mvvvuy3nnndd0vEePHhk7dmzmzp2bJLnvvvvy1ltvNbuf9773vdl2220rhuhTpkzJt771rQ34TgAAAHQPps0BgKIrTIi+cuXKTJ48OR/72Mey8847N11/5plnZs8998yhhx7a4u0WL17cLEBP0nR58eLF6zxn+fLlef311/PXv/41DQ0NLZ7z6KOPNt1H7969s8UWW6x1TuPjrOm8887LWWed1XS5cRIdAACgu2nLtPmzLz/b7o+/ere5aXMAoC0KE6JPmjQp8+bNy29/+9um6375y1/mrrvuyv/3//1/NVzZhuvTp0/69OlT62UAAADUlGlzAKAzK0SIftppp+Wmm27KPffck+HDhzddf9ddd+Xxxx9fa/r78MMPz1577ZXZs2dnyJAhuffee5sdf+6555Kkqf5lyJAhTdetfk59fX369u2bnj17pmfPni2es/p9vPnmm3nppZearWf1cwAAALoz0+YAQFdU0xC9VCrl9NNPzy9+8YvMnj0722+/fbPjX/va13LiiSc2u26XXXbJd7/73RxyyCFJktGjR+cf//Ef8/zzz2fw4MFJkttvvz319fXZaaedms655ZZbmt3P7bffntGjRydJevfund133z133nln04alK1euzJ133pnTTjstSbL77rtnk002yZ133pnDDz88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QSgAANBehOgAAHQpNggFAADakxAdAIAuo1Jliw1CAQCADSVEBwCgU6pmZYsNQgEAoPsSogMA0Om0d2WLDUIBAIBKhOgAABTWmtPme227V26cf2O7VrbYIBQAAFgXIToAAIXU0rT5Nv23yRtvv7FRlS02CAUAANpCiA4AQOFU2iD02Zef3eD7tEEoAACwIYToAADUlA1CAQCAIhOiAwBQM+29QWij9VW2AAAAtJYQHQCADleNDUITlS0AAED761HLB58yZUo+8pGPpH///hk8eHAOO+ywzJ8/v+n4iy++mNNPPz077rhj+vbtm2233TZ/93d/l2XLljW7n6eeeioHHXRQNttsswwePDjnnHNO3n777WbnzJ49Ox/60IfSp0+fvOtd78pVV1211np++MMfZuTIkdl0000zatSo3Hvvvc2Ov/HGG5k0aVK23HLLbL755jn88MPz3HPPtd83BACgC5r5yMyM/N7I7PvzfXP0zKOz78/3zXZTt8vJvzq5wytbJuwyIWNGjhGgAwAAG6ymIfrdd9+dSZMm5fe//31uv/32vPXWW9l///3z6quvJkkWLlyYhQsX5rLLLsu8efNy1VVX5bbbbssXv/jFpvtoaGjIQQcdlDfffDNz5szJz3/+81x11VX55je/2XTOggULctBBB2XffffNAw88kMmTJ+fEE0/Mr3/966Zzrr322px11lm54IILcv/992fXXXfNuHHj8vzzzzedc+aZZ+ZXv/pVrr/++tx9991ZuHBhxo/3kWAAgEoaNwhdva4lKW8QuvT1pRt0n3Wpy5Z9t8zw/sObXT+8fnhmHDlDZQsAANCu6kqlUvuN/2ykJUuWZPDgwbn77ruz9957t3jO9ddfn2OPPTavvvpqevXqlVtvvTUHH3xwFi5cmK233jpJcsUVV+Tcc8/NkiVL0rt375x77rm5+eabM2/evKb7Oeqoo/LSSy/ltttuS5KMGjUqH/nIR/KDH/wgSbJy5cqMGDEip59+er72ta9l2bJlGTRoUKZNm5YjjjgiSfLoo4/mfe97X+bOnZs99thjvc9v+fLlGTBgQJYtW5b6+vqN+l4BABRNSxuE7vD9HdYK0DdG47T5jCNn5NAdD12rIsbEOQAA0FqtzWsL1YneWNMycODAdZ5TX1+fXr3KS587d2522WWXpgA9ScaNG5dTTz01f/rTn/LBD34wc+fOzdixY5vdz7hx4zJ58uQkyZtvvpn77rsv5513XtPxHj16ZOzYsZk7d26S5L777stbb73V7H7e+973Ztttt60Yoq9YsSIrVqxourx8+fLWfisAADqVWm0QOmbkmI26fwAAgPUpTIi+cuXKTJ48OR/72Mey8847t3jOCy+8kL//+7/PySef3HTd4sWLmwXoSZouL168eJ3nLF++PK+//nr++te/pqGhocVzHn300ab76N27d7bYYou1zml8nDVNmTIl3/rWt9bzzAEAOrfGyhYbhAIAAF1RYUL0SZMmZd68efntb3/b4vHly5fnoIMOyk477ZQLL7ywuovbQOedd17OOuuspsvLly/PiBEjargiAICN01Jlyxm3ndHhG4QCAADUSiFC9NNOOy033XRT7rnnngwfPnyt4y+//HIOOOCA9O/fP7/4xS+yySabNB0bMmRI7r333mbnP/fcc03HGr82Xrf6OfX19enbt2969uyZnj17tnjO6vfx5ptv5qWXXmo2jb76OWvq06dP+vTp08rvAgBAsbV3ZUtd6jKw78D07dU3z7y86j7XrGwBAACopR61fPBSqZTTTjstv/jFL3LXXXdl++23X+uc5cuXZ//990/v3r3zy1/+Mptuummz46NHj85DDz2U559/vum622+/PfX19dlpp52azrnzzjub3e7222/P6NGjkyS9e/fO7rvv3uyclStX5s4772w6Z/fdd88mm2zS7Jz58+fnqaeeajoHAKAraFjZkNlPzM70h6Zn9hOz07CyoamyZc1NQjcmQE+Snxzykzwx+YnMmjgr08ZPy6yJs7LgjAUCdAAAoDDqSqVS+332to2+/OUvZ9q0abnxxhuz4447Nl0/YMCA9O3btylAf+211/KLX/wi/fr1azpn0KBB6dmzZxoaGrLbbrtl2LBhueSSS7J48eJ8/vOfz4knnpiLLrooSbJgwYLsvPPOmTRpUr7whS/krrvuyt/93d/l5ptvzrhx45Ik1157bSZOnJh/+Zd/yUc/+tFMnTo11113XR599NGmrvRTTz01t9xyS6666qrU19fn9NNPT5LMmTOnVc+3tbu9AgDUSkvT5tv03yZvvP1Glr6+dIPvd80NQkfUjzBtDgAA1FRr89qahuh1dXUtXn/llVfm+OOPz+zZs7Pvvvu2eM6CBQsycuTIJMmTTz6ZU089NbNn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/vvv6/7771fPnj1lMBi0ZcsWl9fPnTunmTNnKicnRyaTSX379tXq1atdjmlqatKMGTOUlpama665RmPHjtXJkyddjqmsrNSoUaPUpUsXZWRk6JlnntHly5ddjikrK9Ptt9+u5ORkfeMb39C6detarXflypXKz89X586dVVBQoI8++igg7wMA/zg2u2xZ3dLe5LRBBuWac1WYX6jC/EJN6DdBhfmFMRfqWm1WlX1Rpo1/3aiyL8pktVk9vmfHG46rtrHWr69jkEFppjTlpOS4PJ9jztHmBzdrTJ8xMiYYY/q9BgAAAAAAsSusk+jnz59X//79NXXqVI0Z07o+oaSkRLt379Yvf/lL5efn691339X06dPVs2dPfec735EkFRcXa9u2bXrrrbeUmpqqmTNnasyYMfrjH/8oSbJarRo1apQyMzNVXl6uqqoqPfroo+rUqZN+/OMfS5KOHj2qUaNG6cknn9Qbb7yhXbt26bHHHlNWVpaKiookSW+++aZKSkq0evVqFRQUaNmyZSoqKtKhQ4eUkZERoncMgIO3m4caZHA5Jl56z5k2BwAAAAAACAyD3W4PXJrSAQaDQW+//bYeeOAB53M333yzHnroIb3wwgvO5wYMGKB7771X//Zv/6a6ujp1795dGzZs0Lhx4yRJn332mfr06aOKigoNGjRI77zzju677z6dOHFCPXr0kCStXr1a8+bNU01NjZKSkjRv3jxt27ZNBw4ccH6d8ePH6+zZs9q+fbskqaCgQHfeeadWrFghSbLZbMrNzdWsWbP07LPPuv2eLl68qIsXLzof19fXKzc3V3V1dTKbzYF544A4VfZFmYatH9bucd27dFfNhRrn41xzbsz3njumzQMZljvE4/sJAAAAAABiU319vVJTU9vNayO6E33IkCH69a9/ralTp6pnz54qKyvT3/72Ny1dulSStG/fPl26dEnDhw93nnPTTTcpLy/PGaJXVFSoX79+zgBdkoqKivTUU0/pk08+0W233aaKigqXaziOmTNnjiSpublZ+/bt0/z5852vJyQkaPjw4aqoqPC4/gULFuill14KxFsBQK6bYX5a86lX5ywtWqpsc3bMTke33CB0SM4Qryb0fWWQQTnmHB2edVjlx8pj9v0EAAAAAABoKaJD9FdeeUVPPPGEcnJylJiYqISEBP3nf/6n7rrrLklSdXW1kpKS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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "\n", + "my_alpha_A = [150000]\n", + "my_alpha_B = [150000]\n", + "total_alpha_A = my_alpha_A[0]\n", + "total_alpha_B = my_alpha_B[0]\n", + "proportions_A = []\n", + "proportions_B = []\n", + "divs_A = []\n", + "divs_B = []\n", + "tempo = 1\n", + "emission_per_tempo = int(7200/tempo)\n", + "period = int( (365/2) * tempo )\n", + "days = list(range(period))\n", + "for day in days:\n", + " my_proportion_A = my_alpha_A[-1] / total_alpha_A\n", + " my_proportion_B = my_alpha_B[-1] / total_alpha_B\n", + " proportions_A.append(my_proportion_A)\n", + " proportions_B.append(my_proportion_B)\n", + "\n", + " my_divs_A = 0.25 * my_proportion_A * emission_per_tempo\n", + " my_divs_B = 0.25 * my_proportion_B * emission_per_tempo\n", + " divs_A.append(my_divs_A)\n", + " divs_B.append(my_divs_B)\n", + " my_alpha_A.append(my_alpha_A[-1] + my_divs_A)\n", + " my_alpha_B.append(my_alpha_B[-1] + my_divs_B)\n", + " total_alpha_A += emission_per_tempo\n", + " total_alpha_B += emission_per_tempo * 2\n", + "\n", + "# Plotting the graphs\n", + "fig, axs = plt.subplots(3, 1, figsize=(15, 20)) # Increased figure size\n", + "\n", + "# Proportion graph\n", + "axs[0].plot(days, proportions_A, marker='o', linestyle='-', linewidth=2, markersize=8) # Made line and markers bigger\n", + "axs[0].plot(days, proportions_B, marker='o', linestyle='-', linewidth=2, markersize=8) # Made line and markers bigger\n", + "\n", + "axs[0].axhline(y=0.18, color='r', linestyle='--') # Drawing 0.18 percent line\n", + "axs[0].set_title('My Proportion Over Time', fontsize=16) # Increased title font size\n", + "axs[0].set_xlabel('Day', fontsize=14) # Increased x label font size\n", + "axs[0].set_ylabel('Proportion', fontsize=14) # Increased y label font size\n", + "axs[0].grid(True) # Added grid\n", + "axs[0].tick_params(axis='both', which='major', labelsize=12) # Increased tick label size\n", + "\n", + "# Divs graph\n", + "axs[1].plot(days, divs_A, marker='o', linestyle='-', color='r')\n", + "axs[1].plot(days, divs_B, marker='o', linestyle='-', color='r')\n", + "\n", + "axs[1].set_title('My Divs Over Time')\n", + "axs[1].set_xlabel('Day')\n", + "axs[1].set_ylabel('Divs')\n", + "\n", + "# My Alpha graph\n", + "axs[2].plot(days, my_alpha_A[:-1], marker='o', linestyle='-', color='g') # Including initial alpha\n", + "axs[2].plot(days, my_alpha_B[:-1], marker='o', linestyle='-', color='g') # Including initial alpha\n", + "axs[2].set_title('My Alpha Over Time')\n", + "axs[2].set_xlabel('Day')\n", + "axs[2].set_ylabel('My Alpha')\n", + "\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.182845632835794" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "proportions_A[-1]" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.07869791442904046" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "proportions_B[-1]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "311", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.7" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/node/Cargo.toml b/node/Cargo.toml index 7fc6eff48..e5d5de61e 100644 --- a/node/Cargo.toml +++ b/node/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "node-subtensor" -version = "4.0.0-dev" +version = "5.0.4" description = "A fresh FRAME-based Substrate node, ready for hacking." authors = ["Substrate DevHub "] homepage = "https://substrate.io/" diff --git a/node/src/chain_spec/localnet.rs b/node/src/chain_spec/localnet.rs index 73f205acc..4c9720f12 100644 --- a/node/src/chain_spec/localnet.rs +++ b/node/src/chain_spec/localnet.rs @@ -2,6 +2,7 @@ #![allow(clippy::unwrap_used)] use super::*; +use sp_runtime::AccountId32; pub fn localnet_config() -> Result { let wasm_binary = WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?; @@ -72,6 +73,14 @@ fn localnet_genesis( get_account_id_from_seed::("Ferdie"), 2000000000000u128, ), + ( + AccountId32::from_ss58check("5H3qhPGzKMNV9fTPuizxzp8azyFRMd4BnheSuwN9Qxb5Cz3u").unwrap(), + 1_000_000_000_000_000 + ), + ( + AccountId32::from_ss58check("5EeBuJRFUMS3CgisL1FT2w4AdqSQVGWRGNsTdR5YrFd189PT").unwrap(), + 1_000_000_000_000_000 + ), ]; // Check if the environment variable is set diff --git a/node/src/rpc.rs b/node/src/rpc.rs index 511fb74c3..279bb57f3 100644 --- a/node/src/rpc.rs +++ b/node/src/rpc.rs @@ -60,6 +60,8 @@ where C::Api: subtensor_custom_rpc_runtime_api::NeuronInfoRuntimeApi, C::Api: subtensor_custom_rpc_runtime_api::SubnetInfoRuntimeApi, C::Api: subtensor_custom_rpc_runtime_api::SubnetRegistrationRuntimeApi, + C::Api: subtensor_custom_rpc_runtime_api::StakeInfoRuntimeApi, + C::Api: subtensor_custom_rpc_runtime_api::DynamicPoolInfoRuntimeApi, B: sc_client_api::Backend + Send + Sync + 'static, P: TransactionPool + 'static, { diff --git a/pallets/admin-utils/src/lib.rs b/pallets/admin-utils/src/lib.rs index 61c29efff..fb5fed874 100644 --- a/pallets/admin-utils/src/lib.rs +++ b/pallets/admin-utils/src/lib.rs @@ -2,10 +2,10 @@ pub use pallet::*; pub mod weights; +use sp_weights::Weight; pub use weights::WeightInfo; -use sp_runtime::DispatchError; -use sp_runtime::{traits::Member, RuntimeAppPublic}; +use sp_runtime::{traits::Member, DispatchError, DispatchResult, RuntimeAppPublic}; #[cfg(feature = "runtime-benchmarks")] mod benchmarking; @@ -72,6 +72,14 @@ pub mod pallet { MaxAllowedUIdsLessThanCurrentUIds, } + #[pallet::hooks] + impl Hooks> for Pallet { + fn on_initialize(_block_number: BlockNumberFor) -> Weight { + // Continue to change subnet type (from stao to dtao) + T::Subtensor::do_continue_stao_dtao_transition() + } + } + /// Dispatchable functions allows users to interact with the pallet and invoke state changes. #[pallet::call] impl Pallet { @@ -118,9 +126,25 @@ pub mod pallet { Ok(()) } - /// The extrinsic sets the serving rate limit for a subnet. - /// It is only callable by the root account or subnet owner. - /// The extrinsic will call the Subtensor pallet to set the serving rate limit. + /// Set the rate limit at wich delegate take can be set (increased) + /// + #[pallet::call_index(45)] + #[pallet::weight((0, DispatchClass::Operational, Pays::No))] + pub fn sudo_set_tx_delegate_take_rate_limit( + origin: OriginFor, + tx_rate_limit: u64, + ) -> DispatchResult { + ensure_root(origin)?; + T::Subtensor::set_tx_delegate_take_rate_limit(tx_rate_limit); + log::info!( + "TxRateLimitDelegateTakeSet( tx_delegate_take_rate_limit: {:?} ) ", + tx_rate_limit + ); + Ok(()) + } + + /// Set the serving rate limit + /// #[pallet::call_index(3)] #[pallet::weight(T::WeightInfo::sudo_set_serving_rate_limit())] pub fn sudo_set_serving_rate_limit( @@ -274,6 +298,9 @@ pub mod pallet { DispatchClass::Operational, Pays::No ))] + + /// Set adjustment alpha + /// pub fn sudo_set_adjustment_alpha( origin: OriginFor, netuid: u16, @@ -902,33 +929,41 @@ pub mod pallet { Ok(()) } - /// The extrinsic sets the rate limit for delegate take transactions. + /// The extrinsic sets the minimum delegate take. /// It is only callable by the root account. - /// The extrinsic will call the Subtensor pallet to set the rate limit for delegate take transactions. - #[pallet::call_index(45)] + /// The extrinsic will call the Subtensor pallet to set the minimum delegate take. + #[pallet::call_index(46)] #[pallet::weight((0, DispatchClass::Operational, Pays::No))] - pub fn sudo_set_tx_delegate_take_rate_limit( + pub fn sudo_set_min_delegate_take(origin: OriginFor, take: u16) -> DispatchResult { + ensure_root(origin)?; + T::Subtensor::set_min_delegate_take(take); + log::info!("TxMinDelegateTakeSet( tx_min_delegate_take: {:?} ) ", take); + Ok(()) + } + + /// Set global (vs. local) stake weight + /// + #[pallet::call_index(50)] + #[pallet::weight((0, DispatchClass::Operational, Pays::No))] + pub fn sudo_set_global_stake_weight( origin: OriginFor, - tx_rate_limit: u64, + global_stake_weight: u16, ) -> DispatchResult { ensure_root(origin)?; - T::Subtensor::set_tx_delegate_take_rate_limit(tx_rate_limit); - log::info!( - "TxRateLimitDelegateTakeSet( tx_delegate_take_rate_limit: {:?} ) ", - tx_rate_limit - ); + T::Subtensor::set_global_stake_weight(global_stake_weight); Ok(()) } - /// The extrinsic sets the minimum delegate take. - /// It is only callable by the root account. - /// The extrinsic will call the Subtensor pallet to set the minimum delegate take. - #[pallet::call_index(46)] + /// Enable / Disable subnet staking + /// + #[pallet::call_index(44)] #[pallet::weight((0, DispatchClass::Operational, Pays::No))] - pub fn sudo_set_min_delegate_take(origin: OriginFor, take: u16) -> DispatchResult { + pub fn sudo_set_subnet_staking( + origin: OriginFor, + subnet_staking: bool, + ) -> DispatchResult { ensure_root(origin)?; - T::Subtensor::set_min_delegate_take(take); - log::info!("TxMinDelegateTakeSet( tx_min_delegate_take: {:?} ) ", take); + T::Subtensor::set_subnet_staking(subnet_staking); Ok(()) } @@ -997,6 +1032,29 @@ pub mod pallet { log::info!("ToggleSetWeightsCommitReveal( netuid: {:?} ) ", netuid); Ok(()) } + + /// Start changing subnet type (from stao to dtao) + /// Call this extrinsic to initiate the transition, + /// wait until PendingEmission is 0, and then call + /// continue_changing_network_type + #[pallet::call_index(51)] + #[pallet::weight((0, DispatchClass::Operational, Pays::No))] + pub fn change_network_type(origin: OriginFor, netuid: u16) -> DispatchResult { + ensure_root(origin)?; + T::Subtensor::do_start_stao_dtao_transition(netuid) + } + + /// Start changing subnet type (from stao to dtao) for + /// all subnets. + /// Call this extrinsic to initiate the transition, + /// wait until PendingEmission is 0, and then call + /// continue_changing_network_type + #[pallet::call_index(52)] + #[pallet::weight((0, DispatchClass::Operational, Pays::No))] + pub fn change_network_type_all(origin: OriginFor) -> DispatchResult { + ensure_root(origin)?; + T::Subtensor::do_start_stao_dtao_transition_for_all() + } } } @@ -1045,10 +1103,11 @@ pub trait SubtensorInterface { fn if_subnet_exist(netuid: u16) -> bool; fn create_account_if_non_existent(coldkey: &AccountId, hotkey: &AccountId); fn coldkey_owns_hotkey(coldkey: &AccountId, hotkey: &AccountId) -> bool; - fn increase_stake_on_coldkey_hotkey_account( + fn increase_subnet_token_on_coldkey_hotkey_account( coldkey: &AccountId, hotkey: &AccountId, - increment: u64, + netuid: u16, + increment_alpha: u64, ); fn add_balance_to_coldkey_account(coldkey: &AccountId, amount: Balance); fn get_current_block_as_u64() -> u64; @@ -1086,10 +1145,16 @@ pub trait SubtensorInterface { fn set_weights_set_rate_limit(netuid: u16, weights_set_rate_limit: u64); fn init_new_network(netuid: u16, tempo: u16); fn set_weights_min_stake(min_stake: u64); + fn set_global_stake_weight(global_stake_weight: u16); + fn set_subnet_staking(subnet_staking: bool); fn get_nominator_min_required_stake() -> u64; fn set_nominator_min_required_stake(min_stake: u64); fn clear_small_nominations(); fn set_target_stakes_per_interval(target_stakes_per_interval: u64); fn set_commit_reveal_weights_interval(netuid: u16, interval: u64); fn set_commit_reveal_weights_enabled(netuid: u16, enabled: bool); + fn do_start_stao_dtao_transition(netuid: u16) -> DispatchResult; + fn do_start_stao_dtao_transition_for_all() -> DispatchResult; + fn do_continue_stao_dtao_transition() -> Weight; + fn get_pending_emission(netuid: u16) -> u64; } diff --git a/pallets/admin-utils/tests/mock.rs b/pallets/admin-utils/tests/mock.rs index c0985b010..9430f06e2 100644 --- a/pallets/admin-utils/tests/mock.rs +++ b/pallets/admin-utils/tests/mock.rs @@ -10,8 +10,9 @@ use sp_core::U256; use sp_core::{ConstU64, H256}; use sp_runtime::{ traits::{BlakeTwo256, ConstU32, IdentityLookup}, - BuildStorage, DispatchError, + BuildStorage, DispatchError, DispatchResult, }; +use sp_weights::Weight; type Block = frame_system::mocking::MockBlock; @@ -69,6 +70,8 @@ parameter_types! { pub const InitialRho: u16 = 30; pub const InitialKappa: u16 = 32_767; pub const InitialTempo: u16 = 0; + pub const MinTempo: u16 = 2; + pub const MaxTempo: u16 = u16::MAX; pub const SelfOwnership: u64 = 2; pub const InitialImmunityPeriod: u16 = 2; pub const InitialMaxAllowedUids: u16 = 2; @@ -108,6 +111,7 @@ parameter_types! { pub const InitialSubnetLimit: u16 = 10; // Max 10 subnets. pub const InitialNetworkRateLimit: u64 = 0; pub const InitialTargetStakesPerInterval: u16 = 1; + pub const InitialSubnetOwnerLockPeriod: u64 = 7 * 7200 * 3; } @@ -119,11 +123,14 @@ impl pallet_subtensor::Config for Test { type CouncilOrigin = EnsureNever; type SenateMembers = (); type TriumvirateInterface = (); + type EpochConfig = (); type InitialMinAllowedWeights = InitialMinAllowedWeights; type InitialEmissionValue = InitialEmissionValue; type InitialMaxWeightsLimit = InitialMaxWeightsLimit; type InitialTempo = InitialTempo; + type MinTempo = MinTempo; + type MaxTempo = MaxTempo; type InitialDifficulty = InitialDifficulty; type InitialAdjustmentInterval = InitialAdjustmentInterval; type InitialAdjustmentAlpha = InitialAdjustmentAlpha; @@ -160,6 +167,7 @@ impl pallet_subtensor::Config for Test { type InitialSubnetLimit = InitialSubnetLimit; type InitialNetworkRateLimit = InitialNetworkRateLimit; type InitialTargetStakesPerInterval = InitialTargetStakesPerInterval; + type InitialSubnetOwnerLockPeriod = InitialSubnetOwnerLockPeriod; } #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] @@ -284,12 +292,18 @@ impl pallet_admin_utils::SubtensorInterface f SubtensorModule::coldkey_owns_hotkey(coldkey, hotkey) } - fn increase_stake_on_coldkey_hotkey_account( + fn increase_subnet_token_on_coldkey_hotkey_account( coldkey: &AccountId, hotkey: &AccountId, - increment: u64, + netuid: u16, + increment_alpha: u64, ) { - SubtensorModule::increase_stake_on_coldkey_hotkey_account(coldkey, hotkey, increment); + SubtensorModule::increase_subnet_token_on_coldkey_hotkey_account( + coldkey, + hotkey, + netuid, + increment_alpha, + ); } fn add_balance_to_coldkey_account(coldkey: &AccountId, amount: Balance) { @@ -451,6 +465,14 @@ impl pallet_admin_utils::SubtensorInterface f SubtensorModule::clear_small_nominations(); } + fn set_global_stake_weight(global_stake_weight: u16) { + SubtensorModule::set_global_stake_weight(global_stake_weight); + } + + fn set_subnet_staking(subnet_staking: bool) { + SubtensorModule::set_subnet_staking(subnet_staking); + } + fn set_target_stakes_per_interval(target_stakes_per_interval: u64) { SubtensorModule::set_target_stakes_per_interval(target_stakes_per_interval); } @@ -462,6 +484,22 @@ impl pallet_admin_utils::SubtensorInterface f fn set_commit_reveal_weights_enabled(netuid: u16, enabled: bool) { SubtensorModule::set_commit_reveal_weights_enabled(netuid, enabled); } + + fn do_start_stao_dtao_transition(netuid: u16) -> DispatchResult { + SubtensorModule::do_start_stao_dtao_transition(netuid) + } + + fn do_start_stao_dtao_transition_for_all() -> DispatchResult { + SubtensorModule::do_start_stao_dtao_transition_for_all() + } + + fn do_continue_stao_dtao_transition() -> Weight { + SubtensorModule::do_continue_stao_dtao_transition() + } + + fn get_pending_emission(netuid: u16) -> u64 { + SubtensorModule::get_pending_emission(netuid) + } } impl pallet_admin_utils::Config for Test { @@ -534,3 +572,18 @@ pub fn add_network(netuid: u16, tempo: u16) { SubtensorModule::set_network_registration_allowed(netuid, true); SubtensorModule::set_network_pow_registration_allowed(netuid, true); } + +#[allow(dead_code)] +pub fn root_register( + hotkey_account_id: U256 +) { + let result = SubtensorModule::root_register( + <::RuntimeOrigin>::signed(hotkey_account_id), + hotkey_account_id, + ); + assert_ok!(result); + log::info!( + "Register on root, hotkey: {:?}", + hotkey_account_id + ); +} diff --git a/pallets/admin-utils/tests/tests.rs b/pallets/admin-utils/tests/tests.rs index f87b43e74..a8d8eca50 100644 --- a/pallets/admin-utils/tests/tests.rs +++ b/pallets/admin-utils/tests/tests.rs @@ -8,6 +8,13 @@ use sp_core::U256; mod mock; use mock::*; +#[allow(dead_code)] +pub fn add_network(netuid: u16, tempo: u16) { + SubtensorModule::init_new_network(netuid, tempo); + SubtensorModule::set_network_registration_allowed(netuid, true); + SubtensorModule::set_network_pow_registration_allowed(netuid, true); +} + #[test] fn test_sudo_set_default_take() { new_test_ext().execute_with(|| { @@ -697,6 +704,48 @@ fn test_sudo_set_weights_min_stake() { }); } +#[test] +fn test_sudo_global_stake_weight() { + new_test_ext().execute_with(|| { + let to_be_set: u16 = 10; + let init_value: u16 = SubtensorModule::get_global_stake_weight(); + assert_eq!( + AdminUtils::sudo_set_global_stake_weight( + <::RuntimeOrigin>::signed(U256::from(1)), + to_be_set + ), + Err(DispatchError::BadOrigin) + ); + assert_eq!(SubtensorModule::get_global_stake_weight(), init_value); + assert_ok!(AdminUtils::sudo_set_global_stake_weight( + <::RuntimeOrigin>::root(), + to_be_set + )); + assert_eq!(SubtensorModule::get_global_stake_weight(), to_be_set); + }); +} + +#[test] +fn test_sudo_subnet_staking() { + new_test_ext().execute_with(|| { + let to_be_set: bool = true; + let init_value: bool = SubtensorModule::subnet_staking_on(); + assert_eq!( + AdminUtils::sudo_set_subnet_staking( + <::RuntimeOrigin>::signed(U256::from(1)), + to_be_set + ), + Err(DispatchError::BadOrigin) + ); + assert_eq!(SubtensorModule::subnet_staking_on(), init_value); + assert_ok!(AdminUtils::sudo_set_subnet_staking( + <::RuntimeOrigin>::root(), + to_be_set + )); + assert_eq!(SubtensorModule::subnet_staking_on(), to_be_set); + }); +} + #[test] fn test_sudo_set_bonds_moving_average() { new_test_ext().execute_with(|| { @@ -931,32 +980,28 @@ mod sudo_set_nominator_min_required_stake { // Create accounts. let netuid = 1; + let root: u16 = 0; + let tempo: u16 = 13; let hot1 = U256::from(1); let hot2 = U256::from(2); let cold1 = U256::from(3); let cold2 = U256::from(4); SubtensorModule::set_target_stakes_per_interval(10); - // Register network. + + // Register networks. + add_network(root, tempo); add_network(netuid, 0); - // Register hot1. + // Register hot1 on subnet and root. register_ok_neuron(netuid, hot1, cold1, 0); - assert_ok!(SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(cold1), - hot1, - u16::MAX / 10 - )); assert_eq!(SubtensorModule::get_owning_coldkey_for_hotkey(&hot1), cold1); + root_register(hot1); // Register hot2. register_ok_neuron(netuid, hot2, cold2, 0); - assert_ok!(SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(cold2), - hot2, - u16::MAX / 10 - )); assert_eq!(SubtensorModule::get_owning_coldkey_for_hotkey(&hot2), cold2); + root_register(hot2); // Add stake cold1 --> hot1 (non delegation.) SubtensorModule::add_balance_to_coldkey_account(&cold1, 5); @@ -966,7 +1011,7 @@ mod sudo_set_nominator_min_required_stake { 1 )); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&cold1, &hot1), + SubtensorModule::get_total_stake_for_hotkey_and_coldkey(&hot1, &cold1), 1 ); assert_eq!(Balances::free_balance(cold1), 4); @@ -979,7 +1024,7 @@ mod sudo_set_nominator_min_required_stake { 1 )); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&cold2, &hot1), + SubtensorModule::get_total_stake_for_hotkey_and_coldkey(&hot1, &cold2), 1 ); assert_eq!(Balances::free_balance(cold2), 4); @@ -992,7 +1037,7 @@ mod sudo_set_nominator_min_required_stake { 1 )); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&cold1, &hot2), + SubtensorModule::get_total_stake_for_hotkey_and_coldkey(&hot2, &cold1), 1 ); assert_eq!(Balances::free_balance(cold1), 8); @@ -1005,7 +1050,7 @@ mod sudo_set_nominator_min_required_stake { 1 )); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&cold2, &hot2), + SubtensorModule::get_total_stake_for_hotkey_and_coldkey(&hot2, &cold2), 1 ); assert_eq!(Balances::free_balance(cold2), 8); @@ -1016,19 +1061,19 @@ mod sudo_set_nominator_min_required_stake { 0u64 )); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&cold1, &hot1), + SubtensorModule::get_total_stake_for_hotkey_and_coldkey(&hot1, &cold1), 1 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&cold1, &hot2), + SubtensorModule::get_total_stake_for_hotkey_and_coldkey(&hot2, &cold1), 1 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&cold2, &hot1), + SubtensorModule::get_total_stake_for_hotkey_and_coldkey(&hot1, &cold2), 1 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&cold2, &hot2), + SubtensorModule::get_total_stake_for_hotkey_and_coldkey(&hot2, &cold2), 1 ); @@ -1038,19 +1083,19 @@ mod sudo_set_nominator_min_required_stake { 10u64 )); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&cold1, &hot1), + SubtensorModule::get_total_stake_for_hotkey_and_coldkey(&hot1, &cold1), 1 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&cold1, &hot2), + SubtensorModule::get_total_stake_for_hotkey_and_coldkey(&hot2, &cold1), 0 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&cold2, &hot1), + SubtensorModule::get_total_stake_for_hotkey_and_coldkey(&hot1, &cold2), 0 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&cold2, &hot2), + SubtensorModule::get_total_stake_for_hotkey_and_coldkey(&hot2, &cold2), 1 ); @@ -1109,6 +1154,27 @@ fn test_sudo_set_min_delegate_take() { }); } +#[test] +fn test_sudo_set_tx_rate_limit() { + new_test_ext().execute_with(|| { + let to_be_set: u64 = 10; + let init_value: u64 = SubtensorModule::get_tx_rate_limit(); + assert_eq!( + AdminUtils::sudo_set_tx_rate_limit( + <::RuntimeOrigin>::signed(U256::from(1)), + to_be_set + ), + Err(DispatchError::BadOrigin) + ); + assert_eq!(SubtensorModule::get_tx_rate_limit(), init_value); + assert_ok!(AdminUtils::sudo_set_tx_rate_limit( + <::RuntimeOrigin>::root(), + to_be_set + )); + assert_eq!(SubtensorModule::get_tx_rate_limit(), to_be_set); + }); +} + #[test] fn test_sudo_set_weight_commit_interval() { new_test_ext().execute_with(|| { diff --git a/pallets/collective/src/tests.rs b/pallets/collective/src/tests.rs index 672556edb..e70b6b5e5 100644 --- a/pallets/collective/src/tests.rs +++ b/pallets/collective/src/tests.rs @@ -20,7 +20,9 @@ use super::{Event as CollectiveEvent, *}; use crate as pallet_collective; use frame_support::{ - assert_noop, assert_ok, derive_impl, parameter_types, traits::ConstU64, Hashable, + assert_noop, assert_ok, derive_impl, parameter_types, + traits::{ConstU32, ConstU64}, + Hashable, }; use frame_system::{EnsureRoot, EventRecord, Phase}; use sp_core::H256; diff --git a/pallets/commitments/src/tests.rs b/pallets/commitments/src/tests.rs index 7449003f4..b0a25040c 100644 --- a/pallets/commitments/src/tests.rs +++ b/pallets/commitments/src/tests.rs @@ -2,8 +2,7 @@ use super::*; use crate as pallet_commitments; -use frame_support::derive_impl; -use frame_support::traits::ConstU64; +use frame_support::{ derive_impl, traits::ConstU64 }; use sp_core::H256; use sp_runtime::{ testing::Header, @@ -50,6 +49,7 @@ impl pallet_balances::Config for Test { type WeightInfo = (); type FreezeIdentifier = (); type MaxFreezes = (); + type RuntimeHoldReason = (); } #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] diff --git a/pallets/registry/Cargo.toml b/pallets/registry/Cargo.toml index 7c495a42f..36fa5d900 100644 --- a/pallets/registry/Cargo.toml +++ b/pallets/registry/Cargo.toml @@ -24,6 +24,10 @@ scale-info = { workspace = true, features = ["derive"] } frame-benchmarking = { workspace = true, optional = true } frame-support = { workspace = true } frame-system = { workspace = true } +log = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +sp-core = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } enumflags2 = { workspace = true } diff --git a/pallets/registry/src/lib.rs b/pallets/registry/src/lib.rs index 026c03260..515bb71f6 100644 --- a/pallets/registry/src/lib.rs +++ b/pallets/registry/src/lib.rs @@ -5,6 +5,7 @@ mod tests; #[cfg(feature = "runtime-benchmarks")] mod benchmarking; +pub mod migration; pub mod types; pub mod weights; @@ -108,6 +109,26 @@ pub mod pallet { OptionQuery, >; + // #[pallet::hooks] + // impl Hooks> for Pallet { + // fn on_runtime_upgrade() -> frame_support::weights::Weight { + // // --- Migrate storage + // use crate::migration; + // let mut weight = frame_support::weights::Weight::from_parts(0, 0); + + // weight = weight + // // Initializes storage version (to 1) + // .saturating_add(migration::migrate_set_hotkey_identities::()); + + // log::info!( + // "Runtime upgrade migration in registry pallet, total weight = ({})", + // weight + // ); + + // weight + // } + // } + #[pallet::call] impl Pallet { /// Register an identity for an account. This will overwrite any existing identity. diff --git a/pallets/registry/src/migration.rs b/pallets/registry/src/migration.rs new file mode 100644 index 000000000..9b2184814 --- /dev/null +++ b/pallets/registry/src/migration.rs @@ -0,0 +1,137 @@ + +use scale_info::prelude::{ string::{ String, ToString }, vec::Vec }; +use serde::Deserialize; +use sp_core::{crypto::Ss58Codec, ConstU32}; +use sp_runtime::{AccountId32, BoundedVec}; +use sp_std::vec; +use codec::Decode; + +use super::*; +use frame_support::{ + traits::{Get, GetStorageVersion, StorageVersion}, + weights::Weight, +}; +use log; + + +#[derive(Deserialize, Debug)] +struct RegistrationRecordJSON { + address: String, + name: String, + url: String, + description: String, +} + +fn string_to_bounded_vec(input: &String) -> Result>, &'static str> { + let vec_u8: Vec = input.clone().into_bytes(); + + // Check if the length is within bounds + if vec_u8.len() > 64 { + return Err("Input string is too long"); + } + + // Convert to BoundedVec + BoundedVec::>::try_from(vec_u8).map_err(|_| "Failed to convert to BoundedVec") +} + +pub fn migrate_set_hotkey_identities() -> Weight { + let new_storage_version = 1; + let migration_name = "set hotkey identities"; + let mut weight = T::DbWeight::get().reads_writes(1, 1); + + let title = "description".to_string(); + + let onchain_version = Pallet::::on_chain_storage_version(); + log::info!("Current on-chain storage version: {:?}", onchain_version); + if onchain_version < new_storage_version { + log::info!("Starting migration: {}.", migration_name); + + // Include the JSON file with delegate info + let data = include_str!("../../../docs/delegate-info.json"); + + // Deserialize the JSON data into a HashMap + if let Ok(delegates) = serde_json::from_str::>(data) { + + log::info!("{} delegate records loaded", delegates.len()); + + // Iterate through the delegates + for delegate in delegates.iter() { + // Convert fields to bounded vecs + let name_result = string_to_bounded_vec(&delegate.name); + let desc_result = string_to_bounded_vec(&delegate.description); + let url_result = string_to_bounded_vec(&delegate.url); + + // Convert string address into AccountID + let maybe_account_id_32 = AccountId32::from_ss58check(&delegate.address); + let account_id = if maybe_account_id_32.is_ok() { + let account_id_32 = maybe_account_id_32.unwrap(); + if let Ok(acc_id) = T::AccountId::decode(&mut account_id_32.as_ref()) { + Some(acc_id) + } else { + None + } + } else { + None + }; + + if name_result.is_ok() && desc_result.is_ok() && url_result.is_ok() + && account_id.is_some() + { + let desc_title = Data::Raw(string_to_bounded_vec(&title).unwrap()); + let desc_data = Data::Raw(desc_result.unwrap()); + let desc_item = BoundedVec::try_from(vec![(desc_title, desc_data)]).unwrap(); + + let info: IdentityInfo = IdentityInfo { + display: Data::Raw(name_result.unwrap()), + additional: desc_item, + legal: Data::None, + web: Data::Raw(url_result.unwrap()), + riot: Data::None, + email: Data::None, + pgp_fingerprint: None, + image: Data::None, + twitter: Data::None, + }; + + // Insert delegate hotkeys info + let reg: Registration, T::MaxAdditionalFields> = Registration { + deposit: Zero::zero(), + info, + }; + + IdentityOf::::insert(account_id.unwrap(), reg); + weight.saturating_accrue(T::DbWeight::get().reads_writes(0, 1)); + + } else { + log::info!("Migration {} couldn't be completed, bad JSON item for: {}", migration_name, delegate.address); + if !name_result.is_ok() { + log::info!("Name is bad"); + } + if !desc_result.is_ok() { + log::info!("Description is bad"); + } + if !url_result.is_ok() { + log::info!("URL is bad"); + } + if !account_id.is_some() { + log::info!("Account ID is bad"); + } + } + + } + + + } else { + log::info!("Migration {} couldn't be completed, bad JSON file: {}", migration_name, data); + return weight; + } + + + StorageVersion::new(new_storage_version).put::>(); + } else { + log::info!("Migration already done: {}", migration_name); + } + + log::info!("Final weight: {:?}", weight); + weight +} \ No newline at end of file diff --git a/pallets/subtensor/Cargo.toml b/pallets/subtensor/Cargo.toml index cbcf76c82..839a949ae 100644 --- a/pallets/subtensor/Cargo.toml +++ b/pallets/subtensor/Cargo.toml @@ -45,6 +45,7 @@ pallet-membership = { workspace = true } hex-literal = { workspace = true } [dev-dependencies] +itertools = { workspace = true } pallet-balances = { workspace = true, features = ["std"] } sp-version = { workspace = true } # Substrate @@ -101,3 +102,4 @@ try-runtime = [ "pallet-collective/try-runtime" ] pow-faucet = [] +subnet-staking = [] \ No newline at end of file diff --git a/pallets/subtensor/rpc/Cargo.toml b/pallets/subtensor/rpc/Cargo.toml index db2f5f147..111112481 100644 --- a/pallets/subtensor/rpc/Cargo.toml +++ b/pallets/subtensor/rpc/Cargo.toml @@ -39,4 +39,5 @@ std = [ "codec/std", "serde/std" ] +subnet-staking = [] pow-faucet = [] diff --git a/pallets/subtensor/rpc/src/lib.rs b/pallets/subtensor/rpc/src/lib.rs index 2f71e9c21..d8fc78688 100644 --- a/pallets/subtensor/rpc/src/lib.rs +++ b/pallets/subtensor/rpc/src/lib.rs @@ -11,21 +11,20 @@ use std::sync::Arc; use sp_api::ProvideRuntimeApi; +use pallet_subtensor::types::TensorBytes; pub use subtensor_custom_rpc_runtime_api::{ - DelegateInfoRuntimeApi, NeuronInfoRuntimeApi, SubnetInfoRuntimeApi, - SubnetRegistrationRuntimeApi, + DelegateInfoRuntimeApi, DynamicPoolInfoRuntimeApi, NeuronInfoRuntimeApi, StakeInfoRuntimeApi, + SubnetInfoRuntimeApi, SubnetRegistrationRuntimeApi, }; - #[rpc(client, server)] pub trait SubtensorCustomApi { - #[method(name = "delegateInfo_getDelegates")] - fn get_delegates(&self, at: Option) -> RpcResult>; #[method(name = "delegateInfo_getDelegate")] fn get_delegate( &self, delegate_account_vec: Vec, at: Option, ) -> RpcResult>; + #[method(name = "delegateInfo_getDelegated")] fn get_delegated( &self, @@ -33,6 +32,39 @@ pub trait SubtensorCustomApi { at: Option, ) -> RpcResult>; + #[method(name = "delegateInfo_getSubStakeForHotkey")] + fn get_substake_for_hotkey( + &self, + hotkey_bytes: Vec, + at: Option, + ) -> RpcResult>; + #[method(name = "delegateInfo_getSubStakeForColdkey")] + fn get_substake_for_coldkey( + &self, + coldkey_bytes: Vec, + at: Option, + ) -> RpcResult>; + #[method(name = "delegateInfo_getSubStakeForNetuid")] + fn get_substake_for_netuid(&self, netuid: u16, at: Option) -> RpcResult>; + #[method(name = "delegateInfo_getTotalStakeForHotkey")] + fn get_total_stake_for_hotkey( + &self, + hotkey_bytes: Vec, + at: Option, + ) -> RpcResult; + #[method(name = "delegateInfo_getTotalStakeForColdkey")] + fn get_total_stake_for_coldkey( + &self, + hotkey_bytes: Vec, + at: Option, + ) -> RpcResult; + + #[method(name = "delegateInfo_getDelegates")] + fn get_delegates(&self, at: Option) -> RpcResult>; + #[method(name = "delegateInfo_getDelegatesLight")] + fn get_delegates_by_netuid_light(&self, netuid: u16, at: Option) -> RpcResult>; + #[method(name = "delegateInfo_getAllDelegatesTotalStake")] + fn get_all_delegates_total_stake(&self, at: Option) -> RpcResult>; #[method(name = "neuronInfo_getNeuronsLite")] fn get_neurons_lite(&self, netuid: u16, at: Option) -> RpcResult>; #[method(name = "neuronInfo_getNeuronLite")] @@ -49,8 +81,53 @@ pub trait SubtensorCustomApi { #[method(name = "subnetInfo_getSubnetHyperparams")] fn get_subnet_hyperparams(&self, netuid: u16, at: Option) -> RpcResult>; + #[method(name = "subnetInfo_getSubnetInfoV2")] + fn get_subnet_info_v2(&self, netuid: u16, at: Option) -> RpcResult>; + #[method(name = "subnetInfo_getSubnetsInfoV2")] + fn get_subnets_info_v2(&self, at: Option) -> RpcResult>; #[method(name = "subnetInfo_getLockCost")] fn get_network_lock_cost(&self, at: Option) -> RpcResult; + + #[method(name = "subnetInfo_getSubnetStakeInfoForColdKey")] + fn get_subnet_stake_info_for_cold_key( + &self, + coldkey_account_vec: TensorBytes, + netuid: u16, + at: Option, + ) -> RpcResult>; + #[method(name = "subnetInfo_getSubnetStakeInfoForColdKeys")] + fn get_subnet_stake_info_for_coldkeys( + &self, + coldkey_account_vecs: Vec, + netuid: u16, + at: Option, + ) -> RpcResult>; + #[method(name = "subnetInfo_getTotalSubnetStake")] + fn get_total_subnet_stake(&self, netuid: u16, at: Option) -> RpcResult>; + #[method(name = "subnetInfo_getAllStakeInfoForColdKey")] + fn get_all_stake_info_for_coldkey( + &self, + coldkey_account_vec: TensorBytes, + at: Option, + ) -> RpcResult>; + #[method(name = "subnetInfo_getAllSubnetStakeInfoForColdKey")] + fn get_all_subnet_stake_info_for_coldkey( + &self, + coldkey_account_vec: TensorBytes, + at: Option, + ) -> RpcResult>; + #[method(name = "subnetInfo_getTotalStakeForEachSubnet")] + fn get_total_stake_for_each_subnet(&self, at: Option) -> RpcResult>; + + #[method(name = "dynamicPoolInfo_getDynamicPoolInfo")] + fn get_dynamic_pool_info(&self, netuid: u16, at: Option) -> RpcResult>; + #[method(name = "dynamicPoolInfo_getAllDynamicPoolInfos")] + fn get_all_dynamic_pool_infos(&self, at: Option) -> RpcResult>; + + #[method(name = "dynamicPoolInfo_getDynamicPoolInfoV2")] + fn get_dynamic_pool_info_v2(&self, netuid: u16, at: Option) -> RpcResult>; + #[method(name = "dynamicPoolInfo_getAllDynamicPoolInfosV2")] + fn get_all_dynamic_pool_infos_v2(&self, at: Option) -> RpcResult>; } pub struct SubtensorCustom { @@ -99,7 +176,73 @@ where C::Api: NeuronInfoRuntimeApi, C::Api: SubnetInfoRuntimeApi, C::Api: SubnetRegistrationRuntimeApi, + C::Api: StakeInfoRuntimeApi, + C::Api: DynamicPoolInfoRuntimeApi, { + fn get_substake_for_hotkey( + &self, + hotkey_bytes: Vec, + at: Option<::Hash>, + ) -> RpcResult> { + let api = self.client.runtime_api(); + let at = at.unwrap_or_else(|| self.client.info().best_hash); + api.get_substake_for_hotkey(at, hotkey_bytes).map_err(|e| { + Error::RuntimeError(format!("Unable to get delegates info: {:?}", e)).into() + }) + } + + fn get_substake_for_coldkey( + &self, + coldkey_bytes: Vec, + at: Option<::Hash>, + ) -> RpcResult> { + let api = self.client.runtime_api(); + let at = at.unwrap_or_else(|| self.client.info().best_hash); + api.get_substake_for_coldkey(at, coldkey_bytes) + .map_err(|e| { + Error::RuntimeError(format!("Unable to get delegates info: {:?}", e)).into() + }) + } + + fn get_substake_for_netuid( + &self, + netuid: u16, + at: Option<::Hash>, + ) -> RpcResult> { + let api = self.client.runtime_api(); + let at = at.unwrap_or_else(|| self.client.info().best_hash); + api.get_substake_for_netuid(at, netuid).map_err(|e| { + Error::RuntimeError(format!("Unable to get delegates info: {:?}", e)).into() + }) + } + + fn get_total_stake_for_hotkey( + &self, + hotkey_bytes: Vec, + at: Option<::Hash>, + ) -> RpcResult { + let api = self.client.runtime_api(); + let at = at.unwrap_or_else(|| self.client.info().best_hash); + api.get_total_stake_for_hotkey(at, hotkey_bytes) + .map_err(|e| { + Error::RuntimeError(format!("Unable to get total stake for hotkey: {:?}", e)).into() + }) + } + + fn get_total_stake_for_coldkey( + &self, + hotkey_bytes: Vec, + at: Option<::Hash>, + ) -> RpcResult { + let api = self.client.runtime_api(); + let at = at.unwrap_or_else(|| self.client.info().best_hash); + api.get_total_stake_for_coldkey(at, hotkey_bytes) + .map_err(|e| { + Error::RuntimeError(format!("Unable to get total stake for coldkey: {:?}", e)) + .into() + }) + } + fn get_delegates(&self, at: Option<::Hash>) -> RpcResult> { let api = self.client.runtime_api(); let at = at.unwrap_or_else(|| self.client.info().best_hash); @@ -109,6 +252,24 @@ where }) } + fn get_delegates_by_netuid_light(&self, netuid: u16, at: Option<::Hash>) -> RpcResult> { + let api = self.client.runtime_api(); + let at = at.unwrap_or_else(|| self.client.info().best_hash); + + api.get_delegates_by_netuid_light(at, netuid).map_err(|e| { + Error::RuntimeError(format!("Unable to get delegates info: {:?}", e)).into() + }) + } + + fn get_all_delegates_total_stake(&self, at: Option<::Hash>) -> RpcResult> { + let api = self.client.runtime_api(); + let at = at.unwrap_or_else(|| self.client.info().best_hash); + + api.get_all_delegates_total_stake(at).map_err(|e| { + Error::RuntimeError(format!("Unable to get all delegates total stake info: {:?}", e)).into() + }) + } + fn get_delegate( &self, delegate_account_vec: Vec, @@ -195,6 +356,18 @@ where .map_err(|e| Error::RuntimeError(format!("Unable to get subnet info: {:?}", e)).into()) } + fn get_subnet_info_v2( + &self, + netuid: u16, + at: Option<::Hash>, + ) -> RpcResult> { + let api = self.client.runtime_api(); + let at = at.unwrap_or_else(|| self.client.info().best_hash); + + api.get_subnet_info_v2(at, netuid) + .map_err(|e| Error::RuntimeError(format!("Unable to get subnet info: {:?}", e)).into()) + } + fn get_subnet_hyperparams( &self, netuid: u16, @@ -215,12 +388,158 @@ where .map_err(|e| Error::RuntimeError(format!("Unable to get subnets info: {:?}", e)).into()) } + fn get_subnets_info_v2(&self, at: Option<::Hash>) -> RpcResult> { + let api = self.client.runtime_api(); + let at = at.unwrap_or_else(|| self.client.info().best_hash); + + api.get_subnets_info_v2(at) + .map_err(|e| Error::RuntimeError(format!("Unable to get subnets info: {:?}", e)).into()) + } + fn get_network_lock_cost(&self, at: Option<::Hash>) -> RpcResult { let api = self.client.runtime_api(); let at = at.unwrap_or_else(|| self.client.info().best_hash); api.get_network_registration_cost(at).map_err(|e| { - Error::RuntimeError(format!("Unable to get subnet lock cost: {:?}", e)).into() + Error::RuntimeError(format!("Unable to get subnet lock cost: {}", e)).into() + }) + } + + fn get_subnet_stake_info_for_cold_key( + &self, + coldkey_account_vec: TensorBytes, + netuid: u16, + at: Option<::Hash>, + ) -> RpcResult> { + let api = self.client.runtime_api(); + let at = at.unwrap_or_else(|| self.client.info().best_hash); + + api.get_subnet_stake_info_for_coldkey(at, coldkey_account_vec, netuid) + .map_err(|e| { + Error::RuntimeError(format!("Unable to get subnet stake info: {}", e)).into() + }) + } + + fn get_subnet_stake_info_for_coldkeys( + &self, + coldkey_account_vecs: Vec, + netuid: u16, + at: Option<::Hash>, + ) -> RpcResult> { + let api = self.client.runtime_api(); + let at = at.unwrap_or_else(|| self.client.info().best_hash); + + api.get_subnet_stake_info_for_coldkeys(at, coldkey_account_vecs, netuid) + .map_err(|e| { + Error::RuntimeError(format!("Unable to get subnet stake info: {}", e)).into() + }) + } + + fn get_total_subnet_stake( + &self, + netuid: u16, + at: Option<::Hash>, + ) -> RpcResult> { + let api = self.client.runtime_api(); + let at = at.unwrap_or_else(|| self.client.info().best_hash); + + api.get_total_subnet_stake(at, netuid).map_err(|e| { + Error::RuntimeError(format!("Unable to get total subnet stake: {}", e)).into() + }) + } + + fn get_all_stake_info_for_coldkey( + &self, + coldkey_account_vec: TensorBytes, + at: Option<::Hash>, + ) -> RpcResult> { + let api = self.client.runtime_api(); + let at = at.unwrap_or_else(|| self.client.info().best_hash); + + api.get_all_stake_info_for_coldkey(at, coldkey_account_vec) + .map_err(|e| { + Error::RuntimeError(format!("Unable to get all stake info for coldkey: {}", e)) + .into() + }) + } + + fn get_all_subnet_stake_info_for_coldkey( + &self, + coldkey_account_vec: TensorBytes, + at: Option<::Hash>, + ) -> RpcResult> { + let api = self.client.runtime_api(); + let at = at.unwrap_or_else(|| self.client.info().best_hash); + + api.get_all_subnet_stake_info_for_coldkey(at, coldkey_account_vec) + .map_err(|e| { + Error::RuntimeError(format!( + "Unable to get all subnet stake info for coldkey: {}", + e + )) + .into() + }) + } + + fn get_dynamic_pool_info( + &self, + netuid: u16, + at: Option<::Hash>, + ) -> RpcResult> { + let api = self.client.runtime_api(); + let at = at.unwrap_or_else(|| self.client.info().best_hash); + + api.get_dynamic_pool_info(at, netuid).map_err(|e| { + Error::RuntimeError(format!("Unable to get dynamic pool info: {}", e)).into() + }) + } + + fn get_dynamic_pool_info_v2( + &self, + netuid: u16, + at: Option<::Hash>, + ) -> RpcResult> { + let api = self.client.runtime_api(); + let at = at.unwrap_or_else(|| self.client.info().best_hash); + + api.get_dynamic_pool_info_v2(at, netuid).map_err(|e| { + Error::RuntimeError(format!("Unable to get dynamic pool info: {}", e)).into() + }) + } + + fn get_all_dynamic_pool_infos( + &self, + at: Option<::Hash>, + ) -> RpcResult> { + let api = self.client.runtime_api(); + let at = at.unwrap_or_else(|| self.client.info().best_hash); + + api.get_all_dynamic_pool_infos(at).map_err(|e| { + Error::RuntimeError(format!("Unable to get all dynamic pool infos: {}", e)).into() + }) + } + + fn get_all_dynamic_pool_infos_v2( + &self, + at: Option<::Hash>, + ) -> RpcResult> { + let api = self.client.runtime_api(); + let at = at.unwrap_or_else(|| self.client.info().best_hash); + + api.get_all_dynamic_pool_infos_v2(at).map_err(|e| { + Error::RuntimeError(format!("Unable to get all dynamic pool infos: {}", e)).into() + }) + } + + fn get_total_stake_for_each_subnet( + &self, + at: Option<::Hash>, + ) -> RpcResult> { + let api = self.client.runtime_api(); + let at = at.unwrap_or_else(|| self.client.info().best_hash); + + api.get_total_stake_for_each_subnet(at).map_err(|e| { + Error::RuntimeError(format!("Unable to get total stake for each subnet: {}", e)).into() }) } } diff --git a/pallets/subtensor/rpc/tests/tests.rs b/pallets/subtensor/rpc/tests/tests.rs new file mode 100644 index 000000000..e44b8dca5 --- /dev/null +++ b/pallets/subtensor/rpc/tests/tests.rs @@ -0,0 +1,211 @@ +// #![no_std] +// use std::sync::Arc; + +// use sp_api::{ApiRef, ProvideRuntimeApi}; +// pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic; +// use sp_runtime::{ +// generic::{self}, +// traits::{BlakeTwo256, Block as BlockT, Extrinsic, NumberFor, Verify, Zero}, +// }; + +// use codec::{Compact, Encode}; +// use pallet_subtensor::stake_info::SubnetStakeInfo; +// use sp_blockchain::HeaderBackend; +// // use substrate_test_runtime_client::runtime::{Block, Hash}; +// use subtensor_custom_rpc::SubtensorCustomApiServer; +// use subtensor_custom_rpc::{ +// DelegateInfoRuntimeApi, NeuronInfoRuntimeApi, StakeInfoRuntimeApi, SubnetInfoRuntimeApi, +// SubnetRegistrationRuntimeApi, SubtensorCustom, +// }; + +// /// An identifier for an account on this system. +// pub type AccountId = ::Signer; +// /// A simple hash type for all our hashing. +// pub type Hash = H256; +// /// The hashing algorithm used. +// pub type Hashing = BlakeTwo256; +// /// The block number type used in this runtime. +// pub type BlockNumber = u64; +// /// Index of a transaction. +// pub type Nonce = u64; +// /// The item of a block digest. +// pub type DigestItem = sp_runtime::generic::DigestItem; +// /// The digest of a block. +// pub type Digest = sp_runtime::generic::Digest; +// /// A test block. +// pub type Block = sp_runtime::generic::Block; +// /// A test block's header. +// pub type Header = sp_runtime::generic::Header; +// /// Balance of an account. +// pub type Balance = u64; + +// pub struct TestApi {} +// pub struct TestRuntimeApi {} + +// sp_api::mock_impl_runtime_apis! { +// impl DelegateInfoRuntimeApi for TestRuntimeApi { +// #[advanced] +// fn get_delegates(&self, at: Hash) -> Result, sp_api::ApiError> { +// // let result = SubtensorModule::get_delegates(); +// // result.encode() +// Ok(Vec::new()) +// } +// fn get_delegate(&self, delegate_account_vec: Vec) -> Vec { +// unimplemented!() +// } + +// fn get_delegated(&self, delegatee_account_vec: Vec) -> Vec { +// unimplemented!() +// } +// } + +// impl NeuronInfoRuntimeApi for TestRuntimeApi { +// fn get_neurons(netuid: u16) -> Vec { +// unimplemented!() +// } +// fn get_neuron(netuid: u16, uid: u16) -> Vec { +// unimplemented!() +// } +// fn get_neurons_lite(netuid: u16) -> Vec { +// unimplemented!() +// } +// fn get_neuron_lite(netuid: u16, uid: u16) -> Vec { +// unimplemented!() +// } +// } + +// impl StakeInfoRuntimeApi for TestRuntimeApi { +// fn get_stake_info_for_coldkey( coldkey_account_vec: Vec ) -> Vec { +// unimplemented!() +// } +// fn get_stake_info_for_coldkeys( coldkey_account_vecs: Vec> ) -> Vec { +// unimplemented!() +// } +// fn get_subnet_stake_info_for_coldkeys( coldkey_account_vecs: Vec>, netuid: u16 ) -> Vec { +// unimplemented!() +// } +// fn get_total_subnet_stake( netuid: u16 ) -> Vec { +// unimplemented!() +// } +// #[advanced] +// fn get_all_stake_info_for_coldkey(&self, _at: Hash, _coldkey_account_vec: Vec) -> Result, sp_api::ApiError> { + +// // Mock result from pallet as a SubnetStakeInfo with production AccountId +// // let coldkey: T::AccountId = T::AccountId::decode(&mut &coldkey_account_vec[..]) +// // .expect("Failed to decode AccountId"); + +// // let mut result = Vec::<(SubnetStakeInfo, u16, Compact)>::new(); +// // result.push(SubnetStakeInfo{ +// // hotkey: Default::default(), +// // netuid: 1, +// // stake: Compact(1), +// // }); + +// // Mock result from pallet as a tuple with u64 AccountId +// let mut result = Vec::<(u64, u16, Compact)>::new(); +// for i in 0..10 { +// result.push(( +// i, +// i as u16, +// Compact(1), +// )); +// } + +// Ok(result.encode()) +// } +// } + +// impl SubnetRegistrationRuntimeApi for TestRuntimeApi { +// fn get_network_registration_cost() -> u64 { +// unimplemented!() +// } +// } + +// impl SubnetInfoRuntimeApi for TestRuntimeApi { +// fn get_subnet_info(netuid: u16) -> Vec { +// unimplemented!() +// } +// fn get_subnets_info() -> Vec { +// unimplemented!() +// } +// fn get_subnet_hyperparams(netuid: u16) -> Vec { +// unimplemented!() +// } +// } +// } + +// impl ProvideRuntimeApi for TestApi { +// type Api = TestRuntimeApi; + +// fn runtime_api<'a>(&'a self) -> ApiRef<'a, Self::Api> { +// TestRuntimeApi {}.into() +// } +// } +// /// Blockchain database header backend. Does not perform any validation. +// impl HeaderBackend for TestApi { +// fn header( +// &self, +// _id: ::Hash, +// ) -> std::result::Result, sp_blockchain::Error> { +// Ok(None) +// } + +// fn info(&self) -> sc_client_api::blockchain::Info { +// sc_client_api::blockchain::Info { +// best_hash: Default::default(), +// best_number: Zero::zero(), +// finalized_hash: Default::default(), +// finalized_number: Zero::zero(), +// genesis_hash: Default::default(), +// number_leaves: Default::default(), +// finalized_state: None, +// block_gap: None, +// } +// } + +// fn status( +// &self, +// _id: ::Hash, +// ) -> std::result::Result { +// Ok(sc_client_api::blockchain::BlockStatus::Unknown) +// } + +// fn number( +// &self, +// _hash: Block::Hash, +// ) -> std::result::Result>, sp_blockchain::Error> { +// Ok(None) +// } + +// fn hash( +// &self, +// _number: NumberFor, +// ) -> std::result::Result, sp_blockchain::Error> { +// Ok(None) +// } +// } + +// #[tokio::test] +// async fn get_delegates_should_work() { +// let client = Arc::new(TestApi {}); +// let api = SubtensorCustom::new(client); +// let request = api.get_delegates(None); +// let response = request.unwrap(); +// println!("response: {:?}", response); +// } + +// #[tokio::test] +// async fn get_all_stake_info_for_coldkey_should_work() { +// let client = Arc::new(TestApi {}); +// let api = SubtensorCustom::new(client); + +// let magic_address = Vec::from([ +// 0xd2, 0xb7, 0x73, 0x64, 0xd1, 0xc3, 0xb4, 0x45, 0xcd, 0x69, 0xbd, 0x59, 0xf1, 0xa8, 0x7d, +// 0xcb, 0x26, 0xc9, 0xce, 0x3f, 0x46, 0x43, 0x7d, 0x55, 0xb8, 0x8b, 0x43, 0xf1, 0xc1, 0x77, +// 0xe7, 0x76, +// ]); + +// let request = api.get_all_stake_info_for_coldkey(magic_address, None); +// let response = request.unwrap(); +// println!("response: {:?}", response); +// } diff --git a/pallets/subtensor/runtime-api/Cargo.toml b/pallets/subtensor/runtime-api/Cargo.toml index ef3e04947..5d5f9db9d 100644 --- a/pallets/subtensor/runtime-api/Cargo.toml +++ b/pallets/subtensor/runtime-api/Cargo.toml @@ -28,3 +28,4 @@ std = [ "serde/std" ] pow-faucet = [] +subnet-staking = [] \ No newline at end of file diff --git a/pallets/subtensor/runtime-api/src/lib.rs b/pallets/subtensor/runtime-api/src/lib.rs index 9095ad54a..88bef6ca6 100644 --- a/pallets/subtensor/runtime-api/src/lib.rs +++ b/pallets/subtensor/runtime-api/src/lib.rs @@ -1,12 +1,20 @@ #![cfg_attr(not(feature = "std"), no_std)] extern crate alloc; use alloc::vec::Vec; +use pallet_subtensor::types::TensorBytes; // Here we declare the runtime API. It is implemented it the `impl` block in // src/neuron_info.rs, src/subnet_info.rs, and src/delegate_info.rs sp_api::decl_runtime_apis! { pub trait DelegateInfoRuntimeApi { + fn get_substake_for_hotkey( hotkey_bytes: Vec ) -> Vec; + fn get_substake_for_coldkey( coldkey_bytes: Vec ) -> Vec; + fn get_substake_for_netuid( netuid: u16 ) -> Vec; + fn get_total_stake_for_hotkey( hotkey_bytes: Vec ) -> u64; + fn get_total_stake_for_coldkey( coldkey_bytes: Vec ) -> u64; fn get_delegates() -> Vec; + fn get_delegates_by_netuid_light(netuid: u16) -> Vec; + fn get_all_delegates_total_stake() -> Vec; fn get_delegate( delegate_account_vec: Vec ) -> Vec; fn get_delegated( delegatee_account_vec: Vec ) -> Vec; } @@ -22,14 +30,31 @@ sp_api::decl_runtime_apis! { fn get_subnet_info(netuid: u16) -> Vec; fn get_subnets_info() -> Vec; fn get_subnet_hyperparams(netuid: u16) -> Vec; + + fn get_subnet_info_v2(netuid: u16) -> Vec; + fn get_subnets_info_v2() -> Vec; } pub trait StakeInfoRuntimeApi { - fn get_stake_info_for_coldkey( coldkey_account_vec: Vec ) -> Vec; - fn get_stake_info_for_coldkeys( coldkey_account_vecs: Vec> ) -> Vec; + fn get_stake_info_for_coldkey( coldkey_account_vec: TensorBytes ) -> Vec; + fn get_stake_info_for_coldkeys( coldkey_account_vecs: Vec ) -> Vec; + fn get_subnet_stake_info_for_coldkeys( coldkey_account_vecs: Vec, netuid: u16 ) -> Vec; + fn get_subnet_stake_info_for_coldkey( coldkey_account_vec: TensorBytes , netuid: u16) -> Vec; + fn get_total_subnet_stake( netuid: u16 ) -> Vec; + fn get_all_stake_info_for_coldkey( coldkey_account_vec: TensorBytes ) -> Vec; + fn get_all_subnet_stake_info_for_coldkey( coldkey_account_vec: TensorBytes ) -> Vec; + fn get_total_stake_for_each_subnet() -> Vec; } pub trait SubnetRegistrationRuntimeApi { fn get_network_registration_cost() -> u64; } + + pub trait DynamicPoolInfoRuntimeApi { + fn get_dynamic_pool_info(netuid: u16) -> Vec; + fn get_all_dynamic_pool_infos() -> Vec; + + fn get_dynamic_pool_info_v2(netuid: u16) -> Vec; + fn get_all_dynamic_pool_infos_v2() -> Vec; + } } diff --git a/pallets/subtensor/src/benchmarks.rs b/pallets/subtensor/src/benchmarks.rs index a7dd29fbb..3146a65a3 100644 --- a/pallets/subtensor/src/benchmarks.rs +++ b/pallets/subtensor/src/benchmarks.rs @@ -75,33 +75,6 @@ benchmarks! { }: set_weights(RawOrigin::Signed( signer.clone() ), netuid, dests, weights, version_key) - - benchmark_become_delegate { - // This is a whitelisted caller who can make transaction without weights. - let caller: T::AccountId = whitelisted_caller::>(); - let caller_origin = ::RuntimeOrigin::from(RawOrigin::Signed(caller.clone())); - let netuid: u16 = 1; - let version_key: u64 = 1; - let tempo: u16 = 1; - let modality: u16 = 0; - let seed : u32 = 1; - - Subtensor::::init_new_network(netuid, tempo); - Subtensor::::set_burn(netuid, 1); - Subtensor::::set_max_allowed_uids( netuid, 4096 ); - - Subtensor::::set_network_registration_allowed( netuid, true); - assert_eq!(Subtensor::::get_max_allowed_uids(netuid), 4096); - - let coldkey: T::AccountId = account("Test", 0, seed); - let hotkey: T::AccountId = account("Alice", 0, seed); - - let amount_to_be_staked = 1000000000u32.into(); - Subtensor::::add_balance_to_coldkey_account(&coldkey.clone(), amount_to_be_staked); - - assert_ok!(Subtensor::::do_burned_registration(RawOrigin::Signed(coldkey.clone()).into(), netuid, hotkey.clone())); - }: become_delegate(RawOrigin::Signed( coldkey.clone() ), hotkey.clone()) - benchmark_add_stake { let caller: T::AccountId = whitelisted_caller::>(); let caller_origin = ::RuntimeOrigin::from(RawOrigin::Signed(caller.clone())); @@ -142,9 +115,6 @@ benchmarks! { Subtensor::::set_target_stakes_per_interval(100); - // Set our total stake to 1000 TAO - Subtensor::::increase_total_stake(1_000_000_000_000); - Subtensor::::init_new_network(netuid, tempo); Subtensor::::set_network_registration_allowed( netuid, true ); @@ -153,16 +123,15 @@ benchmarks! { let coldkey: T::AccountId = account("Test", 0, seed); let hotkey: T::AccountId = account("Alice", 0, seed); - Subtensor::::set_burn(netuid, 1); + Subtensor::::set_burn(netuid, 1); let wallet_bal = 1000000u32.into(); Subtensor::::add_balance_to_coldkey_account(&coldkey.clone(), wallet_bal); assert_ok!(Subtensor::::do_burned_registration(RawOrigin::Signed(coldkey.clone()).into(), netuid, hotkey.clone())); - assert_ok!(Subtensor::::do_become_delegate(RawOrigin::Signed(coldkey.clone()).into(), hotkey.clone(), Subtensor::::get_default_take())); - // Stake 10% of our current total staked TAO - let u64_staked_amt = 100_000_000_000; + // Stake 10% of our current total staked TAO + let u64_staked_amt = 100_000_000_000; Subtensor::::add_balance_to_coldkey_account(&coldkey.clone(), u64_staked_amt); assert_ok!( Subtensor::::add_stake(RawOrigin::Signed( coldkey.clone() ).into() , hotkey.clone(), u64_staked_amt)); @@ -293,25 +262,27 @@ benchmarks! { let seed : u32 = 1; let coldkey: T::AccountId = account("Test", 0, seed); + let hotkey: T::AccountId = account("Alice", 0, seed); Subtensor::::set_network_rate_limit(1); let amount: u64 = 1; let amount_to_be_staked = 100_000_000_000_000u64; Subtensor::::add_balance_to_coldkey_account(&coldkey.clone(), amount_to_be_staked); - }: register_network(RawOrigin::Signed(coldkey)) + }: register_network(RawOrigin::Signed(coldkey), hotkey) benchmark_dissolve_network { let seed : u32 = 1; let coldkey: T::AccountId = account("Test", 0, seed); + let hotkey: T::AccountId = account("Alice", 0, seed); Subtensor::::set_network_rate_limit(0); let amount: u64 = 1; let amount_to_be_staked = 100_000_000_000_000u64; Subtensor::::add_balance_to_coldkey_account(&coldkey.clone(), amount_to_be_staked); - assert_ok!(Subtensor::::register_network(RawOrigin::Signed(coldkey.clone()).into())); + assert_ok!(Subtensor::::register_network(RawOrigin::Signed(coldkey.clone()).into(), hotkey)); }: dissolve_network(RawOrigin::Signed(coldkey), 1) swap_hotkey { @@ -329,7 +300,6 @@ benchmarks! { Subtensor::::add_balance_to_coldkey_account(&coldkey.clone(), 10_000_000_000u64); assert_ok!(Subtensor::::burned_register(RawOrigin::Signed(coldkey.clone()).into(), netuid, old_hotkey.clone())); - assert_ok!(Subtensor::::become_delegate(RawOrigin::Signed(coldkey.clone()).into(), old_hotkey.clone())); let max_uids = Subtensor::::get_max_allowed_uids(netuid) as u32; for i in 0..max_uids - 1 { diff --git a/pallets/subtensor/src/block_step.rs b/pallets/subtensor/src/block_step.rs index 80733e6b7..05a981087 100644 --- a/pallets/subtensor/src/block_step.rs +++ b/pallets/subtensor/src/block_step.rs @@ -1,9 +1,17 @@ +use crate::types::SubnetType; use super::*; -use frame_support::storage::IterableStorageDoubleMap; -use frame_support::storage::IterableStorageMap; +use sp_core::Get; +use sp_std::vec::Vec; use substrate_fixed::types::I110F18; use substrate_fixed::types::I64F64; -use substrate_fixed::types::I96F32; + +struct SubnetBlockStepInfo { + netuid: u16, + subnet_type: SubnetType, + price: I64F64, + tao_staked: u64, + transition_in_progress: bool, +} impl Pallet { /// Executes the necessary operations for each block. @@ -12,24 +20,118 @@ impl Pallet { log::debug!("block_step for block: {:?} ", block_number); // --- 1. Adjust difficulties. Self::adjust_registration_terms_for_networks(); - // --- 2. Calculate per-subnet emissions - match Self::root_epoch(block_number) { - Ok(_) => (), - Err(e) => { - log::trace!("Error while running root epoch: {:?}", e); - } + // --- 2. Mint and distribute TAO. + Self::run_coinbase(block_number); + // Adjust Tempos every 1000 blocks + if Self::blocks_until_next_epoch(0, 1000, block_number) == 0 { + Self::adjust_tempos(); } - // --- 3. Drains emission tuples ( hotkey, amount ). - Self::drain_emission(block_number); - // --- 4. Generates emission tuples from epoch functions. - Self::generate_emission(block_number); + // Return ok. Ok(()) } - /// Helper function which returns the number of blocks remaining before we will run the epoch on this - /// network. Networks run their epoch when (block_number + netuid + 1 ) % (tempo + 1) = 0 + /// Adjusts the tempo for each network based on their relative prices to ensure operations + /// are performed more frequently on networks with higher prices. + /// + /// This function calculates a value `bi` for each network, which represents the number of blocks + /// that progress before an operation is performed on the network. Networks with higher prices + /// will have operations performed more frequently. The average operation frequency across all + /// networks is aimed to be every `K` blocks. + pub fn adjust_tempos() { + // Retrieve all network UIDs. + let netuids: Vec = Self::get_all_subnet_netuids(); + + // Compute and collect prices for each dynamic subnet, excluding the root subnet. + let mut prices: Vec = Vec::new(); + for netuid in netuids.iter() { + if *netuid == Self::get_root_netuid() || !Self::is_subnet_dynamic(*netuid) { + continue; + } + let price = Self::get_tao_per_alpha_price(*netuid); + prices.push(price); + } + + // Assuming `K` is a predefined constant representing the average desired operation interval in blocks. + let k: I64F64 = I64F64::from_num(10); // Replace 1.0 with the actual value of `K` if available. + + // Calculate tempos using the extracted prices and netuids. + match Self::calculate_tempos(&netuids, k, &prices) { + Ok(tempos) => { + // Set the calculated tempos for each network. + for (netuid, tempo) in tempos.iter() { + Self::set_tempo(*netuid, *tempo); + } + } + Err(e) => { + log::error!("Failed to calculate tempos: {}", e); + } + } + } + + /// Calculates the tempos for each network based on the given prices and a constant `K`. + /// + /// # Arguments + /// * `netuids` - A reference to a vector of network UIDs. + /// * `k` - The constant representing the average desired operation interval in blocks. + /// * `prices` - A reference to a vector of prices for each network. /// + /// # Returns + /// * A result containing either a vector of tuples where each tuple contains a network UID and its corresponding tempo, or an error string if there's a mismatch in vector sizes or other issues. + pub fn calculate_tempos( + netuids: &[u16], + k: I64F64, + prices: &[I64F64], + ) -> Result, &'static str> { + // Check for mismatched vector sizes + if netuids.len() != prices.len() { + return Err("Mismatched vector sizes: netuids and prices must have the same length."); + } + + // Check for empty vectors + if netuids.is_empty() || prices.is_empty() { + return Ok(Vec::new()); + } + + // Calculate total price to find relative frequencies + let total_price: I64F64 = prices.iter().sum(); + if total_price == I64F64::from_num(0.0) { + return Ok(netuids.iter().map(|&uid| (uid, 0)).collect()); // If sum of prices is zero, return zero tempos + } + + // Calculate relative frequencies based on prices + let relative_frequencies: Vec = prices + .iter() + .map(|&price| price / total_price) // relative frequency = price_i / total_price + .collect(); + + // Calculate total relative frequency to normalize it to K + let total_relative_frequency: I64F64 = relative_frequencies.iter().sum(); + let normalization_factor: I64F64 = k / total_relative_frequency; + + // Calculate tempos based on normalized relative frequencies + let min_tempo = T::MinTempo::get(); + let max_tempo = T::MaxTempo::get(); + let tempos: Vec<(u16, u16)> = netuids + .iter() + .zip(relative_frequencies.iter()) + .map(|(&uid, &rel_freq)| { + let mut tempo = (normalization_factor / rel_freq).to_num::(); + if tempo < min_tempo { + tempo = min_tempo; + } + if tempo > max_tempo { + tempo = max_tempo; + } + (uid, tempo) + }) + .collect(); + + Ok(tempos) + } + // Helper function which returns the number of blocks remaining before we will run the epoch on this + // network. Networks run their epoch when (block_number + netuid + 1 ) % (tempo + 1) = 0 + // pub fn blocks_until_next_epoch(netuid: u16, tempo: u16, block_number: u64) -> u64 { // tempo | netuid | # first epoch block // 1 0 0 @@ -45,260 +147,316 @@ impl Pallet { tempo as u64 - (block_number + netuid as u64 + 1) % (tempo as u64 + 1) } - /// Helper function returns the number of tuples to drain on a particular step based on - /// the remaining tuples to sink and the block number - /// - pub fn tuples_to_drain_this_block( - netuid: u16, - tempo: u16, - block_number: u64, - n_remaining: usize, - ) -> usize { - let blocks_until_epoch: u64 = Self::blocks_until_next_epoch(netuid, tempo, block_number); - if blocks_until_epoch / 2 == 0 { - return n_remaining; - } // drain all. - if tempo / 2 == 0 { - return n_remaining; - } // drain all - if n_remaining == 0 { - return 0; - } // nothing to drain at all. - // Else return enough tuples to drain all within half the epoch length. - let to_sink_via_tempo: usize = n_remaining / (tempo as usize / 2); - let to_sink_via_blocks_until_epoch: usize = n_remaining / (blocks_until_epoch as usize / 2); - if to_sink_via_tempo > to_sink_via_blocks_until_epoch { - to_sink_via_tempo - } else { - to_sink_via_blocks_until_epoch + pub fn get_subnet_type(netuid: u16) -> SubnetType { + if Self::is_subnet_dynamic(netuid) { + SubnetType::DTAO + } else { + SubnetType::STAO } } - pub fn get_loaded_emission_tuples(netuid: u16) -> Option> { - LoadedEmission::::get(netuid) - } - - /// Reads from the loaded emission storage which contains lists of pending emission tuples ( hotkey, amount ) - /// and distributes small chunks of them at a time. - /// - pub fn drain_emission(_: u64) { - // --- 1. We iterate across each network. - for (netuid, _) in as IterableStorageMap>::iter() { - let Some(tuples_to_drain) = Self::get_loaded_emission_tuples(netuid) else { - // There are no tuples to emit. - continue; - }; - let mut total_emitted: u64 = 0; - for (hotkey, server_amount, validator_amount) in tuples_to_drain.iter() { - Self::emit_inflation_through_hotkey_account( - hotkey, - *server_amount, - *validator_amount, - ); - total_emitted += *server_amount + *validator_amount; + fn get_subnets() -> Vec { + // Get all the network uids. + Self::get_all_subnet_netuids().iter().map(|&netuid| { + let dynamic = Self::is_subnet_dynamic(netuid); + SubnetBlockStepInfo { + netuid, + subnet_type: Self::get_subnet_type(netuid), + price: { + if netuid == Self::get_root_netuid() || !dynamic { + I64F64::from_num(0.0) + } else { + Self::get_tao_per_alpha_price(netuid) + } + }, + tao_staked: TotalSubnetTAO::::get(netuid), + // TODOSDT: Only consider current subnet, not all (see commented below) + transition_in_progress: SubnetInTransition::::iter().next().is_some(), + // transition_in_progress: SubnetInTransition::::get(netuid).is_some(), } - LoadedEmission::::remove(netuid); - TotalIssuance::::put(TotalIssuance::::get().saturating_add(total_emitted)); - } + }).collect() } - /// Iterates through networks queues more emission onto their pending storage. - /// If a network has no blocks left until tempo, we run the epoch function and generate - /// more token emission tuples for later draining onto accounts. + /// Calculates price threshold for alpha vs. TAO emissions for DTAO /// - pub fn generate_emission(block_number: u64) { - // --- 1. Iterate across each network and add pending emission into stash. - for (netuid, tempo) in as IterableStorageMap>::iter() { - // Skip the root network or subnets with registrations turned off - if netuid == Self::get_root_netuid() || !Self::is_registration_allowed(netuid) { - // Root emission or subnet emission is burned - continue; - } - - // --- 2. Queue the emission due to this network. - let new_queued_emission: u64 = Self::get_subnet_emission_value(netuid); - log::debug!( - "generate_emission for netuid: {:?} with tempo: {:?} and emission: {:?}", - netuid, - tempo, - new_queued_emission, - ); + fn get_emission_price_threshold(subnets: &Vec, total_tao_staked: u64) -> I64F64 { + // Total TAO staked in DTAO subnets + let dtao_tao: u64 = subnets.iter() + .filter(|subnet| subnet.subnet_type == SubnetType::DTAO) + .map(|subnet_info| subnet_info.tao_staked).sum(); - let subnet_has_owner = SubnetOwner::::contains_key(netuid); - let mut remaining = I96F32::from_num(new_queued_emission); - if subnet_has_owner { - let cut = remaining - .saturating_mul(I96F32::from_num(Self::get_subnet_owner_cut())) - .saturating_div(I96F32::from_num(u16::MAX)); + I64F64::from_num(dtao_tao) / I64F64::from_num(total_tao_staked) + } - remaining = remaining.saturating_sub(cut); + pub fn run_coinbase(block_number: u64) { + // Compute and fill the prices from all subnets. + let mut subnets = Self::get_subnets(); + let total_prices: I64F64 = subnets.iter().map(|subnet_info| subnet_info.price).sum(); + + // Compute total TAO staked across all subnets + let total_tao_staked: u64 = subnets.iter() + .filter(|subnet| subnet.netuid != Self::get_root_netuid()) + .map(|subnet_info| subnet_info.tao_staked).sum(); + + // Compute emission per subnet as [p.tao_in/sum_tao for p in pools] + let total_block_emission = Self::get_block_emission().unwrap_or(0); + let total_block_emission_i64f64: I64F64 = I64F64::from_num(total_block_emission); + let mut actual_total_block_emission = 0u64; + + if total_tao_staked != 0 { + // Calculate price threshold for alpha vs. TAO emissions for DTAO + let dtao_tao_fraction: I64F64 = Self::get_emission_price_threshold(&subnets, total_tao_staked); + + subnets.iter_mut().for_each(|subnet_info| { + if !subnet_info.transition_in_progress { + let subnet_proportion: I64F64 = if subnet_info.netuid == Self::get_root_netuid() { + I64F64::from_num(0) + } else { + I64F64::from_num(subnet_info.tao_staked) / I64F64::from_num(total_tao_staked) + }; + let emission_i64f64 = total_block_emission_i64f64 * subnet_proportion; + let subnet_block_emission = emission_i64f64.to_num(); + EmissionValues::::insert(subnet_info.netuid, subnet_block_emission); + // Increment the amount of TAO that is waiting to be distributed through Yuma Consensus. + PendingEmission::::mutate(subnet_info.netuid, |emission| *emission += subnet_block_emission); + + match subnet_info.subnet_type { + SubnetType::DTAO => { + // Condition the inflation of TAO and alpha based on the sum of the prices. + // This keeps the market caps of ALPHA subsumed by TAO. + let tao_in: u64; // The total amount of TAO emitted this block into all pools. + let alpha_in: u64; // The amount of ALPHA emitted this block into each pool. + + if total_prices <= dtao_tao_fraction { + // Alpha prices are lower than 1.0, emit TAO and not ALPHA into the pools. + tao_in = subnet_block_emission; + alpha_in = 0; + } else { + // Alpha prices are greater than 1.0, emit ALPHA and not TAO into the pools. + tao_in = 0; + alpha_in = total_block_emission; + } + + if tao_in > 0 { + // Increment total TAO on subnet + TotalSubnetTAO::::mutate(subnet_info.netuid, |stake| *stake = stake.saturating_add(tao_in)); + + // Increment the pools tao reserve based on the block emission. + DynamicTAOReserve::::mutate(subnet_info.netuid, |reserve| *reserve += tao_in); + + actual_total_block_emission = actual_total_block_emission.saturating_add(tao_in); + } + + if alpha_in > 0 { + // Increment the pools alpha reserve based on the alpha in emission. + DynamicAlphaReserve::::mutate(subnet_info.netuid, |reserve| *reserve += alpha_in); + + // Increment the total supply of alpha because we just added some to the reserve. + DynamicAlphaIssuance::::mutate(subnet_info.netuid, |issuance| *issuance += alpha_in); + } + + // Recalculate the Dynamic K value for the new pool. + DynamicK::::insert( + subnet_info.netuid, + (DynamicTAOReserve::::get(subnet_info.netuid) as u128) + * (DynamicAlphaReserve::::get(subnet_info.netuid) as u128), + ); + }, + SubnetType::STAO => { + if subnet_block_emission != 0 { + TotalSubnetTAO::::mutate(subnet_info.netuid, |stake| *stake = stake.saturating_add(subnet_block_emission)); + actual_total_block_emission = actual_total_block_emission.saturating_add(subnet_block_emission); + } + } + } + } + }); - Self::add_balance_to_coldkey_account( - &Self::get_subnet_owner(netuid), - cut.to_num::(), - ); + // Increment the total amount of TAO in existence based on the total tao_in + TotalIssuance::::mutate(|issuance| *issuance = issuance.saturating_add(actual_total_block_emission)); + } + + //////////////////////////////// + // run epochs. + subnets.iter_mut().for_each(|subnet_info| { + // Check to see if this network has reached tempo. + let tempo: u16 = Self::get_tempo(subnet_info.netuid); + if Self::blocks_until_next_epoch(subnet_info.netuid, tempo, block_number) == 0 { + // Get the pending emission issuance to distribute for this subnet + let emission = PendingEmission::::get(subnet_info.netuid); + // Drain pending emission and update dynamic pools + PendingEmission::::insert(subnet_info.netuid, 0); + + // Run the epoch mechanism and return emission tuples for hotkeys in the network in alpha. + let emission_tuples: Vec<(T::AccountId, u64, u64)> = if T::EpochConfig::simple_epoch() { + Self::fake_epoch(subnet_info.netuid, emission) + } else { + Self::epoch(subnet_info.netuid, emission) + }; + + // Emit the tuples through the hotkeys incrementing their alpha staking balance for this subnet + // as well as all nominators. + for (hotkey, server_amount, validator_amount) in emission_tuples.iter() { + Self::emit_inflation_through_hotkey_account( + hotkey, + subnet_info.netuid, + *server_amount, + *validator_amount, + ); + } - // We are creating tokens here from the coinbase. - Self::coinbase(cut.to_num::()); - } - // --- 5. Add remaining amount to the network's pending emission. - PendingEmission::::mutate(netuid, |queued| *queued += remaining.to_num::()); - log::debug!( - "netuid_i: {:?} queued_emission: +{:?} ", - netuid, - new_queued_emission - ); + // Increase subnet totals + match subnet_info.subnet_type { + SubnetType::DTAO => { + // Increment the total amount of alpha outstanding (the amount on all of the staking accounts) + DynamicAlphaOutstanding::::mutate(subnet_info.netuid, |reserve| *reserve += emission); + // Also increment the total amount of alpha in total everywhere. + DynamicAlphaIssuance::::mutate(subnet_info.netuid, |issuance| *issuance += emission); + }, + SubnetType::STAO => {}, + } - // --- 6. Check to see if this network has reached tempo. - if Self::blocks_until_next_epoch(netuid, tempo, block_number) != 0 { - // --- 3.1 No epoch, increase blocks since last step and continue, + // Some other counters for accounting. + Self::set_blocks_since_last_step(subnet_info.netuid, 0); + Self::set_last_mechanism_step_block(subnet_info.netuid, block_number); + } else { Self::set_blocks_since_last_step( - netuid, - Self::get_blocks_since_last_step(netuid) + 1, + subnet_info.netuid, + Self::get_blocks_since_last_step(subnet_info.netuid) + 1, ); - continue; - } - - // --- 7 This network is at tempo and we are running its epoch. - // First drain the queued emission. - let emission_to_drain: u64 = PendingEmission::::get(netuid); - PendingEmission::::insert(netuid, 0); - - // --- 8. Run the epoch mechanism and return emission tuples for hotkeys in the network. - let emission_tuples_this_block: Vec<(T::AccountId, u64, u64)> = - Self::epoch(netuid, emission_to_drain); - log::debug!( - "netuid_i: {:?} emission_to_drain: {:?} ", - netuid, - emission_to_drain - ); - - // --- 9. Check that the emission does not exceed the allowed total. - let emission_sum: u128 = emission_tuples_this_block - .iter() - .map(|(_account_id, ve, se)| *ve as u128 + *se as u128) - .sum(); - if emission_sum > emission_to_drain as u128 { - continue; - } // Saftey check. - - // --- 10. Sink the emission tuples onto the already loaded. - let mut concat_emission_tuples: Vec<(T::AccountId, u64, u64)> = - emission_tuples_this_block.clone(); - if let Some(mut current_emission_tuples) = Self::get_loaded_emission_tuples(netuid) { - // 10.a We already have loaded emission tuples, so we concat the new ones. - concat_emission_tuples.append(&mut current_emission_tuples); } - LoadedEmission::::insert(netuid, concat_emission_tuples); - - // --- 11 Set counters. - Self::set_blocks_since_last_step(netuid, 0); - Self::set_last_mechanism_step_block(netuid, block_number); - } + }); } - /// Distributes token inflation through the hotkey based on emission. The call ensures that the inflation - /// is distributed onto the accounts in proportion of the stake delegated minus the take. This function - /// is called after an epoch to distribute the newly minted stake according to delegation. - /// + + // Distributes token inflation through the hotkey based on emission. The call ensures that the inflation + // is distributed onto the accounts in proportion of the stake delegated minus the take. This function + // is called after an epoch to distribute the newly minted stake according to delegation. + // + // Algorithm: + // 0. Hotkey always receives server_emission completely (which gets unstaked and removed from TotalSubnetTAO). + // 1. Delegate gets it's take, i.e. a percentage of validator_emission specific to a given subnet (netuid) + // + // remaining_validator_emission is what's left. Here is how it's distributed: + // + // 2. If either delegate_local_stake (total amount of stake under a hotkey for a subnet) or + // delegate_global_dynamic_tao (total delegate stake * alpha_price) are non-zero, then + // for each nominator nominating this delegate do: + // 3.a Nominator reward comes in two parts: Local and Global + // Local = (1 - global_stake_weight) * remaining_validator_emission + // (nominator Alpha in this subnet for hotkey) / (sum of all Alpha in this subnet for hotkey) + // Global = global_stake_weight * remaining_validator_emission * (sum of nominator stake across all subnets) / + // (sum of everybody's stake across all subnets) + // Global Stake Weight effectively is always 1 currently, so there is no local emission, but no matter what's + // the ratio is set in the future, the sum of all rewards is always going to be remaining_validator_emission. + // + // Questions/Comments: + // 1. Can tao_per_alpha_price be zero if get_total_stake_for_hotkey_and_subnet is non-zero? + // 2. TODO: Add tests for how DynamicTAOReserve and DynamicAlphaReserve are affected by staking operations + // 3. Is it theoretically possible that lock cost gets up to about 18M TAO for a single network? Will + // it not overflow initial_dynamic_reserve? + // 4. Should residual after step 3 be non-zero in any case? + // 5. This algorithm re-purposes TotalHotkeySubStake and SubStake state variables to store Alpha (vs. TAO). + // pub fn emit_inflation_through_hotkey_account( - hotkey: &T::AccountId, + delegate: &T::AccountId, + netuid: u16, server_emission: u64, validator_emission: u64, ) { - // --- 1. Check if the hotkey is a delegate. If not, we simply pass the stake through to the - // coldkey - hotkey account as normal. - if !Self::hotkey_is_delegate(hotkey) { - Self::increase_stake_on_hotkey_account(hotkey, server_emission + validator_emission); - return; - } - // Then this is a delegate, we distribute validator_emission, then server_emission. - - // --- 2. The hotkey is a delegate. We first distribute a proportion of the validator_emission to the hotkey - // directly as a function of its 'take' - let total_hotkey_stake: u64 = Self::get_total_stake_for_hotkey(hotkey); - let delegate_take: u64 = - Self::calculate_delegate_proportional_take(hotkey, validator_emission); - let validator_emission_minus_take: u64 = validator_emission - delegate_take; - let mut remaining_validator_emission: u64 = validator_emission_minus_take; - - // 3. -- The remaining emission goes to the owners in proportion to the stake delegated. - for (owning_coldkey_i, stake_i) in - as IterableStorageDoubleMap>::iter_prefix( - hotkey, - ) - { - // --- 4. The emission proportion is remaining_emission * ( stake / total_stake ). - let stake_proportion: u64 = Self::calculate_stake_proportional_emission( - stake_i, - total_hotkey_stake, - validator_emission_minus_take, - ); - Self::increase_stake_on_coldkey_hotkey_account( - &owning_coldkey_i, - hotkey, - stake_proportion, - ); - log::debug!( - "owning_coldkey_i: {:?} hotkey: {:?} emission: +{:?} ", - owning_coldkey_i, - hotkey, - stake_proportion - ); - remaining_validator_emission -= stake_proportion; - } - - // --- 5. Last increase final account balance of delegate after 4, since 5 will change the stake proportion of - // the delegate and effect calculation in 4. - Self::increase_stake_on_hotkey_account( - hotkey, - delegate_take + remaining_validator_emission, + // 1. Else the key is a delegate, first compute the delegate take from the emission. + let take_proportion: I64F64 = I64F64::from_num(DelegatesTake::::get(delegate, netuid)) + / I64F64::from_num(u16::MAX); + let delegate_take: I64F64 = take_proportion * I64F64::from_num(validator_emission); + let delegate_take_u64: u64 = delegate_take.to_num::(); + let remaining_validator_emission: u64 = validator_emission - delegate_take_u64; + let mut residual: u64 = remaining_validator_emission; + + // 3. For each nominator compute its proportion of stake weight and distribute the remaining emission to them. + let global_stake_weight: I64F64 = Self::get_global_stake_weight_float(); + let delegate_local_stake: u64 = + Self::get_total_stake_for_hotkey_and_subnet(delegate, netuid); + let delegate_global_dynamic_tao = Self::get_hotkey_global_dynamic_tao(delegate); + log::debug!( + "global_stake_weight: {:?}, delegate_local_stake: {:?}, delegate_global_stake: {:?}", + global_stake_weight, + delegate_local_stake, + delegate_global_dynamic_tao ); - log::debug!("delkey: {:?} delegate_take: +{:?} ", hotkey, delegate_take); - // Also emit the server_emission to the hotkey - // The server emission is distributed in-full to the delegate owner. - // We do this after 4. for the same reason as above. - Self::increase_stake_on_hotkey_account(hotkey, server_emission); - } - /// Increases the stake on the cold - hot pairing by increment while also incrementing other counters. - /// This function should be called rather than set_stake under account. - /// - pub fn block_step_increase_stake_on_coldkey_hotkey_account( - coldkey: &T::AccountId, - hotkey: &T::AccountId, - increment: u64, - ) { - TotalColdkeyStake::::mutate(coldkey, |old| old.saturating_add(increment)); - TotalHotkeyStake::::insert( - hotkey, - TotalHotkeyStake::::get(hotkey).saturating_add(increment), - ); - Stake::::insert( - hotkey, - coldkey, - Stake::::get(hotkey, coldkey).saturating_add(increment), - ); - TotalStake::::put(TotalStake::::get().saturating_add(increment)); - } + if delegate_local_stake + delegate_global_dynamic_tao != 0 { + Staker::::iter_prefix(delegate) + .for_each(|(nominator_i, _)| { + // 3.a Compute the stake weight percentage for the nominatore weight. + let nominator_local_stake: u64 = Self::get_subnet_stake_for_coldkey_and_hotkey( + &nominator_i, + delegate, + netuid, + ); + let nominator_local_emission_i: I64F64 = if delegate_local_stake == 0 { + I64F64::from_num(0) + } else { + let nominator_local_percentage: I64F64 = + I64F64::from_num(nominator_local_stake) + / I64F64::from_num(delegate_local_stake); + nominator_local_percentage + * I64F64::from_num(remaining_validator_emission) + * (I64F64::from_num(1.0) - global_stake_weight) + }; + log::debug!( + "nominator_local_emission_i: {:?}", + nominator_local_emission_i + ); + + let nominator_global_stake: u64 = + Self::get_nominator_global_dynamic_tao(&nominator_i, delegate); // Get global stake. + let nominator_global_emission_i: I64F64 = if delegate_global_dynamic_tao == 0 { + I64F64::from_num(0) + } else { + let nominator_global_percentage: I64F64 = + I64F64::from_num(nominator_global_stake) + / I64F64::from_num(delegate_global_dynamic_tao); + nominator_global_percentage + * I64F64::from_num(remaining_validator_emission) + * global_stake_weight + }; + log::debug!( + "nominator_global_emission_i: {:?}", + nominator_global_emission_i + ); + let nominator_emission_u64: u64 = + (nominator_global_emission_i + nominator_local_emission_i).to_num::(); + + // 3.b Increase the stake of the nominator. + log::debug!( + "nominator: {:?}, global_emission: {:?}, local_emission: {:?}", + nominator_i, + nominator_global_emission_i, + nominator_local_emission_i + ); + residual -= nominator_emission_u64; + Self::increase_subnet_token_on_coldkey_hotkey_account( + &nominator_i, + delegate, + netuid, + nominator_emission_u64, + ); + }); + } - /// Decreases the stake on the cold - hot pairing by the decrement while decreasing other counters. - /// - pub fn block_step_decrease_stake_on_coldkey_hotkey_account( - coldkey: &T::AccountId, - hotkey: &T::AccountId, - decrement: u64, - ) { - TotalColdkeyStake::::mutate(coldkey, |old| old.saturating_sub(decrement)); - TotalHotkeyStake::::insert( - hotkey, - TotalHotkeyStake::::get(hotkey).saturating_sub(decrement), + // --- 4. Last increase final account balance of delegate after 4, since 5 will change the stake proportion of + // the delegate and effect calculation in 4. + let total_delegate_emission: u64 = delegate_take_u64 + residual; + log::debug!( + "total_delegate_emission: {:?}", + delegate_take_u64 + server_emission ); - Stake::::insert( - hotkey, - coldkey, - Stake::::get(hotkey, coldkey).saturating_sub(decrement), + Self::increase_subnet_token_on_hotkey_account(delegate, netuid, total_delegate_emission); + let coldkey: T::AccountId = Self::get_owning_coldkey_for_hotkey(delegate); + let tao_server_emission: u64 = Self::compute_dynamic_unstake(netuid, server_emission); + Self::add_balance_to_coldkey_account( + &coldkey, + tao_server_emission, ); - TotalStake::::put(TotalStake::::get().saturating_sub(decrement)); } /// Returns emission awarded to a hotkey as a function of its proportion of the total stake. @@ -316,17 +474,17 @@ impl Pallet { proportional_emission.to_num::() } - /// Returns the delegated stake 'take' assigned to this key. (If exists, otherwise 0) - /// - pub fn calculate_delegate_proportional_take(hotkey: &T::AccountId, emission: u64) -> u64 { - if Self::hotkey_is_delegate(hotkey) { - let take_proportion: I64F64 = - I64F64::from_num(Delegates::::get(hotkey)) / I64F64::from_num(u16::MAX); - let take_emission: I64F64 = take_proportion * I64F64::from_num(emission); - take_emission.to_num::() - } else { - 0 - } + // Returns the delegated stake 'take' assigned to this key. (If exists, otherwise 0) + // + pub fn calculate_delegate_proportional_take( + hotkey: &T::AccountId, + netuid: u16, + emission: u64, + ) -> u64 { + let take_proportion: I64F64 = I64F64::from_num(DelegatesTake::::get(hotkey, netuid)) + / I64F64::from_num(u16::MAX); + let take_emission: I64F64 = take_proportion * I64F64::from_num(emission); + take_emission.to_num::() } /// Adjusts the network difficulties/burns of every active network. Resetting state parameters. @@ -335,7 +493,7 @@ impl Pallet { log::debug!("adjust_registration_terms_for_networks"); // --- 1. Iterate through each network. - for (netuid, _) in as IterableStorageMap>::iter() { + for (netuid, _) in NetworksAdded::::iter() { // --- 2. Pull counters for network difficulty. let last_adjustment_block: u64 = Self::get_last_adjustment_block(netuid); let adjustment_interval: u16 = Self::get_adjustment_interval(netuid); diff --git a/pallets/subtensor/src/delegate_info.rs b/pallets/subtensor/src/delegate_info.rs index b33415a3b..8de934265 100644 --- a/pallets/subtensor/src/delegate_info.rs +++ b/pallets/subtensor/src/delegate_info.rs @@ -1,16 +1,17 @@ use super::*; +use alloc::collections::BTreeMap; +use codec::Compact; use frame_support::pallet_prelude::{Decode, Encode}; -use frame_support::storage::IterableStorageMap; -use frame_support::IterableStorageDoubleMap; +use sp_core::{hexdisplay::AsBytesRef, Get}; use substrate_fixed::types::U64F64; +use sp_std::vec::Vec; + extern crate alloc; -use codec::Compact; -use sp_core::hexdisplay::AsBytesRef; #[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)] pub struct DelegateInfo { delegate_ss58: T::AccountId, - take: Compact, + take: Vec<(Compact, Compact)>, nominators: Vec<(T::AccountId, Compact)>, // map of nominator_ss58 to stake amount owner_ss58: T::AccountId, registrations: Vec>, // Vec of netuid this delegate is registered on @@ -19,28 +20,184 @@ pub struct DelegateInfo { total_daily_return: Compact, // Delegators current daily return } +#[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)] +pub struct DelegateInfoLight { + delegate_ss58: T::AccountId, + owner_ss58: T::AccountId, + take: u16, // take as number if it is default for all subnets or u16::MAX if it is custom + owner_stake: Compact, + total_stake: Compact, +} + +#[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)] +pub struct SubStakeElement { + hotkey: T::AccountId, + coldkey: T::AccountId, + netuid: Compact, + stake: Compact, +} + impl Pallet { - fn get_delegate_by_existing_account(delegate: AccountIdOf) -> DelegateInfo { - let mut nominators = Vec::<(T::AccountId, Compact)>::new(); - - for (nominator, stake) in - as IterableStorageDoubleMap>::iter_prefix( - delegate.clone(), - ) - { - if stake == 0 { - continue; - } - // Only add nominators with stake - nominators.push((nominator.clone(), stake.into())); + /// Returns all `SubStakeElement` instances associated with a given hotkey. + /// + /// This function takes a hotkey's bytes representation, decodes it to the `AccountId` type, + /// and then iterates through all the coldkeys that have staked on this hotkey across all + /// subnetworks (netuids). For each coldkey, it retrieves the stake amount and constructs + /// a `SubStakeElement` instance which is then added to the response vector. + /// + /// # Arguments + /// + /// * `hotkey_bytes` - A byte vector representing the hotkey for which to retrieve the `SubStakeElement` instances. + /// + /// # Returns + /// + /// A vector of `SubStakeElement` instances representing all the stakes associated with the given hotkey. + /// + /// # Panics + /// + /// This function will panic if the hotkey cannot be decoded into an `AccountId`. + /// + pub fn get_substake_for_hotkey(hotkey_bytes: Vec) -> Vec> { + if hotkey_bytes.len() != 32 { + return Vec::new(); } + let hotkey: AccountIdOf = + T::AccountId::decode(&mut hotkey_bytes.as_bytes_ref()).unwrap(); + let coldkey = Self::get_owning_coldkey_for_hotkey(&hotkey); + + SubStake::::iter_prefix((&coldkey, &hotkey)) + .map(|(netuid, stake)| { + SubStakeElement { + hotkey: hotkey.clone(), + coldkey: coldkey.clone(), + netuid: Compact(netuid), + stake: Compact(stake), + } + }).collect() + } + + /// Returns all `SubStakeElement` instances associated with a given coldkey. + /// + /// This function takes a coldkey's bytes representation, decodes it to the `AccountId` type, + /// and then iterates through all the hotkeys that have staked on this coldkey across all + /// subnetworks (netuids). For each hotkey, it retrieves the stake amount and constructs + /// a `SubStakeElement` instance which is then added to the response vector. + /// + /// # Arguments + /// + /// * `coldkey_bytes` - A byte vector representing the coldkey for which to retrieve the `SubStakeElement` instances. + /// + /// # Returns + /// + /// A vector of `SubStakeElement` instances representing all the stakes associated with the given coldkey. + /// + /// # Panics + /// + /// This function will panic if the coldkey cannot be decoded into an `AccountId`. + /// + pub fn get_substake_for_coldkey(coldkey_bytes: Vec) -> Vec> { + if coldkey_bytes.len() != 32 { + return Vec::new(); + } + let coldkey: AccountIdOf = + T::AccountId::decode(&mut coldkey_bytes.as_slice()).expect("Coldkey decoding failed"); + SubStake::::iter_prefix((&coldkey,)).map(|((hotkey, nid), stake)|{ + SubStakeElement { + hotkey, + coldkey: coldkey.clone(), + netuid: Compact(nid), + stake: Compact(stake), + } + }).collect() + } + + /// Returns all `SubStakeElement` instances associated with a given netuid. + /// + /// This function iterates through all the stakes in the `SubStake` storage, filtering + /// those that match the provided netuid. For each matching stake, it constructs a + /// `SubStakeElement` instance and adds it to the response vector. + /// + /// # Arguments + /// + /// * `netuid` - A 16-bit unsigned integer representing the netuid for which to retrieve the `SubStakeElement` instances. + /// + /// # Returns + /// + /// A vector of `SubStakeElement` instances representing all the stakes associated with the given netuid. + /// + pub fn get_substake_for_netuid(netuid: u16) -> Vec> { + SubStake::::iter().filter(|((_, _, nid), stake)| { + *nid == netuid && *stake != 0 + }).map(|((coldkey, hotkey, nid), stake)|{ + SubStakeElement { + hotkey, + coldkey, + netuid: Compact(nid), + stake: Compact(stake), + } + }).collect() + } + + /// Returns Global Dynamic TAO balance for a hotkey. + /// + /// This function retrieves GDT of a hotkey. + /// + /// # Arguments + /// + /// * `hotkey_bytes` - A byte vector representing the hotkey for which to retrieve the `SubStakeElement` instances. + /// + /// # Returns + /// + /// u64 representing the GDT of the hotkey + /// + pub fn get_total_stake_for_hotkey(hotkey_bytes: Vec) -> u64 { + let account_id: AccountIdOf = + T::AccountId::decode(&mut hotkey_bytes.as_slice()).expect("Hotkey decoding failed"); + Self::get_hotkey_global_dynamic_tao(&account_id) + } + + /// Returns Global Dynamic TAO balance for a coldkey. + /// + /// This function iterates through all hotkeys associated with the coldkey and adds + /// GDT for each hotkey to the result + /// + /// # Arguments + /// + /// * `coldkey_bytes` - A byte vector representing the hotkey for which to retrieve the `SubStakeElement` instances. + /// + /// # Returns + /// + /// u64 representing the GDT of the coldkey + /// + pub fn get_total_stake_for_coldkey(coldkey_bytes: Vec) -> u64 { + let account_id: AccountIdOf = + T::AccountId::decode(&mut coldkey_bytes.as_slice()).expect("Coldkey decoding failed"); - let registrations = Self::get_registered_networks_for_hotkey(&delegate.clone()); + // O(1) complexity on number of coldkeys in storage + SubStake::::iter_prefix((account_id,)).map(|((_hotkey, netuid), stake)| { + Self::estimate_dynamic_unstake(netuid, stake) + }).sum() + } + + fn get_delegate_by_existing_account(delegate: &AccountIdOf) -> DelegateInfo { + let all_netuids: Vec = Self::get_all_subnet_netuids(); + let nominators = + Staker::::iter_key_prefix(delegate).map(|nominator| { + let mut total_staked_to_delegate_i: u64 = 0; + for netuid_i in all_netuids.iter() { + total_staked_to_delegate_i += + Self::get_subnet_stake_for_coldkey_and_hotkey(&nominator, delegate, *netuid_i); + } + (nominator, total_staked_to_delegate_i) + }).filter(|(_nominator, total_staked_to_delegate)| *total_staked_to_delegate != 0) + .map(|(nominator, total_staked_to_delegate_i)| (nominator, Compact(total_staked_to_delegate_i))) + .collect(); + let registrations = Self::get_registered_networks_for_hotkey(delegate); let mut validator_permits = Vec::>::new(); let mut emissions_per_day: U64F64 = U64F64::from_num(0); for netuid in registrations.iter() { - let _uid = Self::get_uid_for_net_and_hotkey(*netuid, &delegate.clone()); + let _uid = Self::get_uid_for_net_and_hotkey(*netuid, delegate); if _uid.is_err() { continue; // this should never happen } else { @@ -57,10 +214,26 @@ impl Pallet { } } - let owner = Self::get_owning_coldkey_for_hotkey(&delegate.clone()); - let take: Compact = >::get(delegate.clone()).into(); + let owner = Self::get_owning_coldkey_for_hotkey(delegate); - let total_stake: U64F64 = Self::get_total_stake_for_hotkey(&delegate.clone()).into(); + // Create a vector of tuples (netuid, take). If a take is not set in DelegatesTake, use default value + let take = NetworksAdded::::iter() + .filter(|(_, added)| *added) + .map(|(netuid, _)| { + ( + Compact(netuid), + Compact( + if let Ok(take) = DelegatesTake::::try_get(delegate, netuid) { + take + } else { + >::get() + }, + ), + ) + }) + .collect(); + + let total_stake: U64F64 = Self::get_hotkey_global_dynamic_tao(delegate).into(); let mut return_per_1000: U64F64 = U64F64::from_num(0); @@ -69,7 +242,7 @@ impl Pallet { / (total_stake / U64F64::from_num(1000)); } - return DelegateInfo { + DelegateInfo { delegate_ss58: delegate.clone(), take, nominators, @@ -78,9 +251,23 @@ impl Pallet { validator_permits, return_per_1000: U64F64::to_num::(return_per_1000).into(), total_daily_return: U64F64::to_num::(emissions_per_day).into(), - }; + } } + fn get_delegate_by_existing_account_light_by_netuid(delegate: &AccountIdOf, netuid: u16) -> DelegateInfoLight { + let owner = Self::get_owning_coldkey_for_hotkey(delegate); + let take = DelegatesTake::::get(delegate, netuid); + let owner_stake: u64 = Self::get_subnet_stake_for_coldkey_and_hotkey(&owner, delegate, netuid); + let total_stake: u64 = Self::get_total_stake_for_hotkey_and_subnet(delegate, netuid); + DelegateInfoLight { + delegate_ss58: delegate.clone(), + owner_ss58: owner, + take, + owner_stake: owner_stake.into(), + total_stake: total_stake.into(), + } + } + pub fn get_delegate(delegate_account_vec: Vec) -> Option> { if delegate_account_vec.len() != 32 { return None; @@ -89,45 +276,72 @@ impl Pallet { let delegate: AccountIdOf = T::AccountId::decode(&mut delegate_account_vec.as_bytes_ref()).ok()?; // Check delegate exists - if !>::contains_key(delegate.clone()) { + if DelegatesTake::::iter_prefix(&delegate).next().is_none() { return None; } - let delegate_info = Self::get_delegate_by_existing_account(delegate.clone()); + let delegate_info = Self::get_delegate_by_existing_account(&delegate); Some(delegate_info) } /// get all delegates info from storage /// pub fn get_delegates() -> Vec> { - let mut delegates = Vec::>::new(); - for delegate in as IterableStorageMap>::iter_keys() { - let delegate_info = Self::get_delegate_by_existing_account(delegate.clone()); - delegates.push(delegate_info); - } + // Get all hotkeys registered on the netuid + Self::get_all_subnet_netuids().iter() + .flat_map(|netuid| { + Uids::::iter_prefix(netuid) + .map(|(delegate, _)| Self::get_delegate_by_existing_account(&delegate)) + }).collect() + } - delegates + /// get all delegates for a subnet + /// + /// * `netuid` - Subnet ID to find all registered delegates + /// + pub fn get_delegates_by_netuid_light(netuid: u16) -> Vec> { + // Get all hotkeys registered on the netuid + Uids::::iter_prefix(netuid) + .map(|(delegate, _)| Self::get_delegate_by_existing_account_light_by_netuid(&delegate, netuid)) + .collect() + } + + /// get all delegates' light info from storage + /// + /// * `netuid` - Subnet ID to find all delegates total stakes for + /// + pub fn get_all_delegates_total_stake() -> Vec<(T::AccountId, Compact)> { + // Get all hotkeys registered on all subnets + Self::get_all_subnet_netuids().iter() + .flat_map(|netuid| { + Uids::::iter_prefix(netuid).map(|(delegate, _)| + (delegate.clone(), Self::get_hotkey_global_dynamic_tao(&delegate).into()) + ) + }).collect() } /// get all delegate info and staked token amount for a given delegatee account /// - pub fn get_delegated(delegatee_account_vec: Vec) -> Vec<(DelegateInfo, Compact)> { - let Ok(delegatee) = T::AccountId::decode(&mut delegatee_account_vec.as_bytes_ref()) else { + /// * `coldkey_account_vec` - Coldkey account to find all delegations made by it + /// + pub fn get_delegated(coldkey_account_vec: Vec) -> Vec<(DelegateInfo, Compact)> { + let Ok(coldkey) = T::AccountId::decode(&mut coldkey_account_vec.as_bytes_ref()) else { return Vec::new(); // No delegates for invalid account }; - let mut delegates: Vec<(DelegateInfo, Compact)> = Vec::new(); - for delegate in as IterableStorageMap>::iter_keys() { - let staked_to_this_delegatee = - Self::get_stake_for_coldkey_and_hotkey(&delegatee.clone(), &delegate.clone()); - if staked_to_this_delegatee == 0 { - continue; // No stake to this delegate - } - // Staked to this delegate, so add to list - let delegate_info = Self::get_delegate_by_existing_account(delegate.clone()); - delegates.push((delegate_info, staked_to_this_delegatee.into())); - } + let mut hotkey_stakes: BTreeMap<::AccountId, u64> = BTreeMap::new(); + SubStake::::iter_prefix((&coldkey,)).for_each(|((hotkey, _), stake)| { + hotkey_stakes.entry(hotkey).and_modify(|s| *s += stake).or_insert(stake); + }); - delegates + hotkey_stakes.iter() + .filter(|(_, &total_staked_to_delegate)| total_staked_to_delegate != 0) + .map(|(delegate_id, &total_delegate_stake)| { + ( + Self::get_delegate_by_existing_account(delegate_id), + Compact(total_delegate_stake), + ) + }) + .collect() } } diff --git a/pallets/subtensor/src/dynamic_pool_info.rs b/pallets/subtensor/src/dynamic_pool_info.rs new file mode 100644 index 000000000..f5babf430 --- /dev/null +++ b/pallets/subtensor/src/dynamic_pool_info.rs @@ -0,0 +1,101 @@ +use super::*; +use frame_support::{ + pallet_prelude::{Decode, Encode}, +}; +extern crate alloc; +use codec::Compact; +use sp_std::vec::Vec; + +#[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)] +pub struct DynamicPoolInfo { + pub subnet_stake: Compact, + pub alpha_issuance: Compact, + pub alpha_outstanding: Compact, + pub alpha_reserve: Compact, + pub tao_reserve: Compact, + pub k: Compact, + pub price: Compact, + pub netuid: Compact, +} + +#[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)] +pub struct DynamicPoolInfoV2 { + pub netuid: u16, + pub alpha_issuance: u64, + pub alpha_outstanding: u64, + pub alpha_reserve: u64, + pub tao_reserve: u64, + pub k: u128, +} + +impl Pallet { + pub fn get_dynamic_pool_info(netuid: u16) -> Option { + if !Self::if_subnet_exist(netuid) { + return None; + } + + let subnet_stake: u64 = Self::get_total_stake_on_subnet(netuid); + let alpha_issuance: u64 = Self::get_alpha_issuance(netuid); + let alpha_outstanding: u64 = Self::get_alpha_outstanding(netuid); + let alpha_reserve: u64 = Self::get_alpha_reserve(netuid); + let tao_reserve: u64 = Self::get_tao_reserve(netuid); + let k: u128 = Self::get_pool_k(netuid); + let price = Self::get_tao_per_alpha_price(netuid).to_num::(); + + // Return the dynamic pool info. + Some(DynamicPoolInfo { + subnet_stake: Compact(subnet_stake), + alpha_issuance: Compact(alpha_issuance), + alpha_outstanding: Compact(alpha_outstanding), + alpha_reserve: Compact(alpha_reserve), + tao_reserve: Compact(tao_reserve), + k: Compact(k), + price: Compact(price), + netuid: Compact(netuid), + }) + } + + pub fn get_all_dynamic_pool_infos() -> Vec> { + let mut all_pool_infos = Vec::new(); + + for (netuid, added) in NetworksAdded::::iter() { + if added { + let pool_info = Self::get_dynamic_pool_info(netuid); + all_pool_infos.push(pool_info); + } + } + + all_pool_infos + } + + pub fn get_dynamic_pool_info_v2(netuid: u16) -> Option { + if !Self::is_subnet_dynamic(netuid) || !Self::if_subnet_exist(netuid) { + return None; + } + + let alpha_issuance: u64 = Self::get_alpha_issuance(netuid); + let alpha_outstanding: u64 = Self::get_alpha_outstanding(netuid); + let alpha_reserve: u64 = Self::get_alpha_reserve(netuid); + let tao_reserve: u64 = Self::get_tao_reserve(netuid); + let k: u128 = Self::get_pool_k(netuid); + + // Return the dynamic pool info. + Some(DynamicPoolInfoV2 { + netuid: netuid.into(), + alpha_issuance: alpha_issuance, + alpha_outstanding: alpha_outstanding, + alpha_reserve: alpha_reserve, + tao_reserve: tao_reserve, + k: k, + }) + } + + pub fn get_all_dynamic_pool_infos_v2() -> Vec { + Self::get_all_subnet_netuids() + .iter() + .map(|&netuid| Self::get_dynamic_pool_info_v2(netuid)) + .filter(|info| info.is_some()) + .map(|info| info.unwrap()) + .collect() + } +} diff --git a/pallets/subtensor/src/epoch.rs b/pallets/subtensor/src/epoch.rs index cc146dd59..f63110ba5 100644 --- a/pallets/subtensor/src/epoch.rs +++ b/pallets/subtensor/src/epoch.rs @@ -5,9 +5,78 @@ use sp_std::vec; use substrate_fixed::types::{I32F32, I64F64, I96F32}; impl Pallet { - /// Calculates reward consensus and returns the emissions for uids/hotkeys in a given `netuid`. - /// (Dense version used only for testing purposes.) - #[allow(clippy::indexing_slicing)] + pub fn get_global_stake_weights(hotkeys: &[(u16, T::AccountId)]) -> Vec { + // Initialize a vector to hold the global stake values in 64-bit fixed-point format, setting initial values to 0.0. + let mut global_stake_64: Vec = vec![I64F64::from_num(0.0); hotkeys.len()]; + + // Iterate over each hotkey to calculate and assign the global stake values. + for (uid_i, hotkey) in hotkeys.iter() { + global_stake_64[*uid_i as usize] = + I64F64::from_num(Self::get_hotkey_global_dynamic_tao(hotkey)); + } + // Normalize the global stake values in-place. + inplace_normalize_64(&mut global_stake_64); + + global_stake_64 + } + + pub fn get_local_stake_weights(netuid: u16, hotkeys: &[(u16, T::AccountId)]) -> Vec { + // Initialize a vector to hold the local stake values in 64-bit fixed-point format, setting initial values to 0.0. + let mut local_stake_64: Vec = vec![I64F64::from_num(0.0); hotkeys.len()]; + + // Iterate over each hotkey to calculate and assign the local stake values. + for (uid_i, hotkey) in hotkeys.iter() { + local_stake_64[*uid_i as usize] = + I64F64::from_num(Self::get_total_stake_for_hotkey_and_subnet(hotkey, netuid)); + } + // Normalize the local stake values in-place. + inplace_normalize_64(&mut local_stake_64); + + // Return + local_stake_64 + } + + pub fn get_stakes(netuid: u16, hotkeys: &[(u16, T::AccountId)]) -> Vec { + // Get the stake weight alpha + let alpha: I64F64 = Self::get_global_stake_weight_float(); + + // Get local and global terms. + let local_stake_weights: Vec = Self::get_local_stake_weights(netuid, hotkeys); + let global_stake_weights: Vec = Self::get_global_stake_weights(hotkeys); + + // Average local and global weights. + let averaged_stake_64: Vec = local_stake_weights + .iter() + .zip(global_stake_weights.iter()) + .map(|(local, global)| (I64F64::from_num(1.0) - alpha) * (*local) + alpha * (*global)) + .collect(); + + // Convert the averaged stake values from 64-bit fixed-point to 32-bit fixed-point representation. + vec_fixed64_to_fixed32(averaged_stake_64) + } + + /// Fake epoch output with zero mining rewards. + pub fn fake_epoch(netuid: u16, rao_emission: u64) -> Vec<(T::AccountId, u64, u64)> { + let hotkeys: Vec<(u16, T::AccountId)> = Keys::::iter_prefix(netuid).collect(); + + // Set stake weights + let stake = Self::get_stakes(netuid, &hotkeys); + let cloned_stake: Vec = stake + .iter() + .map(|si| fixed_proportion_to_u16(*si)) + .collect::>(); + StakeWeight::::insert(netuid, cloned_stake); + + let stake: Vec = Self::get_stakes(netuid, &hotkeys); + let emission: Vec = stake.iter().map(|e: &I32F32| I96F32::from_num(*e) * I96F32::from_num(rao_emission) ).collect(); + let validator_emission: Vec = emission.iter().map(|e: &I96F32| e.to_num::() ).collect(); + let server_emission = 0u64; + + hotkeys.into_iter().map(|(uid_i, hotkey)| (hotkey, server_emission, validator_emission[uid_i as usize])).collect() + } + + // Calculates reward consensus and returns the emissions for uids/hotkeys in a given `netuid`. + // (Dense version used only for testing purposes.) pub fn epoch_dense(netuid: u16, rao_emission: u64) -> Vec<(T::AccountId, u64, u64)> { // Get subnetwork size. let n: u16 = Self::get_subnetwork_n(netuid); @@ -55,22 +124,19 @@ impl Pallet { .collect(); log::trace!("Outdated:\n{:?}\n", &outdated); - // =========== - // == Stake == - // =========== + // ============= + // == Hotkeys == + // ============= let hotkeys: Vec<(u16, T::AccountId)> = as IterableStorageDoubleMap>::iter_prefix(netuid) .collect(); log::trace!("hotkeys: {:?}", &hotkeys); - // Access network stake as normalized vector. - let mut stake_64: Vec = vec![I64F64::from_num(0.0); n as usize]; - for (uid_i, hotkey) in &hotkeys { - stake_64[*uid_i as usize] = I64F64::from_num(Self::get_total_stake_for_hotkey(hotkey)); - } - inplace_normalize_64(&mut stake_64); - let stake: Vec = vec_fixed64_to_fixed32(stake_64); + // =================== + // == Stake values. == + // =================== + let stake = Self::get_stakes(netuid, &hotkeys); log::trace!("S:\n{:?}\n", &stake); // ======================= @@ -91,7 +157,6 @@ impl Pallet { // Get new validator permits. let new_validator_permits: Vec = is_topk(&stake, max_allowed_validators as usize); log::trace!("new_validator_permits: {:?}", new_validator_permits); - // ================== // == Active Stake == // ================== @@ -269,6 +334,10 @@ impl Pallet { // == Value storage == // =================== let cloned_emission: Vec = combined_emission.clone(); + let cloned_stake: Vec = stake + .iter() + .map(|si| fixed_proportion_to_u16(*si)) + .collect::>(); let cloned_ranks: Vec = ranks .iter() .map(|xi| fixed_proportion_to_u16(*xi)) @@ -296,6 +365,7 @@ impl Pallet { .collect::>(); Active::::insert(netuid, active.clone()); Emission::::insert(netuid, cloned_emission); + StakeWeight::::insert(netuid, cloned_stake); Rank::::insert(netuid, cloned_ranks); Trust::::insert(netuid, cloned_trust); Consensus::::insert(netuid, cloned_consensus); @@ -387,24 +457,19 @@ impl Pallet { let block_at_registration: Vec = Self::get_block_at_registration(netuid); log::trace!("Block at registration: {:?}", &block_at_registration); - // =========== - // == Stake == - // =========== + // ============= + // == Hotkeys == + // ============= - let hotkeys: Vec<(u16, T::AccountId)> = - as IterableStorageDoubleMap>::iter_prefix(netuid) - .collect(); + // Keys stores (netuid, uid) --> hotkey association, which is initially added in append_neuron + let hotkeys: Vec<(u16, T::AccountId)> = Keys::::iter_prefix(netuid).collect(); log::trace!("hotkeys: {:?}", &hotkeys); - // Access network stake as normalized vector. - let mut stake_64: Vec = vec![I64F64::from_num(0.0); n as usize]; - for (uid_i, hotkey) in &hotkeys { - stake_64[*uid_i as usize] = I64F64::from_num(Self::get_total_stake_for_hotkey(hotkey)); - } - inplace_normalize_64(&mut stake_64); - let stake: Vec = vec_fixed64_to_fixed32(stake_64); - // range: I32F32(0, 1) - log::trace!("S: {:?}", &stake); + // =========== + // == Stake == + // =========== + let stake = Self::get_stakes(netuid, hotkeys.as_slice()); + log::trace!("S:\n{:?}\n", &stake); // ======================= // == Validator permits == @@ -629,6 +694,10 @@ impl Pallet { // == Value storage == // =================== let cloned_emission: Vec = combined_emission.clone(); + let cloned_stakes: Vec = stake + .iter() + .map(|si| fixed_proportion_to_u16(*si)) + .collect::>(); let cloned_ranks: Vec = ranks .iter() .map(|xi| fixed_proportion_to_u16(*xi)) @@ -657,6 +726,7 @@ impl Pallet { Active::::insert(netuid, active.clone()); Emission::::insert(netuid, cloned_emission); Rank::::insert(netuid, cloned_ranks); + StakeWeight::::insert(netuid, cloned_stakes); Trust::::insert(netuid, cloned_trust); Consensus::::insert(netuid, cloned_consensus); Incentive::::insert(netuid, cloned_incentive); @@ -707,18 +777,6 @@ impl Pallet { I32F32::from_num(Self::get_kappa(netuid)) / I32F32::from_num(u16::MAX) } - pub fn get_normalized_stake(netuid: u16) -> Vec { - let n = Self::get_subnetwork_n(netuid); - let mut stake_64: Vec = (0..n) - .map(|neuron_uid| { - I64F64::from_num(Self::get_stake_for_uid_and_subnetwork(netuid, neuron_uid)) - }) - .collect(); - inplace_normalize_64(&mut stake_64); - let stake: Vec = vec_fixed64_to_fixed32(stake_64); - stake - } - pub fn get_block_at_registration(netuid: u16) -> Vec { let n = Self::get_subnetwork_n(netuid); let block_at_registration: Vec = (0..n) diff --git a/pallets/subtensor/src/errors.rs b/pallets/subtensor/src/errors.rs index 62c1d799b..45c30edf2 100644 --- a/pallets/subtensor/src/errors.rs +++ b/pallets/subtensor/src/errors.rs @@ -114,6 +114,8 @@ mod errors { DelegateTakeTooLow, /// Delegate take is too high. DelegateTakeTooHigh, + /// subnet creator attempts to remove their funds within the lock period + SubnetCreatorLock, /// Not allowed to commit weights. WeightsCommitNotAllowed, /// No commit found for the provided hotkey+netuid combination when attempting to reveal the weights. @@ -122,9 +124,19 @@ mod errors { InvalidRevealCommitTempo, /// Committed hash does not equal the hashed reveal data. InvalidRevealCommitHashNotMatch, + /// Only STAO subnets are allowed to be dissolved + NotAllowedToDissolve, /// Attempting to call set_weights when commit/reveal is enabled CommitRevealEnabled, /// Attemtping to commit/reveal weights when disabled. CommitRevealDisabled, + /// This subnet cannot be converted to DTAO + CannotBeConverted, + /// Subnet type transition is already in progress + TranstinioAlreadyInProgress, + /// Operation is temporarily not allowed + TemporarilyNotAllowed, + /// Subnet has zero stake + NoStakeInSubnet, } } diff --git a/pallets/subtensor/src/events.rs b/pallets/subtensor/src/events.rs index 47cc9973b..764051a0c 100644 --- a/pallets/subtensor/src/events.rs +++ b/pallets/subtensor/src/events.rs @@ -12,9 +12,9 @@ mod events { /// a network is removed. NetworkRemoved(u16), /// stake has been transferred from the a coldkey account onto the hotkey staking account. - StakeAdded(T::AccountId, u64), + StakeAdded(T::AccountId, u16, u64), /// stake has been removed from the hotkey staking account onto the coldkey account. - StakeRemoved(T::AccountId, u64), + StakeRemoved(T::AccountId, u16, u64), /// a caller successfully sets their weights on a subnetwork. WeightsSet(u16, u16), /// a new neuron account has been registered to the chain. diff --git a/pallets/subtensor/src/lib.rs b/pallets/subtensor/src/lib.rs index 61eb17f4a..6f50180ab 100644 --- a/pallets/subtensor/src/lib.rs +++ b/pallets/subtensor/src/lib.rs @@ -25,6 +25,8 @@ use sp_runtime::{ DispatchError, }; use sp_std::marker::PhantomData; +use sp_std::vec; +use sp_std::vec::Vec; // ============================ // ==== Benchmark Imports ===== @@ -49,9 +51,11 @@ mod utils; mod weights; pub mod delegate_info; +pub mod dynamic_pool_info; pub mod neuron_info; pub mod stake_info; pub mod subnet_info; +pub mod types; // apparently this is stabilized since rust 1.36 extern crate alloc; @@ -63,6 +67,7 @@ pub mod migration; #[frame_support::pallet] pub mod pallet { + use crate::types::{SubnetTransition, SubnetType}; use frame_support::{ dispatch::GetDispatchInfo, pallet_prelude::{DispatchResult, StorageMap, ValueQuery, *}, @@ -112,6 +117,9 @@ pub mod pallet { /// Interface to allow other pallets to control who can register identities type TriumvirateInterface: crate::CollectiveInterface; + /// Flag for using simple epoch function with no miner emissions + type EpochConfig: crate::EpochConfiguration; + /// ================================= /// ==== Initial Value Constants ==== /// ================================= @@ -131,6 +139,12 @@ pub mod pallet { /// Tempo for each network. #[pallet::constant] type InitialTempo: Get; + /// Minimum Tempo for each network. + #[pallet::constant] + type MinTempo: Get; + /// Maximum Tempo for each network. + #[pallet::constant] + type MaxTempo: Get; /// Initial Difficulty. #[pallet::constant] type InitialDifficulty: Get; @@ -194,7 +208,7 @@ pub mod pallet { /// Initial default delegation take. #[pallet::constant] type InitialDefaultTake: Get; - /// Initial minimum delegation take. + /// Initial minimum delegate take. #[pallet::constant] type InitialMinTake: Get; /// Initial weights version key. @@ -239,6 +253,9 @@ pub mod pallet { /// Initial target stakes per interval issuance. #[pallet::constant] type InitialTargetStakesPerInterval: Get; + /// Initial subnet lock period + #[pallet::constant] + type InitialSubnetOwnerLockPeriod: Get; } /// Alias for the account ID. @@ -273,11 +290,26 @@ pub mod pallet { pub fn DefaultMinTake() -> u16 { T::InitialMinTake::get() } - /// Default account take. + /// Default u64 zero value #[pallet::type_value] - pub fn DefaultAccountTake() -> u64 { + pub fn DefaultZeroU64() -> u64 { 0 } + /// Default bool value + #[pallet::type_value] + pub fn DefaultBool() -> bool { + false + } + /// Default u16 MAX value + #[pallet::type_value] + pub fn DefaultMaxU16() -> u16 { + u16::MAX + } + /// Default value of global stake weight (0.5) + #[pallet::type_value] + pub fn DefaultGlobalStakeWeight() -> u16 { + u16::MAX / 2 + } /// Default stakes per interval. #[pallet::type_value] pub fn DefaultStakesPerInterval() -> (u64, u64) { @@ -304,20 +336,31 @@ pub mod pallet { T::AccountId::decode(&mut TrailingZeroInput::zeroes()) .expect("trailing zeroes always produce a valid account ID; qed") } + /// Default take + #[pallet::type_value] + pub fn DefaultAccountTake() -> u64 { + 0 + } /// Default target stakes per interval. #[pallet::type_value] pub fn DefaultTargetStakesPerInterval() -> u64 { T::InitialTargetStakesPerInterval::get() } + /// Default lock period of subnet owner + #[pallet::type_value] + pub fn DefaultSubnetOwnerLockPeriod() -> u64 { + T::InitialSubnetOwnerLockPeriod::get() + } + /// Default stake interval. #[pallet::type_value] pub fn DefaultStakeInterval() -> u64 { 360 } + #[pallet::storage] // --- ITEM ( GlobalStakeWeight ) + pub type GlobalStakeWeight = StorageValue<_, u16, ValueQuery, DefaultGlobalStakeWeight>; #[pallet::storage] // --- ITEM ( total_stake ) - pub type TotalStake = StorageValue<_, u64, ValueQuery>; - #[pallet::storage] // --- ITEM ( default_take ) pub type MaxTake = StorageValue<_, u16, ValueQuery, DefaultDefaultTake>; #[pallet::storage] // --- ITEM ( min_take ) pub type MinTake = StorageValue<_, u16, ValueQuery, DefaultMinTake>; @@ -330,12 +373,9 @@ pub mod pallet { StorageValue<_, u64, ValueQuery, DefaultTargetStakesPerInterval>; #[pallet::storage] // --- ITEM (default_stake_interval) pub type StakeInterval = StorageValue<_, u64, ValueQuery, DefaultStakeInterval>; - #[pallet::storage] // --- MAP ( hot ) --> stake | Returns the total amount of stake under a hotkey. - pub type TotalHotkeyStake = - StorageMap<_, Identity, T::AccountId, u64, ValueQuery, DefaultAccountTake>; - #[pallet::storage] // --- MAP ( cold ) --> stake | Returns the total amount of stake under a coldkey. - pub type TotalColdkeyStake = - StorageMap<_, Identity, T::AccountId, u64, ValueQuery, DefaultAccountTake>; + #[pallet::storage] // --- MAP ( netuid ) --> stake | Returns the total amount of stake attached to a subnet. + pub type TotalSubnetStake = + StorageMap<_, Identity, u16, u64, ValueQuery, DefaultZeroU64>; #[pallet::storage] /// MAP (hot, cold) --> stake | Returns a tuple (u64: stakes, u64: block_number) pub type TotalHotkeyColdkeyStakesThisInterval = StorageDoubleMap< @@ -354,18 +394,76 @@ pub mod pallet { #[pallet::storage] // --- MAP ( hot ) --> take | Returns the hotkey delegation take. And signals that this key is open for delegation. pub type Delegates = StorageMap<_, Blake2_128Concat, T::AccountId, u16, ValueQuery, DefaultDefaultTake>; - #[pallet::storage] // --- DMAP ( hot, cold ) --> stake | Returns the stake under a coldkey prefixed by hotkey. - pub type Stake = StorageDoubleMap< + #[pallet::storage] // --- DMAP ( hot, subnetid ) --> take | Returns the hotkey delegation take by subnet. + pub type DelegatesTake = StorageDoubleMap< _, Blake2_128Concat, T::AccountId, Identity, + u16, + u16, + ValueQuery, + DefaultDefaultTake, + >; + #[pallet::storage] // --- DMAP ( hot, cold ) --> is_staker | Allows to iterate over all nominators of a hotkey + pub type Staker = StorageDoubleMap< + _, + Blake2_128Concat, T::AccountId, + Identity, + T::AccountId, + bool, + ValueQuery, + DefaultBool, + >; + // This value is alpha for DTAO networks and TAO for STAO networks + #[pallet::storage] // --- DMAP ( hot, netuid ) --> stake | Returns the total stake attached to a hotkey on a subnet. + pub type TotalHotkeySubStake = StorageDoubleMap< + _, + Blake2_128Concat, + T::AccountId, + Identity, + u16, + u64, + ValueQuery, + DefaultZeroU64, + >; + // This value is alpha for DTAO networks and TAO for STAO networks + #[pallet::storage] // --- NMAP ( cold, hot, netuid ) --> stake | Returns the stake under a subnet prefixed by coldkey, hotkey, netuid triplet. + pub type SubStake = StorageNMap< + _, + ( + NMapKey, // cold + NMapKey, // hot + NMapKey, // subnet + ), u64, ValueQuery, - DefaultAccountTake, >; + /// Flag that determines if subnet staking is on by default + #[pallet::type_value] + pub fn DefaultSubnetStaking() -> bool { + cfg!(feature = "subnet-staking") + } + #[pallet::storage] // --- ITEM( SubnetStakingOn ) --> Subnet staking enabled + pub type SubnetStakingOn = StorageValue<_, bool, ValueQuery, DefaultSubnetStaking>; + #[pallet::storage] // --- MAP ( netuid ) --> DynamicTAOReserve | Returns the TAO reserve for a given netuid. + pub type DynamicTAOReserve = StorageMap<_, Identity, u16, u64, ValueQuery>; + #[pallet::storage] // --- MAP ( netuid ) --> DynamicAlphaReserve | Returns the dynamic sub-reserve for a given netuid. + pub type DynamicAlphaReserve = StorageMap<_, Identity, u16, u64, ValueQuery>; + #[pallet::storage] // --- MAP ( netuid ) --> issuance | Returns the total dynamic token issuance. + pub type DynamicAlphaIssuance = StorageMap<_, Identity, u16, u64, ValueQuery>; + #[pallet::storage] // --- MAP ( netuid ) --> issuance | Returns the total dynamic token issuance outstanding. + pub type DynamicAlphaOutstanding = StorageMap<_, Identity, u16, u64, ValueQuery>; + #[pallet::storage] // --- MAP ( netuid ) --> DynamicK | Returns the dynamic K value for a given netuid. + pub type DynamicK = StorageMap<_, Identity, u16, u128, ValueQuery>; + #[pallet::storage] // --- MAP ( netuid ) --> is_subnet_dynamic | Returns true if the network is using dynamic staking. + pub type IsDynamic = StorageMap<_, Identity, u16, bool, ValueQuery>; + #[pallet::storage] // --- ITEM ( GlobalStakeWeight ) + pub type SubnetOwnerLockPeriod = + StorageValue<_, u64, ValueQuery, DefaultSubnetOwnerLockPeriod>; + /// ===================================== /// ==== Difficulty / Registrations ===== /// ===================================== @@ -630,9 +728,17 @@ pub mod pallet { pub fn DefaultSubnetLocked() -> u64 { 0 } + /// Default value for subnet total stake. + #[pallet::type_value] + pub fn DefaultTotalSubnetTAO() -> u64 { + 0 + } /// Default value for network tempo #[pallet::type_value] pub fn DefaultTempo() -> u16 { + if cfg!(feature = "pow-faucet") { + return 4; + } T::InitialTempo::get() } @@ -644,7 +750,7 @@ pub mod pallet { #[pallet::storage] // --- MAP ( netuid ) --> pending_emission pub type PendingEmission = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultPendingEmission>; - #[pallet::storage] // --- MAP ( netuid ) --> blocks_since_last_step + #[pallet::storage] // --- MAP ( netuid ) --> blocks_since_last_step. pub type BlocksSinceLastStep = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultBlocksSinceLastStep>; #[pallet::storage] // --- MAP ( netuid ) --> last_mechanism_step_block @@ -653,9 +759,15 @@ pub mod pallet { #[pallet::storage] // --- MAP ( netuid ) --> subnet_owner pub type SubnetOwner = StorageMap<_, Identity, u16, T::AccountId, ValueQuery, DefaultSubnetOwner>; - #[pallet::storage] // --- MAP ( netuid ) --> subnet_locked + #[pallet::storage] + pub type SubnetCreator = + StorageMap<_, Identity, u16, T::AccountId, ValueQuery, DefaultSubnetOwner>; + #[pallet::storage] pub type SubnetLocked = StorageMap<_, Identity, u16, u64, ValueQuery, DefaultSubnetLocked>; + #[pallet::storage] + pub type TotalSubnetTAO = + StorageMap<_, Identity, u16, u64, ValueQuery, DefaultTotalSubnetTAO>; /// ================================= /// ==== Axon / Promo Endpoints ===== @@ -705,6 +817,10 @@ pub mod pallet { /// Default value for rate limiting #[pallet::type_value] pub fn DefaultTxRateLimit() -> u64 { + // TODO we should figure out a better way of saying this is a dev net. + if cfg!(feature = "pow-faucet") { + return 0; + } T::InitialTxRateLimit::get() } /// Default value for delegate take rate limiting @@ -994,7 +1110,9 @@ pub mod pallet { #[pallet::storage] // --- DMAP ( netuid ) --> (hotkey, se, ve) pub(super) type LoadedEmission = StorageMap<_, Identity, u16, Vec<(T::AccountId, u64, u64)>, OptionQuery>; - + #[pallet::storage] // --- DMAP ( netuid ) --> stake_weight + pub(super) type StakeWeight = + StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyU16Vec>; #[pallet::storage] // --- DMAP ( netuid ) --> active pub(super) type Active = StorageMap<_, Identity, u16, Vec, ValueQuery, EmptyBoolVec>; @@ -1052,6 +1170,15 @@ pub mod pallet { DefaultBonds, >; + // --- MAP ( netuid ) --> SubnetTransition. If present, then subnet is in the state of type transition (e.g. stao -> dtao) + #[pallet::storage] + pub type SubnetInTransition = StorageMap< + Hasher = Identity, + Key = u16, + Value = SubnetTransition, + QueryKind = OptionQuery, + >; + /// ================== /// ==== Genesis ===== /// ================== @@ -1173,17 +1300,9 @@ pub mod pallet { // Fill stake information. Owner::::insert(hotkey.clone(), coldkey.clone()); - TotalHotkeyStake::::insert(hotkey.clone(), stake); - TotalColdkeyStake::::insert( - coldkey.clone(), - TotalColdkeyStake::::get(coldkey).saturating_add(*stake), - ); - // Update total issuance value TotalIssuance::::put(TotalIssuance::::get().saturating_add(*stake)); - Stake::::insert(hotkey.clone(), coldkey.clone(), stake); - next_uid += 1; } } @@ -1272,7 +1391,7 @@ pub mod pallet { // Initializes storage version (to 1) .saturating_add(migration::migrate_to_v1_separate_emission::()) // Storage version v1 -> v2 - .saturating_add(migration::migrate_to_v2_fixed_total_stake::()) + // .saturating_add(migration::migrate_to_v2_fixed_total_stake::()) // Doesn't check storage version. TODO: Remove after upgrade .saturating_add(migration::migrate_create_root_network::()) // Storage version v2 -> v3 @@ -1280,13 +1399,28 @@ pub mod pallet { hex, )) // Storage version v3 -> v4 - .saturating_add(migration::migrate_delete_subnet_21::()) - // Storage version v4 -> v5 .saturating_add(migration::migrate_delete_subnet_3::()) + // Storage version v4 -> v5 + .saturating_add(migration::migrate_delete_subnet_21::()) // Doesn't check storage version. TODO: Remove after upgrade - .saturating_add(migration::migration5_total_issuance::(false)); - - weight + .saturating_add(migration::migration5_total_issuance::(false)) + // Storage version v6 -> v7 + .saturating_add(migration::migrate_stake_to_substake::()) + // Storage version v7 -> v8 + .saturating_add(migration::migrate_remove_deprecated_stake_variables::()) + // Storage version v8 -> v9 + .saturating_add(migration::migrate_populate_subnet_creator::()) + // Storage version v9 -> v10 + .saturating_add(migration::migrate_clear_delegates::()) + // Storage version v9 -> v11 + .saturating_add(migration::migrate_fix_subnet_lock_1::()); + + log::info!( + "Runtime upgrade migration in subtensor pallet, total weight = ({})", + weight + ); + + frame_support::weights::Weight::from_parts(0, 0) } } @@ -1520,66 +1654,35 @@ pub mod pallet { Self::do_set_root_weights(origin, netuid, hotkey, dests, weights, version_key) } - /// --- Sets the key as a delegate. - /// - /// # Args: - /// * 'origin': (Origin): - /// - The signature of the caller's coldkey. - /// - /// * 'hotkey' (T::AccountId): - /// - The hotkey we are delegating (must be owned by the coldkey.) - /// - /// * 'take' (u64): - /// - The stake proportion that this hotkey takes from delegations. - /// - /// # Event: - /// * DelegateAdded; - /// - On successfully setting a hotkey as a delegate. - /// - /// # Raises: - /// * 'NotRegistered': - /// - The hotkey we are delegating is not registered on the network. - /// - /// * 'NonAssociatedColdKey': - /// - The hotkey we are delegating is not owned by the calling coldket. - /// - #[pallet::call_index(1)] - #[pallet::weight((Weight::from_parts(79_000_000, 0) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(3)), DispatchClass::Normal, Pays::No))] - pub fn become_delegate(origin: OriginFor, hotkey: T::AccountId) -> DispatchResult { - Self::do_become_delegate(origin, hotkey, Self::get_default_take()) - } - /// --- Allows delegates to decrease its take value. /// /// # Args: /// * 'origin': (::Origin): - /// - The signature of the caller's coldkey. + /// - The signature of the caller's coldkey. /// /// * 'hotkey' (T::AccountId): - /// - The hotkey we are delegating (must be owned by the coldkey.) + /// - The hotkey we are delegating (must be owned by the coldkey.) /// /// * 'netuid' (u16): - /// - Subnet ID to decrease take for + /// - Subnet ID to decrease take for /// /// * 'take' (u16): - /// - The new stake proportion that this hotkey takes from delegations. - /// The new value can be between 0 and 11_796 and should be strictly - /// lower than the previous value. It T is the new value (rational number), - /// the the parameter is calculated as [65535 * T]. For example, 1% would be - /// [0.01 * 65535] = [655.35] = 655 + /// - The new stake proportion that this hotkey takes from delegations. + /// The new value can be between 0 and 11_796 and should be strictly + /// lower than the previous value. It T is the new value (rational number), + /// the the parameter is calculated as [65535 * T]. For example, 1% would be + /// [0.01 * 65535] = [655.35] = 655 /// /// # Event: /// * TakeDecreased; - /// - On successfully setting a decreased take for this hotkey. + /// - On successfully setting a decreased take for this hotkey. /// /// # Raises: /// * 'NotRegistered': - /// - The hotkey we are delegating is not registered on the network. + /// - The hotkey we are delegating is not registered on the network. /// /// * 'NonAssociatedColdKey': - /// - The hotkey we are delegating is not owned by the calling coldkey. + /// - The hotkey we are delegating is not owned by the calling coldkey. /// /// * 'DelegateTakeTooLow': /// - The delegate is setting a take which is not lower than the previous. @@ -1589,37 +1692,41 @@ pub mod pallet { pub fn decrease_take( origin: OriginFor, hotkey: T::AccountId, + netuid: u16, take: u16, ) -> DispatchResult { - Self::do_decrease_take(origin, hotkey, take) + Self::do_decrease_take(origin, hotkey, netuid, take) } /// --- Allows delegates to increase its take value. This call is rate-limited. /// /// # Args: /// * 'origin': (::Origin): - /// - The signature of the caller's coldkey. + /// - The signature of the caller's coldkey. /// /// * 'hotkey' (T::AccountId): - /// - The hotkey we are delegating (must be owned by the coldkey.) + /// - The hotkey we are delegating (must be owned by the coldkey.) + /// + /// * 'netuid' (u16): + /// - Subnet ID to decrease take for /// /// * 'take' (u16): - /// - The new stake proportion that this hotkey takes from delegations. - /// The new value can be between 0 and 11_796 and should be strictly - /// greater than the previous value. T is the new value (rational number), - /// the the parameter is calculated as [65535 * T]. For example, 1% would be - /// [0.01 * 65535] = [655.35] = 655 + /// - The new stake proportion that this hotkey takes from delegations. + /// The new value can be between 0 and 11_796 and should be strictly + /// greater than the previous value. It T is the new value (rational number), + /// the the parameter is calculated as [65535 * T]. For example, 1% would be + /// [0.01 * 65535] = [655.35] = 655 /// /// # Event: - /// * TakeIncreased; - /// - On successfully setting a increased take for this hotkey. + /// * TakeDecreased; + /// - On successfully setting a decreased take for this hotkey. /// /// # Raises: /// * 'NotRegistered': - /// - The hotkey we are delegating is not registered on the network. + /// - The hotkey we are delegating is not registered on the network. /// /// * 'NonAssociatedColdKey': - /// - The hotkey we are delegating is not owned by the calling coldkey. + /// - The hotkey we are delegating is not owned by the calling coldkey. /// /// * 'DelegateTakeTooHigh': /// - The delegate is setting a take which is not greater than the previous. @@ -1629,9 +1736,30 @@ pub mod pallet { pub fn increase_take( origin: OriginFor, hotkey: T::AccountId, + netuid: u16, take: u16, ) -> DispatchResult { - Self::do_increase_take(origin, hotkey, take) + Self::do_increase_take(origin, hotkey, netuid, take) + } + + /// Sets the delegator takes for multiple subnets if the subnets exist and the takes do not exceed the initial default take and respect the rate limit. + /// + /// # Arguments + /// * `hotkey` - The account ID of the hotkey. + /// * `takes` - A vector of tuples where each tuple contains a subnet ID and the corresponding take rate. + /// + /// # Errors + /// Returns `Error::::NetworkDoesNotExist` if any of the subnets do not exist. + /// Returns `Error::::InvalidTake` if any take exceeds the initial default take. + /// Returns `Error::::TxRateLimitExceeded` if the rate limit is exceeded. + #[pallet::call_index(68)] + #[pallet::weight((0, DispatchClass::Normal, Pays::No))] + pub fn set_delegate_takes( + origin: OriginFor, + hotkey: T::AccountId, + takes: Vec<(u16, u16)>, + ) -> DispatchResult { + Self::do_set_delegate_takes(origin, &hotkey, takes) } /// --- Adds stake to a hotkey. The call is made from the @@ -1641,28 +1769,32 @@ pub mod pallet { /// attacks on its hotkey running in production code. /// /// # Args: - /// * 'origin': (Origin): - /// - The signature of the caller's coldkey. + /// * 'origin': (Origin): + /// - The signature of the caller's coldkey. /// - /// * 'hotkey' (T::AccountId): - /// - The associated hotkey account. + /// * 'hotkey' (T::AccountId): + /// - The associated hotkey account. /// - /// * 'amount_staked' (u64): - /// - The amount of stake to be added to the hotkey staking account. + /// * 'amount_staked' (u64): + /// - The amount of stake to be added to the hotkey staking account. /// /// # Event: - /// * StakeAdded; - /// - On the successfully adding stake to a global account. + /// * StakeAdded; + /// - On the successfully adding stake to a global account. /// /// # Raises: - /// * 'NotEnoughBalanceToStake': - /// - Not enough balance on the coldkey to add onto the global account. + /// * 'CouldNotConvertToBalance': + /// - Unable to convert the passed stake value to a balance. + /// + /// * 'NotEnoughBalanceToStake': + /// - Not enough balance on the coldkey to add onto the global account. + /// + /// * 'NonAssociatedColdKey': + /// - The calling coldkey is not associated with this hotkey. /// - /// * 'NonAssociatedColdKey': - /// - The calling coldkey is not associated with this hotkey. + /// * 'BalanceWithdrawalError': + /// - Errors stemming from transaction pallet. /// - /// * 'BalanceWithdrawalError': - /// - Errors stemming from transaction pallet. /// #[pallet::call_index(2)] #[pallet::weight((Weight::from_parts(124_000_000, 0) @@ -1673,7 +1805,54 @@ pub mod pallet { hotkey: T::AccountId, amount_staked: u64, ) -> DispatchResult { - Self::do_add_stake(origin, hotkey, amount_staked) + Self::do_add_stake(origin, hotkey, Self::get_root_netuid(), amount_staked) + } + + /// Adds stake to a hotkey on a subnet. The call is made from the + /// coldkey account linked in the hotkey. + /// Only the associated coldkey is allowed to make staking and + /// unstaking requests. This protects the neuron against + /// attacks on its hotkey running in production code. + /// + /// # Args: + /// * 'origin': (Origin): + /// - The signature of the caller's coldkey. + /// + /// * 'hotkey' (T::AccountId): + /// - The associated hotkey account. + /// + /// * 'netuid' (u16): + /// - ID of the subnet. + /// + /// * 'amount_staked' (u64): + /// - The amount of stake to be added to the hotkey staking account. + /// + /// # Event: + /// * StakeAdded; + /// - On the successfully adding stake to a global account. + /// + /// # Raises: + /// * 'NotEnoughBalanceToStake': + /// - Not enough balance on the coldkey to add onto the global account. + /// + /// * 'NonAssociatedColdKey': + /// - The calling coldkey is not associated with this hotkey. + /// + /// * 'BalanceWithdrawalError': + /// - Errors stemming from transaction pallet. + /// + /// + #[pallet::call_index(63)] + #[pallet::weight((Weight::from_parts(65_000_000,0) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(6)), DispatchClass::Normal, Pays::No))] + pub fn add_subnet_stake( + origin: OriginFor, + hotkey: T::AccountId, + netuid: u16, + amount_staked: u64, + ) -> DispatchResult { + Self::do_add_stake(origin, hotkey, netuid, amount_staked) } /// Remove stake from the staking account. The call must be made @@ -1714,7 +1893,53 @@ pub mod pallet { hotkey: T::AccountId, amount_unstaked: u64, ) -> DispatchResult { - Self::do_remove_stake(origin, hotkey, amount_unstaked) + Self::do_remove_stake(origin, hotkey, Self::get_root_netuid(), amount_unstaked) + } + + /// Removes stake from a hotkey account and adds it onto a coldkey. + /// + /// # Args: + /// * 'origin': (RuntimeOrigin): + /// - The signature of the caller's coldkey. + /// + /// * 'hotkey' (T::AccountId): + /// - The associated hotkey account. + /// + /// * 'stake_to_be_added' (u64): + /// - The amount of stake to be added to the hotkey staking account. + /// + /// # Event: + /// * StakeRemoved; + /// - On the successfully removing stake from the hotkey account. + /// + /// # Raises: + /// * 'NotRegistered': + /// - Thrown if the account we are attempting to unstake from is non existent. + /// + /// * 'NonAssociatedColdKey': + /// - Thrown if the coldkey does not own the hotkey we are unstaking from. + /// + /// * 'NotEnoughStaketoWithdraw': + /// - Thrown if there is not enough stake on the hotkey to withdwraw this amount. + /// + /// * 'CouldNotConvertToBalance': + /// - Thrown if we could not convert this amount to a balance. + /// + /// * 'TxRateLimitExceeded': + /// - Thrown if key has hit transaction rate limit + /// + #[pallet::call_index(64)] + #[pallet::weight((Weight::from_parts(63_000_000,0) + .saturating_add(Weight::from_parts(0, 43991)) + .saturating_add(T::DbWeight::get().reads(14)) + .saturating_add(T::DbWeight::get().writes(9)), DispatchClass::Normal, Pays::No))] + pub fn remove_subnet_stake( + origin: OriginFor, + hotkey: T::AccountId, + netuid: u16, + amount_unstaked: u64, + ) -> DispatchResult { + Self::do_remove_stake(origin, hotkey, netuid, amount_unstaked) } /// Serves or updates axon /promethteus information for the neuron associated with the caller. If the caller is @@ -2016,11 +2241,11 @@ pub mod pallet { /// User register a new subnetwork #[pallet::call_index(59)] - #[pallet::weight((Weight::from_parts(157_000_000, 0) - .saturating_add(T::DbWeight::get().reads(16)) - .saturating_add(T::DbWeight::get().writes(30)), DispatchClass::Operational, Pays::No))] - pub fn register_network(origin: OriginFor) -> DispatchResult { - Self::user_add_network(origin) + #[pallet::weight((Weight::from_parts(85_000_000, 0) + .saturating_add(T::DbWeight::get().reads(16)) + .saturating_add(T::DbWeight::get().writes(28)), DispatchClass::Operational, Pays::No))] + pub fn register_network(origin: OriginFor, hotkey: T::AccountId) -> DispatchResult { + Self::user_add_network(origin, hotkey, SubnetType::STAO) } /// Facility extrinsic for user to get taken from faucet @@ -2058,8 +2283,8 @@ pub mod pallet { impl Pallet { /// Returns the transaction priority for setting weights. pub fn get_priority_set_weights(hotkey: &T::AccountId, netuid: u16) -> u64 { - if let Ok(uid) = Self::get_uid_for_net_and_hotkey(netuid, hotkey) { - let _stake = Self::get_total_stake_for_hotkey(hotkey); + if Uids::::contains_key(netuid, hotkey) { + let uid = Self::get_uid_for_net_and_hotkey(netuid, &hotkey.clone()).unwrap(); let current_block_number: u64 = Self::get_current_block_as_u64(); let default_priority: u64 = current_block_number - Self::get_last_update_for_uid(netuid, uid); @@ -2071,7 +2296,7 @@ pub mod pallet { /// Is the caller allowed to set weights pub fn check_weights_min_stake(hotkey: &T::AccountId) -> bool { // Blacklist weights transactions for low stake peers. - Self::get_total_stake_for_hotkey(hotkey) >= Self::get_weights_min_stake() + Self::get_hotkey_global_dynamic_tao(hotkey) >= Self::get_weights_min_stake() } /// Helper function to check if register is allowed @@ -2219,9 +2444,9 @@ where Err(InvalidTransaction::Call.into()) } } - Some(Call::set_root_weights { netuid, .. }) => { - if Self::check_weights_min_stake(who) { - let priority: u64 = Self::get_priority_set_weights(who, *netuid); + Some(Call::set_root_weights { netuid, hotkey, .. }) => { + if Self::check_weights_min_stake(hotkey) { + let priority: u64 = Self::get_priority_set_weights(hotkey, *netuid); Ok(ValidTransaction { priority, longevity: 1, @@ -2342,13 +2567,6 @@ where } } -use sp_std::vec; - -// TODO: unravel this rats nest, for some reason rustc thinks this is unused even though it's -// used not 25 lines below -#[allow(unused)] -use sp_std::vec::Vec; - /// Trait for managing a membership pallet instance in the runtime pub trait MemberManagement { /// Add member @@ -2423,3 +2641,15 @@ impl CollectiveInterface for () { Ok(true) } } + +/// Trait for switching between simple and normal epoch in runtime +pub trait EpochConfiguration { + /// Return true if simple epoch function is to be used + fn simple_epoch() -> bool; +} + +impl EpochConfiguration for () { + fn simple_epoch() -> bool { + false + } +} diff --git a/pallets/subtensor/src/math.rs b/pallets/subtensor/src/math.rs index e10cc0001..22851403c 100644 --- a/pallets/subtensor/src/math.rs +++ b/pallets/subtensor/src/math.rs @@ -204,7 +204,7 @@ pub fn sigmoid_safe(input: I32F32, rho: I32F32, kappa: I32F32) -> I32F32 { sigmoid_output } -// Returns a bool vector where an item is true if the vector item is in topk values. +// Returns a bool vector where an item is true if the vector item is in top k values. #[allow(dead_code, clippy::indexing_slicing)] pub fn is_topk(vector: &[I32F32], k: usize) -> Vec { let n: usize = vector.len(); diff --git a/pallets/subtensor/src/migration.rs b/pallets/subtensor/src/migration.rs index 16777bf06..73ec462e4 100644 --- a/pallets/subtensor/src/migration.rs +++ b/pallets/subtensor/src/migration.rs @@ -1,7 +1,8 @@ use super::*; +use alloc::collections::BTreeMap; use frame_support::traits::DefensiveResult; use frame_support::{ - pallet_prelude::{Identity, OptionQuery}, + pallet_prelude::{Blake2_128Concat, Identity, OptionQuery, ValueQuery}, storage_alias, traits::{fungible::Inspect as _, Get, GetStorageVersion, StorageVersion}, weights::Weight, @@ -23,6 +24,29 @@ pub mod deprecated_loaded_emission_format { StorageMap, Identity, u16, Vec<(AccountIdOf, u64)>, OptionQuery>; } +pub mod deprecated_stake_variables { + use super::*; + + type AccountIdOf = ::AccountId; + + #[storage_alias] // --- MAP ( hot ) --> stake | Returns the total amount of stake under a hotkey. + pub type TotalHotkeyStake = + StorageMap, Identity, AccountIdOf, u64, ValueQuery>; + #[storage_alias] // --- MAP ( cold ) --> stake | Returns the total amount of stake under a coldkey. + pub type TotalColdkeyStake = + StorageMap, Identity, AccountIdOf, u64, ValueQuery>; + #[storage_alias] // --- DMAP ( hot, cold ) --> stake | Returns the stake under a coldkey prefixed by hotkey. + pub type Stake = StorageDoubleMap< + Pallet, + Blake2_128Concat, + AccountIdOf, + Identity, + AccountIdOf, + u64, + ValueQuery, + >; +} + /// Performs migration to update the total issuance based on the sum of stakes and total balances. /// This migration is applicable only if the current storage version is 5, after which it updates the storage version to 6. /// @@ -31,44 +55,47 @@ pub mod deprecated_loaded_emission_format { pub fn migration5_total_issuance(test: bool) -> Weight { let mut weight = T::DbWeight::get().reads(1); // Initialize migration weight - // Execute migration if the current storage version is 5 - if Pallet::::on_chain_storage_version() == StorageVersion::new(5) || test { - // Calculate the sum of all stake values - let stake_sum: u64 = Stake::::iter().fold(0, |accumulator, (_, _, stake_value)| { - accumulator.saturating_add(stake_value) - }); - weight = weight - .saturating_add(T::DbWeight::get().reads_writes(Stake::::iter().count() as u64, 0)); - - // Calculate the sum of all stake values - let locked_sum: u64 = SubnetLocked::::iter() - .fold(0, |accumulator, (_, locked_value)| { - accumulator.saturating_add(locked_value) - }); - weight = weight.saturating_add( - T::DbWeight::get().reads_writes(SubnetLocked::::iter().count() as u64, 0), - ); - - // Retrieve the total balance sum - let total_balance = T::Currency::total_issuance(); - match TryInto::::try_into(total_balance) { - Ok(total_balance_sum) => { - weight = weight.saturating_add(T::DbWeight::get().reads(1)); - - // Compute the total issuance value - let total_issuance_value: u64 = stake_sum + total_balance_sum + locked_sum; + use deprecated_stake_variables as old; - // Update the total issuance in storage - TotalIssuance::::put(total_issuance_value); + // Grab current version + let new_storage_version = 6; + let onchain_version = Pallet::::on_chain_storage_version(); - // Update the storage version to 6 - StorageVersion::new(6).put::>(); - weight = weight.saturating_add(T::DbWeight::get().writes(1)); - } - Err(_) => { - log::error!("Failed to convert total balance to u64, bailing"); - } + // Only runs if we haven't already updated version past above new_storage_version. + if onchain_version < new_storage_version { + // Execute migration if the current storage version is 5 + if Pallet::::on_chain_storage_version() == StorageVersion::new(5) || test { + // Calculate the sum of all stake values + let stake_sum: u64 = old::Stake::::iter().fold(0, |accumulator, (_, _, stake_value)| { + accumulator.saturating_add(stake_value) + }); + weight = weight + .saturating_add(T::DbWeight::get().reads_writes(old::Stake::::iter().count() as u64, 0)); + + // Calculate the sum of all stake values + let locked_sum: u64 = SubnetLocked::::iter() + .fold(0, |accumulator, (_, locked_value)| { + accumulator.saturating_add(locked_value) + }); + weight = weight.saturating_add( + T::DbWeight::get().reads_writes(SubnetLocked::::iter().count() as u64, 0), + ); + + // Retrieve the total balance sum + let total_balance = T::Currency::total_issuance(); + weight = weight.saturating_add(T::DbWeight::get().reads(1)); + + // Compute the total issuance value + let total_issuance_value: u64 = stake_sum + total_balance + locked_sum; + + // Update the total issuance in storage + TotalIssuance::::put(total_issuance_value); + weight = weight.saturating_add(T::DbWeight::get().writes(1)); } + + // Update the storage version to 6 + StorageVersion::new(new_storage_version).put::>(); + weight = weight.saturating_add(T::DbWeight::get().writes(1)); } weight // Return the computed weight of the migration process @@ -85,7 +112,10 @@ pub fn migrate_transfer_ownership_to_foundation(coldkey: [u8; 32]) -> // Only runs if we haven't already updated version past above new_storage_version. if onchain_version < new_storage_version { - info!(target: LOG_TARGET_1, ">>> Migrating subnet 1 and 11 to foundation control {:?}", onchain_version); + info!( + target: LOG_TARGET_1, + ">>> Migrating subnet 1 and 11 to foundation control {:?}", onchain_version + ); // We have to decode this using a byte slice as we don't have crypto-std let coldkey_account: ::AccountId = @@ -186,7 +216,10 @@ pub fn migrate_delete_subnet_3() -> Weight { // Only runs if we haven't already updated version past above new_storage_version. if onchain_version < new_storage_version && Pallet::::if_subnet_exist(3) { - info!(target: LOG_TARGET_1, ">>> Removing subnet 3 {:?}", onchain_version); + info!( + target: LOG_TARGET_1, + ">>> Removing subnet 3 {:?}", onchain_version + ); let netuid = 3; @@ -270,7 +303,10 @@ pub fn migrate_delete_subnet_21() -> Weight { // Only runs if we haven't already updated version past above new_storage_version. if onchain_version < new_storage_version && Pallet::::if_subnet_exist(21) { - info!(target: LOG_TARGET_1, ">>> Removing subnet 21 {:?}", onchain_version); + info!( + target: LOG_TARGET_1, + ">>> Removing subnet 21 {:?}", onchain_version + ); let netuid = 21; @@ -353,7 +389,10 @@ pub fn migrate_to_v1_separate_emission() -> Weight { // Only runs if we haven't already updated version to 1. if onchain_version < 1 { - info!(target: LOG_TARGET, ">>> Updating the LoadedEmission to a new format {:?}", onchain_version); + info!( + target: LOG_TARGET, + ">>> Updating the LoadedEmission to a new format {:?}", onchain_version + ); // We transform the storage values from the old into the new format. @@ -377,7 +416,10 @@ pub fn migrate_to_v1_separate_emission() -> Weight { |netuid: u16, netuid_emissions: Vec<(AccountIdOf, u64)>| -> Option, u64, u64)>> { - info!(target: LOG_TARGET, " Do migration of netuid: {:?}...", netuid); + info!( + target: LOG_TARGET, + " Do migration of netuid: {:?}...", netuid + ); // We will assume all loaded emission is validator emissions, // so this will get distributed over delegatees (nominators), if there are any @@ -410,67 +452,194 @@ pub fn migrate_to_v1_separate_emission() -> Weight { const LOG_TARGET_1: &str = "fixtotalstakestorage"; -pub fn migrate_to_v2_fixed_total_stake() -> Weight { - let new_storage_version = 2; +pub fn migrate_stake_to_substake() -> Weight { + let new_storage_version = 7; + let mut weight = T::DbWeight::get().reads_writes(1, 1); - // Check storage version - let mut weight = T::DbWeight::get().reads(1); + use deprecated_stake_variables as old; - // Grab current version let onchain_version = Pallet::::on_chain_storage_version(); + log::info!("Current on-chain storage version: {:?}", onchain_version); // Debug print + if onchain_version < new_storage_version { + log::info!("Starting migration from Stake to SubStake."); // Debug print + let mut counter = 0; + old::Stake::::iter().for_each(|(hotkey, coldkey, stake)| { + if stake > 0 { + // Ensure we're only migrating non-zero stakes + // Insert into SubStake with netuid set to 0 for all entries + SubStake::::insert((&coldkey, &hotkey, &0u16), stake); + // Accrue read and write weights + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + counter += 1; + } + }); + log::info!("Inserted {} entries into SubStake", counter); + + // Assuming TotalHotkeySubStake needs to be updated similarly + let mut total_stakes: BTreeMap = BTreeMap::new(); + let mut total_subnet_stakes: BTreeMap = BTreeMap::new(); + SubStake::::iter().for_each(|((coldkey, hotkey, netuid), stake)| { + *total_stakes.entry(hotkey.clone()).or_insert(0) += stake; + *total_subnet_stakes.entry(netuid).or_insert(0) += stake; + if stake > 0 { + Staker::::insert(&hotkey, &coldkey, true); + weight.saturating_accrue(T::DbWeight::get().reads_writes(0, 1)); + } + }); - // Only runs if we haven't already updated version past above new_storage_version. + for (hotkey, total_stake) in total_stakes.iter() { + TotalHotkeySubStake::::insert(hotkey, &0u16, *total_stake); + weight.saturating_accrue(T::DbWeight::get().reads_writes(0, 1)); + } + log::info!( + "Inserted {} entries into TotalHotkeySubStake", + total_stakes.len() + ); + + // For STAO the total stake is the same thing as TotalSubnetTAO for DTAO, so + // we are using this map for both STAO and DTAO. + for (netuid, total_stake) in total_subnet_stakes.iter() { + TotalSubnetTAO::::insert(netuid, total_stake); + weight.saturating_accrue(T::DbWeight::get().reads_writes(0, 1)); + } + log::info!( + "Inserted {} entries into TotalSubnetTAO", + total_subnet_stakes.len() + ); + + // Remove the old `TotalStake` type. + frame_support::storage::unhashed::kill(&frame_support::storage::storage_prefix( + "SubtensorModule".as_bytes(), + "TotalStake".as_bytes(), + )); + + // Update the storage version to indicate this migration has been completed + log::info!( + "Migration completed, updating storage version to: {:?}", + new_storage_version + ); // Debug print + StorageVersion::new(new_storage_version).put::>(); + weight += T::DbWeight::get().writes(1); + } else { + log::info!("Migration to fill SubStake from Stake already done!"); // Debug print + } + + log::info!("Final weight: {:?}", weight); // Debug print + weight +} + +pub fn migrate_remove_deprecated_stake_variables() -> Weight { + let new_storage_version = 8; + let mut weight = T::DbWeight::get().reads_writes(1, 1); + + use deprecated_stake_variables as old; + + let onchain_version = Pallet::::on_chain_storage_version(); + log::info!("Current on-chain storage version: {:?}", onchain_version); // Debug print if onchain_version < new_storage_version { - info!(target: LOG_TARGET_1, ">>> Fixing the TotalStake and TotalColdkeyStake storage {:?}", onchain_version); + log::info!("Starting migration: Remove TotalColdkeyStake and TotalHotkeyStake."); // Debug print + old::TotalHotkeyStake::::iter().for_each(|(hotkey, _)| { + old::TotalHotkeyStake::::remove(hotkey); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + }); - // Stake and TotalHotkeyStake are known to be accurate - // TotalColdkeyStake is known to be inaccurate - // TotalStake is known to be inaccurate + old::TotalColdkeyStake::::iter().for_each(|(hotkey, _)| { + old::TotalColdkeyStake::::remove(hotkey); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + }); - TotalStake::::put(0); // Set to 0 + // Update the storage version to indicate this migration has been completed + log::info!( + "Migration completed, updating storage version to: {:?}", + new_storage_version + ); // Debug print + StorageVersion::new(new_storage_version).put::>(); weight.saturating_accrue(T::DbWeight::get().writes(1)); - // We iterate over TotalColdkeyStake keys and set them to 0 - let total_coldkey_stake_keys = TotalColdkeyStake::::iter_keys().collect::>(); - for coldkey in total_coldkey_stake_keys { - weight.saturating_accrue(T::DbWeight::get().reads(1)); - TotalColdkeyStake::::insert(coldkey, 0); // Set to 0 - weight.saturating_accrue(T::DbWeight::get().writes(1)); - } + // Remove Stake values + // old::Stake::::translate(|_, _, _| { + // weight.saturating_accrue(T::DbWeight::get().reads_writes(0, 1)); + // None + // }); + } else { + log::info!("Migration to remove deprecated storage variables already done!"); + // Debug print + } - // Now we iterate over the entire stake map, and sum each coldkey stake - // We also track TotalStake - for (_, coldkey, stake) in Stake::::iter() { - weight.saturating_accrue(T::DbWeight::get().reads(1)); - // Get the current coldkey stake - let mut total_coldkey_stake = TotalColdkeyStake::::get(coldkey.clone()); - weight.saturating_accrue(T::DbWeight::get().reads(1)); - // Add the stake to the coldkey stake - total_coldkey_stake = total_coldkey_stake.saturating_add(stake); - // Update the coldkey stake - TotalColdkeyStake::::insert(coldkey, total_coldkey_stake); - weight.saturating_accrue(T::DbWeight::get().writes(1)); - - // Get the current total stake - let mut total_stake = TotalStake::::get(); - weight.saturating_accrue(T::DbWeight::get().reads(1)); - // Add the stake to the total stake - total_stake = total_stake.saturating_add(stake); - // Update the total stake - TotalStake::::put(total_stake); - weight.saturating_accrue(T::DbWeight::get().writes(1)); - } + log::info!("Final weight: {:?}", weight); // Debug print + weight +} - // Now both TotalStake and TotalColdkeyStake are accurate +pub fn migrate_populate_subnet_creator() -> Weight { + let new_storage_version = 9; + let mut weight = T::DbWeight::get().reads_writes(1, 1); - // Update storage version. - StorageVersion::new(new_storage_version).put::>(); // Update to version so we don't run this again. - // One write to storage version - weight.saturating_accrue(T::DbWeight::get().writes(1)); + let onchain_version = Pallet::::on_chain_storage_version(); + log::info!("Current on-chain storage version: {:?}", onchain_version); + if onchain_version < new_storage_version { + log::info!("Starting migration: Populate subnet creator."); + SubnetOwner::::iter().for_each(|(netuid, owner)| { + SubnetCreator::::insert(netuid, owner); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + }); + StorageVersion::new(new_storage_version).put::>(); + } else { + log::info!("Migration to populate subnet creator already done!"); + } - weight + log::info!("Final weight: {:?}", weight); + weight +} + +pub fn migrate_clear_delegates() -> Weight { + let new_storage_version = 10; + let migration_name = "clear delegates map"; + let mut weight = T::DbWeight::get().reads_writes(1, 1); + + let onchain_version = Pallet::::on_chain_storage_version(); + log::info!("Current on-chain storage version: {:?}", onchain_version); + if onchain_version < new_storage_version { + log::info!("Starting migration: {}.", migration_name); + + // Remove Delegates values + let count = Delegates::::clear(u32::MAX, None); + weight.saturating_accrue(T::DbWeight::get().reads_writes(count.backend as u64, count.backend as u64)); + + StorageVersion::new(new_storage_version).put::>(); } else { - info!(target: LOG_TARGET_1, "Migration to v2 already done!"); - Weight::zero() + log::info!("Migration already done: {}", migration_name); } + + log::info!("Final weight: {:?}", weight); + weight } + +pub fn migrate_fix_subnet_lock_1() -> Weight { + let new_storage_version = 11; + let migration_name = "fix subnet 1 locked amount"; + let mut weight = T::DbWeight::get().reads_writes(1, 1); + + let onchain_version = Pallet::::on_chain_storage_version(); + log::info!("Current on-chain storage version: {:?}", onchain_version); + if onchain_version < new_storage_version { + log::info!("Starting migration: {}.", migration_name); + + // This migration will only succeed if subnet 1 has pending emission of >= 1 TAO, + // otherwise it will be postponed until the next runtime upgrade + let netuid = 1; + let required_lock = Pallet::::get_initial_lock_on_transition(); + if PendingEmission::::get(netuid) >= required_lock { + PendingEmission::::mutate(netuid, |emission| *emission = emission.saturating_sub(required_lock)); + SubnetLocked::::mutate(netuid, |lock| *lock = lock.saturating_add(required_lock)); + weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); + StorageVersion::new(new_storage_version).put::>(); + } else { + log::info!("Migration cannot be completed at this time (no pending emission): {}", migration_name); + } + } else { + log::info!("Migration already done: {}", migration_name); + } + + log::info!("Final weight: {:?}", weight); + weight +} \ No newline at end of file diff --git a/pallets/subtensor/src/neuron_info.rs b/pallets/subtensor/src/neuron_info.rs index e3b84ab20..81b7cd6df 100644 --- a/pallets/subtensor/src/neuron_info.rs +++ b/pallets/subtensor/src/neuron_info.rs @@ -1,8 +1,9 @@ use super::*; use frame_support::pallet_prelude::{Decode, Encode}; -use frame_support::storage::IterableStorageDoubleMap; extern crate alloc; use codec::Compact; +use sp_std::vec; +use sp_std::vec::Vec; #[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)] pub struct NeuronInfo { @@ -13,7 +14,7 @@ pub struct NeuronInfo { active: bool, axon_info: AxonInfo, prometheus_info: PrometheusInfo, - stake: Vec<(T::AccountId, Compact)>, // map of coldkey to stake on this neuron/hotkey (includes delegations) + pub stake: Vec<(T::AccountId, Compact)>, // map of coldkey to stake on this neuron/hotkey (includes delegations) rank: Compact, emission: Compact, incentive: Compact, @@ -30,14 +31,14 @@ pub struct NeuronInfo { #[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)] pub struct NeuronInfoLite { - hotkey: T::AccountId, + pub hotkey: T::AccountId, coldkey: T::AccountId, - uid: Compact, + pub uid: Compact, netuid: Compact, active: bool, axon_info: AxonInfo, prometheus_info: PrometheusInfo, - stake: Vec<(T::AccountId, Compact)>, // map of coldkey to stake on this neuron/hotkey (includes delegations) + pub stake: Vec<(T::AccountId, Compact)>, // TODO: this needs to be mapped on to stake weight not just raw stake. rank: Compact, emission: Compact, incentive: Compact, @@ -77,9 +78,7 @@ impl Pallet { }; let axon_info = Self::get_axon_info(netuid, &hotkey.clone()); - let prometheus_info = Self::get_prometheus_info(netuid, &hotkey.clone()); - let coldkey = Owner::::get(hotkey.clone()).clone(); let active = Self::get_active_for_uid(netuid, uid); @@ -94,6 +93,10 @@ impl Pallet { let last_update = Self::get_last_update_for_uid(netuid, uid); let validator_permit = Self::get_validator_permit_for_uid(netuid, uid); + let stake_weight = Self::get_stake_weight_for_uid(netuid, uid) as u64; + let stake: Vec<(T::AccountId, Compact)> = + vec![(coldkey.clone(), Compact(stake_weight))]; + let weights = >::get(netuid, uid) .iter() .filter_map(|(i, w)| { @@ -116,13 +119,6 @@ impl Pallet { }) .collect::, Compact)>>(); - let stake: Vec<(T::AccountId, Compact)> = - as IterableStorageDoubleMap>::iter_prefix( - hotkey.clone(), - ) - .map(|(coldkey, stake)| (coldkey, stake.into())) - .collect(); - let neuron = NeuronInfo { hotkey: hotkey.clone(), coldkey: coldkey.clone(), @@ -159,16 +155,12 @@ impl Pallet { fn get_neuron_lite_subnet_exists(netuid: u16, uid: u16) -> Option> { let hotkey = match Self::get_hotkey_for_net_and_uid(netuid, uid) { - Ok(h) => h, + Ok(key) => key, Err(_) => return None, }; - - let axon_info = Self::get_axon_info(netuid, &hotkey.clone()); - - let prometheus_info = Self::get_prometheus_info(netuid, &hotkey.clone()); - - let coldkey = Owner::::get(hotkey.clone()).clone(); - + let axon_info = Self::get_axon_info(netuid, &hotkey); + let prometheus_info = Self::get_prometheus_info(netuid, &hotkey); + let coldkey = Owner::::get(&hotkey); let active = Self::get_active_for_uid(netuid, uid); let rank = Self::get_rank_for_uid(netuid, uid); let emission = Self::get_emission_for_uid(netuid, uid); @@ -181,16 +173,13 @@ impl Pallet { let last_update = Self::get_last_update_for_uid(netuid, uid); let validator_permit = Self::get_validator_permit_for_uid(netuid, uid); + let stake_weight = Self::get_stake_weight_for_uid(netuid, uid) as u64; let stake: Vec<(T::AccountId, Compact)> = - as IterableStorageDoubleMap>::iter_prefix( - hotkey.clone(), - ) - .map(|(coldkey, stake)| (coldkey, stake.into())) - .collect(); + vec![(coldkey.clone(), Compact(stake_weight))]; let neuron = NeuronInfoLite { - hotkey: hotkey.clone(), - coldkey: coldkey.clone(), + hotkey, + coldkey, uid: uid.into(), netuid: netuid.into(), active, diff --git a/pallets/subtensor/src/registration.rs b/pallets/subtensor/src/registration.rs index 88730f7c3..99070ec1f 100644 --- a/pallets/subtensor/src/registration.rs +++ b/pallets/subtensor/src/registration.rs @@ -1,9 +1,10 @@ use super::*; -use frame_support::storage::IterableStorageDoubleMap; +use frame_support::{storage::IterableStorageDoubleMap}; use sp_core::{Get, H256, U256}; use sp_io::hashing::{keccak_256, sha2_256}; +use sp_std::vec; +use sp_std::vec::Vec; use system::pallet_prelude::BlockNumberFor; - const LOG_TARGET: &str = "runtime::subtensor::registration"; impl Pallet { @@ -92,15 +93,16 @@ impl Pallet { // --- 7. Ensure the callers coldkey has enough stake to perform the transaction. let current_block_number: u64 = Self::get_current_block_as_u64(); - let registration_cost = Self::get_burn_as_u64(netuid); + let registration_cost_as_u64 = Self::get_burn_as_u64(netuid); + let registration_cost_as_balance = registration_cost_as_u64; ensure!( - Self::can_remove_balance_from_coldkey_account(&coldkey, registration_cost), + Self::can_remove_balance_from_coldkey_account(&coldkey, registration_cost_as_balance), Error::::NotEnoughBalanceToStake ); // --- 8. Ensure the remove operation from the coldkey is a success. let actual_burn_amount = - Self::remove_balance_from_coldkey_account(&coldkey, registration_cost)?; + Self::remove_balance_from_coldkey_account(&coldkey, registration_cost_as_balance)?; // The burn occurs here. Self::burn_tokens(actual_burn_amount); @@ -115,8 +117,6 @@ impl Pallet { ); // --- 11. Append neuron or prune it. - let subnetwork_uid: u16; - let current_subnetwork_n: u16 = Self::get_subnetwork_n(netuid); // Possibly there is no neuron slots at all. ensure!( @@ -124,23 +124,12 @@ impl Pallet { Error::::NoNeuronIdAvailable ); - if current_subnetwork_n < Self::get_max_allowed_uids(netuid) { - // --- 12.1.1 No replacement required, the uid appends the subnetwork. - // We increment the subnetwork count here but not below. - subnetwork_uid = current_subnetwork_n; - - // --- 12.1.2 Expand subnetwork with new account. - Self::append_neuron(netuid, &hotkey, current_block_number); - log::info!("add new neuron account"); - } else { - // --- 13.1.1 Replacement required. - // We take the neuron with the lowest pruning score here. - subnetwork_uid = Self::get_neuron_to_prune(netuid); - - // --- 13.1.1 Replace the neuron account with the new info. - Self::replace_neuron(netuid, subnetwork_uid, &hotkey, current_block_number); - log::info!("prune neuron"); - } + let subnetwork_uid = Self::do_registration_no_checks( + netuid, + &hotkey, + &coldkey, + current_block_number + ); // --- 14. Record the registration and increment block and interval counters. BurnRegistrationsThisInterval::::mutate(netuid, |val| *val += 1); @@ -310,8 +299,6 @@ impl Pallet { ); // --- 11. Append neuron or prune it. - let subnetwork_uid: u16; - let current_subnetwork_n: u16 = Self::get_subnetwork_n(netuid); // Possibly there is no neuron slots at all. ensure!( @@ -319,23 +306,12 @@ impl Pallet { Error::::NoNeuronIdAvailable ); - if current_subnetwork_n < Self::get_max_allowed_uids(netuid) { - // --- 11.1.1 No replacement required, the uid appends the subnetwork. - // We increment the subnetwork count here but not below. - subnetwork_uid = current_subnetwork_n; - - // --- 11.1.2 Expand subnetwork with new account. - Self::append_neuron(netuid, &hotkey, current_block_number); - log::info!("add new neuron account"); - } else { - // --- 11.1.1 Replacement required. - // We take the neuron with the lowest pruning score here. - subnetwork_uid = Self::get_neuron_to_prune(netuid); - - // --- 11.1.1 Replace the neuron account with the new info. - Self::replace_neuron(netuid, subnetwork_uid, &hotkey, current_block_number); - log::info!("prune neuron"); - } + let subnetwork_uid = Self::do_registration_no_checks( + netuid, + &hotkey, + &coldkey, + current_block_number + ); // --- 12. Record the registration and increment block and interval counters. POWRegistrationsThisInterval::::mutate(netuid, |val| *val += 1); @@ -355,6 +331,40 @@ impl Pallet { Ok(()) } + pub fn do_registration_no_checks( + netuid: u16, + hotkey: &T::AccountId, + coldkey: &T::AccountId, + current_block_number: u64 + ) -> u16 { + let subnetwork_uid: u16; + let current_subnetwork_n: u16 = Self::get_subnetwork_n(netuid); + + if current_subnetwork_n < Self::get_max_allowed_uids(netuid) { + // --- 12.1.1 No replacement required, the uid appends the subnetwork. + // We increment the subnetwork count here but not below. + subnetwork_uid = current_subnetwork_n; + + // --- 12.1.2 Expand subnetwork with new account. + Self::append_neuron(netuid, hotkey, current_block_number); + log::info!("add new neuron account"); + } else { + // --- 13.1.1 Replacement required. + // We take the neuron with the lowest pruning score here. + subnetwork_uid = Self::get_neuron_to_prune(netuid); + + // --- 13.1.1 Replace the neuron account with the new info. + Self::replace_neuron(netuid, subnetwork_uid, hotkey, current_block_number); + log::info!("prune neuron"); + } + + // Since all registered hotkeys are delegates, this extrinsic effectively sets + // delegate take the first time, so we need to watch the rate limits + Self::set_last_tx_block_delegate_take(coldkey, current_block_number); + + subnetwork_uid + } + pub fn do_faucet( origin: T::RuntimeOrigin, block_number: u64, @@ -394,8 +404,8 @@ impl Pallet { UsedWork::::insert(work.clone(), current_block_number); // --- 5. Add Balance via faucet. - let balance_to_add: u64 = 100_000_000_000; - Self::coinbase(100_000_000_000); // We are creating tokens here from the coinbase. + let balance_to_add: u64 = 3_000_000_000_000; + Self::coinbase(balance_to_add); // We are creating tokens here from the coinbase. Self::add_balance_to_coldkey_account(&coldkey, balance_to_add); @@ -622,30 +632,26 @@ impl Pallet { .saturating_accrue(T::DbWeight::get().reads((TotalNetworks::::get() + 1u16) as u64)); let swap_cost = 1_000_000_000u64; + let swap_cost_as_balance = swap_cost; ensure!( Self::can_remove_balance_from_coldkey_account(&coldkey, swap_cost), Error::::NotEnoughBalanceToPaySwapHotKey ); - let actual_burn_amount = Self::remove_balance_from_coldkey_account(&coldkey, swap_cost)?; + let actual_burn_amount = + Self::remove_balance_from_coldkey_account(&coldkey, swap_cost_as_balance)?; Self::burn_tokens(actual_burn_amount); Owner::::remove(old_hotkey); Owner::::insert(new_hotkey, coldkey.clone()); weight.saturating_accrue(T::DbWeight::get().writes(2)); - if let Ok(total_hotkey_stake) = TotalHotkeyStake::::try_get(old_hotkey) { - TotalHotkeyStake::::remove(old_hotkey); - TotalHotkeyStake::::insert(new_hotkey, total_hotkey_stake); - - weight.saturating_accrue(T::DbWeight::get().writes(2)); - } - - if let Ok(delegate_take) = Delegates::::try_get(old_hotkey) { - Delegates::::remove(old_hotkey); - Delegates::::insert(new_hotkey, delegate_take); - - weight.saturating_accrue(T::DbWeight::get().writes(2)); + for (netuid, delegate_take) in DelegatesTake::::iter_prefix(old_hotkey) { + DelegatesTake::::insert(new_hotkey, netuid, delegate_take); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); } + let subnet_limit = SubnetLimit::::get().into(); + let _ = DelegatesTake::::clear_prefix(old_hotkey, subnet_limit, None); + weight.saturating_accrue(T::DbWeight::get().writes(subnet_limit.into())); if let Ok(last_tx) = LastTxBlock::::try_get(old_hotkey) { LastTxBlock::::remove(old_hotkey); @@ -654,16 +660,16 @@ impl Pallet { weight.saturating_accrue(T::DbWeight::get().writes(2)); } - let mut coldkey_stake: Vec<(T::AccountId, u64)> = vec![]; - for (coldkey, stake_amount) in Stake::::iter_prefix(old_hotkey) { - coldkey_stake.push((coldkey.clone(), stake_amount)); + let mut coldkey_stake: Vec<(T::AccountId, bool)> = vec![]; + for (coldkey, is_staker) in Staker::::iter_prefix(old_hotkey) { + coldkey_stake.push((coldkey.clone(), is_staker)); } - let _ = Stake::::clear_prefix(old_hotkey, coldkey_stake.len() as u32, None); + let _ = Staker::::clear_prefix(old_hotkey, coldkey_stake.len() as u32, None); weight.saturating_accrue(T::DbWeight::get().writes(coldkey_stake.len() as u64)); for (coldkey, stake_amount) in coldkey_stake { - Stake::::insert(new_hotkey, coldkey, stake_amount); + Staker::::insert(new_hotkey, coldkey, stake_amount); weight.saturating_accrue(T::DbWeight::get().writes(1)); } diff --git a/pallets/subtensor/src/root.rs b/pallets/subtensor/src/root.rs index 42c783c3b..ed783e501 100644 --- a/pallets/subtensor/src/root.rs +++ b/pallets/subtensor/src/root.rs @@ -17,17 +17,30 @@ use super::*; use crate::math::*; +use crate::types::{SubnetType, SubnetTransition}; use frame_support::dispatch::Pays; -use frame_support::storage::{IterableStorageDoubleMap, IterableStorageMap}; use frame_support::traits::Get; use frame_support::weights::Weight; use sp_std::vec; use substrate_fixed::{ transcendental::log2, - types::{I64F64, I96F32}, + types::I96F32, }; impl Pallet { + /// Retrieves a boolean true is subnet emissions are determined by + /// subnet specific staking. + /// + /// # Returns: + /// * 'bool': Whether subnet emissions are determined by subnet specific staking. + /// + pub fn subnet_staking_on() -> bool { + SubnetStakingOn::::get() + } + pub fn set_subnet_staking(subnet_staking: bool) { + SubnetStakingOn::::put(subnet_staking); + } + /// Retrieves the unique identifier (UID) for the root network. /// /// The root network is a special case and has a fixed UID of 0. @@ -92,17 +105,6 @@ impl Pallet { Self::get_max_allowed_uids(Self::get_root_netuid()) } - /// Returns the emission value for the given subnet. - /// - /// This function retrieves the emission value for the given subnet. - /// - /// # Returns: - /// * 'u64': The emission value for the given subnet. - /// - pub fn get_subnet_emission_value(netuid: u16) -> u64 { - EmissionValues::::get(netuid) - } - /// Returns true if the subnetwork exists. /// /// This function checks if a subnetwork with the given UID exists. @@ -123,7 +125,7 @@ impl Pallet { /// * 'Vec': Netuids of all subnets. /// pub fn get_all_subnet_netuids() -> Vec { - as IterableStorageMap>::iter() + NetworksAdded::::iter() .map(|(netuid, _)| netuid) .collect() } @@ -206,79 +208,10 @@ impl Pallet { false } - /// Sets the emission values for each netuid - /// - pub fn set_emission_values(netuids: &[u16], emission: Vec) -> Result<(), &'static str> { - log::debug!( - "set_emission_values: netuids: {:?} emission:{:?}", - netuids, - emission - ); - - // Be careful this function can fail. - if Self::contains_invalid_root_uids(netuids) { - log::error!("set_emission_values: contains_invalid_root_uids"); - return Err("Invalid netuids"); - } - if netuids.len() != emission.len() { - log::error!("set_emission_values: netuids.len() != emission.len()"); - return Err("netuids and emission must have the same length"); - } - for (netuid_i, emission_i) in netuids.iter().zip(emission) { - log::debug!("set netuid:{:?} emission:{:?}", netuid_i, emission_i); - EmissionValues::::insert(*netuid_i, emission_i); - } - Ok(()) - } - - /// Retrieves weight matrix associated with the root network. - /// Weights represent the preferences for each subnetwork. - /// - /// # Returns: - /// A 2D vector ('Vec>') where each entry [i][j] represents the weight of subnetwork - /// 'j' with according to the preferences of key. Validator 'i' within the root network. + /// Returns the network rate limit /// - pub fn get_root_weights() -> Vec> { - // --- 0. The number of validators on the root network. - let n: usize = Self::get_num_root_validators() as usize; - - // --- 1 The number of subnets to validate. - log::debug!("subnet size before cast: {:?}", Self::get_num_subnets()); - let k: usize = Self::get_num_subnets() as usize; - log::debug!("n: {:?} k: {:?}", n, k); - - // --- 2. Initialize a 2D vector with zeros to store the weights. The dimensions are determined - // by `n` (number of validators) and `k` (total number of subnets). - let mut weights: Vec> = vec![vec![I64F64::from_num(0.0); k]; n]; - log::debug!("weights:\n{:?}\n", weights); - - let subnet_list = Self::get_all_subnet_netuids(); - - // --- 3. Iterate over stored weights and fill the matrix. - for (uid_i, weights_i) in - as IterableStorageDoubleMap>>::iter_prefix( - Self::get_root_netuid(), - ) - { - // --- 4. Iterate over each weight entry in `weights_i` to update the corresponding value in the - // initialized `weights` 2D vector. Here, `uid_j` represents a subnet, and `weight_ij` is the - // weight of `uid_i` with respect to `uid_j`. - for (netuid, weight_ij) in &weights_i { - let idx = uid_i as usize; - if let Some(weight) = weights.get_mut(idx) { - if let Some((w, _)) = weight - .iter_mut() - .zip(&subnet_list) - .find(|(_, subnet)| *subnet == netuid) - { - *w = I64F64::from_num(*weight_ij); - } - } - } - } - - // --- 5. Return the filled weights matrix. - weights + pub fn get_network_rate_limit() -> u64 { + NetworkRateLimit::::get() } /// Sets the network rate limit and emit the `NetworkRateLimitSet` event @@ -288,165 +221,6 @@ impl Pallet { Self::deposit_event(Event::NetworkRateLimitSet(limit)); } - /// Checks if registrations are allowed for a given subnet. - /// - /// This function retrieves the subnet hyperparameters for the specified subnet and checks the `registration_allowed` flag. - /// If the subnet doesn't exist or doesn't have hyperparameters defined, it returns `false`. - /// - /// # Arguments - /// - /// * `netuid` - The unique identifier of the subnet. - /// - /// # Returns - /// - /// * `bool` - `true` if registrations are allowed for the subnet, `false` otherwise. - pub fn is_registration_allowed(netuid: u16) -> bool { - Self::get_subnet_hyperparams(netuid) - .map(|params| params.registration_allowed) - .unwrap_or(false) - } - - /// Computes and sets emission values for the root network which determine the emission for all subnets. - /// - /// This function is responsible for calculating emission based on network weights, stake values, - /// and registered hotkeys. - /// - pub fn root_epoch(block_number: u64) -> Result<(), &'static str> { - // --- 0. The unique ID associated with the root network. - let root_netuid: u16 = Self::get_root_netuid(); - - // --- 1. Check if we should update the emission values based on blocks since emission was last set. - let blocks_until_next_epoch: u64 = - Self::blocks_until_next_epoch(root_netuid, Self::get_tempo(root_netuid), block_number); - if blocks_until_next_epoch != 0 { - // Not the block to update emission values. - log::debug!("blocks_until_next_epoch: {:?}", blocks_until_next_epoch); - return Err(""); - } - - // --- 2. Retrieves the number of root validators on subnets. - let n: u16 = Self::get_num_root_validators(); - log::debug!("n:\n{:?}\n", n); - if n == 0 { - // No validators. - return Err("No validators to validate emission values."); - } - - // --- 3. Obtains the number of registered subnets. - let k: u16 = Self::get_all_subnet_netuids().len() as u16; - log::debug!("k:\n{:?}\n", k); - if k == 0 { - // No networks to validate. - return Err("No networks to validate emission values."); - } - - // --- 4. Determines the total block emission across all the subnetworks. This is the - // value which will be distributed based on the computation below. - let block_emission: I64F64 = I64F64::from_num(Self::get_block_emission()?); - log::debug!("block_emission:\n{:?}\n", block_emission); - - // --- 5. A collection of all registered hotkeys on the root network. Hotkeys - // pairs with network UIDs and stake values. - let mut hotkeys: Vec<(u16, T::AccountId)> = vec![]; - for (uid_i, hotkey) in - as IterableStorageDoubleMap>::iter_prefix(root_netuid) - { - hotkeys.push((uid_i, hotkey)); - } - log::debug!("hotkeys:\n{:?}\n", hotkeys); - - // --- 6. Retrieves and stores the stake value associated with each hotkey on the root network. - // Stakes are stored in a 64-bit fixed point representation for precise calculations. - let mut stake_i64: Vec = vec![I64F64::from_num(0.0); n as usize]; - for ((_, hotkey), stake) in hotkeys.iter().zip(&mut stake_i64) { - *stake = I64F64::from_num(Self::get_total_stake_for_hotkey(hotkey)); - } - inplace_normalize_64(&mut stake_i64); - log::debug!("S:\n{:?}\n", &stake_i64); - - // --- 7. Retrieves the network weights in a 2D Vector format. Weights have shape - // n x k where is n is the number of registered peers and k is the number of subnets. - let mut weights: Vec> = Self::get_root_weights(); - log::debug!("W:\n{:?}\n", &weights); - - // Normalize weights. - inplace_row_normalize_64(&mut weights); - log::debug!("W(norm):\n{:?}\n", &weights); - - // --- 8. Calculates the rank of networks. Rank is a product of weights and stakes. - // Ranks will have shape k, a score for each subnet. - let ranks: Vec = matmul_64(&weights, &stake_i64); - log::debug!("R:\n{:?}\n", &ranks); - - // --- 9. Calculates the trust of networks. Trust is a sum of all stake with weights > 0. - // Trust will have shape k, a score for each subnet. - let total_networks = Self::get_num_subnets(); - let mut trust = vec![I64F64::from_num(0); total_networks as usize]; - let mut total_stake: I64F64 = I64F64::from_num(0); - for (weights, hotkey_stake) in weights.iter().zip(stake_i64) { - total_stake += hotkey_stake; - for (weight, trust_score) in weights.iter().zip(&mut trust) { - if *weight > 0 { - *trust_score += hotkey_stake; - } - } - } - - log::debug!("T_before normalization:\n{:?}\n", &trust); - log::debug!("Total_stake:\n{:?}\n", &total_stake); - - if total_stake == 0 { - return Err("No stake on network"); - } - - for trust_score in trust.iter_mut() { - if let Some(quotient) = trust_score.checked_div(total_stake) { - *trust_score = quotient; - } - } - - // --- 10. Calculates the consensus of networks. Consensus is a sigmoid normalization of the trust scores. - // Consensus will have shape k, a score for each subnet. - log::debug!("T:\n{:?}\n", &trust); - let one = I64F64::from_num(1); - let mut consensus = vec![I64F64::from_num(0); total_networks as usize]; - for (trust_score, consensus_i) in trust.iter_mut().zip(&mut consensus) { - let shifted_trust = *trust_score - I64F64::from_num(Self::get_float_kappa(0)); // Range( -kappa, 1 - kappa ) - let temperatured_trust = shifted_trust * I64F64::from_num(Self::get_rho(0)); // Range( -rho * kappa, rho ( 1 - kappa ) ) - let exponentiated_trust: I64F64 = - substrate_fixed::transcendental::exp(-temperatured_trust) - .expect("temperatured_trust is on range( -rho * kappa, rho ( 1 - kappa ) )"); - - *consensus_i = one / (one + exponentiated_trust); - } - - log::debug!("C:\n{:?}\n", &consensus); - let mut weighted_emission = vec![I64F64::from_num(0); total_networks as usize]; - for ((emission, consensus_i), rank) in - weighted_emission.iter_mut().zip(&consensus).zip(&ranks) - { - *emission = *consensus_i * (*rank); - } - inplace_normalize_64(&mut weighted_emission); - log::debug!("Ei64:\n{:?}\n", &weighted_emission); - - // -- 11. Converts the normalized 64-bit fixed point rank values to u64 for the final emission calculation. - let emission_as_tao: Vec = weighted_emission - .iter() - .map(|v: &I64F64| *v * block_emission) - .collect(); - - // --- 12. Converts the normalized 64-bit fixed point rank values to u64 for the final emission calculation. - let emission_u64: Vec = vec_fixed64_to_u64(emission_as_tao); - log::debug!("Eu64:\n{:?}\n", &emission_u64); - - // --- 13. Set the emission values for each subnet directly. - let netuids: Vec = Self::get_all_subnet_netuids(); - log::debug!("netuids: {:?} values: {:?}", netuids, emission_u64); - - Self::set_emission_values(&netuids, emission_u64) - } - /// Registers a user's hotkey to the root network. /// /// This function is responsible for registering the hotkey of a user. @@ -505,6 +279,9 @@ impl Pallet { // Declare a variable to hold the root UID. let subnetwork_uid: u16; + // GDT of hotkey + let hotkey_gdt = Self::get_hotkey_global_dynamic_tao(&hotkey); + // --- 8. Check if the root net is below its allowed size. // max allowed is senate size. if current_num_root_validators < Self::get_max_root_validators() { @@ -517,30 +294,24 @@ impl Pallet { } else { // --- 13.1.1 The network is full. Perform replacement. // Find the neuron with the lowest stake value to replace. - let mut lowest_stake: u64 = u64::MAX; - let mut lowest_uid: u16 = 0; - // Iterate over all keys in the root network to find the neuron with the lowest stake. - for (uid_i, hotkey_i) in - as IterableStorageDoubleMap>::iter_prefix( - root_netuid, - ) - { - let stake_i: u64 = Self::get_total_stake_for_hotkey(&hotkey_i); - if stake_i < lowest_stake { - lowest_stake = stake_i; - lowest_uid = uid_i; - } - } + let (lowest_stake, lowest_uid) = Keys::::iter_prefix(root_netuid).fold( + (u64::MAX, 0), + |(lowest_stake, lowest_uid), (uid_i, hotkey_i)| { + let stake_i: u64 = Self::get_hotkey_global_dynamic_tao(&hotkey_i); + if stake_i < lowest_stake { + (stake_i, uid_i) + } else { + (lowest_stake, lowest_uid) + } + }, + ); subnetwork_uid = lowest_uid; let replaced_hotkey: T::AccountId = Self::get_hotkey_for_net_and_uid(root_netuid, subnetwork_uid)?; // --- 13.1.2 The new account has a higher stake than the one being replaced. - ensure!( - lowest_stake < Self::get_total_stake_for_hotkey(&hotkey), - Error::::StakeTooLowForRoot - ); + ensure!(lowest_stake < hotkey_gdt, Error::::StakeTooLowForRoot); // --- 13.1.3 The new account has a higher stake than the one being replaced. // Replace the neuron account with new information. @@ -554,20 +325,20 @@ impl Pallet { ); } - let current_stake = Self::get_total_stake_for_hotkey(&hotkey); + let current_stake = hotkey_gdt; // If we're full, we'll swap out the lowest stake member. let members = T::SenateMembers::members(); if (members.len() as u32) == T::SenateMembers::max_members() { let mut sorted_members = members.clone(); sorted_members.sort_by(|a, b| { - let a_stake = Self::get_total_stake_for_hotkey(a); - let b_stake = Self::get_total_stake_for_hotkey(b); + let a_stake = Self::get_hotkey_global_dynamic_tao(a); + let b_stake = Self::get_hotkey_global_dynamic_tao(b); b_stake.cmp(&a_stake) }); if let Some(last) = sorted_members.last() { - let last_stake = Self::get_total_stake_for_hotkey(last); + let last_stake = Self::get_hotkey_global_dynamic_tao(last); if last_stake < current_stake { T::SenateMembers::swap_member(last, &hotkey).map_err(|e| e.error)?; @@ -578,11 +349,6 @@ impl Pallet { T::SenateMembers::add_member(&hotkey).map_err(|e| e.error)?; } - // --- 13. Force all members on root to become a delegate. - if !Self::hotkey_is_delegate(&hotkey) { - Self::delegate_hotkey(&hotkey, 11_796); // 18% cut defaulted. - } - // --- 14. Update the registration counters for both the block and interval. RegistrationsThisInterval::::mutate(root_netuid, |val| *val += 1); RegistrationsThisBlock::::mutate(root_netuid, |val| *val += 1); @@ -660,7 +426,7 @@ impl Pallet { // Check to see if the hotkey has enough stake to set weights. ensure!( - Self::get_total_stake_for_hotkey(&hotkey) >= Self::get_weights_min_stake(), + Self::get_hotkey_global_dynamic_tao(&hotkey) >= Self::get_weights_min_stake(), Error::::NotEnoughStakeToSetWeights ); @@ -781,11 +547,23 @@ impl Pallet { /// * 'NotEnoughBalanceToStake': If there isn't enough balance to stake for network registration. /// * 'BalanceWithdrawalError': If an error occurs during balance withdrawal for network registration. /// - pub fn user_add_network(origin: T::RuntimeOrigin) -> dispatch::DispatchResult { + pub fn user_add_network( + origin: T::RuntimeOrigin, + hotkey: T::AccountId, + subnet_type: SubnetType, + ) -> dispatch::DispatchResult { // --- 0. Ensure the caller is a signed user. let coldkey = ensure_signed(origin)?; - // --- 1. Rate limit for network registrations. + // --- 1. Ensure that the hotkey is not owned by another key. + if Owner::::contains_key(&hotkey) { + ensure!( + Self::coldkey_owns_hotkey(&coldkey, &hotkey), + Error::::NonAssociatedColdKey + ); + } + + // --- 2. Check rate limit for network registrations. let current_block = Self::get_current_block_as_u64(); let last_lock_block = Self::get_network_last_lock_block(); ensure!( @@ -793,7 +571,7 @@ impl Pallet { Error::::NetworkTxRateLimitExceeded ); - // --- 2. Calculate and lock the required tokens. + // --- 3. Calculate and lock the required tokens to register a network. let lock_amount: u64 = Self::get_network_lock_cost(); log::debug!("network lock_amount: {:?}", lock_amount); ensure!( @@ -801,48 +579,36 @@ impl Pallet { Error::::NotEnoughBalanceToStake ); - // --- 4. Determine the netuid to register. + // --- 5. Determine the netuid to register by iterating through netuids to find next lowest netuid. let netuid_to_register: u16 = { - log::debug!( - "subnet count: {:?}\nmax subnets: {:?}", - Self::get_num_subnets(), - Self::get_max_subnets() - ); - if Self::get_num_subnets().saturating_sub(1) < Self::get_max_subnets() { - // We subtract one because we don't want root subnet to count towards total - let mut next_available_netuid = 0; - loop { - next_available_netuid += 1; - if !Self::if_subnet_exist(next_available_netuid) { - log::debug!("got subnet id: {:?}", next_available_netuid); - break next_available_netuid; - } + let mut next_available_netuid = 0; + loop { + next_available_netuid += 1; + if !Self::if_subnet_exist(next_available_netuid) { + break next_available_netuid; } - } else { - let netuid_to_prune = Self::get_subnet_to_prune(); - ensure!(netuid_to_prune > 0, Error::::AllNetworksInImmunity); - - Self::remove_network(netuid_to_prune); - log::debug!("remove_network: {:?}", netuid_to_prune,); - Self::deposit_event(Event::NetworkRemoved(netuid_to_prune)); - netuid_to_prune } }; + // Ensure no type transition is in progress for subnet + // TODOSDT: Remove this check + ensure!( + SubnetInTransition::::iter().next().is_none(), + Error::::TemporarilyNotAllowed + ); + // --- 5. Perform the lock operation. let actual_lock_amount = Self::remove_balance_from_coldkey_account(&coldkey, lock_amount)?; - Self::set_subnet_locked_balance(netuid_to_register, actual_lock_amount); - Self::set_network_last_lock(actual_lock_amount); - - // --- 6. Set initial and custom parameters for the network. - Self::init_new_network(netuid_to_register, 360); - log::debug!("init_new_network: {:?}", netuid_to_register,); - // --- 7. Set netuid storage. - let current_block_number: u64 = Self::get_current_block_as_u64(); - NetworkLastRegistered::::set(current_block_number); - NetworkRegisteredAt::::insert(netuid_to_register, current_block_number); - SubnetOwner::::insert(netuid_to_register, coldkey); + Self::user_add_network_no_checks( + subnet_type, + coldkey, + hotkey, + netuid_to_register, + lock_amount, + actual_lock_amount, + 360, + ); // --- 8. Emit the NetworkAdded event. log::info!( @@ -856,6 +622,69 @@ impl Pallet { Ok(()) } + pub fn user_add_network_no_checks( + subnet_type: SubnetType, + coldkey: T::AccountId, + hotkey: T::AccountId, + netuid_to_register: u16, + lock_amount: u64, + actual_lock_amount: u64, + tempo: u16, + ) { + Self::set_subnet_locked_balance(netuid_to_register, actual_lock_amount); + Self::set_network_last_lock(actual_lock_amount); + + // --- 6. Create a new network and set initial and custom parameters for the network. + Self::init_new_network(netuid_to_register, tempo); + let current_block_number: u64 = Self::get_current_block_as_u64(); + NetworkLastRegistered::::set(current_block_number); + NetworkRegisteredAt::::insert(netuid_to_register, current_block_number); + log::debug!("init_new_network: {:?}", netuid_to_register,); + + // --- 7. Set Subnet owner to the coldkey. + SubnetOwner::::insert(netuid_to_register, coldkey.clone()); // Set the owner (which can change.) + SubnetCreator::::insert(netuid_to_register, hotkey.clone()); // Set the creator hotkey (which is forever.) + + let initial_alpha = match subnet_type { + SubnetType::STAO => { + lock_amount + }, + SubnetType::DTAO => { + // --- 8. Instantiate initial token supply based on lock cost. + let initial_tao_reserve: u64 = lock_amount; + let initial_dynamic_reserve: u64 = lock_amount * Self::get_num_subnets() as u64; + let initial_dynamic_outstanding: u64 = lock_amount * Self::get_num_subnets() as u64; + let initial_dynamic_k: u128 = + (initial_tao_reserve as u128) * (initial_dynamic_reserve as u128); + + DynamicTAOReserve::::insert(netuid_to_register, initial_tao_reserve); + DynamicAlphaReserve::::insert(netuid_to_register, initial_dynamic_reserve); + DynamicAlphaOutstanding::::insert(netuid_to_register, initial_dynamic_outstanding); + DynamicK::::insert(netuid_to_register, initial_dynamic_k); + IsDynamic::::insert(netuid_to_register, true); // Turn on dynamic staking. + + initial_dynamic_outstanding + }, + }; + + TotalSubnetTAO::::insert(netuid_to_register, actual_lock_amount); + + // Add the staker for nominator iterations + Staker::::insert(&hotkey, &coldkey, true); + + // --- 9. Register the owner to the network and expand size. + Self::create_account_if_non_existent(&coldkey, &hotkey); + Self::append_neuron(netuid_to_register, &hotkey, current_block_number); + + // --- 10. Distribute initial supply of tokens to the owners. + Self::increase_subnet_token_on_coldkey_hotkey_account( + &coldkey, + &hotkey, + netuid_to_register, + initial_alpha, + ); + } + /// Facilitates the removal of a user's subnetwork. /// /// # Args: @@ -885,6 +714,12 @@ impl Pallet { Error::::NotSubnetOwner ); + // Ensure the network is of STAO type. We don't allow to dissolve DTAO subnets + ensure!( + Self::get_subnet_type(netuid) == SubnetType::STAO, + Error::::NotAllowedToDissolve + ); + // --- 4. Explicitly erase the network and all its parameters. Self::remove_network(netuid); @@ -947,7 +782,7 @@ impl Pallet { ActivityCutoff::::insert(netuid, ActivityCutoff::::get(netuid)); } if !EmissionValues::::contains_key(netuid) { - EmissionValues::::insert(netuid, EmissionValues::::get(netuid)); + EmissionValues::::insert(netuid, DefaultEmissionValues::::get()); } if !MaxWeightsLimit::::contains_key(netuid) { MaxWeightsLimit::::insert(netuid, MaxWeightsLimit::::get(netuid)); @@ -1008,6 +843,9 @@ impl Pallet { // --- 7. Remove various network-related storages. NetworkRegisteredAt::::remove(netuid); + // Remove TotalSubnetTAO + TotalSubnetTAO::::remove(netuid); + // --- 8. Remove incentive mechanism memory. let _ = Uids::::clear_prefix(netuid, u32::max_value(), None); let _ = Keys::::clear_prefix(netuid, u32::max_value(), None); @@ -1018,7 +856,7 @@ impl Pallet { // --- 9. Iterate over stored weights and fill the matrix. for (uid_i, weights_i) in - as IterableStorageDoubleMap>>::iter_prefix( + Weights::::iter_prefix( Self::get_root_netuid(), ) { @@ -1065,6 +903,8 @@ impl Pallet { Self::add_balance_to_coldkey_account(&owner_coldkey, reserved_amount); Self::set_subnet_locked_balance(netuid, 0); SubnetOwner::::remove(netuid); + + // TODO: Unstake all nominators and return their stakes } /// This function calculates the lock cost for a network based on the last lock amount, minimum lock cost, last lock block, and current block. @@ -1109,55 +949,6 @@ impl Pallet { lock_cost } - /// This function is used to determine which subnet to prune when the total number of networks has reached the limit. - /// It iterates over all the networks and finds the oldest subnet with the minimum emission value that is not in the immunity period. - /// - /// # Returns: - /// * 'u16': - /// - The uid of the network to be pruned. - /// - pub fn get_subnet_to_prune() -> u16 { - let mut netuids: Vec = vec![]; - let current_block = Self::get_current_block_as_u64(); - - // Even if we don't have a root subnet, this still works - for netuid in NetworksAdded::::iter_keys_from(NetworksAdded::::hashed_key_for(0)) { - if current_block.saturating_sub(Self::get_network_registered_block(netuid)) - < Self::get_network_immunity_period() - { - continue; - } - - // This iterator seems to return them in order anyways, so no need to sort by key - netuids.push(netuid); - } - - // Now we sort by emission, and then by subnet creation time. - netuids.sort_by(|a, b| { - use sp_std::cmp::Ordering; - - match Self::get_emission_value(*b).cmp(&Self::get_emission_value(*a)) { - Ordering::Equal => { - if Self::get_network_registered_block(*b) - < Self::get_network_registered_block(*a) - { - Ordering::Less - } else { - Ordering::Equal - } - } - v => v, - } - }); - - log::info!("Netuids Order: {:?}", netuids); - - match netuids.last() { - Some(netuid) => *netuid, - None => 0, - } - } - pub fn get_network_registered_block(netuid: u16) -> u64 { NetworkRegisteredAt::::get(netuid) } @@ -1191,4 +982,283 @@ impl Pallet { pub fn get_lock_reduction_interval() -> u64 { NetworkLockReductionInterval::::get() } + + pub fn get_initial_lock_on_transition() -> u64 { + 1_000_000_000 + } + + // TODOSDT: When we make it available for subnet owners (not just sudo), + // make sure only subnet ower can call this. + pub fn do_start_stao_dtao_transition( + netuid: u16, + ) -> DispatchResult { + // Ensure this subnet exists. + ensure!( + Self::if_subnet_exist(netuid), + Error::::SubNetworkDoesNotExist + ); + + // Find the owner + let coldkey = SubnetOwner::::get(netuid); + + // Ensure the network is of STAO type. + ensure!( + Self::get_subnet_type(netuid) == SubnetType::STAO, + Error::::CannotBeConverted + ); + + // Ensure subnet_lock is above initial DTAO lock + let subnet_lock = SubnetLocked::::get(netuid); + ensure!( + subnet_lock >= Self::get_initial_lock_on_transition(), + Error::::NoStakeInSubnet + ); + + // Ensure another transition for this subnet is not already in progress + // TODOSDT: Only block for networks in transition (see commented below) + ensure!( + SubnetInTransition::::iter().next().is_none(), + Error::::TemporarilyNotAllowed + ); + // ensure!( + // SubnetInTransition::::get(netuid).is_none(), + // Error::::TranstinioAlreadyInProgress + // ); + + // All looks good: Add the starting transition record for this subnet + let subnet_creator = SubnetCreator::::get(netuid); + Self::do_start_stao_dtao_transition_no_checks( + netuid, + coldkey, + subnet_creator, + subnet_lock, + ); + + Ok(()) + } + + /// Starts stao->dtao transition for all STAO subnets + pub fn do_start_stao_dtao_transition_for_all() -> DispatchResult { + // Ensure no transition is already in progress + ensure!( + SubnetInTransition::::iter().next().is_none(), + Error::::TemporarilyNotAllowed + ); + + Self::get_all_subnet_netuids().iter() + .filter(|&netuid| *netuid != Self::get_root_netuid()) + .filter(|&netuid| Self::get_subnet_type(*netuid) == SubnetType::STAO) + .map(|netuid| { + // Find the owner + let coldkey = SubnetOwner::::get(netuid); + + // Ensure subnet_lock is above initial DTAO lock + let subnet_lock = SubnetLocked::::get(netuid); + ensure!( + subnet_lock >= Self::get_initial_lock_on_transition(), + Error::::NoStakeInSubnet + ); + + // All looks good: Add the starting transition record for this subnet + let subnet_creator = SubnetCreator::::get(netuid); + Self::do_start_stao_dtao_transition_no_checks( + *netuid, + coldkey, + subnet_creator, + subnet_lock, + ); + + Ok(()) + }) + .fold(Ok(()), |cumulative, local| { + match local { + Err(_) => local, + Ok(()) => cumulative + } + }) + } + + /// Function that starts transition: + /// - Create SubnetInTransition record + /// - Clear SubnetLocked and credit the balance to owner coldkey less 1 TAO + /// - Initialize dynamic pool as (tao reserve = 1, alpha reserve = 1, alpha out = 1) + /// - Do NOT clear TotalSubnetTAO because it is used later as a criteria for everyone + /// being unstaked + /// + fn do_start_stao_dtao_transition_no_checks( + netuid: u16, + coldkey: T::AccountId, + subnet_creator: T::AccountId, + subnet_lock: u64, + ) { + let num_subnets = Self::get_num_subnets() as u64; + let initial_total_tao = Self::get_initial_lock_on_transition(); + let initial_alpha_per_tao = num_subnets; + SubnetInTransition::::insert( + netuid, + SubnetTransition { + substake_current_key: SubStake::::iter_keys().next(), + coldkey: coldkey.clone(), + hotkey: subnet_creator, + initial_total_tao, + initial_alpha_per_tao, + } + ); + + // Release SubnetLock when transition is done, only reserve 1 TAO and + // produce exactly 1 Alpha res and 1 Alpha out + SubnetLocked::::insert(netuid, 0u64); + Self::add_balance_to_coldkey_account( + &coldkey, + subnet_lock.saturating_sub(initial_total_tao), + ); + } + + pub fn do_continue_stao_dtao_transition() -> Weight { + let max_block_weight = T::BlockWeights::get().max_block; + let mut weight = T::DbWeight::get().reads_writes(1, 0); + let mut counter: u32 = 0; + let mut tao_counter: u64 = 0; + + // Find if there's a network to convert with zero pending emission + let netuid = match SubnetInTransition::::iter_keys().filter(|&netuid| { + // If pending emission is non-zero, don't proceed. We need to wait until it is drained. + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 0)); + PendingEmission::::get(netuid) == 0 + }).next() { + Some(netuid) => netuid, + None => { + return weight; + } + }; + + // Get current SubnetTransition + if let Some(mut transition) = SubnetInTransition::::get(netuid) { + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 0)); + + // TODOSDT: SubStake can change for other subnets => no guarantees for iteration from a key + let mut finished = false; + while !finished { + if let Some(substake_key) = transition.substake_current_key { + // Find the key next after the current before making changes + let encoded_start_key = SubStake::::hashed_key_for(&substake_key); + transition.substake_current_key = SubStake::::iter_keys_from(encoded_start_key).next(); + + // Apply transition changes only for current netuid + if substake_key.2 == netuid { + // Unstake everyone - remove stake from state maps (including TotalSubnetTAO) + // Because the network was STAO, alpha to tao conversion is 1:1 + let stake = SubStake::::get(&substake_key); + Self::do_remove_stake_no_checks( + &substake_key.0, + &substake_key.1, + netuid, + stake, + ); + tao_counter = tao_counter.saturating_add(stake); + weight.saturating_accrue(T::DbWeight::get().reads_writes(5, 5)); + } + + // Continue iteration + if transition.substake_current_key.is_none() { + // Since we're blocking every operation with SubStake in the current + // implementation, we don't need to start over here + finished = true; + log::info!("STAO -> DTAO transition: Finished one iteration over SubStake map"); + + // TODOSDT: Start over (or think of something better) for mainnet + // version if all operations aren't blocked + // Start over because we are not guaranteed to go over all keys: + // SubStake is changing as we do this iteration + // transition.substake_current_key = SubStake::::iter_keys().next(); + // weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 0)); + } + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 0)); + + // See if we can stop early because we unstaked everyone + // TODOSDT: Didn't work when experimented with subnet 0. After full iteration, 1 rao remained. + // We need a better way to detect this. + if TotalSubnetTAO::::get(netuid) == 0 { + finished = true; + } + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 0)); + + counter = counter.saturating_add(1); + } else { + finished = true; + } + + // See if we have to stop because of weight. + // Do not allow this to take more than ~10% of block by compute time + // TODOSDT: Make it 10%, since we're blocking all operations on testnet now, setting it to 50% + if weight.ref_time() >= max_block_weight.ref_time() / 2 { + break; + } + } + + if finished { + let complete_weight = Self::do_complete_stao_dtao_transition( + netuid, + &transition + ); + weight.saturating_accrue(complete_weight); + } else { + SubnetInTransition::::insert( + netuid, + transition, + ); + weight.saturating_accrue(T::DbWeight::get().reads_writes(0, 1)); + } + log::info!( + "STAO -> DTAO transition processed {} entries with the total of {} TAO for subnet {}", + counter, tao_counter as f64 / 1000000000., netuid + ); + } + + weight + } + + fn do_complete_stao_dtao_transition( + netuid: u16, + transition: &SubnetTransition, + ) -> Weight { + // Remove transition record + SubnetInTransition::::remove(netuid); + + // Restake subnet owner with initial_total_tao + Self::increase_subnet_token_on_coldkey_hotkey_account( + &transition.coldkey, + &transition.hotkey, + netuid, + transition.initial_total_tao, + ); + + // Add initial stake to TotalSubnetTAO + TotalSubnetTAO::::insert(netuid, transition.initial_total_tao); + + // Mark the network as dynamic + IsDynamic::::insert(netuid, true); + + // Initialize dynamic pool + let lock_amount = transition.initial_total_tao; + let initial_tao_reserve: u64 = lock_amount; + let initial_dynamic_reserve: u64 = lock_amount; + let initial_dynamic_outstanding: u64 = lock_amount; + let initial_dynamic_k: u128 = + (initial_tao_reserve as u128) * (initial_dynamic_reserve as u128); + DynamicTAOReserve::::insert(netuid, initial_tao_reserve); + DynamicAlphaReserve::::insert(netuid, initial_dynamic_reserve); + DynamicAlphaOutstanding::::insert(netuid, initial_dynamic_outstanding); + DynamicK::::insert(netuid, initial_dynamic_k); + + // Reset subnet tempo + Tempo::::insert(netuid, T::InitialTempo::get()); + + log::info!( + "STAO -> DTAO transition completed for netuid {}", + netuid, + ); + + T::DbWeight::get().reads_writes(2, 12) + } } diff --git a/pallets/subtensor/src/stake_info.rs b/pallets/subtensor/src/stake_info.rs index d66235657..45724cb0a 100644 --- a/pallets/subtensor/src/stake_info.rs +++ b/pallets/subtensor/src/stake_info.rs @@ -1,8 +1,11 @@ use super::*; use frame_support::pallet_prelude::{Decode, Encode}; extern crate alloc; +use crate::types::TensorBytes; use codec::Compact; use sp_core::hexdisplay::AsBytesRef; +use sp_std::vec; +use sp_std::vec::Vec; #[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)] pub struct StakeInfo { @@ -11,6 +14,14 @@ pub struct StakeInfo { stake: Compact, } +#[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)] +pub struct SubnetStakeInfo { + hotkey: T::AccountId, + netuid: u16, + // Made public so we can access it during our tests. + pub stake: Compact, +} + impl Pallet { fn _get_stake_info_for_coldkeys( coldkeys: Vec, @@ -23,7 +34,7 @@ impl Pallet { for coldkey_ in coldkeys { let mut stake_info_for_coldkey: Vec> = Vec::new(); - for (hotkey, coldkey, stake) in >::iter() { + for ((coldkey, hotkey, _netuid), stake) in >::iter() { if coldkey == coldkey_ { stake_info_for_coldkey.push(StakeInfo { hotkey, @@ -39,17 +50,21 @@ impl Pallet { stake_info } + /// This function is used to retrieve the stake associated with a vector of coldkeys . + /// It iterates over the `Stake` storage map and returns the stake information for the UI. + /// + /// # Arguments: + /// * `coldkey_account_bytes`: Vec - The TensorBytes representing the coldkey account. pub fn get_stake_info_for_coldkeys( - coldkey_account_vecs: Vec>, + coldkey_account_bytes_vec: Vec, ) -> Vec<(T::AccountId, Vec>)> { let mut coldkeys: Vec = Vec::new(); - for coldkey_account_vec in coldkey_account_vecs { - if coldkey_account_vec.len() != 32 { + for coldkey_account_bytes in coldkey_account_bytes_vec { + if coldkey_account_bytes.as_ref().len() != 32 { continue; // Invalid coldkey } - let Ok(coldkey) = T::AccountId::decode(&mut coldkey_account_vec.as_bytes_ref()) else { - continue; - }; + let coldkey: AccountIdOf = + T::AccountId::decode(&mut coldkey_account_bytes.as_bytes_ref()).unwrap(); coldkeys.push(coldkey); } @@ -60,24 +75,214 @@ impl Pallet { Self::_get_stake_info_for_coldkeys(coldkeys) } - pub fn get_stake_info_for_coldkey(coldkey_account_vec: Vec) -> Vec> { - if coldkey_account_vec.len() != 32 { + /// This function is used to retrieve the all the stake associated with a coldkey + /// It iterates over the `Stake` storage map and returns the stake information for the UI. + /// + /// # Arguments: + /// * `coldkey_account_bytes`: TensorBytes - The TensorBytes representing the coldkey account. + pub fn get_stake_info_for_coldkey(coldkey_account_bytes: TensorBytes) -> Vec> { + if coldkey_account_bytes.as_ref().len() != 32 { return Vec::new(); // Invalid coldkey } - let Ok(coldkey) = T::AccountId::decode(&mut coldkey_account_vec.as_bytes_ref()) else { - return Vec::new(); - }; + let coldkey: AccountIdOf = + T::AccountId::decode(&mut coldkey_account_bytes.as_bytes_ref()).unwrap(); let stake_info = Self::_get_stake_info_for_coldkeys(vec![coldkey]); if stake_info.is_empty() { - Vec::new() // Invalid coldkey + // Invalid coldkey + Vec::new() } else { - let Some(first) = stake_info.first() else { - return Vec::new(); - }; + stake_info.first().unwrap().1.clone() + } + } + + /// This function is used to retrieve the stake associated with a coldkey on a specific subnet. + /// It iterates over the `SubStake` storage map and returns the stake information for the UI. + /// + /// # Arguments: + /// * `coldkey_account_bytes`: TensorBytes - The TensorBytes representing the coldkey account. + /// * `netuid`: u16 - The unique identifier of the network. + pub fn get_subnet_stake_info_for_coldkey( + coldkey_account_bytes: TensorBytes, + netuid: u16, + ) -> Vec> { + if coldkey_account_bytes.as_ref().len() != 32 { + return Vec::new(); // Invalid coldkey + } - first.1.clone() + let coldkey: T::AccountId = T::AccountId::decode(&mut coldkey_account_bytes.as_bytes_ref()) + .expect("Failed to decode AccountId"); + + // Filter `SubStake` storage map for entries matching the coldkey and netuid. + let mut subnet_stake_info: Vec> = Vec::new(); + for ((coldkey_iter, hotkey, subnet), stake) in SubStake::::iter() { + if coldkey == coldkey_iter && netuid == subnet { + subnet_stake_info.push(SubnetStakeInfo { + hotkey, + netuid, + stake: Compact(stake), + }); + } } + + subnet_stake_info + } + + /// This function is used to get the stake that a vector of coldkeys holds on the subnet. + /// It iterates over the `SubStake` storage map and returns the stake mapped to the UI. + /// + /// # Args: + /// * 'coldkey_account_byte_vecs': Vec: + /// - The vector of coldkey account TensorBytes. + /// * 'netuid': u16: + /// - The network uid. + /// + /// # Returns: + /// A vector of tuples, each containing a `T::AccountId` (coldkey) and a vector of `SubnetStakeInfo`. + pub fn get_subnet_stake_info_for_coldkeys( + coldkey_account_byte_vecs: Vec, + netuid: u16, + ) -> Vec<(T::AccountId, Vec>)> { + let mut results: Vec<(T::AccountId, Vec>)> = Vec::new(); + + for coldkey_account_vec in coldkey_account_byte_vecs { + if coldkey_account_vec.as_ref().len() != 32 { + continue; // Skip invalid coldkey + } + + let coldkey: T::AccountId = + T::AccountId::decode(&mut coldkey_account_vec.as_bytes_ref()) + .expect("Failed to decode AccountId"); + + // Filter `SubStake` storage map for entries matching the coldkey and netuid. + let mut subnet_stake_info: Vec> = Vec::new(); + for ((coldkey_iter, hotkey, subnet), stake) in SubStake::::iter() { + if coldkey == coldkey_iter && netuid == subnet { + subnet_stake_info.push(SubnetStakeInfo { + hotkey, + netuid, + stake: Compact(stake), // Wrap the stake in Compact + }); + } + } + + if !subnet_stake_info.is_empty() { + results.push((coldkey, subnet_stake_info)); + } + } + + results + } + + /// This function returns the total amount of stake on a subnet. + /// It returns a number, which is the sum of the stakes on the subnet identified by the subnet's UID. + /// + /// # Args: + /// * 'netuid': u16: + /// - The network uid. + /// + /// # Returns: + /// The total stake as a `Compact`. + pub fn get_total_subnet_stake(netuid: u16) -> Compact { + // Return the total stake wrapped in Compact. + Compact(TotalSubnetTAO::::get(netuid)) + } + + /// This function is used to get all the stake information for a given coldkey across all subnets. + /// It iterates over the `SubStake` storage map and returns a vector of all stakes associated with the coldkey. + /// + /// # Args: + /// * 'coldkey_account_bytes': TensorBytes: + /// - TensorBytes representation of the coldkey. + /// + /// # Returns: + /// A vector of tuples, each containing a hotkey (`T::AccountId`), netuid (`u16`), and stake amount (`Compact`). + pub fn get_all_stake_info_for_coldkey( + coldkey_account_bytes: TensorBytes, + ) -> Vec<(T::AccountId, u16, Compact)> { + if coldkey_account_bytes.as_ref().len() != 32 { + return Vec::new(); // Invalid coldkey, return empty vector + } + + let coldkey: T::AccountId = T::AccountId::decode(&mut coldkey_account_bytes.as_bytes_ref()) + .expect("Failed to decode AccountId"); + + // Initialize a vector to hold all stake information. + let mut all_stake_info: Vec<(T::AccountId, u16, Compact)> = Vec::new(); + + // Iterate over `SubStake` storage map for entries matching the coldkey and collect their information. + // If stake != 0 + for ((coldkey_iter, hotkey, netuid), stake) in SubStake::::iter() { + // if coldkey == coldkey_iter { + // all_stake_info.push((hotkey, netuid, Compact(stake))); + // } + if coldkey == coldkey_iter && stake != 0 { + all_stake_info.push((hotkey, netuid, Compact(stake))); + } + } + + // Return the vector of all stake information. + all_stake_info + } + + /// This function is used to retrieve all the subnet stake info associated with a coldkey across all subnets. + /// It iterates over the `SubStake` storage map and returns the stake information for the UI. + /// + /// # Arguments: + /// * `coldkey_account_bytes`: TensorBytes - The TensorBytes representing the coldkey account. + pub fn get_all_subnet_stake_info_for_coldkey( + coldkey_account_bytes: TensorBytes, + ) -> Vec> { + if coldkey_account_bytes.as_ref().len() != 32 { + return Vec::new(); // Invalid coldkey + } + + let coldkey: T::AccountId = T::AccountId::decode(&mut coldkey_account_bytes.as_bytes_ref()) + .expect("Failed to decode AccountId"); + + // Filter `SubStake` storage map for entries matching the coldkey across all subnets. + let mut all_subnet_stake_info: Vec> = Vec::new(); + for ((coldkey_iter, hotkey, netuid), stake) in SubStake::::iter() { + if coldkey == coldkey_iter { + all_subnet_stake_info.push(SubnetStakeInfo { + hotkey, + netuid, + stake: Compact(stake), + }); + } + } + + all_subnet_stake_info + } + + /// This function returns the total stake for each subnet. + /// It iterates over the `SubStake` storage map and calculates the sum of stakes for each subnet. + /// + /// # Returns: + /// A vector of tuples, each containing the subnet UID (`u16`) and the total stake (`Compact`) for that subnet. + pub fn get_total_stake_for_each_subnet() -> Vec<(u16, Compact)> { + // Initialize a vector to store the total stake for each subnet. + let mut subnet_stakes: Vec<(u16, u64)> = Vec::new(); + + // Iterate over the `SubStake` storage map and calculate the total stake for each subnet. + for ((_, _, subnet), stake) in SubStake::::iter() { + // Check if the subnet already exists in the vector. + if let Some(index) = subnet_stakes.iter().position(|(s, _)| *s == subnet) { + // If the subnet exists, update its total stake. + subnet_stakes[index].1 += stake; + } else { + // If the subnet doesn't exist, add a new entry to the vector. + subnet_stakes.push((subnet, stake)); + } + } + + // Convert the vector of tuples to the desired output format. + let total_stakes: Vec<(u16, Compact)> = subnet_stakes + .into_iter() + .map(|(subnet, total_stake)| (subnet, Compact(total_stake))) + .collect(); + + total_stakes } } diff --git a/pallets/subtensor/src/staking.rs b/pallets/subtensor/src/staking.rs index 08b65b8a7..28dedf287 100644 --- a/pallets/subtensor/src/staking.rs +++ b/pallets/subtensor/src/staking.rs @@ -1,6 +1,5 @@ use super::*; use frame_support::{ - storage::IterableStorageDoubleMap, traits::{ tokens::{ fungible::{Balanced as _, Inspect as _, Mutate as _}, @@ -9,91 +8,12 @@ use frame_support::{ Imbalance, }, }; +use sp_core::Get; +use sp_std::vec::Vec; +use substrate_fixed::types::I64F64; +use types::SubnetType; impl Pallet { - /// ---- The implementation for the extrinsic become_delegate: signals that this hotkey allows delegated stake. - /// - /// # Args: - /// * 'origin': (RuntimeOrigin): - /// - The signature of the caller's coldkey. - /// - /// * 'hotkey' (T::AccountId): - /// - The hotkey we are delegating (must be owned by the coldkey.) - /// - /// * 'take' (u16): - /// - The stake proportion that this hotkey takes from delegations. - /// - /// # Event: - /// * DelegateAdded; - /// - On successfully setting a hotkey as a delegate. - /// - /// # Raises: - /// * 'NotRegistered': - /// - The hotkey we are delegating is not registered on the network. - /// - /// * 'NonAssociatedColdKey': - /// - The hotkey we are delegating is not owned by the calling coldket. - /// - /// * 'TxRateLimitExceeded': - /// - Thrown if key has hit transaction rate limit - /// - pub fn do_become_delegate( - origin: T::RuntimeOrigin, - hotkey: T::AccountId, - take: u16, - ) -> dispatch::DispatchResult { - // --- 1. We check the coldkey signuture. - let coldkey = ensure_signed(origin)?; - log::info!( - "do_become_delegate( origin:{:?} hotkey:{:?}, take:{:?} )", - coldkey, - hotkey, - take - ); - - // --- 2. Ensure we are delegating an known key. - // --- 3. Ensure that the coldkey is the owner. - Self::do_take_checks(&coldkey, &hotkey)?; - - // --- 4. Ensure we are not already a delegate (dont allow changing delegate take.) - ensure!( - !Self::hotkey_is_delegate(&hotkey), - Error::::HotKeyAlreadyDelegate - ); - - // --- 5. Ensure we don't exceed tx rate limit - let block: u64 = Self::get_current_block_as_u64(); - ensure!( - !Self::exceeds_tx_rate_limit(Self::get_last_tx_block(&coldkey), block), - Error::::DelegateTxRateLimitExceeded - ); - - // --- 5.1 Ensure take is within the min ..= InitialDefaultTake (18%) range - let min_take = MinTake::::get(); - let max_take = MaxTake::::get(); - ensure!(take >= min_take, Error::::DelegateTakeTooLow); - ensure!(take <= max_take, Error::::DelegateTakeTooHigh); - - // --- 6. Delegate the key. - Self::delegate_hotkey(&hotkey, take); - - // Set last block for rate limiting - Self::set_last_tx_block(&coldkey, block); - Self::set_last_tx_block_delegate_take(&coldkey, block); - - // --- 7. Emit the staking event. - log::info!( - "DelegateAdded( coldkey:{:?}, hotkey:{:?}, take:{:?} )", - coldkey, - hotkey, - take - ); - Self::deposit_event(Event::DelegateAdded(coldkey, hotkey, take)); - - // --- 8. Ok and return. - Ok(()) - } - /// ---- The implementation for the extrinsic decrease_take /// /// # Args: @@ -103,6 +23,9 @@ impl Pallet { /// * 'hotkey' (T::AccountId): /// - The hotkey we are delegating (must be owned by the coldkey.) /// + /// * 'netuid' (u16): + /// - Subnet ID to decrease take for + /// /// * 'take' (u16): /// - The stake proportion that this hotkey takes from delegations for subnet ID. /// @@ -123,32 +46,36 @@ impl Pallet { pub fn do_decrease_take( origin: T::RuntimeOrigin, hotkey: T::AccountId, + netuid: u16, take: u16, ) -> dispatch::DispatchResult { // --- 1. We check the coldkey signature. let coldkey = ensure_signed(origin)?; log::info!( - "do_decrease_take( origin:{:?} hotkey:{:?}, take:{:?} )", + "do_decrease_take( origin:{:?} hotkey:{:?}, netuid:{:?}, take:{:?} )", coldkey, hotkey, + netuid, take ); // --- 2. Ensure we are delegating a known key. // Ensure that the coldkey is the owner. - Self::do_take_checks(&coldkey, &hotkey)?; + Self::do_account_checks(&coldkey, &hotkey)?; // --- 3. Ensure we are always strictly decreasing, never increasing take - if let Ok(current_take) = Delegates::::try_get(&hotkey) { + if let Ok(current_take) = DelegatesTake::::try_get(&hotkey, netuid) { ensure!(take < current_take, Error::::DelegateTakeTooLow); } // --- 3.1 Ensure take is within the min ..= InitialDefaultTake (18%) range let min_take = MinTake::::get(); + let max_take = MaxTake::::get(); ensure!(take >= min_take, Error::::DelegateTakeTooLow); + ensure!(take <= max_take, Error::::DelegateTakeTooHigh); // --- 4. Set the new take value. - Delegates::::insert(hotkey.clone(), take); + DelegatesTake::::insert(hotkey.clone(), netuid, take); // --- 5. Emit the take value. log::info!( @@ -172,6 +99,9 @@ impl Pallet { /// * 'hotkey' (T::AccountId): /// - The hotkey we are delegating (must be owned by the coldkey.) /// + /// * 'netuid' (u16): + /// - Subnet ID to decrease take for + /// /// * 'take' (u16): /// - The stake proportion that this hotkey takes from delegations for subnet ID. /// @@ -195,23 +125,25 @@ impl Pallet { pub fn do_increase_take( origin: T::RuntimeOrigin, hotkey: T::AccountId, + netuid: u16, take: u16, ) -> dispatch::DispatchResult { // --- 1. We check the coldkey signature. let coldkey = ensure_signed(origin)?; log::info!( - "do_increase_take( origin:{:?} hotkey:{:?}, take:{:?} )", + "do_increase_take( origin:{:?} hotkey:{:?}, netuid:{:?}, take:{:?} )", coldkey, hotkey, + netuid, take ); // --- 2. Ensure we are delegating a known key. // Ensure that the coldkey is the owner. - Self::do_take_checks(&coldkey, &hotkey)?; + Self::do_account_checks(&coldkey, &hotkey)?; // --- 3. Ensure we are strinctly increasing take - if let Ok(current_take) = Delegates::::try_get(&hotkey) { + if let Ok(current_take) = DelegatesTake::::try_get(&hotkey, netuid) { ensure!(take > current_take, Error::::DelegateTakeTooLow); } @@ -233,7 +165,7 @@ impl Pallet { Self::set_last_tx_block_delegate_take(&coldkey, block); // --- 6. Set the new take value. - Delegates::::insert(hotkey.clone(), take); + DelegatesTake::::insert(hotkey.clone(), netuid, take); // --- 7. Emit the take value. log::info!( @@ -248,52 +180,63 @@ impl Pallet { Ok(()) } - /// ---- The implementation for the extrinsic add_stake: Adds stake to a hotkey account. - /// - /// # Args: - /// * 'origin': (RuntimeOrigin): - /// - The signature of the caller's coldkey. - /// - /// * 'hotkey' (T::AccountId): - /// - The associated hotkey account. - /// - /// * 'stake_to_be_added' (u64): - /// - The amount of stake to be added to the hotkey staking account. - /// - /// # Event: - /// * StakeAdded; - /// - On the successfully adding stake to a global account. - /// - /// # Raises: - /// * 'NotEnoughBalanceToStake': - /// - Not enough balance on the coldkey to add onto the global account. - /// - /// * 'NonAssociatedColdKey': - /// - The calling coldkey is not associated with this hotkey. - /// - /// * 'BalanceWithdrawalError': - /// - Errors stemming from transaction pallet. - /// - /// * 'TxRateLimitExceeded': - /// - Thrown if key has hit transaction rate limit - /// + // ---- The implementation for the extrinsic add_stake: Adds stake to a hotkey account. + // + // # Args: + // * 'origin': (RuntimeOrigin): + // - The signature of the caller's coldkey. + // + // * 'hotkey' (T::AccountId): + // - The associated hotkey account. + // + // * 'stake_to_be_added' (u64): + // - The amount of stake to be added to the hotkey staking account. + // + // # Event: + // * StakeAdded; + // - On the successfully adding stake to a global account. + // + // # Raises: + // * 'CouldNotConvertToBalance': + // - Unable to convert the passed stake value to a balance. + // + // * 'NotEnoughBalanceToStake': + // - Not enough balance on the coldkey to add onto the global account. + // + // * 'NonAssociatedColdKey': + // - The calling coldkey is not associated with this hotkey. + // + // * 'BalanceWithdrawalError': + // - Errors stemming from transaction pallet. + // + // * 'TxRateLimitExceeded': + // - Thrown if key has hit transaction rate limit + // pub fn do_add_stake( origin: T::RuntimeOrigin, hotkey: T::AccountId, - stake_to_be_added: u64, + netuid: u16, + tao_to_be_added: u64, ) -> dispatch::DispatchResult { // We check that the transaction is signed by the caller and retrieve the T::AccountId coldkey information. let coldkey = ensure_signed(origin)?; log::info!( - "do_add_stake( origin:{:?} hotkey:{:?}, stake_to_be_added:{:?} )", + "do_add_stake( origin:{:?} hotkey:{:?}, netuid:{:?}, stake_to_be_added:{:?} )", coldkey, hotkey, - stake_to_be_added + netuid, + tao_to_be_added + ); + + // Ensure that the netuid exists. + ensure!( + Self::if_subnet_exist(netuid), + Error::::SubNetworkDoesNotExist ); // Ensure the callers coldkey has enough stake to perform the transaction. ensure!( - Self::can_remove_balance_from_coldkey_account(&coldkey, stake_to_be_added), + Self::can_remove_balance_from_coldkey_account(&coldkey, tao_to_be_added), Error::::NotEnoughBalanceToStake ); @@ -303,12 +246,24 @@ impl Pallet { Error::::HotKeyAccountNotExists ); - // Ensure that the hotkey allows delegation or that the hotkey is owned by the calling coldkey. + // Ensure that the hotkey allows delegation (registered on the network) + // or that the hotkey is owned by the calling coldkey. ensure!( - Self::hotkey_is_delegate(&hotkey) || Self::coldkey_owns_hotkey(&coldkey, &hotkey), + IsNetworkMember::::get(&hotkey, netuid) || Self::coldkey_owns_hotkey(&coldkey, &hotkey), Error::::HotKeyNotDelegateAndSignerNotOwnHotKey ); + // Ensure no type transition is in progress for subnet + // TODOSDT: Only block for networks in transition (see commented below) + ensure!( + SubnetInTransition::::iter().next().is_none(), + Error::::TemporarilyNotAllowed + ); + // ensure!( + // SubnetInTransition::::get(netuid).is_none(), + // Error::::TemporarilyNotAllowed + // ); + // Ensure we don't exceed stake rate limit let stakes_this_interval = Self::get_stakes_this_interval_for_coldkey_hotkey(&coldkey, &hotkey); @@ -322,8 +277,9 @@ impl Pallet { // If coldkey is not owner of the hotkey, it's a nomination stake. if !Self::coldkey_owns_hotkey(&coldkey, &hotkey) { - let total_stake_after_add = - Stake::::get(&hotkey, &coldkey).saturating_add(stake_to_be_added); + let current_stake_alpha = SubStake::::get((&coldkey, &hotkey, netuid)); + let current_stake_tao = Self::estimate_dynamic_unstake(netuid, current_stake_alpha); + let total_stake_after_add = current_stake_tao.saturating_add(tao_to_be_added); ensure!( total_stake_after_add >= NominatorMinRequiredStake::::get(), @@ -332,75 +288,87 @@ impl Pallet { } // Ensure the remove operation from the coldkey is a success. - let actual_amount_to_stake = - Self::remove_balance_from_coldkey_account(&coldkey, stake_to_be_added)?; + Self::remove_balance_from_coldkey_account(&coldkey, tao_to_be_added) + .map_err(|_| Error::::BalanceWithdrawalError)?; + + // Compute Dynamic Stake. + let dynamic_stake = Self::compute_dynamic_stake(netuid, tao_to_be_added); // If we reach here, add the balance to the hotkey. - Self::increase_stake_on_coldkey_hotkey_account(&coldkey, &hotkey, actual_amount_to_stake); + Self::increase_subnet_token_on_coldkey_hotkey_account(&coldkey, &hotkey, netuid, dynamic_stake); - // Set last block for rate limiting + // -- 12. Set last block for rate limiting let block: u64 = Self::get_current_block_as_u64(); Self::set_last_tx_block(&coldkey, block); - - // Emit the staking event. Self::set_stakes_this_interval_for_coldkey_hotkey( &coldkey, &hotkey, stakes_this_interval + 1, block, ); + + // --- 13. Emit the staking event. log::info!( - "StakeAdded( hotkey:{:?}, stake_to_be_added:{:?} )", + "StakeAdded( hotkey:{:?}, netuid:{:?}, stake_to_be_added:{:?} )", hotkey, - actual_amount_to_stake + netuid, + tao_to_be_added ); - Self::deposit_event(Event::StakeAdded(hotkey, actual_amount_to_stake)); + Self::deposit_event(Event::StakeAdded(hotkey, netuid, tao_to_be_added)); - // Ok and return. + // --- 14. Ok and return. Ok(()) } - /// ---- The implementation for the extrinsic remove_stake: Removes stake from a hotkey account and adds it onto a coldkey. + /// The implementation for the extrinsic remove_stake: Removes stake from a hotkey account and adds it onto a coldkey. /// /// # Args: /// * 'origin': (RuntimeOrigin): - /// - The signature of the caller's coldkey. + /// - The signature of the caller's coldkey. /// /// * 'hotkey' (T::AccountId): - /// - The associated hotkey account. + /// - The associated hotkey account. /// /// * 'stake_to_be_added' (u64): - /// - The amount of stake to be added to the hotkey staking account. + /// - The amount of stake to be added to the hotkey staking account. /// /// # Event: /// * StakeRemoved; - /// - On the successfully removing stake from the hotkey account. + /// - On the successfully removing stake from the hotkey account. /// /// # Raises: /// * 'NotRegistered': - /// - Thrown if the account we are attempting to unstake from is non existent. + /// - Thrown if the account we are attempting to unstake from is non existent. /// /// * 'NonAssociatedColdKey': - /// - Thrown if the coldkey does not own the hotkey we are unstaking from. + /// - Thrown if the coldkey does not own the hotkey we are unstaking from. /// /// * 'NotEnoughStakeToWithdraw': /// - Thrown if there is not enough stake on the hotkey to withdwraw this amount. /// /// * 'TxRateLimitExceeded': - /// - Thrown if key has hit transaction rate limit + /// - Thrown if key has hit transaction rate limit /// pub fn do_remove_stake( origin: T::RuntimeOrigin, hotkey: T::AccountId, - stake_to_be_removed: u64, + netuid: u16, + alpha_to_be_removed: u64, ) -> dispatch::DispatchResult { // We check the transaction is signed by the caller and retrieve the T::AccountId coldkey information. let coldkey = ensure_signed(origin)?; log::info!( - "do_remove_stake( origin:{:?} hotkey:{:?}, stake_to_be_removed:{:?} )", + "do_remove_stake( origin:{:?} netuid:{:?}, hotkey:{:?}, stake_to_be_removed:{:?} )", coldkey, hotkey, - stake_to_be_removed + netuid, + alpha_to_be_removed + ); + + // Ensure that the netuid exists. + ensure!( + Self::if_subnet_exist(netuid), + Error::::SubNetworkDoesNotExist ); // Ensure that the hotkey account exists this is only possible through registration. @@ -411,16 +379,16 @@ impl Pallet { // Ensure that the hotkey allows delegation or that the hotkey is owned by the calling coldkey. ensure!( - Self::hotkey_is_delegate(&hotkey) || Self::coldkey_owns_hotkey(&coldkey, &hotkey), + IsNetworkMember::::get(&hotkey, netuid) || Self::coldkey_owns_hotkey(&coldkey, &hotkey), Error::::HotKeyNotDelegateAndSignerNotOwnHotKey ); // Ensure that the stake amount to be removed is above zero. - ensure!(stake_to_be_removed > 0, Error::::StakeToWithdrawIsZero); + ensure!(alpha_to_be_removed > 0, Error::::StakeToWithdrawIsZero); // Ensure that the hotkey has enough stake to withdraw. ensure!( - Self::has_enough_stake(&coldkey, &hotkey, stake_to_be_removed), + Self::has_enough_stake(&coldkey, &hotkey, netuid, alpha_to_be_removed), Error::::NotEnoughStakeToWithdraw ); @@ -432,86 +400,278 @@ impl Pallet { Error::::UnstakeRateLimitExceeded ); - // We remove the balance from the hotkey. - Self::decrease_stake_on_coldkey_hotkey_account(&coldkey, &hotkey, stake_to_be_removed); + // If this is a nomination stake, check if total stake after removing will be above + // the minimum required stake. - // We add the balance to the coldkey. If the above fails we will not credit this coldkey. - Self::add_balance_to_coldkey_account(&coldkey, stake_to_be_removed); + // If coldkey is not owner of the hotkey, it's a nomination stake. + let block: u64 = Self::get_current_block_as_u64(); + if !Self::coldkey_owns_hotkey(&coldkey, &hotkey) { + let current_stake_alpha = SubStake::::get((&coldkey, &hotkey, netuid)); + let alpha_after_remove = current_stake_alpha.saturating_sub(alpha_to_be_removed); + let total_stake_after_remove = Self::estimate_dynamic_unstake(netuid, alpha_after_remove); - // If the stake is below the minimum, we clear the nomination from storage. - // This only applies to nominator stakes. - // If the coldkey does not own the hotkey, it's a nominator stake. - let new_stake = Self::get_stake_for_coldkey_and_hotkey(&coldkey, &hotkey); - Self::clear_small_nomination_if_required(&hotkey, &coldkey, new_stake); + ensure!( + total_stake_after_remove == 0 || total_stake_after_remove >= NominatorMinRequiredStake::::get(), + Error::::NomStakeBelowMinimumThreshold + ); + } else { + // If coldkey is owner of the hotkey, then ensure that subnet lock period has expired + let subnet_lock_period: u64 = Self::get_subnet_owner_lock_period(); + if Self::get_subnet_creator_hotkey(netuid) == hotkey { + ensure!( + block - Self::get_network_registered_block(netuid) >= subnet_lock_period, + Error::::SubnetCreatorLock + ) + } + } + + // Remove stake from state maps + Self::do_remove_stake_no_checks( + &coldkey, + &hotkey, + netuid, + alpha_to_be_removed, + ); // Set last block for rate limiting - let block: u64 = Self::get_current_block_as_u64(); Self::set_last_tx_block(&coldkey, block); - - // Emit the unstaking event. Self::set_stakes_this_interval_for_coldkey_hotkey( &coldkey, &hotkey, unstakes_this_interval + 1, block, ); + + // Emit the unstaking event. log::info!( "StakeRemoved( hotkey:{:?}, stake_to_be_removed:{:?} )", hotkey, - stake_to_be_removed + alpha_to_be_removed ); - Self::deposit_event(Event::StakeRemoved(hotkey, stake_to_be_removed)); + Self::deposit_event(Event::StakeRemoved(hotkey, netuid, alpha_to_be_removed)); - // Done and ok. + // --- 11. Done and ok. Ok(()) } - // Returns true if the passed hotkey allow delegative staking. - // - pub fn hotkey_is_delegate(hotkey: &T::AccountId) -> bool { - Delegates::::contains_key(hotkey) - } + /// Removes the stake assuming all checks have passed + /// + pub fn do_remove_stake_no_checks( + coldkey: &T::AccountId, + hotkey: &T::AccountId, + netuid: u16, + alpha_to_be_removed: u64, + ) { + // We remove the balance from the hotkey. + Self::decrease_subnet_token_on_coldkey_hotkey_account( + coldkey, + hotkey, + netuid, + alpha_to_be_removed, + ); - // Sets the hotkey as a delegate with take. - // - pub fn delegate_hotkey(hotkey: &T::AccountId, take: u16) { - Delegates::::insert(hotkey, take); + // Compute Dynamic unstake. + let tao_unstaked: u64 = Self::compute_dynamic_unstake(netuid, alpha_to_be_removed); + + // We add the balance to the coldkey. If the above fails we will not credit this coldkey. + Self::add_balance_to_coldkey_account(coldkey, tao_unstaked); } - // Returns the total amount of stake in the staking table. - // - pub fn get_total_stake() -> u64 { - TotalStake::::get() + /// Computes the dynamic unstake amount based on the current reserves and the stake to be removed. + /// This function is used to dynamically adjust the reserves of a subnet when unstaking occurs, + /// ensuring that the reserve ratios are maintained according to the bonding curve defined by `k`. + /// + /// # Arguments + /// * `netuid` - The unique identifier for the network (subnet) from which the stake is being removed. + /// * `stake_to_be_removed` - The amount of stake (in terms of alpha tokens) to be removed from the subnet. + /// + /// # Returns + /// * `u64` - The amount of tao tokens that will be released as a result of the unstake operation. + /// + /// # Details + /// The function first checks if the subnet identified by `netuid` supports dynamic staking. If not, + /// it simply returns the `stake_to_be_removed` as the amount of tao to be released, since no dynamic calculations are needed. + /// + /// For dynamic subnets, the function retrieves the current tao and alpha reserves (`tao_reserve` and `dynamic_reserve`), + /// along with the bonding curve constant `k`. It then calculates the new alpha reserve by adding the `stake_to_be_removed` + /// to the current alpha reserve. Using the bonding curve equation `tao_reserve = k / alpha_reserve`, it computes the new + /// tao reserve. + /// + /// The difference between the old and new tao reserves gives the amount of tao that will be released. This is calculated + /// by subtracting the new tao reserve from the old tao reserve. The function then updates the subnet's reserves in storage + /// and decrements the outstanding alpha by the amount of stake removed. + /// + /// # Panics + /// The function will panic if the new dynamic reserve calculation overflows, although this is highly unlikely due to the + /// use of saturating arithmetic operations. + pub fn compute_dynamic_unstake(netuid: u16, stake_to_be_removed: u64) -> u64 { + let subnet_type = Self::get_subnet_type(netuid); + + // STAO networks do not have dynamic stake + let stake_to_be_removed = match subnet_type { + SubnetType::DTAO => { + let tao_reserve = DynamicTAOReserve::::get(netuid); + let dynamic_reserve = DynamicAlphaReserve::::get(netuid); + let k = DynamicK::::get(netuid); + + // Calculate the new dynamic reserve after adding the stake to be removed + let new_dynamic_reserve = dynamic_reserve.saturating_add(stake_to_be_removed); + // Calculate the new tao reserve based on the new dynamic reserve + let new_tao_reserve: u64 = (k / (new_dynamic_reserve as u128)) as u64; + // Calculate the amount of tao to be pulled out based on the difference in tao reserves + let tao = tao_reserve.saturating_sub(new_tao_reserve); + + // Update the reserves with the new values + DynamicTAOReserve::::insert(netuid, new_tao_reserve); + DynamicAlphaReserve::::insert(netuid, new_dynamic_reserve); + DynamicAlphaOutstanding::::mutate(netuid, |outstanding| { + *outstanding -= stake_to_be_removed + }); // Decrement outstanding alpha. + + tao + } + SubnetType::STAO => stake_to_be_removed + }; + + TotalSubnetTAO::::mutate( + netuid, + |total_tao| *total_tao = total_tao.saturating_sub(stake_to_be_removed) + ); + + stake_to_be_removed } - // Increases the total amount of stake by the passed amount. - // - pub fn increase_total_stake(increment: u64) { - TotalStake::::put(Self::get_total_stake().saturating_add(increment)); + /// Returns the amount of TAO returned if stake_to_be_removed is unstaked + /// Doesn't make any state changes + /// + pub fn estimate_dynamic_unstake(netuid: u16, stake_to_be_removed: u64) -> u64 { + let subnet_type = Self::get_subnet_type(netuid); + + // STAO networks do not have dynamic stake + match subnet_type { + SubnetType::DTAO => { + let tao_reserve = DynamicTAOReserve::::get(netuid); + let dynamic_reserve = DynamicAlphaReserve::::get(netuid); + let k = DynamicK::::get(netuid); + + // Calculate the new dynamic reserve after adding the stake to be removed + let new_dynamic_reserve = dynamic_reserve.saturating_add(stake_to_be_removed); + // Calculate the new tao reserve based on the new dynamic reserve + let new_tao_reserve: u64 = (k / (new_dynamic_reserve as u128)) as u64; + // Calculate the amount of tao to be pulled out based on the difference in tao reserves + tao_reserve.saturating_sub(new_tao_reserve) + } + SubnetType::STAO => stake_to_be_removed + } } - // Decreases the total amount of stake by the passed amount. - // - pub fn decrease_total_stake(decrement: u64) { - TotalStake::::put(Self::get_total_stake().saturating_sub(decrement)); + /// Computes the dynamic stake amount based on the current reserves and the stake to be added. + /// This function is used to dynamically adjust the reserves of a subnet when staking occurs, + /// ensuring that the reserve ratios are maintained according to the bonding curve defined by `k`. + /// + /// # Arguments + /// * `netuid` - The unique identifier for the network (subnet) where the stake is being added. + /// * `stake_to_be_added` - The amount of stake (in terms of alpha tokens) to be added to the subnet. + /// + /// # Returns + /// * `u64` - The amount of dynamic token that will be pulled out as a result of the stake operation. + /// + /// # Details + /// The function first checks if the subnet identified by `netuid` supports dynamic staking. If not, + /// it simply returns the `stake_to_be_added` as the amount of dynamic token to be pulled out, since no dynamic calculations are needed. + /// + /// For dynamic subnets, the function retrieves the current tao and alpha reserves (`tao_reserve` and `dynamic_reserve`), + /// along with the bonding curve constant `k`. It then calculates the new tao reserve by adding the `stake_to_be_added` + /// to the current tao reserve. Using the bonding curve equation `dynamic_reserve = k / tao_reserve`, it computes the new + /// dynamic reserve. + /// + /// The difference between the old and new dynamic reserves gives the amount of dynamic token that will be pulled out. This is calculated + /// by subtracting the new dynamic reserve from the old dynamic reserve. The function then updates the subnet's reserves in storage + /// and increments the outstanding alpha by the amount of stake added. + /// + /// # Panics + /// The function will panic if the new tao reserve calculation overflows, although this is highly unlikely due to the + /// use of saturating arithmetic operations. + pub fn compute_dynamic_stake(netuid: u16, tao_to_be_added: u64) -> u64 { + let subnet_type = Self::get_subnet_type(netuid); + + TotalSubnetTAO::::mutate(netuid, |stake| *stake = stake.saturating_add(tao_to_be_added)); + + // STAO networks do not have dynamic stake + match subnet_type { + SubnetType::DTAO => { + let tao_reserve = DynamicTAOReserve::::get(netuid); + let dynamic_reserve = DynamicAlphaReserve::::get(netuid); + let k = DynamicK::::get(netuid); + + // Calculate the new tao reserve after adding the stake + let new_tao_reserve = tao_reserve.saturating_add(tao_to_be_added); + // Calculate the new dynamic reserve based on the new tao reserve + let new_dynamic_reserve: u64 = (k / (new_tao_reserve as u128)) as u64; + // Calculate the amount of dynamic token to be pulled out based on the difference in dynamic reserves + let dynamic_token = dynamic_reserve.saturating_sub(new_dynamic_reserve); + + // Update the reserves with the new values + DynamicTAOReserve::::insert(netuid, new_tao_reserve); + DynamicAlphaReserve::::insert(netuid, new_dynamic_reserve); + DynamicAlphaOutstanding::::mutate(netuid, |outstanding| *outstanding += dynamic_token); // Increment outstanding alpha. + + dynamic_token + } + SubnetType::STAO => tao_to_be_added + } } - // Returns the total amount of stake under a hotkey (delegative or otherwise) + // Getters for Dynamic terms // - pub fn get_total_stake_for_hotkey(hotkey: &T::AccountId) -> u64 { - TotalHotkeyStake::::get(hotkey) + pub fn get_total_stake_on_subnet(netuid: u16) -> u64 { + TotalSubnetTAO::::get(netuid) + } + pub fn get_tao_reserve(netuid: u16) -> u64 { + DynamicTAOReserve::::get(netuid) + } + pub fn set_tao_reserve(netuid: u16, amount: u64) { + DynamicTAOReserve::::insert(netuid, amount); + } + pub fn get_alpha_reserve(netuid: u16) -> u64 { + DynamicAlphaReserve::::get(netuid) + } + pub fn set_alpha_reserve(netuid: u16, amount: u64) { + DynamicAlphaReserve::::insert(netuid, amount); + } + pub fn get_alpha_outstanding(netuid: u16) -> u64 { + DynamicAlphaOutstanding::::get(netuid) + } + pub fn set_alpha_outstanding(netuid: u16, amount: u64) { + DynamicAlphaOutstanding::::insert(netuid, amount); + } + pub fn get_pool_k(netuid: u16) -> u128 { + DynamicK::::get(netuid) + } + pub fn get_alpha_issuance(netuid: u16) -> u64 { + DynamicAlphaIssuance::::get(netuid) + } + pub fn set_pool_k(netuid: u16, k: u128) { + DynamicK::::insert(netuid, k); + } + pub fn is_subnet_dynamic(netuid: u16) -> bool { + IsDynamic::::get(netuid) + } + pub fn set_subnet_dynamic(netuid: u16) { + IsDynamic::::insert(netuid, true) } - // Returns the total amount of stake held by the coldkey (delegative or otherwise) - // - pub fn get_total_stake_for_coldkey(coldkey: &T::AccountId) -> u64 { - TotalColdkeyStake::::get(coldkey) + // Returns the total amount of stake under a subnet (delegative or otherwise) + pub fn get_total_stake_for_subnet(target_subnet: u16) -> u64 { + SubStake::::iter() + .filter(|((_, _, subnet), _)| *subnet == target_subnet) + .fold(0, |acc, (_, stake)| acc.saturating_add(stake)) } - // Returns the stake under the cold - hot pairing in the staking table. + // Returns the total amount of stake under a hotkey for a subnet (delegative or otherwise) // - pub fn get_stake_for_coldkey_and_hotkey(coldkey: &T::AccountId, hotkey: &T::AccountId) -> u64 { - Stake::::get(hotkey, coldkey) + pub fn get_total_stake_for_hotkey_and_subnet(hotkey: &T::AccountId, netuid: u16) -> u64 { + TotalHotkeySubStake::::get(hotkey, netuid) } // Retrieves the total stakes for a given hotkey (account ID) for the current staking interval. @@ -558,7 +718,6 @@ impl Pallet { // pub fn create_account_if_non_existent(coldkey: &T::AccountId, hotkey: &T::AccountId) { if !Self::hotkey_account_exists(hotkey) { - Stake::::insert(hotkey, coldkey, 0); Owner::::insert(hotkey, coldkey); } } @@ -571,8 +730,56 @@ impl Pallet { // Returns the hotkey take // - pub fn get_hotkey_take(hotkey: &T::AccountId) -> u16 { - Delegates::::get(hotkey) + pub fn get_delegate_take(hotkey: &T::AccountId, netuid: u16) -> u16 { + DelegatesTake::::get(hotkey, netuid) + } + + pub fn do_set_delegate_takes( + origin: T::RuntimeOrigin, + hotkey: &T::AccountId, + takes: Vec<(u16, u16)>, + ) -> dispatch::DispatchResult { + let coldkey = ensure_signed(origin)?; + log::trace!( + "do_increase_take( origin:{:?} hotkey:{:?}, take:{:?} )", + coldkey, + hotkey, + takes + ); + + // --- 2. Ensure we are delegating a known key. + // Ensure that the coldkey is the owner. + Self::do_account_checks(&coldkey, hotkey)?; + let block: u64 = Self::get_current_block_as_u64(); + + for (netuid, take) in takes { + // Check if the subnet exists before setting the take. + ensure!( + Self::if_subnet_exist(netuid), + Error::::SubNetworkDoesNotExist + ); + + // Ensure the take does not exceed the initial default take. + let max_take = T::InitialDefaultTake::get(); + ensure!(take <= max_take, Error::::DelegateTakeTooHigh); + + // Enforce the rate limit (independently on do_add_stake rate limits) + ensure!( + !Self::exceeds_tx_delegate_take_rate_limit( + Self::get_last_tx_block_delegate_take(hotkey), + block + ), + Error::::DelegateTxRateLimitExceeded + ); + + // Insert the take into the storage. + DelegatesTake::::insert(hotkey, netuid, take); + } + + // Set last block for rate limiting after all takes are set + Self::set_last_tx_block_delegate_take(hotkey, block); + + Ok(()) } // Returns true if the hotkey account has been created. @@ -593,77 +800,180 @@ impl Pallet { // Returns true if the cold-hot staking account has enough balance to fufil the decrement. // - pub fn has_enough_stake(coldkey: &T::AccountId, hotkey: &T::AccountId, decrement: u64) -> bool { - Self::get_stake_for_coldkey_and_hotkey(coldkey, hotkey) >= decrement + pub fn has_enough_stake( + coldkey: &T::AccountId, + hotkey: &T::AccountId, + netuid: u16, + decrement: u64, + ) -> bool { + Self::get_subnet_stake_for_coldkey_and_hotkey(coldkey, hotkey, netuid) >= decrement } - // Increases the stake on the hotkey account under its owning coldkey. // - pub fn increase_stake_on_hotkey_account(hotkey: &T::AccountId, increment: u64) { - Self::increase_stake_on_coldkey_hotkey_account( + pub fn increase_subnet_token_on_hotkey_account(hotkey: &T::AccountId, netuid: u16, increment: u64) { + Self::increase_subnet_token_on_coldkey_hotkey_account( &Self::get_owning_coldkey_for_hotkey(hotkey), hotkey, + netuid, increment, ); } // Decreases the stake on the hotkey account under its owning coldkey. // - pub fn decrease_stake_on_hotkey_account(hotkey: &T::AccountId, decrement: u64) { - Self::decrease_stake_on_coldkey_hotkey_account( + pub fn decrease_subnet_token_on_hotkey_account(hotkey: &T::AccountId, netuid: u16, decrement: u64) { + Self::decrease_subnet_token_on_coldkey_hotkey_account( &Self::get_owning_coldkey_for_hotkey(hotkey), hotkey, + netuid, decrement, ); } - // Increases the stake on the cold - hot pairing by increment while also incrementing other counters. - // This function should be called rather than set_stake under account. + // Returns the subent stake under the cold - hot pairing in the staking table. // - pub fn increase_stake_on_coldkey_hotkey_account( + pub fn get_subnet_stake_for_coldkey_and_hotkey( coldkey: &T::AccountId, hotkey: &T::AccountId, - increment: u64, + netuid: u16, + ) -> u64 { + SubStake::::try_get((coldkey, hotkey, netuid)).unwrap_or(0) + } + + pub fn get_tao_per_alpha_price(netuid: u16) -> I64F64 { + let tao_reserve: u64 = DynamicTAOReserve::::get(netuid); + let alpha_reserve: u64 = DynamicAlphaReserve::::get(netuid); + if alpha_reserve == 0 { + I64F64::from_num(1.0) + } else { + I64F64::from_num(tao_reserve) / I64F64::from_num(alpha_reserve) + } + } + + /// Returns the stake under the cold - hot pairing in the staking table. + /// + /// TODO: We could probably store this total as a state variable + pub fn get_hotkey_global_dynamic_tao(hotkey: &T::AccountId) -> u64 { + let mut global_dynamic_tao: I64F64 = I64F64::from_num(0.0); + let netuids: Vec = Self::get_all_subnet_netuids(); + for netuid in netuids.iter() { + if IsDynamic::::get(*netuid) { + // Computes the proportion of TAO owned by this netuid. + let other_subnet_token: I64F64 = + I64F64::from_num(Self::get_total_stake_for_hotkey_and_subnet(hotkey, *netuid)); + let other_dynamic_outstanding: I64F64 = + I64F64::from_num(DynamicAlphaOutstanding::::get(*netuid)); + let other_tao_reserve: I64F64 = + I64F64::from_num(DynamicTAOReserve::::get(*netuid)); + let my_proportion: I64F64 = if other_dynamic_outstanding != 0 { + other_subnet_token / other_dynamic_outstanding + } else { + I64F64::from_num(1.0) + }; + global_dynamic_tao += my_proportion * other_tao_reserve; + } else { + // Computes the amount of TAO owned in the non dynamic subnet. + let other_subnet_token_tao: u64 = + Self::get_total_stake_for_hotkey_and_subnet(hotkey, *netuid); + global_dynamic_tao += I64F64::from_num(other_subnet_token_tao); + } + } + global_dynamic_tao.to_num::() + } + + /// Returns the stake under the cold - hot pairing in the staking table. + /// + pub fn get_nominator_global_dynamic_tao(coldkey: &T::AccountId, hotkey: &T::AccountId) -> u64 { + let mut global_dynamic_tao: I64F64 = I64F64::from_num(0.0); + let netuids: Vec = Self::get_all_subnet_netuids(); + for netuid in netuids.iter() { + if IsDynamic::::get(*netuid) { + // Computes the proportion of TAO owned by this netuid. + let other_subnet_token: I64F64 = I64F64::from_num( + Self::get_subnet_stake_for_coldkey_and_hotkey(coldkey, hotkey, *netuid), + ); + let other_dynamic_outstanding: I64F64 = + I64F64::from_num(DynamicAlphaOutstanding::::get(*netuid)); + let other_tao_reserve: I64F64 = + I64F64::from_num(DynamicTAOReserve::::get(*netuid)); + let my_proportion: I64F64 = if other_dynamic_outstanding != 0 { + other_subnet_token / other_dynamic_outstanding + } else { + I64F64::from_num(1.0) + }; + global_dynamic_tao += my_proportion * other_tao_reserve; + } else { + // Computes the amount of TAO owned in the stable subnet. + let other_subnet_token_tao: u64 = + Self::get_subnet_stake_for_coldkey_and_hotkey(coldkey, hotkey, *netuid); + global_dynamic_tao += I64F64::from_num(other_subnet_token_tao); + } + } + global_dynamic_tao.to_num::() + } + + /// Increases the stake on the cold - hot pairing by increment while also incrementing other counters. + /// This function should be called rather than set_stake under account. + /// + pub fn increase_subnet_token_on_coldkey_hotkey_account( + coldkey: &T::AccountId, + hotkey: &T::AccountId, + netuid: u16, + increment_alpha: u64, ) { - TotalColdkeyStake::::insert( - coldkey, - TotalColdkeyStake::::get(coldkey).saturating_add(increment), - ); - TotalHotkeyStake::::insert( - hotkey, - TotalHotkeyStake::::get(hotkey).saturating_add(increment), - ); - Stake::::insert( - hotkey, - coldkey, - Stake::::get(hotkey, coldkey).saturating_add(increment), - ); - TotalStake::::put(TotalStake::::get().saturating_add(increment)); + if increment_alpha == 0 { + return; + } + TotalHotkeySubStake::::mutate(hotkey, netuid, |stake| { + *stake = stake.saturating_add(increment_alpha); + }); + SubStake::::mutate((coldkey, hotkey, netuid), |stake| { + *stake = stake.saturating_add(increment_alpha) + }); + Staker::::insert(hotkey, coldkey, true); } - // Decreases the stake on the cold - hot pairing by the decrement while decreasing other counters. - // - pub fn decrease_stake_on_coldkey_hotkey_account( + /// Decreases the stake on the cold - hot pairing by the decrement while decreasing other counters. + /// + pub fn decrease_subnet_token_on_coldkey_hotkey_account( coldkey: &T::AccountId, hotkey: &T::AccountId, - decrement: u64, + netuid: u16, + decrement_alpha: u64, ) { - TotalColdkeyStake::::mutate(coldkey, |old| *old = old.saturating_sub(decrement)); - TotalHotkeyStake::::insert( - hotkey, - TotalHotkeyStake::::get(hotkey).saturating_sub(decrement), - ); - Stake::::insert( - hotkey, - coldkey, - Stake::::get(hotkey, coldkey).saturating_sub(decrement), - ); - TotalStake::::put(TotalStake::::get().saturating_sub(decrement)); + if decrement_alpha == 0 { + return; + } + let existing_total_stake = TotalHotkeySubStake::::get(&hotkey, netuid); + if existing_total_stake == decrement_alpha { + TotalHotkeySubStake::::remove(hotkey, netuid); + } else { + TotalHotkeySubStake::::insert( + hotkey, + netuid, + existing_total_stake.saturating_sub(decrement_alpha) + ); + } + + // Delete substake map entry if all stake is removed + let existing_substake = SubStake::::get((coldkey, hotkey, netuid)); + if existing_substake == decrement_alpha { + SubStake::::remove((coldkey, hotkey, netuid)); + } else { + SubStake::::insert( + (coldkey, hotkey, netuid), + existing_substake.saturating_sub(decrement_alpha), + ); + } + + // Delete staker map entry if all stake is removed + if SubStake::::iter_prefix((&coldkey, &hotkey)).next().is_none() { + Staker::::remove(hotkey, coldkey); + } } /// Empties the stake associated with a given coldkey-hotkey account pairing. - /// This function retrieves the current stake for the specified coldkey-hotkey pairing, - /// then subtracts this stake amount from both the TotalColdkeyStake and TotalHotkeyStake. + /// This function retrieves the current stake for the specified coldkey-hotkey pairing. /// It also removes the stake entry for the hotkey-coldkey pairing and adjusts the TotalStake /// and TotalIssuance by subtracting the removed stake amount. /// @@ -673,24 +983,40 @@ impl Pallet { /// /// * `coldkey` - A reference to the AccountId of the coldkey involved in the staking. /// * `hotkey` - A reference to the AccountId of the hotkey associated with the coldkey. - pub fn empty_stake_on_coldkey_hotkey_account( - coldkey: &T::AccountId, - hotkey: &T::AccountId, - ) -> u64 { - let current_stake: u64 = Stake::::get(hotkey, coldkey); - TotalColdkeyStake::::mutate(coldkey, |old| *old = old.saturating_sub(current_stake)); - TotalHotkeyStake::::mutate(hotkey, |stake| *stake = stake.saturating_sub(current_stake)); - Stake::::remove(hotkey, coldkey); - TotalStake::::mutate(|stake| *stake = stake.saturating_sub(current_stake)); - TotalIssuance::::mutate(|issuance| *issuance = issuance.saturating_sub(current_stake)); + pub fn empty_stake_on_coldkey_hotkey_account(coldkey: &T::AccountId, hotkey: &T::AccountId, netuid: u16) -> u64 { + let unstaked_tao = { + let stake = SubStake::::get((&coldkey, &hotkey, netuid)); + // Determine the type of network. + // For STAO stake is TAO, for DTAO stake is alpha and needs to be unstaked + match Self::get_subnet_type(netuid) { + SubnetType::DTAO => { + Self::compute_dynamic_unstake(netuid, stake) + }, + SubnetType::STAO => { + stake + } + } + }; + + // Clear SubStake entry + SubStake::::remove((coldkey, hotkey, netuid)); + + // Clear Staker entry + if SubStake::::iter_prefix((&coldkey, &hotkey)).next().is_none() { + Staker::::remove(hotkey, coldkey); + } - current_stake + // Reduce Total Issuance by total unstaked TAO + TotalIssuance::::mutate(|issuance| *issuance = issuance.saturating_sub(unstaked_tao)); + + unstaked_tao } /// Clears the nomination for an account, if it is a nominator account and the stake is below the minimum required threshold. pub fn clear_small_nomination_if_required( hotkey: &T::AccountId, coldkey: &T::AccountId, + netuid: u16, stake: u64, ) { // Verify if the account is a nominator account by checking ownership of the hotkey by the coldkey. @@ -699,7 +1025,7 @@ impl Pallet { if stake < Self::get_nominator_min_required_stake() { // Remove the stake from the nominator account. (this is a more forceful unstake operation which ) // Actually deletes the staking account. - let cleared_stake = Self::empty_stake_on_coldkey_hotkey_account(coldkey, hotkey); + let cleared_stake = Self::empty_stake_on_coldkey_hotkey_account(coldkey, hotkey, netuid); // Add the stake to the coldkey account. Self::add_balance_to_coldkey_account(coldkey, cleared_stake); } @@ -712,8 +1038,8 @@ impl Pallet { /// used with caution. pub fn clear_small_nominations() { // Loop through all staking accounts to identify and clear nominations below the minimum stake. - for (hotkey, coldkey, stake) in Stake::::iter() { - Self::clear_small_nomination_if_required(&hotkey, &coldkey, stake); + for ((coldkey, hotkey, netuid), stake) in SubStake::::iter() { + Self::clear_small_nomination_if_required(&hotkey, &coldkey, netuid, stake); } } @@ -742,16 +1068,17 @@ impl Pallet { } // This bit is currently untested. @todo - - T::Currency::can_withdraw(coldkey, amount) - .into_result(false) - .is_ok() + T::Currency::can_withdraw( + coldkey, + amount, + ) + .into_result(false) + .is_ok() } pub fn get_coldkey_balance( coldkey: &T::AccountId, - ) -> <::Currency as fungible::Inspect<::AccountId>>::Balance - { + ) -> <::Currency as fungible::Inspect<::AccountId>>::Balance { T::Currency::reducible_balance(coldkey, Preservation::Expendable, Fortitude::Polite) } @@ -765,14 +1092,14 @@ impl Pallet { } let credit = T::Currency::withdraw( - coldkey, - amount, - Precision::BestEffort, - Preservation::Preserve, - Fortitude::Polite, - ) - .map_err(|_| Error::::BalanceWithdrawalError)? - .peek(); + coldkey, + amount, + Precision::BestEffort, + Preservation::Preserve, + Fortitude::Polite, + ) + .map_err(|_| Error::::BalanceWithdrawalError)? + .peek(); if credit == 0 { return Err(Error::::ZeroBalanceAfterWithdrawn.into()); @@ -783,16 +1110,37 @@ impl Pallet { pub fn unstake_all_coldkeys_from_hotkey_account(hotkey: &T::AccountId) { // Iterate through all coldkeys that have a stake on this hotkey account. - for (delegate_coldkey_i, stake_i) in - as IterableStorageDoubleMap>::iter_prefix( + let all_netuids: Vec = Self::get_all_subnet_netuids(); + for (coldkey_i, _) in + Staker::::iter_prefix( hotkey, ) { - // Remove the stake from the coldkey - hotkey pairing. - Self::decrease_stake_on_coldkey_hotkey_account(&delegate_coldkey_i, hotkey, stake_i); - - // Add the balance to the coldkey account. - Self::add_balance_to_coldkey_account(&delegate_coldkey_i, stake_i); + for &netuid_i in all_netuids.iter() { + // Get the subnet type + let subnet_type = Self::get_subnet_type(netuid_i); + + // Get the stake on this uid. + let stake_alpha_i = + Self::get_subnet_stake_for_coldkey_and_hotkey(&coldkey_i, hotkey, netuid_i); + + let stake_tao_i = match subnet_type { + SubnetType::DTAO => { + Self::compute_dynamic_unstake(netuid_i, stake_alpha_i) + }, + SubnetType::STAO => { + stake_alpha_i + }, + }; + + // Remove the stake from the coldkey - hotkey pairing. + Self::decrease_subnet_token_on_coldkey_hotkey_account( + &coldkey_i, hotkey, netuid_i, stake_alpha_i + ); + + // Add the balance to the coldkey account. + Self::add_balance_to_coldkey_account(&coldkey_i, stake_tao_i); + } } } } diff --git a/pallets/subtensor/src/subnet_info.rs b/pallets/subtensor/src/subnet_info.rs index cf6b66aea..f13965c43 100644 --- a/pallets/subtensor/src/subnet_info.rs +++ b/pallets/subtensor/src/subnet_info.rs @@ -1,8 +1,9 @@ use super::*; use frame_support::pallet_prelude::{Decode, Encode}; -use frame_support::storage::IterableStorageMap; extern crate alloc; use codec::Compact; +use sp_std::vec::Vec; +use crate::dynamic_pool_info::DynamicPoolInfoV2; #[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)] pub struct SubnetInfo { @@ -21,7 +22,7 @@ pub struct SubnetInfo { tempo: Compact, network_modality: Compact, network_connect: Vec<[u16; 2]>, - emission_values: Compact, + pub emission_values: Compact, burn: Compact, owner: T::AccountId, } @@ -54,6 +55,23 @@ pub struct SubnetHyperparams { commit_reveal_weights_enabled: bool, } +#[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)] +pub struct SubnetInfoV2 { + netuid: u16, + owner: T::AccountId, + max_allowed_validators: u16, + scaling_law_power: u16, + subnetwork_n: u16, + max_allowed_uids: u16, + blocks_since_last_step: Compact, + network_modality: u16, + emission_values: Compact, + burn: Compact, + tao_locked: Compact, + hyperparameters: SubnetHyperparams, + dynamic_pool: Option, +} + impl Pallet { pub fn get_subnet_info(netuid: u16) -> Option> { if !Self::if_subnet_exist(netuid) { @@ -107,7 +125,7 @@ impl Pallet { pub fn get_subnets_info() -> Vec>> { let mut subnet_netuids = Vec::::new(); let mut max_netuid: u16 = 0; - for (netuid, added) in as IterableStorageMap>::iter() { + for (netuid, added) in NetworksAdded::::iter() { if added { subnet_netuids.push(netuid); if netuid > max_netuid { @@ -126,11 +144,47 @@ impl Pallet { subnets_info } - pub fn get_subnet_hyperparams(netuid: u16) -> Option { + pub fn get_subnet_info_v2(netuid: u16) -> Option> { if !Self::if_subnet_exist(netuid) { return None; } + let max_allowed_validators = Self::get_max_allowed_validators(netuid); + let scaling_law_power = Self::get_scaling_law_power(netuid); + let subnetwork_n = Self::get_subnetwork_n(netuid); + let max_allowed_uids = Self::get_max_allowed_uids(netuid); + let blocks_since_last_step = Self::get_blocks_since_last_step(netuid); + let network_modality = >::get(netuid); + let emission_values = Self::get_emission_value(netuid); + let burn: Compact = Self::get_burn_as_u64(netuid).into(); + + Some(SubnetInfoV2 { + netuid: netuid.into(), + owner: Self::get_subnet_owner(netuid), + max_allowed_validators: max_allowed_validators.into(), + scaling_law_power: scaling_law_power.into(), + subnetwork_n: subnetwork_n.into(), + max_allowed_uids: max_allowed_uids.into(), + blocks_since_last_step: Compact(blocks_since_last_step as u32), + network_modality: network_modality.into(), + emission_values: emission_values.into(), + burn, + tao_locked: Self::get_total_stake_on_subnet(netuid).into(), + hyperparameters: Self::get_subnet_hyperparams_no_checks(netuid), + dynamic_pool: Self::get_dynamic_pool_info_v2(netuid), + }) + } + + pub fn get_subnets_info_v2() -> Vec> { + Self::get_all_subnet_netuids() + .iter() + .map(|&netuid| Self::get_subnet_info_v2(netuid)) + .filter(|info| info.is_some()) + .map(|info| info.unwrap()) + .collect() + } + + pub fn get_subnet_hyperparams_no_checks(netuid: u16) -> SubnetHyperparams { let rho = Self::get_rho(netuid); let kappa = Self::get_kappa(netuid); let immunity_period = Self::get_immunity_period(netuid); @@ -156,7 +210,7 @@ impl Pallet { let commit_reveal_weights_interval = Self::get_commit_reveal_weights_interval(netuid); let commit_reveal_weights_enabled = Self::get_commit_reveal_weights_enabled(netuid); - Some(SubnetHyperparams { + SubnetHyperparams { rho: rho.into(), kappa: kappa.into(), immunity_period: immunity_period.into(), @@ -181,6 +235,18 @@ impl Pallet { difficulty: difficulty.into(), commit_reveal_weights_interval: commit_reveal_weights_interval.into(), commit_reveal_weights_enabled, - }) + } + } + + pub fn get_subnet_hyperparams(netuid: u16) -> Option { + if Self::if_subnet_exist(netuid) { + Some(Self::get_subnet_hyperparams_no_checks(netuid)) + } else { + None + } + } + + pub fn get_subnet_limit() -> u16 { + SubnetLimit::::get() } } diff --git a/pallets/subtensor/src/types.rs b/pallets/subtensor/src/types.rs new file mode 100644 index 000000000..44f0a360e --- /dev/null +++ b/pallets/subtensor/src/types.rs @@ -0,0 +1,62 @@ +#![cfg_attr(not(feature = "std"), no_std)] +extern crate alloc; +#[allow(unused_imports)] +use alloc::vec::Vec; +use scale_info::TypeInfo; +use serde::{Deserialize, Serialize}; +use sp_core::hexdisplay::AsBytesRef; +use sp_core::Bytes; +use sp_runtime::codec::{Decode, Encode, MaxEncodedLen}; + +/// Wrapper for Bytes that implements TypeInfo +/// Needed as Bytes doesnt implement it anymore , and the node can't serialize Vec +#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, Serialize, Deserialize)] +pub struct TensorBytes(pub Bytes); + +impl TypeInfo for TensorBytes { + type Identity = Self; + + fn type_info() -> scale_info::Type { + scale_info::Type::builder() + .path(scale_info::Path::new("TensorBytes", module_path!())) + .composite( + scale_info::build::Fields::unnamed() + .field(|f| f.ty::>().type_name("Bytes")), + ) + } +} + +impl AsRef<[u8]> for TensorBytes { + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + +impl AsBytesRef for TensorBytes { + fn as_bytes_ref(&self) -> &[u8] { + &self.0 + } +} + +impl From> for TensorBytes { + fn from(bytes: Vec) -> Self { + TensorBytes(sp_core::Bytes(bytes)) + } +} + +#[derive(PartialEq)] +pub enum SubnetType { + STAO, + DTAO +} + +/// Subnet type transtion state +/// +#[derive(Encode, Decode, TypeInfo, MaxEncodedLen, Debug)] +pub struct SubnetTransition { + pub substake_current_key: Option<(AccountId, AccountId, u16)>, + pub coldkey: AccountId, + pub hotkey: AccountId, + pub initial_total_tao: u64, + pub initial_alpha_per_tao: u64, +} diff --git a/pallets/subtensor/src/uids.rs b/pallets/subtensor/src/uids.rs index 4ae2c24de..465513030 100644 --- a/pallets/subtensor/src/uids.rs +++ b/pallets/subtensor/src/uids.rs @@ -1,7 +1,7 @@ use super::*; use frame_support::storage::IterableStorageDoubleMap; -use frame_support::storage::IterableStorageMap; use sp_std::vec; +use sp_std::vec::Vec; impl Pallet { /// Returns the number of filled slots on a network. @@ -116,23 +116,12 @@ impl Pallet { /// Returns the stake of the uid on network or 0 if it doesnt exist. /// pub fn get_stake_for_uid_and_subnetwork(netuid: u16, neuron_uid: u16) -> u64 { - if let Ok(hotkey) = Self::get_hotkey_for_net_and_uid(netuid, neuron_uid) { - Self::get_total_stake_for_hotkey(&hotkey) - } else { - 0 + match Self::get_hotkey_for_net_and_uid(netuid, neuron_uid) { + Ok(hotkey) => SubStake::::get((Owner::::get(&hotkey), &hotkey, netuid)), + Err(_) => 0, } } - /// Return the total number of subnetworks available on the chain. - /// - pub fn get_number_of_subnets() -> u16 { - let mut number_of_subnets: u16 = 0; - for (_, _) in as IterableStorageMap>::iter() { - number_of_subnets += 1; - } - number_of_subnets - } - /// Return a list of all networks a hotkey is registered on. /// pub fn get_registered_networks_for_hotkey(hotkey: &T::AccountId) -> Vec { diff --git a/pallets/subtensor/src/utils.rs b/pallets/subtensor/src/utils.rs index 54b7818c9..f6def4921 100644 --- a/pallets/subtensor/src/utils.rs +++ b/pallets/subtensor/src/utils.rs @@ -1,6 +1,8 @@ use super::*; use crate::system::{ensure_root, ensure_signed_or_root}; +use sp_std::vec::Vec; use sp_core::U256; +use substrate_fixed::types::I64F64; impl Pallet { pub fn ensure_subnet_owner_or_root( @@ -163,9 +165,21 @@ impl Pallet { pub fn set_stake_interval(block: u64) { StakeInterval::::set(block); } + pub fn get_stake_weight_for_uid(netuid: u16, uid: u16) -> u16 { + let vec = StakeWeight::::get(netuid); + if (uid as usize) < vec.len() { + vec[uid as usize] + } else { + 0 + } + } pub fn get_rank_for_uid(netuid: u16, uid: u16) -> u16 { let vec = Rank::::get(netuid); - vec.get(uid as usize).copied().unwrap_or(0) + if (uid as usize) < vec.len() { + vec[uid as usize] + } else { + 0 + } } pub fn get_trust_for_uid(netuid: u16, uid: u16) -> u16 { let vec = Trust::::get(netuid); @@ -251,10 +265,26 @@ impl Pallet { BlockAtRegistration::::get(netuid, neuron_uid) } - // ======================== - // ===== Take checks ====== - // ======================== - pub fn do_take_checks(coldkey: &T::AccountId, hotkey: &T::AccountId) -> Result<(), Error> { + // ============================== + // ==== Global Stake Weight ===== + // ============================== + pub fn get_global_stake_weight() -> u16 { + GlobalStakeWeight::::get() + } + pub fn get_global_stake_weight_float() -> I64F64 { + I64F64::from_num(GlobalStakeWeight::::get()) / I64F64::from_num(u16::MAX) + } + pub fn set_global_stake_weight(global_stake_weight: u16) { + GlobalStakeWeight::::put(global_stake_weight); + } + + // =========================== + // ===== Account checks ====== + // =========================== + pub fn do_account_checks( + coldkey: &T::AccountId, + hotkey: &T::AccountId, + ) -> Result<(), Error> { // Ensure we are delegating a known key. ensure!( Self::hotkey_account_exists(hotkey), @@ -306,19 +336,15 @@ impl Pallet { // === Token Management === // ======================== pub fn burn_tokens(amount: u64) { - TotalIssuance::::put(TotalIssuance::::get().saturating_sub(amount)); + TotalIssuance::::mutate(|issuance| *issuance = issuance.saturating_sub(amount)); } pub fn coinbase(amount: u64) { - TotalIssuance::::put(TotalIssuance::::get().saturating_add(amount)); + TotalIssuance::::mutate(|issuance| *issuance = issuance.saturating_add(amount)); } pub fn get_default_take() -> u16 { // Default to maximum MaxTake::::get() } - pub fn set_max_take(default_take: u16) { - MaxTake::::put(default_take); - Self::deposit_event(Event::DefaultTakeSet(default_take)); - } pub fn get_min_take() -> u16 { MinTake::::get() } @@ -331,6 +357,20 @@ impl Pallet { SubnetLocked::::get(netuid) } + // =========================== + // ========= Staking ========= + // =========================== + + // Returns the stake under the cold - hot pairing in the staking table. + // + pub fn get_total_stake_for_hotkey_and_coldkey( + hotkey: &T::AccountId, + coldkey: &T::AccountId, + ) -> u64 { + SubStake::::iter_prefix((coldkey, hotkey)) + .fold(0, |sum, (_, stake)| sum + stake) + } + // ======================== // ========= Sudo ========= // ======================== @@ -600,6 +640,9 @@ impl Pallet { )); } + pub fn get_subnet_creator_hotkey(netuid: u16) -> T::AccountId { + SubnetCreator::::get(netuid) + } pub fn get_subnet_owner(netuid: u16) -> T::AccountId { SubnetOwner::::get(netuid) } @@ -651,6 +694,46 @@ impl Pallet { SubnetOwner::::iter_values().any(|owner| *address == owner) } + pub fn get_subnet_owner_lock_period() -> u64 { + SubnetOwnerLockPeriod::::get() + } + + pub fn set_subnet_owner_lock_period(subnet_owner_lock_period: u64) { + SubnetOwnerLockPeriod::::set(subnet_owner_lock_period); + } + + /// Calculates the slippage for both staking and unstaking operations. + /// + /// # Arguments + /// * `netuid` - The unique identifier for the network (subnet). + /// * `stake_change` - The amount of stake being added (positive) or removed (negative). + /// + /// # Returns + /// * `I64F64` - The slippage amount, which is the difference in price. + pub fn calculate_slippage( + netuid: u16, + stake_change: i64, // Positive for staking, negative for unstaking + ) -> I64F64 { + let tao_reserve = DynamicTAOReserve::::get(netuid); + let dynamic_reserve = DynamicAlphaReserve::::get(netuid); + let k = DynamicK::::get(netuid); + + // Calculate new reserves based on whether stake is being added or removed + let new_dynamic_reserve = if stake_change > 0 { + dynamic_reserve.saturating_add(stake_change as u64) + } else { + dynamic_reserve.saturating_sub(stake_change.unsigned_abs()) + }; + + let new_tao_reserve = (k / new_dynamic_reserve as u128) as u64; + + let initial_price = I64F64::from_num(tao_reserve) / I64F64::from_num(dynamic_reserve); + let new_price = I64F64::from_num(new_tao_reserve) / I64F64::from_num(new_dynamic_reserve); + + // Slippage is the difference in price + initial_price - new_price + } + pub fn get_nominator_min_required_stake() -> u64 { NominatorMinRequiredStake::::get() } diff --git a/pallets/subtensor/src/weights.rs b/pallets/subtensor/src/weights.rs index 72c811f80..50b8777cd 100644 --- a/pallets/subtensor/src/weights.rs +++ b/pallets/subtensor/src/weights.rs @@ -3,6 +3,7 @@ use crate::math::*; use sp_core::H256; use sp_runtime::traits::{BlakeTwo256, Hash}; use sp_std::vec; +use sp_std::vec::Vec; impl Pallet { /// ---- The implementation for committing weight hashes. @@ -228,7 +229,7 @@ impl Pallet { // --- 6. Check to see if the hotkey has enought stake to set weights. ensure!( - Self::get_total_stake_for_hotkey(&hotkey) >= Self::get_weights_min_stake(), + Self::check_weights_min_stake(&hotkey), Error::::NotEnoughStakeToSetWeights ); diff --git a/pallets/subtensor/tests/block_step.rs b/pallets/subtensor/tests/block_step.rs index e1b4fe1de..12a45aa30 100644 --- a/pallets/subtensor/tests/block_step.rs +++ b/pallets/subtensor/tests/block_step.rs @@ -3,123 +3,10 @@ use frame_support::assert_ok; use frame_system::Config; use mock::*; use sp_core::U256; +use substrate_fixed::types::I64F64; -#[test] -#[allow(clippy::unwrap_used)] -fn test_loaded_emission() { - new_test_ext(1).execute_with(|| { - let n: u16 = 100; - let netuid: u16 = 1; - let tempo: u16 = 10; - let netuids: Vec = vec![1]; - let emission: Vec = vec![1000000000]; - add_network(netuid, tempo, 0); - SubtensorModule::set_max_allowed_uids(netuid, n); - SubtensorModule::set_adjustment_alpha(netuid, 58000); // Set to old value. - SubtensorModule::set_emission_values(&netuids, emission).unwrap(); - for i in 0..n { - SubtensorModule::append_neuron(netuid, &U256::from(i), 0); - } - assert!(SubtensorModule::get_loaded_emission_tuples(netuid).is_none()); - - // Try loading at block 0 - let block: u64 = 0; - assert_eq!( - SubtensorModule::blocks_until_next_epoch(netuid, tempo, block), - 8 - ); - SubtensorModule::generate_emission(block); - assert!(SubtensorModule::get_loaded_emission_tuples(netuid).is_none()); - - // Try loading at block = 9; - let block: u64 = 8; - assert_eq!( - SubtensorModule::blocks_until_next_epoch(netuid, tempo, block), - 0 - ); - SubtensorModule::generate_emission(block); - assert!(SubtensorModule::get_loaded_emission_tuples(netuid).is_some()); - assert_eq!( - SubtensorModule::get_loaded_emission_tuples(netuid) - .unwrap() - .len(), - n as usize - ); - - // Try draining the emission tuples - // None remaining because we are at epoch. - let block: u64 = 8; - SubtensorModule::drain_emission(block); - assert!(SubtensorModule::get_loaded_emission_tuples(netuid).is_none()); - - // Generate more emission. - SubtensorModule::generate_emission(8); - assert_eq!( - SubtensorModule::get_loaded_emission_tuples(netuid) - .unwrap() - .len(), - n as usize - ); - - for block in 9..19 { - let mut n_remaining: usize = 0; - let mut n_to_drain: usize = 0; - if let Some(tuples) = SubtensorModule::get_loaded_emission_tuples(netuid) { - n_remaining = tuples.len(); - n_to_drain = - SubtensorModule::tuples_to_drain_this_block(netuid, tempo, block, tuples.len()); - } - SubtensorModule::drain_emission(block); // drain it with 9 more blocks to go - if let Some(tuples) = SubtensorModule::get_loaded_emission_tuples(netuid) { - assert_eq!(tuples.len(), n_remaining - n_to_drain); - } - log::info!("n_to_drain: {:?}", n_to_drain); - log::info!( - "SubtensorModule::get_loaded_emission_tuples( netuid ).len(): {:?}", - n_remaining - n_to_drain - ); - } - }) -} - -#[test] -fn test_tuples_to_drain_this_block() { - new_test_ext(1).execute_with(|| { - // pub fn tuples_to_drain_this_block( netuid: u16, tempo: u16, block_number: u64, n_remaining: usize ) -> usize { - assert_eq!(SubtensorModule::tuples_to_drain_this_block(0, 1, 0, 10), 10); // drain all epoch block. - assert_eq!(SubtensorModule::tuples_to_drain_this_block(0, 0, 0, 10), 10); // drain all no tempo. - assert_eq!(SubtensorModule::tuples_to_drain_this_block(0, 10, 0, 10), 2); // drain 10 / ( 10 / 2 ) = 2 - assert_eq!(SubtensorModule::tuples_to_drain_this_block(0, 20, 0, 10), 1); // drain 10 / ( 20 / 2 ) = 1 - assert_eq!(SubtensorModule::tuples_to_drain_this_block(0, 10, 0, 20), 5); // drain 20 / ( 9 / 2 ) = 5 - assert_eq!(SubtensorModule::tuples_to_drain_this_block(0, 20, 0, 0), 0); // nothing to drain. - assert_eq!(SubtensorModule::tuples_to_drain_this_block(0, 10, 1, 20), 5); // drain 19 / ( 10 / 2 ) = 4 - assert_eq!( - SubtensorModule::tuples_to_drain_this_block(0, 10, 10, 20), - 4 - ); // drain 19 / ( 10 / 2 ) = 4 - assert_eq!( - SubtensorModule::tuples_to_drain_this_block(0, 10, 15, 20), - 10 - ); // drain 19 / ( 10 / 2 ) = 4 - assert_eq!( - SubtensorModule::tuples_to_drain_this_block(0, 10, 19, 20), - 20 - ); // drain 19 / ( 10 / 2 ) = 4 - assert_eq!( - SubtensorModule::tuples_to_drain_this_block(0, 10, 20, 20), - 20 - ); // drain 19 / ( 10 / 2 ) = 4 - for i in 0..10 { - for j in 0..10 { - for k in 0..10 { - for l in 0..10 { - assert!(SubtensorModule::tuples_to_drain_this_block(i, j, k, l) <= 10); - } - } - } - } - }) -} +#[macro_use] +mod helpers; #[test] fn test_blocks_until_epoch() { @@ -804,69 +691,485 @@ fn test_burn_adjustment_case_e_zero_registrations() { }); } +// To run this test with logging and Rust backtrace enabled, and to see all output (stdout/stderr) without capturing by the test runner, use: +// RUST_BACKTRACE=1 cargo test --package pallet-subtensor --test block_step test_subnet_staking_emission -- --nocapture #[test] -fn test_emission_based_on_registration_status() { +fn test_subnet_staking_emission() { new_test_ext(1).execute_with(|| { - let n: u16 = 100; - let netuid_off: u16 = 1; - let netuid_on: u16 = 2; - let tempo: u16 = 1; - let netuids: Vec = vec![netuid_off, netuid_on]; - let emissions: Vec = vec![1000000000, 1000000000]; - - // Add subnets with registration turned off and on - add_network(netuid_off, tempo, 0); - add_network(netuid_on, tempo, 0); - SubtensorModule::set_max_allowed_uids(netuid_off, n); - SubtensorModule::set_max_allowed_uids(netuid_on, n); - SubtensorModule::set_emission_values(&netuids, emissions).unwrap(); - SubtensorModule::set_network_registration_allowed(netuid_off, false); - SubtensorModule::set_network_registration_allowed(netuid_on, true); - - // Populate the subnets with neurons - for i in 0..n { - SubtensorModule::append_neuron(netuid_off, &U256::from(i), 0); - SubtensorModule::append_neuron(netuid_on, &U256::from(i), 0); - } - - // Generate emission at block 0 - let block: u64 = 0; - SubtensorModule::generate_emission(block); + let delegate = U256::from(1); + SubtensorModule::set_target_stakes_per_interval(20); + let lock_amount = 100_000_000_000; + add_dynamic_network(1, 1, 1, 1, lock_amount); + add_dynamic_network(2, 1, 1, 1, lock_amount); + assert_eq!(SubtensorModule::get_num_subnets(), 2); - // Verify that no emission tuples are loaded for the subnet with registration off - assert!(SubtensorModule::get_loaded_emission_tuples(netuid_off).is_none()); + // Remove subnet creator lock + SubtensorModule::set_subnet_owner_lock_period(0); - // Verify that emission tuples are loaded for the subnet with registration on - assert!(SubtensorModule::get_loaded_emission_tuples(netuid_on).is_some()); + // Alpha on delegate should be lock_amount, lock_amount * 2 + assert_eq!( + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&delegate, &delegate, 1), + lock_amount + ); assert_eq!( - SubtensorModule::get_loaded_emission_tuples(netuid_on) - .unwrap() - .len(), - n as usize + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&delegate, &delegate, 2), + 2 * lock_amount ); - // Step to the next epoch block - let epoch_block: u16 = tempo; - step_block(epoch_block); + let netuid_1_tao_unstaked = SubtensorModule::estimate_dynamic_unstake(1, lock_amount / 2); + let netuid_1_tao: I64F64 = I64F64::from_num(lock_amount - netuid_1_tao_unstaked); + let netuid_2_tao: I64F64 = I64F64::from_num(lock_amount); + let total_tao_staked: I64F64 = netuid_1_tao + netuid_2_tao; + + // Unstake half of alpha for subnets 1 to achieve skew on emisson values + assert_ok!(SubtensorModule::remove_subnet_stake( + <::RuntimeOrigin>::signed(delegate), + delegate, + 1, + lock_amount / 2 + )); - // Verify that no emission tuples are loaded for the subnet with registration off - assert!(SubtensorModule::get_loaded_emission_tuples(netuid_off).is_none()); + SubtensorModule::run_coinbase(1); + // Subnet block emission is subnet tao staked / total tao staked = + let tao = 1_000_000_000.; + assert_approx_eq!( + SubtensorModule::get_emission_value(1) as f64 / tao, + (netuid_1_tao / total_tao_staked).to_num::() + ); + assert_approx_eq!( + SubtensorModule::get_emission_value(2) as f64 / tao, + (netuid_2_tao / total_tao_staked).to_num::() + ); + }); +} + +#[test] +fn test_run_coinbase_price_greater_than_1() { + new_test_ext(1).execute_with(|| { + // Create subnet with price 4 + let netuid: u16 = 1; + let lock_amount = 100_000_000_000; + setup_dynamic_network(netuid, 1u16, 1u16, lock_amount); + add_dynamic_stake(netuid, 1u16, 1u16, 100_000_000_000u64); + assert_eq!(SubtensorModule::get_tao_per_alpha_price(netuid), 4.0); + + // Make some TAO + SubtensorModule::coinbase(100); + let total_issuance = SubtensorModule::get_total_issuance(); + let block_emission = SubtensorModule::get_block_emission().unwrap(); + assert_eq!(total_issuance, 100); + assert!(block_emission > 0); + + // Check that running run_coinbase behaves correctly + let tao_reserve_before = SubtensorModule::get_tao_reserve(netuid); + log::info!("Tao reserve before: {:?}", tao_reserve_before); + let alpha_reserve_before = SubtensorModule::get_alpha_reserve(netuid); + log::info!("Alpha reserve before: {:?}", alpha_reserve_before); + let pending_before = SubtensorModule::get_pending_emission(netuid); + log::info!("Pending alpha before: {:?}", pending_before); + SubtensorModule::run_coinbase(1); + let tao_reserve_after = SubtensorModule::get_tao_reserve(netuid); + log::info!("Tao reserve after: {:?}", tao_reserve_after); + let alpha_reserve_after = SubtensorModule::get_alpha_reserve(netuid); + log::info!("Alpha reserve after: {:?}", alpha_reserve_after); + let pending_after = SubtensorModule::get_pending_emission(netuid); + log::info!("Pending alpha after: {:?}", pending_after); log::info!( - "Emissions for netuid with registration off: {:?}", - SubtensorModule::get_loaded_emission_tuples(netuid_off) + "Tao emissions: {:?}", + SubtensorModule::get_emission_value(netuid) ); - // Verify that emission tuples are loaded for the subnet with registration on - assert!(SubtensorModule::get_loaded_emission_tuples(netuid_on).is_some()); + assert!(tao_reserve_after == tao_reserve_before); + assert!(alpha_reserve_after > alpha_reserve_before); + assert!(pending_after > pending_before); + }) +} + +#[test] +fn test_run_coinbase_price_less_than_1() { + new_test_ext(1).execute_with(|| { + // Create subnet with price 0.64 by unstaking 25 TAO + let netuid: u16 = 1; + let lock_amount = 100_000_000_000; + setup_dynamic_network(netuid, 1u16, 1u16, lock_amount); + remove_dynamic_stake(netuid, 1u16, 1u16, 25_000_000_000u64); + assert_i64f64_approx_eq!(SubtensorModule::get_tao_per_alpha_price(netuid), 0.64); + + // Make some TAO + SubtensorModule::coinbase(100); + let total_issuance = SubtensorModule::get_total_issuance(); + let block_emission = SubtensorModule::get_block_emission().unwrap(); + assert_eq!(total_issuance, 100); + assert!(block_emission > 0); + + // Check that running run_coinbase behaves correctly + let tao_reserve_before = SubtensorModule::get_tao_reserve(netuid); + let alpha_reserve_before = SubtensorModule::get_alpha_reserve(netuid); + let pending_before = SubtensorModule::get_pending_emission(netuid); + SubtensorModule::run_coinbase(1); + let tao_reserve_after = SubtensorModule::get_tao_reserve(netuid); + let alpha_reserve_after = SubtensorModule::get_alpha_reserve(netuid); + let pending_after = SubtensorModule::get_pending_emission(netuid); log::info!( - "Emissions for netuid with registration on: {:?}", - SubtensorModule::get_loaded_emission_tuples(netuid_on) + "Subnet emissions: {:?}", + SubtensorModule::get_emission_value(netuid) ); + + assert!(tao_reserve_after > tao_reserve_before); + assert_eq!(alpha_reserve_after, alpha_reserve_before); + assert!(pending_after > pending_before); + }) +} + +#[test] +fn test_10_subnet_take_basic_ok() { + new_test_ext(1).execute_with(|| { + let netuid1 = 1; + let hotkey0 = U256::from(1); + let coldkey0 = U256::from(3); + let coldkey1 = U256::from(4); + + // Create networks. + let lock_amount = 100_000_000_000; + setup_dynamic_network(netuid1, 3u16, 1u16, lock_amount); + SubtensorModule::add_balance_to_coldkey_account(&coldkey0, 1_000_000_000_000); + SubtensorModule::add_balance_to_coldkey_account(&coldkey1, 1_000_000_000_000); + SubtensorModule::add_balance_to_coldkey_account(&hotkey0, 1_000_000_000_000); + + // SubStake (Alpha balance) + // Subnet 1, cold0, hot0: LC1 (100) + // + // DynamicTAOReserve (get_tao_reserve) assertions + // Subnet 1: 100 + // + // DynamicAlphaReserve (get_alpha_reserve) assertions + // Subnet 1: 100 + // + // DynamicAlphaOutstanding (get_alpha_outstading) assertions + // Subnet 1: 100 + // + assert_substake_eq!(&coldkey0, &hotkey0, netuid1, 100_000_000_000); + assert_eq!(SubtensorModule::get_tao_reserve(netuid1), 100_000_000_000); + assert_eq!(SubtensorModule::get_alpha_reserve(netuid1), 100_000_000_000); assert_eq!( - SubtensorModule::get_loaded_emission_tuples(netuid_on) - .unwrap() - .len(), - n as usize + SubtensorModule::get_alpha_outstanding(netuid1), + 100_000_000_000 + ); + + // Coldkey / hotkey 0 sets the take on subnet 1 to 10% + assert_ok!(SubtensorModule::do_decrease_take( + <::RuntimeOrigin>::signed(coldkey0), + hotkey0, + netuid1, + u16::MAX / 10 + )); + + // Nominate 100 from coldkey/hotkey 1 to hotkey0 on subnet 1 + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(coldkey1), + hotkey0, + netuid1, + 100_000_000_000 + )); + + // SubStake (Alpha balance) + // Subnet 1, cold0, hot0: 100 + // cold1, hot0: 50 + // + // DynamicTAOReserve (get_tao_reserve) assertions + // Subnet 1: 200 + // + // DynamicAlphaReserve (get_alpha_reserve) assertions + // Subnet 1: 50 + // + // DynamicAlphaOutstanding (get_alpha_outstading) assertions + // Subnet 1: 150 + // + assert_substake_eq!(&coldkey0, &hotkey0, netuid1, 100_000_000_000); + assert_substake_eq!(&coldkey1, &hotkey0, netuid1, 50_000_000_000); + assert_eq!(SubtensorModule::get_tao_reserve(netuid1), 200_000_000_000); + assert_eq!(SubtensorModule::get_alpha_reserve(netuid1), 50_000_000_000); + assert_eq!( + SubtensorModule::get_alpha_outstanding(netuid1), + 150_000_000_000 + ); + + // Emission + // + // Emit inflation through run_coinbase + // We will emit 0 server emission (which should go in-full to the owner of the hotkey). + // We will emit 200 validator emission, which should be distributed in-part to the nominators. + // + let emission = 200_000_000_000; + SubtensorModule::emit_inflation_through_hotkey_account(&hotkey0, netuid1, 0, emission); + + // SubStake (Alpha balance) + // Subnet 1, cold0, hot0: 350 - 110 = 240 + // cold1, hot0: 110 + // + assert_substake_approx_eq!(&coldkey0, &hotkey0, netuid1, 240.); + assert_substake_approx_eq!(&coldkey1, &hotkey0, netuid1, 110.); + }); +} + +#[test] +fn test_20_subnet_take_basic_ok() { + new_test_ext(1).execute_with(|| { + let netuid1 = 1; + let hotkey0 = U256::from(1); + let coldkey0 = U256::from(3); + let coldkey1 = U256::from(4); + + // Create networks. + let lock_amount = 100_000_000_000; + setup_dynamic_network(netuid1, 3u16, 1u16, lock_amount); + SubtensorModule::add_balance_to_coldkey_account(&coldkey0, 1_000_000_000_000); + SubtensorModule::add_balance_to_coldkey_account(&coldkey1, 1_000_000_000_000); + SubtensorModule::add_balance_to_coldkey_account(&hotkey0, 1_000_000_000_000); + + // SubStake (Alpha balance) + // Subnet 1, cold0, hot0: LC1 (100) + // + // DynamicTAOReserve (get_tao_reserve) assertions + // Subnet 1: 100 + // + // DynamicAlphaReserve (get_alpha_reserve) assertions + // Subnet 1: 100 + // + // DynamicAlphaOutstanding (get_alpha_outstading) assertions + // Subnet 1: 100 + // + assert_substake_eq!(&coldkey0, &hotkey0, netuid1, 100_000_000_000); + assert_eq!(SubtensorModule::get_tao_reserve(netuid1), 100_000_000_000); + assert_eq!(SubtensorModule::get_alpha_reserve(netuid1), 100_000_000_000); + assert_eq!( + SubtensorModule::get_alpha_outstanding(netuid1), + 100_000_000_000 + ); + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey_and_subnet(&hotkey0, netuid1), + 100_000_000_000 + ); + + // Coldkey / hotkey 0 sets the take on subnet 1 to 10% + assert_ok!(SubtensorModule::do_decrease_take( + <::RuntimeOrigin>::signed(coldkey0), + hotkey0, + netuid1, + u16::MAX / 10 + )); + + // Nominate 100 from coldkey/hotkey 1 to hotkey0 on subnet 1 + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(coldkey1), + hotkey0, + netuid1, + 100_000_000_000 + )); + + // SubStake (Alpha balance) + // Subnet 1, cold0, hot0: 100 + // cold1, hot0: 50 + // + // DynamicTAOReserve (get_tao_reserve) assertions + // Subnet 1: 200 + // + // DynamicAlphaReserve (get_alpha_reserve) assertions + // Subnet 1: 50 + // + // DynamicAlphaOutstanding (get_alpha_outstading) assertions + // Subnet 1: 150 + // + assert_substake_eq!(&coldkey0, &hotkey0, netuid1, 100_000_000_000); + assert_substake_eq!(&coldkey1, &hotkey0, netuid1, 50_000_000_000); + assert_eq!(SubtensorModule::get_tao_reserve(netuid1), 200_000_000_000); + assert_eq!(SubtensorModule::get_alpha_reserve(netuid1), 50_000_000_000); + assert_eq!( + SubtensorModule::get_alpha_outstanding(netuid1), + 150_000_000_000 + ); + + // Emission + // + // Emit inflation through run_coinbase + // We will emit 0 server emission (which should go in-full to the owner of the hotkey). + // We will emit 200 validator emission, which should be distributed in-part to the nominators. + // + let emission = 200_000_000_000; + SubtensorModule::emit_inflation_through_hotkey_account(&hotkey0, netuid1, 0, emission); + + // SubStake (Alpha balance) + // Subnet 1, cold0, hot0: 100 + 10% * 200 + 90% * 200 * 2/3 = + // cold1, hot0: 50 + 90% * 200 * 1/3 + // + assert_substake_approx_eq!(&coldkey0, &hotkey0, netuid1, 240.); + assert_substake_approx_eq!(&coldkey1, &hotkey0, netuid1, 110.); + }); +} + +#[test] +fn test_two_subnets_take_ok() { + new_test_ext(1).execute_with(|| { + let netuid1 = 1; + let netuid2 = 2; + let hotkey0 = U256::from(1); + let hotkey1 = U256::from(2); + let coldkey0 = U256::from(3); + let coldkey1 = U256::from(4); + let take1 = u16::MAX / 20 * 3; + let take2 = u16::MAX / 10; + + // Create networks. + let lock_cost = 100_000_000_000; + setup_dynamic_network(netuid1, 3u16, 1u16, lock_cost); + setup_dynamic_network(netuid2, 3u16, 2u16, lock_cost); + SubtensorModule::add_balance_to_coldkey_account(&coldkey0, 1_000_000_000_000); + SubtensorModule::add_balance_to_coldkey_account(&coldkey1, 1_000_000_000_000); + SubtensorModule::add_balance_to_coldkey_account(&hotkey0, 1_000_000_000_000); + SubtensorModule::add_balance_to_coldkey_account(&hotkey1, 1_000_000_000_000); + + // SubStake (Alpha balance) + // Subnet 1, cold0, hot0: LC1 (100) + // + // DynamicTAOReserve (get_tao_reserve) assertions + // Subnet 1: 100 + // Subnet 2: 100 + // + // DynamicAlphaReserve (get_alpha_reserve) assertions + // Subnet 1: 100 + // Subnet 2: 200 + // + // DynamicAlphaOutstanding (get_alpha_outstading) assertions + // Subnet 1: 100 + // Subnet 2: 200 + // + assert_substake_eq!(&coldkey0, &hotkey0, netuid1, 100_000_000_000); + assert_substake_eq!(&coldkey0, &hotkey1, netuid2, 200_000_000_000); + assert_eq!(SubtensorModule::get_tao_reserve(netuid1), 100_000_000_000); + assert_eq!(SubtensorModule::get_alpha_reserve(netuid1), 100_000_000_000); + assert_eq!( + SubtensorModule::get_alpha_outstanding(netuid1), + 100_000_000_000 + ); + assert_eq!(SubtensorModule::get_tao_reserve(netuid2), 100_000_000_000); + assert_eq!(SubtensorModule::get_alpha_reserve(netuid2), 200_000_000_000); + assert_eq!( + SubtensorModule::get_alpha_outstanding(netuid2), + 200_000_000_000 + ); + + // Hotkey 0 sets the take on subnet 1 + assert_ok!(SubtensorModule::do_decrease_take( + <::RuntimeOrigin>::signed(coldkey0), + hotkey0, + netuid1, + take1 + )); + + // Hotkey 1 sets the take on subnet 2 + assert_ok!(SubtensorModule::do_decrease_take( + <::RuntimeOrigin>::signed(coldkey0), + hotkey1, + netuid2, + take2 + )); + + // Nominate 100 from coldkey1 to hotkey0 on subnet 1 + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(coldkey1), + hotkey0, + netuid1, + 100_000_000_000 + )); + + // Nominate 100 from coldkey1 to hotkey1 on subnet 2 + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(coldkey1), + hotkey1, + netuid2, + 100_000_000_000 + )); + + // SubStake (Alpha balance) + // Subnet 1, cold0, hot0: 100 + // cold1, hot0: 50 + // Subnet 2, cold0, hot1: 200 + // cold1, hot1: 100 + // + // DynamicTAOReserve (get_tao_reserve) assertions + // Subnet 1: 200 + // + // DynamicAlphaReserve (get_alpha_reserve) assertions + // Subnet 1: 50 + // + // DynamicAlphaOutstanding (get_alpha_outstading) assertions + // Subnet 1: 150 + // + assert_substake_eq!(&coldkey0, &hotkey0, netuid1, 100_000_000_000); + assert_substake_eq!(&coldkey1, &hotkey0, netuid1, 50_000_000_000); + assert_substake_eq!(&coldkey0, &hotkey1, netuid2, 200_000_000_000); + assert_substake_eq!(&coldkey1, &hotkey1, netuid2, 100_000_000_000); + assert_eq!(SubtensorModule::get_tao_reserve(netuid1), 200_000_000_000); + assert_eq!(SubtensorModule::get_alpha_reserve(netuid1), 50_000_000_000); + assert_eq!( + SubtensorModule::get_alpha_outstanding(netuid1), + 150_000_000_000 + ); + assert_eq!(SubtensorModule::get_tao_reserve(netuid2), 200_000_000_000); + assert_eq!(SubtensorModule::get_alpha_reserve(netuid2), 100_000_000_000); + assert_eq!( + SubtensorModule::get_alpha_outstanding(netuid2), + 300_000_000_000 + ); + + // Emission + // + // Emit inflation through run_coinbase + // We will emit 0 server emission (which should go in-full to the owner of the hotkey). + // We will emit 100 validator emission through each of hotkeys, which should be + // distributed in-part to the nominators. + // + let emission = 100_000_000_000; + SubtensorModule::emit_inflation_through_hotkey_account(&hotkey0, netuid1, 0, emission); + SubtensorModule::emit_inflation_through_hotkey_account(&hotkey1, netuid2, 0, emission); + + let emission_take_1 = emission as f64 / 1_000_000_000_f64 * take1 as f64 / u16::MAX as f64; + let emission_take_2 = emission as f64 / 1_000_000_000_f64 * take2 as f64 / u16::MAX as f64; + let remaining_emission_1 = emission as f64 / 1_000_000_000_f64 - emission_take_1; + let remaining_emission_2 = emission as f64 / 1_000_000_000_f64 - emission_take_2; + let substake_0_0_1 = 100. + emission_take_1 + remaining_emission_1 * 2. / 3.; + let substake_1_0_1 = 50. + remaining_emission_1 * 1. / 3.; + let substake_0_1_1 = 200. + emission_take_2 + remaining_emission_2 * 2. / 3.; + let substake_1_1_1 = 100. + remaining_emission_2 * 1. / 3.; + + assert_substake_approx_eq!(&coldkey0, &hotkey0, netuid1, substake_0_0_1); + assert_substake_approx_eq!(&coldkey1, &hotkey0, netuid1, substake_1_0_1); + assert_substake_approx_eq!(&coldkey0, &hotkey1, netuid2, substake_0_1_1); + assert_substake_approx_eq!(&coldkey1, &hotkey1, netuid2, substake_1_1_1); + }); +} + +#[test] +fn test_root_subnet_gets_no_pending_emission() { + new_test_ext(1).execute_with(|| { + let netuid1 = 0; + let netuid2 = 1; + + // Create networks. + let lock_cost = 100_000_000_000; + + // It doesn't matter if we setup root as stao or dtao, it is irrelevant for pending emission code + setup_dynamic_network(netuid1, 3u16, 1u16, lock_cost); + setup_dynamic_network(netuid2, 3u16, 2u16, lock_cost); + + SubtensorModule::run_coinbase(1); + + assert_eq!( + SubtensorModule::get_pending_emission(netuid1), + 0 + ); + assert!( + SubtensorModule::get_pending_emission(netuid2) != 0, ); }); } diff --git a/pallets/subtensor/tests/difficulty.rs b/pallets/subtensor/tests/difficulty.rs index 24552261d..3ad588a70 100644 --- a/pallets/subtensor/tests/difficulty.rs +++ b/pallets/subtensor/tests/difficulty.rs @@ -2,6 +2,9 @@ use crate::mock::*; mod mock; use sp_core::U256; +// To run just the tests in this file, use the following command: +// cargo test -p pallet-subtensor --test difficulty + #[test] #[cfg(not(tarpaulin))] fn test_registration_difficulty_adjustment() { diff --git a/pallets/subtensor/tests/dtao.rs b/pallets/subtensor/tests/dtao.rs new file mode 100644 index 000000000..4b15b815a --- /dev/null +++ b/pallets/subtensor/tests/dtao.rs @@ -0,0 +1,1298 @@ +use crate::mock::*; +use frame_support::assert_ok; +use frame_system::Config; +use itertools::izip; +use pallet_subtensor::*; +use sp_core::U256; +use substrate_fixed::types::I64F64; +use types::SubnetType; +mod mock; + +#[macro_use] +mod helpers; + +// To run just the tests in this file, use the following command: +// Use the following command to run the tests in this file with verbose logging: +// RUST_LOG=debug cargo test -p pallet-subtensor --test dtao + +#[test] +fn test_add_subnet_stake_ok_no_emission() { + new_test_ext(1).execute_with(|| { + let hotkey = U256::from(0); + let coldkey = U256::from(1); + let lock_cost = 100_000_000_000; // 100 TAO + + SubtensorModule::add_balance_to_coldkey_account(&coldkey, lock_cost); + // Check + // -- that the lock cost is 100 TAO. + // -- that the balance is 100 TAO. + // -- that the root pool is empty. + // -- that the root alpha pool is empty. + // -- that the root price is 1.0. + // -- that the root has zero k value. + assert_eq!(SubtensorModule::get_network_lock_cost(), lock_cost); + assert_eq!(SubtensorModule::get_coldkey_balance(&coldkey), lock_cost); + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey_and_subnet(&hotkey, 0), + 0 + ); // 1 subnets * 100 TAO lock cost. + assert_eq!(SubtensorModule::get_total_stake_for_subnet(0), 0); + assert_eq!(SubtensorModule::get_tao_per_alpha_price(0), 1.0); + assert_eq!(SubtensorModule::get_tao_reserve(0), 0); + assert_eq!(SubtensorModule::get_alpha_reserve(0), 0); + assert_eq!(SubtensorModule::get_pool_k(0), 0); + assert!(!SubtensorModule::is_subnet_dynamic(0)); + + log::info!( + "Alpha Outstanding is {:?}", + SubtensorModule::get_alpha_outstanding(0) + ); + // Register a network with this coldkey + hotkey for a lock cost of 100 TAO. + step_block(1); + assert_ok!(SubtensorModule::user_add_network( + <::RuntimeOrigin>::signed(coldkey), + hotkey, + SubnetType::DTAO + )); + + // Check: + // -- that the lock cost is now doubled. + // -- that the lock cost has been withdrawn from the balance. + // -- that the owner of the new subnet is the coldkey. + // -- that the new network has someone registered. + // -- that the registered key is the hotkey. + // -- that the hotkey is owned by the owning coldkey. + // -- that the hotkey has stake on the new network equal to the lock cost. Alpha/TAO price of 1 to 1. + // -- that the total stake per subnet is 100 TAO. + // -- that the new alpha/tao price is 1.0. + // -- that the tao reserve is 100 TAO. + // -- that the alpha reserve is 100 ALPHA + // -- that the k factor is 100 TAO * 100 ALPHA. + // -- that the new network is dynamic + assert_eq!(SubtensorModule::get_network_lock_cost(), 199_999_999_000); // 200 TAO. + // TODO:(sam)Decide how to deal with ED , as this account can only stake 199 + assert_eq!( + SubtensorModule::get_coldkey_balance(&coldkey), + ExistentialDeposit::get() + ); // 0 TAO. + assert_eq!(SubtensorModule::get_subnet_owner(1), coldkey); + assert_eq!(SubtensorModule::get_subnetwork_n(1), 1); + assert_eq!( + SubtensorModule::get_hotkey_for_net_and_uid(1, 0).unwrap(), + hotkey + ); + assert_eq!( + SubtensorModule::get_owning_coldkey_for_hotkey(&hotkey), + coldkey + ); + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey_and_subnet(&hotkey, 1), + 100_000_000_000 + ); // 1 subnets * 100 TAO lock cost. + assert_eq!( + SubtensorModule::get_total_stake_for_subnet(1), + 100_000_000_000 + ); + assert_eq!(SubtensorModule::get_tao_per_alpha_price(1), 1.0); + assert_eq!(SubtensorModule::get_tao_reserve(1), 100_000_000_000); + assert_eq!(SubtensorModule::get_alpha_reserve(1), 100_000_000_000); + assert_eq!( + SubtensorModule::get_pool_k(1), + 100_000_000_000 * 100_000_000_000 + ); + assert!(SubtensorModule::is_subnet_dynamic(1)); + log::info!( + "Alpha Outstanding is {:?}", + SubtensorModule::get_alpha_outstanding(1) + ); + + // Register a new network + assert_eq!( + SubtensorModule::get_network_lock_cost(), + 2 * (lock_cost - ExistentialDeposit::get()) + ); + SubtensorModule::add_balance_to_coldkey_account( + &coldkey, + 2 * (lock_cost - ExistentialDeposit::get()), + ); + assert_ok!(SubtensorModule::user_add_network( + <::RuntimeOrigin>::signed(coldkey), + hotkey, + SubnetType::DTAO + )); + + // Check: + // -- that the lock cost is now doubled. + // -- that the lock cost has been withdrawn from the balance. + // -- that the owner of the new subnet is the coldkey. + // -- that the new network as someone registered. + // -- that the registered key is the hotkey. + // -- that the hotkey is owned by the owning coldkey. + // -- that the hotkey has stake on the new network equal to the lock cost. Alpha/TAO price of 1 to 1. + // -- that the total stake per subnet 2 is 400 TAO. + // -- that the new alpha/tao price is 0.5. + // -- that the tao reserve is 200 TAO. + // -- that the alpha reserve is 400 ALPHA + // -- that the k factor is 200 TAO * 400 ALPHA. + // -- that the new network is dynamic + // TODO:(sam)Decide how to deal with ED , as this account can only stake 199 + assert_eq!( + SubtensorModule::get_network_lock_cost(), + 400_000_000_000 - ExistentialDeposit::get() * 4 + ); // 400 TAO. + assert_eq!( + SubtensorModule::get_coldkey_balance(&coldkey), + ExistentialDeposit::get() + ); // 0 TAO. + assert_eq!(SubtensorModule::get_subnet_owner(2), coldkey); + assert_eq!(SubtensorModule::get_subnetwork_n(2), 1); + assert_eq!( + SubtensorModule::get_hotkey_for_net_and_uid(2, 0).unwrap(), + hotkey + ); + assert_eq!( + SubtensorModule::get_owning_coldkey_for_hotkey(&hotkey), + coldkey + ); + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey_and_subnet(&hotkey, 2), + 400_000_000_000 - ExistentialDeposit::get() * 4 + ); // 2 subnets * 2 TAO lock cost. + assert_eq!( + SubtensorModule::get_total_stake_for_subnet(2), + 400_000_000_000 - ExistentialDeposit::get() * 4 + ); + assert_eq!(SubtensorModule::get_tao_per_alpha_price(2), 0.5); + assert_eq!( + SubtensorModule::get_tao_reserve(2), + 200_000_000_000 - ExistentialDeposit::get() * 2 + ); + assert_eq!( + SubtensorModule::get_alpha_reserve(2), + 400_000_000_000 - ExistentialDeposit::get() * 4 + ); + assert_eq!( + SubtensorModule::get_pool_k(2), + (200_000_000_000 - ExistentialDeposit::get() as u128 * 2u128) + * (400_000_000_000 - ExistentialDeposit::get() as u128 * 4u128) + ); + assert!(SubtensorModule::is_subnet_dynamic(2)); + log::info!( + "Alpha Outstanding is {:?}", + SubtensorModule::get_alpha_outstanding(2) + ); + + // Let's remove all of our stake from subnet 2. + // Check: + // -- that the balance is initially 0 + // -- that the unstake event is ok. + // -- that the balance is 100 TAO. Given the slippage. + // -- that the price per alpha has changed to 0.125 + // -- that the tao reserve is 100 TAO. + // -- that the alpha reserve is 800 ALPHA + // -- that the k factor is 100 TAO * 400 ALPHA. (unchanged) + // TODO:(sam)Decide how to deal with ED , free balance will always be 1 + assert_eq!(Balances::free_balance(coldkey), ExistentialDeposit::get()); + // We set this to zero , otherwise the alpha calculation is off due to the fact that many tempos will be run + // over the default lock period (3 months) + SubtensorModule::set_subnet_owner_lock_period(0); + assert_eq!( + SubtensorModule::get_pool_k(2), + (200_000_000_000 - ExistentialDeposit::get() as u128 * 2u128) + * (400_000_000_000 - ExistentialDeposit::get() as u128 * 4u128) + ); + + run_to_block(3); + assert_ok!(SubtensorModule::remove_subnet_stake( + <::RuntimeOrigin>::signed(coldkey), + hotkey, + 2, + 400_000_000_000 - ExistentialDeposit::get() * 4 + )); + // assert_eq!( Balances::free_balance(coldkey), 100_000_000_000); + // Also use more rigour calculation for slippage via K + assert_i64f64_approx_eq!(SubtensorModule::get_tao_per_alpha_price(2), 0.125); + assert_eq!( + round_to_significant_figures(SubtensorModule::get_tao_reserve(2), 3), + 100_000_000_000 + ); + // Yet another ugly approximation + assert_eq!( + round_to_significant_figures(SubtensorModule::get_alpha_reserve(2), 2), + 800_000_000_000 + ); + + log::info!( + "Alpha Reserve is {:?}", + SubtensorModule::get_alpha_reserve(2) + ); + log::info!("Tao Reserve is {:?}", SubtensorModule::get_tao_reserve(2)); + + // Let's run a block step. + // Alpha pending emission is not zero at start because we already ran to block 3 + // and had emissions + // Check + // -- that the pending emission for the 2 subnets is correct + // -- that the pending alpha emission of the 2 subnets is correct. + let tao = 1_000_000_000; + + assert_i64f64_approx_eq!(SubtensorModule::get_tao_per_alpha_price(1), 0.9901); // diluted because of emissions in run_to_block + assert_i64f64_approx_eq!(SubtensorModule::get_tao_per_alpha_price(2), 0.125); + step_block(1); + assert_i64f64_approx_eq!(SubtensorModule::get_tao_reserve(1), 100_000_000_000u64); + assert_i64f64_approx_eq!(SubtensorModule::get_tao_reserve(2).div_ceil(tao), 101); + assert_i64f64_approx_eq!(SubtensorModule::get_alpha_reserve(1).div_ceil(tao), 102); + assert_i64f64_approx_eq!(SubtensorModule::get_alpha_reserve(2).div_ceil(tao), 802); + run_to_block(10); + assert_i64f64_approx_eq!(SubtensorModule::get_tao_reserve(1).div_ceil(tao), 100); + assert_i64f64_approx_eq!(SubtensorModule::get_tao_reserve(2).div_ceil(tao), 101); + assert_i64f64_approx_eq!(SubtensorModule::get_alpha_reserve(1).div_ceil(tao), 108); + assert_i64f64_approx_eq!(SubtensorModule::get_alpha_reserve(2).div_ceil(tao), 808); + run_to_block(30); + assert_i64f64_approx_eq!(SubtensorModule::get_tao_reserve(1).div_ceil(tao), 104); + assert_i64f64_approx_eq!(SubtensorModule::get_tao_reserve(2).div_ceil(tao), 105); + assert_i64f64_approx_eq!(SubtensorModule::get_alpha_reserve(1).div_ceil(tao), 120); + assert_i64f64_approx_eq!(SubtensorModule::get_alpha_reserve(2).div_ceil(tao), 820); + + for _ in 0..100 { + step_block(1); + log::info!( + "S1: {}, S2: {}", + SubtensorModule::get_tao_per_alpha_price(1), + SubtensorModule::get_tao_per_alpha_price(2) + ); + } + }); +} + +#[test] +fn test_stake_unstake() { + new_test_ext(1).execute_with(|| { + // init params. + let hotkey = U256::from(0); + let coldkey = U256::from(1); + + // Register subnet. + SubtensorModule::add_balance_to_coldkey_account(&coldkey, 100_000_000_000); // 100 TAO. + assert_ok!(SubtensorModule::user_add_network( + <::RuntimeOrigin>::signed(coldkey), + hotkey, + SubnetType::DTAO + )); + assert_eq!(SubtensorModule::get_tao_reserve(1), 100_000_000_000); + assert_eq!(SubtensorModule::get_alpha_reserve(1), 100_000_000_000); + assert_eq!(SubtensorModule::get_tao_per_alpha_price(1), 1.0); + + SubtensorModule::add_balance_to_coldkey_account(&coldkey, 100_000_000_000); // 100 TAO. + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(coldkey), + hotkey, + 1, + 100_000_000_000 + )); + assert_eq!(SubtensorModule::get_tao_reserve(1), 200_000_000_000); + assert_eq!(SubtensorModule::get_alpha_reserve(1), 50_000_000_000); + assert_eq!(SubtensorModule::get_tao_per_alpha_price(1), 4); // Price is increased from the stake operation. + }) +} + +// To run this test, use the following command: +// cargo test -p pallet-subtensor --test dtao test_calculate_tempos +fn round_to_significant_figures(num: u64, significant_figures: u32) -> u64 { + if num == 0 { + return 0; + } + let digits = (num as f64).log10().floor() as u32 + 1; // Calculate the number of digits in the number + let scale = 10u64.pow(digits - significant_figures); // Determine the scaling factor + + // Scale down, round, and scale up + ((num as f64 / scale as f64).round() as u64) * scale +} +#[test] +fn test_calculate_tempos() { + new_test_ext(1).execute_with(|| { + let netuids = vec![1, 2, 3]; + let k = I64F64::from_num(10); // Example constant K + let prices = vec![ + I64F64::from_num(100.0), + I64F64::from_num(200.0), + I64F64::from_num(300.0), + ]; + + let expected_tempos = vec![ + (1, 60), // Calculated tempo for netuid 1 + (2, 30), // Calculated tempo for netuid 2 + (3, 20), // Calculated tempo for netuid 3 + ]; + + let tempos = SubtensorModule::calculate_tempos(&netuids, k, &prices).unwrap(); + assert_eq!(tempos, expected_tempos, "Tempos calculated incorrectly"); + + // Edge case: Empty netuids and prices + let empty_netuids = vec![]; + let empty_prices = vec![]; + let empty_tempos = + SubtensorModule::calculate_tempos(&empty_netuids, k, &empty_prices).unwrap(); + assert!( + empty_tempos.is_empty(), + "Empty tempos should be an empty vector" + ); + + // Edge case: Zero prices + let zero_prices = vec![ + I64F64::from_num(0.0), + I64F64::from_num(0.0), + I64F64::from_num(0.0), + ]; + let zero_tempos = SubtensorModule::calculate_tempos(&netuids, k, &zero_prices).unwrap(); + assert_eq!( + zero_tempos, + vec![(1, 0), (2, 0), (3, 0)], + "Zero prices should lead to zero tempos" + ); + + // Edge case: Negative prices + let negative_prices = vec![ + I64F64::from_num(-100.0), + I64F64::from_num(-200.0), + I64F64::from_num(-300.0), + ]; + let negative_tempos = + SubtensorModule::calculate_tempos(&netuids, k, &negative_prices).unwrap(); + assert_eq!( + negative_tempos, expected_tempos, + "Negative prices should be treated as positive for tempo calculation" + ); + + // Edge case: Very large prices + let large_prices = vec![ + I64F64::from_num(1e12), + I64F64::from_num(2e12), + I64F64::from_num(3e12), + ]; + let large_tempos = SubtensorModule::calculate_tempos(&netuids, k, &large_prices).unwrap(); + assert_eq!( + large_tempos, expected_tempos, + "Large prices should scale similarly in tempo calculation" + ); + + // Edge case: Mismatched vector sizes + let mismatched_prices = vec![I64F64::from_num(100.0), I64F64::from_num(200.0)]; // Missing price for netuid 3 + assert!( + SubtensorModule::calculate_tempos(&netuids, k, &mismatched_prices).is_err(), + "Mismatched vector sizes should result in an error" + ); + + // Edge case: Extremely small non-zero prices + let small_prices = vec![ + I64F64::from_num(1e-12), + I64F64::from_num(1e-12), + I64F64::from_num(1e-12), + ]; + let small_tempos = SubtensorModule::calculate_tempos(&netuids, k, &small_prices).unwrap(); + assert_eq!( + small_tempos, + vec![(1, 30), (2, 30), (3, 30)], + "Extremely small prices should return same tempos" + ); + + // Edge case: Prices with high precision + let high_precision_prices = vec![ + I64F64::from_num(100.123456789), + I64F64::from_num(200.123456789), + I64F64::from_num(300.123456789), + ]; + let high_precision_tempos = + SubtensorModule::calculate_tempos(&netuids, k, &high_precision_prices).unwrap(); + assert_eq!( + high_precision_tempos, + vec![(1, 59), (2, 30), (3, 20)], + "High precision prices should affect tempo calculations" + ); + }); +} + +/////////////////////////////////////////////////////////////////////////////// +// Price tests +// +// - Price of a single subnet is 1 if TAO is 1 and Alpha is 1 +// - Price of a single subnet with numerous unstakes +// - Price of a single subnet with numerous stakes + +#[test] +fn test_price_tao_1_alpha_1() { + new_test_ext(1).execute_with(|| { + let delegate = U256::from(1); + SubtensorModule::set_target_stakes_per_interval(20); + let lock_amount = 100_000_000_000; + add_dynamic_network(1, 1, 1, 1, lock_amount); + + // Alpha on delegate should be lock_amount + assert_eq!( + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&delegate, &delegate, 1), + lock_amount + ); + + let expected_price = I64F64::from_num(1.0); + let actual_price: I64F64 = SubtensorModule::get_tao_per_alpha_price(1); + + assert_eq!(expected_price, actual_price); + }); +} + +#[test] +fn test_price_tao_alpha_unstake() { + [ + 1u64, + 2, + 3, + 4, + 5, + 100, + 200, + 1234, + 1_000_000_000, + 100_000_000_000, + ] + .iter() + .for_each(|&unstake_alpha_amount| { + new_test_ext(1).execute_with(|| { + let delegate = U256::from(1); + SubtensorModule::set_target_stakes_per_interval(20); + let lock_amount = 100_000_000_000; + add_dynamic_network(1, 1, 1, 1, lock_amount); + + // Remove subnet creator lock + SubtensorModule::set_subnet_owner_lock_period(0); + + // Alpha on delegate should be lock_amount + assert_eq!( + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&delegate, &delegate, 1), + lock_amount + ); + + let unstaked_tao = SubtensorModule::estimate_dynamic_unstake(1, unstake_alpha_amount); + + // Unstake half of alpha for subnets 1 + assert_ok!(SubtensorModule::remove_subnet_stake( + <::RuntimeOrigin>::signed(delegate), + delegate, + 1, + unstake_alpha_amount + )); + + let tao_reserve = lock_amount - unstaked_tao; + let alpha_reserve = lock_amount + unstake_alpha_amount; + + let expected_price = I64F64::from_num(tao_reserve) / I64F64::from_num(alpha_reserve); + let actual_price: I64F64 = SubtensorModule::get_tao_per_alpha_price(1); + + // assert_approx_eq!(expected_price.to_num::(), actual_price.to_num::()); + + assert_eq!(expected_price, actual_price); + }); + }); +} + +#[test] +fn test_price_tao_alpha_stake() { + [ + 1, + 2, + 3, + 100, + 1000, + 1000000000u64, + 10000000000u64, + 100000000000u64, + ] + .iter() + .for_each(|&stake_tao_amount| { + new_test_ext(1).execute_with(|| { + let delegate = U256::from(1); + SubtensorModule::set_target_stakes_per_interval(20); + let lock_amount = 100_000_000_000; + add_dynamic_network(1, 1, 1, 1, lock_amount); + SubtensorModule::add_balance_to_coldkey_account( + &delegate, + stake_tao_amount + ExistentialDeposit::get(), + ); + + // Alpha on delegate should be lock_amount + assert_eq!( + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&delegate, &delegate, 1), + lock_amount + ); + + let k = lock_amount as u128 * lock_amount as u128; + let new_tao_reserve = lock_amount + stake_tao_amount; + let new_alpha_reserve: I64F64 = I64F64::from_num(k / new_tao_reserve as u128); + let expected_price = + I64F64::from_num(new_tao_reserve) / I64F64::from_num(new_alpha_reserve); + + // Unstake half of alpha for subnets 1 + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(delegate), + delegate, + 1, + stake_tao_amount + )); + + // Get actual price + let actual_price: I64F64 = SubtensorModule::get_tao_per_alpha_price(1); + // assert_approx_eq!(expected_price.to_num::(), actual_price.to_num::()); + assert_eq!(expected_price, actual_price); + }); + }); +} + +#[test] +fn test_sum_prices_diverges_2_subnets() { + new_test_ext(1).execute_with(|| { + SubtensorModule::set_target_stakes_per_interval(20); + let lock_amount = 100_000_000_000; + add_dynamic_network(1, 1, 1, 1, lock_amount); + add_dynamic_network(2, 1, 1, 1, lock_amount); + + for block in 1..=1000 { + SubtensorModule::run_coinbase(block); + } + + let expected_sum = 1.0; + let actual_price_1: I64F64 = SubtensorModule::get_tao_per_alpha_price(1); + let actual_price_2: I64F64 = SubtensorModule::get_tao_per_alpha_price(2); + let actual_sum = (actual_price_1 + actual_price_2).to_num::(); + + assert_approx_eq!(expected_sum, actual_sum); + }); +} + +#[test] +fn test_sum_prices_diverges_3_subnets() { + new_test_ext(1).execute_with(|| { + SubtensorModule::set_target_stakes_per_interval(20); + let lock_amount = 100_000_000_000; + add_dynamic_network(1, 1, 1, 1, lock_amount); + add_dynamic_network(2, 1, 1, 1, lock_amount); + add_dynamic_network(3, 1, 1, 1, lock_amount); + + for block in 1..=1000 { + SubtensorModule::run_coinbase(block); + } + + let expected_sum = 1.0; + let actual_price_1: I64F64 = SubtensorModule::get_tao_per_alpha_price(1); + let actual_price_2: I64F64 = SubtensorModule::get_tao_per_alpha_price(2); + let actual_price_3: I64F64 = SubtensorModule::get_tao_per_alpha_price(3); + let actual_sum = (actual_price_1 + actual_price_2 + actual_price_3).to_num::(); + + assert_approx_eq!(expected_sum, actual_sum); + }); +} + +//////////////////////////////// +// Dissolve tests +// + +#[test] +fn test_dissolve_dtao_fail() { + new_test_ext(1).execute_with(|| { + SubtensorModule::set_target_stakes_per_interval(20); + let lock_amount = 100_000_000_000; + add_dynamic_network(1, 1, 1, 1, lock_amount); + + assert_eq!( + SubtensorModule::dissolve_network( + <::RuntimeOrigin>::signed(U256::from(1)), + 1, + ), + Err(Error::::NotAllowedToDissolve.into()) + ); + }); +} + +//////////////////////////////// +// Block emission tests: +// Check that TotalSubnetTAO + DynamicAlphaReserve have properly increased +// + +#[test] +fn test_block_emission_adds_up_1_subnet() { + new_test_ext(1).execute_with(|| { + SubtensorModule::set_target_stakes_per_interval(20); + let lock_amount = 100_000_000_000; + add_dynamic_network(1, 1, 1, 1, lock_amount); + + let block_emission = SubtensorModule::get_block_emission().unwrap_or(0); + + let total_subnet_tao_before = pallet_subtensor::TotalSubnetTAO::::get(1); + let dynamic_alpha_reserve_before = pallet_subtensor::DynamicAlphaReserve::::get(1); + + SubtensorModule::run_coinbase(1); + + let total_subnet_tao_after = pallet_subtensor::TotalSubnetTAO::::get(1); + let dynamic_alpha_reserve_after = pallet_subtensor::DynamicAlphaReserve::::get(1); + + assert_eq!( + total_subnet_tao_before + dynamic_alpha_reserve_before + block_emission, + total_subnet_tao_after + dynamic_alpha_reserve_after + ); + }); +} + +#[test] +fn test_block_emission_adds_up_many_subnets() { + new_test_ext(1).execute_with(|| { + SubtensorModule::set_target_stakes_per_interval(1000); + + let subnet_count = 20; + + let hotkey = U256::from(1); + let coldkey = U256::from(1); + pallet_subtensor::SubnetOwnerLockPeriod::::set(0); + + for netuid in 1u16..=subnet_count { + let lock_amount = 100_000_000_000 * netuid as u64; + add_dynamic_network(netuid, 1, 1, 1, lock_amount); + + // Get amount of alpha in the network + let alpha = pallet_subtensor::DynamicAlphaReserve::::get(netuid); + + // Remove stake to make prices lower so that they add up to lower than 1.0 + assert_ok!(SubtensorModule::remove_subnet_stake( + <::RuntimeOrigin>::signed(coldkey), + hotkey, + netuid, + alpha * 19 / 20 + )); + } + + let block_emission = SubtensorModule::get_block_emission().unwrap_or(0); + + let all_total_subnet_tao_before: u64 = (1u16..=subnet_count) + .map(pallet_subtensor::TotalSubnetTAO::::get) + .sum(); + let all_dynamic_alpha_reserve_before: u64 = (1u16..=subnet_count) + .map(pallet_subtensor::DynamicAlphaReserve::::get) + .sum(); + + SubtensorModule::run_coinbase(1); + + let all_total_subnet_tao_after: u64 = (1u16..=subnet_count) + .map(pallet_subtensor::TotalSubnetTAO::::get) + .sum(); + let all_dynamic_alpha_reserve_after: u64 = (1u16..=subnet_count) + .map(pallet_subtensor::DynamicAlphaReserve::::get) + .sum(); + + // Approximate equality of TAO emissions + assert_eq!( + (all_total_subnet_tao_before + all_dynamic_alpha_reserve_before + block_emission) + / 10_000_000_000, + (all_total_subnet_tao_after + all_dynamic_alpha_reserve_after) / 10_000_000_000 + ); + // Alpha emissions should be zero + assert_eq!( + all_dynamic_alpha_reserve_before, + all_dynamic_alpha_reserve_after + ); + }); +} + +/// This test is only applicable when prices add up to lower than 1, so TAO is emitted +/// +#[test] +fn test_tao_subnet_emissions_are_proportional() { + new_test_ext(1).execute_with(|| { + SubtensorModule::set_target_stakes_per_interval(20); + + let subnet_count = 10; + let hotkey = U256::from(1); + let coldkey = U256::from(1); + pallet_subtensor::SubnetOwnerLockPeriod::::set(0); + + for netuid in 1u16..=subnet_count { + let lock_amount = 100_000_000_000 * netuid as u64; + add_dynamic_network(netuid, 1, 1, 1, lock_amount); + + // Get amount of alpha in the network + let alpha = pallet_subtensor::DynamicAlphaReserve::::get(netuid); + + // Remove stake to make prices lower so that they add up to lower than threshold + assert_ok!(SubtensorModule::remove_subnet_stake( + <::RuntimeOrigin>::signed(coldkey), + hotkey, + netuid, + alpha * 19 / 20 + )); + } + + // Check that we archieved price threshold requirement + let price_sum = (1u16..=subnet_count) + .map(|netuid| SubtensorModule::get_tao_per_alpha_price(netuid).to_num::()) + .sum::(); + assert!(price_sum < get_price_threshold()); + + let block_emission = SubtensorModule::get_block_emission().unwrap_or(0); + + let total_subnet_tao_before: Vec = (1u16..=subnet_count) + .map(pallet_subtensor::TotalSubnetTAO::::get) + .collect(); + let dynamic_alpha_reserve_before: Vec = (1u16..=subnet_count) + .map(pallet_subtensor::DynamicAlphaReserve::::get) + .collect(); + let total_total_subnet_tao_before: u64 = (1u16..=subnet_count) + .map(pallet_subtensor::TotalSubnetTAO::::get) + .sum(); + + SubtensorModule::run_coinbase(1); + + let total_subnet_tao_after: Vec = (1u16..=subnet_count) + .map(pallet_subtensor::TotalSubnetTAO::::get) + .collect(); + let dynamic_alpha_reserve_after: Vec = (1u16..=subnet_count) + .map(pallet_subtensor::DynamicAlphaReserve::::get) + .collect(); + + // Ensure subnet TAO emissions are proportional to the their total TAO + izip!( + &dynamic_alpha_reserve_before, + &total_subnet_tao_before, + &dynamic_alpha_reserve_after, + &total_subnet_tao_after, + ) + .map(|(alpha_bef, tao_bef, alpha_af, tao_af)| { + (tao_bef, tao_af - tao_bef, alpha_af - alpha_bef) + }) + .for_each(|(tao_bef, emission, alpha_emission)| { + let expected_emission = + block_emission as f64 * (*tao_bef) as f64 / total_total_subnet_tao_before as f64; + + // In this test we don't expect any alpha emission, only TAO + assert!(((emission as f64 - expected_emission).abs() / expected_emission) < 0.00001); + assert!(alpha_emission == 0); + }); + + // Also ensure emissions add up to block emission + let actual_block_emission: u64 = izip!( + &total_subnet_tao_after, + &dynamic_alpha_reserve_after, + &total_subnet_tao_before, + &dynamic_alpha_reserve_before, + ) + .map(|(alpha_bef, tao_bef, alpha_af, tao_af)| alpha_bef + tao_bef - alpha_af - tao_af) + .sum(); + assert_approx_eq!( + block_emission as f64 / 1_000_000., + actual_block_emission as f64 / 1_000_000. + ); + + // Ensure total subnet tao increased by block emission + let total_total_subnet_tao_after: u64 = (1u16..=subnet_count) + .map(pallet_subtensor::TotalSubnetTAO::::get) + .sum(); + assert_approx_eq!( + (total_total_subnet_tao_after - total_total_subnet_tao_before) as f64 / 1_000., + block_emission as f64 / 1_000. + ); + }); +} + +/// Tests that alpha emissions for every dynamic subnet is numerically equal to +/// total block emission if sum of prices is higher than 1 +#[test] +fn test_alpha_emission() { + new_test_ext(1).execute_with(|| { + SubtensorModule::set_target_stakes_per_interval(20); + + let subnet_count = 10; + + for netuid in 1u16..=subnet_count { + let lock_amount = 100_000_000_000 * netuid as u64; + add_dynamic_network(netuid, 1, 1, 1, lock_amount); + } + + // Check that we archieved price threshold requirement + let price_sum = (1u16..=subnet_count) + .map(|netuid| SubtensorModule::get_tao_per_alpha_price(netuid).to_num::()) + .sum::(); + assert!(price_sum > get_price_threshold()); + + let block_emission = SubtensorModule::get_block_emission().unwrap_or(0); + + let total_subnet_tao_before: Vec = (1u16..=subnet_count) + .map(pallet_subtensor::TotalSubnetTAO::::get) + .collect(); + let dynamic_alpha_reserve_before: Vec = (1u16..=subnet_count) + .map(pallet_subtensor::DynamicAlphaReserve::::get) + .collect(); + let total_total_subnet_tao_before: u64 = (1u16..=subnet_count) + .map(pallet_subtensor::TotalSubnetTAO::::get) + .sum(); + + SubtensorModule::run_coinbase(1); + + let total_subnet_tao_after: Vec = (1u16..=subnet_count) + .map(pallet_subtensor::TotalSubnetTAO::::get) + .collect(); + let dynamic_alpha_reserve_after: Vec = (1u16..=subnet_count) + .map(pallet_subtensor::DynamicAlphaReserve::::get) + .collect(); + + // Ensure subnet alpha emissions are all equal to block emission + izip!( + &dynamic_alpha_reserve_before, + &total_subnet_tao_before, + &dynamic_alpha_reserve_after, + &total_subnet_tao_after, + ) + .map(|(alpha_bef, tao_bef, alpha_af, tao_af)| { + (tao_af - tao_bef, alpha_af - alpha_bef) + }) + .for_each(|(emission, alpha_emission)| { + let expected_alpha_emission = block_emission as f64; + assert!(((alpha_emission as f64 - expected_alpha_emission).abs() / expected_alpha_emission) < 0.00001); + assert!(emission == 0); + }); + + // Ensure total subnet tao didn't change + let total_total_subnet_tao_after: u64 = (1u16..=subnet_count) + .map(pallet_subtensor::TotalSubnetTAO::::get) + .sum(); + assert!(total_total_subnet_tao_after == total_total_subnet_tao_before); + }); +} + +/// Prices need to not converge to the same value, but should remain somewhat proportional to stakes +#[test] +fn test_prices_converge_proportionally() { + new_test_ext(1).execute_with(|| { + SubtensorModule::set_target_stakes_per_interval(20); + + let subnet_count = 10; + pallet_subtensor::SubnetOwnerLockPeriod::::set(0); + + for netuid in 1u16..=subnet_count { + let lock_amount = 100_000_000_000 * netuid as u64; + add_dynamic_network(netuid, u16::MAX, 1, 1, lock_amount); + } + + let mut prev_sq_err = f64::MAX; + let sq_err = || { + let total_subnet_tao: u64 = (1u16..=subnet_count) + .map(pallet_subtensor::TotalSubnetTAO::::get) + .sum(); + + let mut err = 0.; + for netuid in 1u16..=subnet_count { + let tao = pallet_subtensor::TotalSubnetTAO::::get(netuid); + let expected_price = + tao as f64 / total_subnet_tao as f64; + let actual_price = SubtensorModule::get_tao_per_alpha_price(netuid); + + let diff = expected_price - actual_price.to_num::(); + err += diff * diff; + } + + err + }; + + for block in 1u64..20000 { + SubtensorModule::run_coinbase(block); + + // If this passes, the prices are likely to converge, + // nonetheless if it doesn't this is the indication of something + // being wrong. + if block % 100 == 0 || block < 10 { + let err = sq_err(); + assert!(err < prev_sq_err); + prev_sq_err = err; + } + } + }); +} + +/// Verify that total subnet TAO is always equal to dynamic TAO reserve, +/// no matter if prices add up to <1 or >1, or epochs pass. +#[test] +fn test_total_tao_equals_dynamic_tao_reserve() { + new_test_ext(1).execute_with(|| { + SubtensorModule::set_target_stakes_per_interval(20); + + let subnet_count = 10; + let tempo = 360; + pallet_subtensor::SubnetOwnerLockPeriod::::set(0); + + for netuid in 1u16..=subnet_count { + let lock_amount = 100_000_000_000 * netuid as u64; + add_dynamic_network(netuid, tempo, 1, 1, lock_amount); + } + + let mut emissions_non_zero = false; + let mut emissions_drained = false; + + // Prices greater or lower than threshold + let mut prices_greater_than_one = false; + let mut prices_lower_than_one = false; + + for block in 1u64..5000 { + SubtensorModule::run_coinbase(block); + + for netuid in 1u16..=subnet_count { + assert_eq!( + pallet_subtensor::TotalSubnetTAO::::get(netuid), + pallet_subtensor::DynamicTAOReserve::::get(netuid) + ); + } + + // Check if this test encountered a moment when emissions were drained (epoch) + if !emissions_drained { + if !emissions_non_zero { + emissions_non_zero = pallet_subtensor::PendingEmission::::iter().all(|(_, e)| e != 0); + } else { + emissions_drained = pallet_subtensor::PendingEmission::::iter().any(|(_, e)| e == 0); + } + } + + // Check if this test encountered both prices > 1 and prices < 1 + if (1u16..=subnet_count) + .map(|netuid| SubtensorModule::get_tao_per_alpha_price(netuid).to_num::()) + .sum::() > get_price_threshold() { + prices_greater_than_one = true; + } else { + prices_lower_than_one = true; + } + } + + assert!(emissions_drained); + assert!(prices_lower_than_one); + assert!(prices_greater_than_one); + }); +} + +/// Test that if sum of prices is a small step greater than threshold, we get alpha emission +/// +#[test] +fn test_alpha_emission_edgecase_ok() { + new_test_ext(1).execute_with(|| { + SubtensorModule::set_target_stakes_per_interval(20); + + let netuid_stao = 1; + let netuid_dtao = 2; + let coldkey = U256::from(1); + let hotkey = U256::from(1); + pallet_subtensor::SubnetOwnerLockPeriod::::set(0); + + // Create one stao and one dtao subnet + let lock_amount = 100_000_000_000; + create_staked_stao_network(netuid_stao, lock_amount, 0); + add_dynamic_network(netuid_dtao, 1, 1, 1, lock_amount); + + // At this point both dtao price and price threshold are 0.5 + // If we add 1 rao stake, price will be slightly higher + let alpha_to_add = 1; + + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(coldkey), + hotkey, + netuid_dtao, + alpha_to_add + )); + + // Check that we archieved price threshold requirement + let price_sum = SubtensorModule::get_tao_per_alpha_price(netuid_dtao).to_num::(); + assert!(price_sum > get_price_threshold()); + + let block_emission = SubtensorModule::get_block_emission().unwrap_or(0); + + let total_subnet_tao_before = pallet_subtensor::TotalSubnetTAO::::get(netuid_dtao); + let dynamic_alpha_reserve_before = pallet_subtensor::DynamicAlphaReserve::::get(netuid_dtao); + + SubtensorModule::run_coinbase(1); + + let total_subnet_tao_after = pallet_subtensor::TotalSubnetTAO::::get(netuid_dtao); + let dynamic_alpha_reserve_after = pallet_subtensor::DynamicAlphaReserve::::get(netuid_dtao); + + // Ensure subnet alpha emissions are all equal to block emission + let expected_alpha_emission = block_emission as f64; + let alpha_emission = dynamic_alpha_reserve_after - dynamic_alpha_reserve_before; + assert!(((alpha_emission as f64 - expected_alpha_emission).abs() / expected_alpha_emission) < 0.00001); + + // Ensure total subnet tao didn't change + assert!(total_subnet_tao_after == total_subnet_tao_before); + }); +} + +/// Test that if sum of prices is a small step lower than threshold, we get tao emission +/// +#[test] +fn test_tao_emission_edgecase_ok() { + new_test_ext(1).execute_with(|| { + SubtensorModule::set_target_stakes_per_interval(20); + + let netuid_stao = 1; + let netuid_dtao = 2; + let coldkey = U256::from(1); + let hotkey = U256::from(1); + pallet_subtensor::SubnetOwnerLockPeriod::::set(0); + + // Create one stao and one dtao subnet + let lock_amount = 100_000_000_000; + create_staked_stao_network(netuid_stao, lock_amount, 0); + add_dynamic_network(netuid_dtao, 1, 1, 1, lock_amount); + + // At this point both dtao price and price threshold are 0.5 + // If we remove 1 rao stake, price will be slightly lower + let alpha_to_add = 1; + + assert_ok!(SubtensorModule::remove_subnet_stake( + <::RuntimeOrigin>::signed(coldkey), + hotkey, + netuid_dtao, + alpha_to_add + )); + + // Check that we archieved price threshold requirement + let price_sum = SubtensorModule::get_tao_per_alpha_price(netuid_dtao).to_num::(); + assert!(price_sum < get_price_threshold()); + + let total_subnet_tao_before = pallet_subtensor::TotalSubnetTAO::::get(netuid_dtao); + let dynamic_alpha_reserve_before = pallet_subtensor::DynamicAlphaReserve::::get(netuid_dtao); + + SubtensorModule::run_coinbase(1); + + let total_subnet_tao_after = pallet_subtensor::TotalSubnetTAO::::get(netuid_dtao); + let dynamic_alpha_reserve_after = pallet_subtensor::DynamicAlphaReserve::::get(netuid_dtao); + + // Ensure subnet alpha emissions are zero + assert_eq!(dynamic_alpha_reserve_after, dynamic_alpha_reserve_before); + + // Ensure total subnet tao is not zero + assert!(total_subnet_tao_after > total_subnet_tao_before); + }); +} + +/////////////////////////////////////////////////////////////////// +// Lock cost tests +// +// - Back to back lock price in the same block doubles +// - Lock price is the same as previous in 14 * 7200 blocks +// - Lock price is get_network_min_lock() in 28 * 7200 blocks +// - No panics or errors in 28 * 7200 + 1 blocks, lock price remains get_network_min_lock() +// - Cases when remaining balance after lock is ED+1, ED, ED-1, +// - test what can_remove_balance_from_coldkey_account returns +// - test that we don't register network and kill account +// +// get_network_lock_cost() + +#[test] +fn test_lock_cost_doubles_in_same_block() { + new_test_ext(1).execute_with(|| { + SubtensorModule::set_target_stakes_per_interval(20); + let lock_amount1 = SubtensorModule::get_network_lock_cost(); + add_dynamic_network(1, 1, 1, 1, lock_amount1); + let lock_amount2 = SubtensorModule::get_network_lock_cost(); + + assert_eq!(lock_amount1 * 2, lock_amount2); + }); +} + +#[test] +fn test_lock_cost_remains_same_after_lock_reduction_interval() { + new_test_ext(1).execute_with(|| { + SubtensorModule::set_target_stakes_per_interval(20); + let lock_amount1 = SubtensorModule::get_network_lock_cost(); + add_dynamic_network(1, 1, 1, 1, lock_amount1); + step_block(SubtensorModule::get_lock_reduction_interval() as u16); + let lock_amount2 = SubtensorModule::get_network_lock_cost(); + + assert_eq!(lock_amount1, lock_amount2); + }); +} + +#[test] +fn test_lock_cost_is_min_after_2_lock_reduction_intervals() { + new_test_ext(1).execute_with(|| { + SubtensorModule::set_target_stakes_per_interval(20); + let lock_amount1 = SubtensorModule::get_network_lock_cost(); + let min_lock_cost = SubtensorModule::get_network_min_lock(); + add_dynamic_network(1, 1, 1, 1, lock_amount1); + step_block(2 * SubtensorModule::get_lock_reduction_interval() as u16); + let lock_amount2 = SubtensorModule::get_network_lock_cost(); + + assert_eq!(lock_amount2, min_lock_cost); + }); +} + +#[test] +fn test_lock_cost_is_min_after_2_lock_reduction_intervals_2_subnets() { + new_test_ext(1).execute_with(|| { + SubtensorModule::set_target_stakes_per_interval(20); + let lock_amount1 = SubtensorModule::get_network_lock_cost(); + let min_lock_cost = SubtensorModule::get_network_min_lock(); + add_dynamic_network(1, 1, 1, 1, lock_amount1); + let lock_amount2 = SubtensorModule::get_network_lock_cost(); + add_dynamic_network(2, 1, 1, 1, lock_amount2); + step_block(2 * SubtensorModule::get_lock_reduction_interval() as u16); + let lock_amount3 = SubtensorModule::get_network_lock_cost(); + + assert_eq!(lock_amount3, min_lock_cost); + }); +} + +#[test] +fn test_registration_after_2_lock_reduction_intervals_ok() { + new_test_ext(1).execute_with(|| { + SubtensorModule::set_target_stakes_per_interval(20); + let lock_amount1 = SubtensorModule::get_network_lock_cost(); + add_dynamic_network(1, 1, 1, 1, lock_amount1); + step_block(2 * SubtensorModule::get_lock_reduction_interval() as u16 + 1); + add_dynamic_network(2, 1, 1, 1, lock_amount1); + }); +} + +#[test] +fn test_registration_balance_minimal_ok() { + new_test_ext(1).execute_with(|| { + SubtensorModule::set_target_stakes_per_interval(20); + let lock_amount = SubtensorModule::get_network_lock_cost(); + let hotkey = U256::from(0); + let coldkey = U256::from(1); + + SubtensorModule::add_balance_to_coldkey_account(&coldkey, lock_amount); + assert_ok!(SubtensorModule::user_add_network( + <::RuntimeOrigin>::signed(coldkey), + hotkey, + SubnetType::DTAO + )); + + let account = System::account(coldkey); + assert_eq!(account.data.free, ExistentialDeposit::get()); + }); +} + +#[test] +fn test_registration_balance_minimal_plus_ed_ok() { + new_test_ext(1).execute_with(|| { + SubtensorModule::set_target_stakes_per_interval(20); + let lock_amount = SubtensorModule::get_network_lock_cost(); + let hotkey = U256::from(0); + let coldkey = U256::from(1); + + SubtensorModule::add_balance_to_coldkey_account( + &coldkey, + lock_amount + ExistentialDeposit::get(), + ); + assert_ok!(SubtensorModule::user_add_network( + <::RuntimeOrigin>::signed(coldkey), + hotkey, + SubnetType::DTAO + )); + + let account = System::account(coldkey); + assert_eq!(account.data.free, ExistentialDeposit::get()); + }); +} + +#[test] +fn test_registration_balance_minimal_plus_ed_plus_1_ok() { + new_test_ext(1).execute_with(|| { + SubtensorModule::set_target_stakes_per_interval(20); + let lock_amount = SubtensorModule::get_network_lock_cost(); + let hotkey = U256::from(0); + let coldkey = U256::from(1); + + SubtensorModule::add_balance_to_coldkey_account( + &coldkey, + lock_amount + ExistentialDeposit::get() + 1, + ); + assert_ok!(SubtensorModule::user_add_network( + <::RuntimeOrigin>::signed(coldkey), + hotkey, + SubnetType::DTAO + )); + + let account = System::account(coldkey); + assert_eq!(account.data.free, ExistentialDeposit::get() + 1); + }); +} + +#[test] +fn test_registration_balance_minimal_plus_ed_minus_1_ok() { + new_test_ext(1).execute_with(|| { + SubtensorModule::set_target_stakes_per_interval(20); + let lock_amount = SubtensorModule::get_network_lock_cost(); + let hotkey = U256::from(0); + let coldkey = U256::from(1); + + SubtensorModule::add_balance_to_coldkey_account( + &coldkey, + lock_amount + ExistentialDeposit::get() - 1, + ); + assert_ok!(SubtensorModule::user_add_network( + <::RuntimeOrigin>::signed(coldkey), + hotkey, + SubnetType::DTAO + )); + + let account = System::account(coldkey); + assert_eq!(account.data.free, ExistentialDeposit::get()); + }); +} + +#[ignore] +#[test] +fn test_stake_unstake_total_issuance() { + new_test_ext(1).execute_with(|| { + // init params. + let hotkey = U256::from(0); + let coldkey = U256::from(1); + let coldkey2 = U256::from(2); + let lock_amount = 100_000_000_000_u64; + let stake = 100_000_000_000_u64; + let ed = ExistentialDeposit::get(); + + // Register subnet and become a delegate. + SubtensorModule::add_balance_to_coldkey_account(&coldkey, lock_amount); + assert_ok!(SubtensorModule::user_add_network( + <::RuntimeOrigin>::signed(coldkey), + hotkey, + SubnetType::DTAO + )); + assert_eq!(SubtensorModule::get_tao_reserve(1), lock_amount); + assert_eq!(SubtensorModule::get_alpha_reserve(1), lock_amount); + assert_eq!(SubtensorModule::get_tao_per_alpha_price(1), 1.0); + + SubtensorModule::add_balance_to_coldkey_account(&coldkey2, stake); + + // Total issuance in balances pallet should be equal to stake + ED now + assert_eq!(PalletBalances::total_issuance(), stake + ed); + + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(coldkey2), + hotkey, + 1, + stake + )); + + assert_eq!(SubtensorModule::get_tao_reserve(1), lock_amount + stake); + let expected_alpha = + lock_amount as f64 * stake as f64 / (lock_amount as f64 + stake as f64); + assert_eq!(SubtensorModule::get_alpha_reserve(1), expected_alpha as u64); + assert_eq!(SubtensorModule::get_tao_per_alpha_price(1), 4); // Price is increased from the stake operation. + + // Total issuance goes down to 2 * ED because we staked everything + assert_eq!(PalletBalances::total_issuance(), 2 * ed); + + // Unstake everything + assert_ok!(SubtensorModule::remove_subnet_stake( + <::RuntimeOrigin>::signed(coldkey2), + hotkey, + 1, + expected_alpha as u64 + )); + + // Total issuance goes up to stake + ED because we unstaked everything and got the balance back + assert_eq!(PalletBalances::total_issuance(), stake + ed); + }) +} diff --git a/pallets/subtensor/tests/dynamic_pool_info.rs b/pallets/subtensor/tests/dynamic_pool_info.rs new file mode 100644 index 000000000..b2c7f3f3a --- /dev/null +++ b/pallets/subtensor/tests/dynamic_pool_info.rs @@ -0,0 +1,54 @@ +mod mock; +use frame_support::assert_ok; +use frame_system::Config; +use mock::*; +use pallet_subtensor::types::SubnetType; +use sp_core::U256; + +#[test] +fn test_dynamic_pool_info() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let hotkey = U256::from(0); + let coldkey = U256::from(1); + let lock_cost = SubtensorModule::get_network_lock_cost(); + + SubtensorModule::add_balance_to_coldkey_account(&coldkey, 500_000_000_000_000); // 500 TAO. + log::info!("Network lock cost is {:?}", lock_cost); + + // Register a network + assert_ok!(SubtensorModule::user_add_network( + <::RuntimeOrigin>::signed(coldkey), + hotkey, + SubnetType::DTAO + )); + + // Check initial dynamic pool info after registration + let initial_pool_info = SubtensorModule::get_dynamic_pool_info_v2(netuid).unwrap(); + + assert_eq!( + initial_pool_info.alpha_issuance, 0, + "Alpha issuance should be initialized to 0" + ); + assert_eq!( + initial_pool_info.alpha_outstanding, lock_cost, + "Alpha outstanding should be initialized to lock_cost" + ); + assert_eq!( + initial_pool_info.alpha_reserve, lock_cost, + "Alpha reserve should be initialized to lock_cost" + ); + assert_eq!( + initial_pool_info.tao_reserve, lock_cost, + "Tao reserve should be initialized to lock_cost" + ); + assert_eq!( + initial_pool_info.netuid, netuid, + "NetUID should match the one used for registration" + ); + + let all_pool_infos = SubtensorModule::get_all_dynamic_pool_infos_v2(); + assert_eq!(all_pool_infos.len(), 1); // Assuming only one network is added + assert_eq!(all_pool_infos[0], initial_pool_info); + }); +} diff --git a/pallets/subtensor/tests/epoch.rs b/pallets/subtensor/tests/epoch.rs index 0bfd11ba4..532e28075 100644 --- a/pallets/subtensor/tests/epoch.rs +++ b/pallets/subtensor/tests/epoch.rs @@ -4,9 +4,15 @@ use frame_system::Config; use rand::{distributions::Uniform, rngs::StdRng, seq::SliceRandom, thread_rng, Rng, SeedableRng}; use sp_core::U256; use std::time::Instant; -use substrate_fixed::types::I32F32; +use substrate_fixed::types::{I32F32, I64F64}; mod mock; +#[macro_use] +mod helpers; + +// To run just the tests in this file, use the following command: +// cargo test -p pallet-subtensor --test epoch + pub fn fixed(val: f32) -> I32F32 { I32F32::from_num(val) } @@ -114,7 +120,7 @@ fn distribute_nodes( fn uid_stats(netuid: u16, uid: u16) { log::info!( "stake: {:?}", - SubtensorModule::get_total_stake_for_hotkey(&(U256::from(uid))) + SubtensorModule::get_hotkey_global_dynamic_tao(&(U256::from(uid))) ); log::info!("rank: {:?}", SubtensorModule::get_rank_for_uid(netuid, uid)); log::info!( @@ -174,9 +180,10 @@ fn init_run_epochs( // let stake: u64 = 1; // alternative test: all nodes receive stake, should be same outcome, except stake SubtensorModule::add_balance_to_coldkey_account(&(U256::from(key)), stake); SubtensorModule::append_neuron(netuid, &(U256::from(key)), 0); - SubtensorModule::increase_stake_on_coldkey_hotkey_account( + SubtensorModule::increase_subnet_token_on_coldkey_hotkey_account( &U256::from(key), &U256::from(key), + netuid, stake, ); } @@ -552,9 +559,15 @@ fn test_1_graph() { let uid: u16 = 0; let stake_amount: u64 = 1; add_network(netuid, u16::MAX - 1, 0); // set higher tempo to avoid built-in epoch, then manual epoch instead + SubtensorModule::set_global_stake_weight(0); // Set the stake weight to 100% on this subnet alone. SubtensorModule::set_max_allowed_uids(netuid, 1); SubtensorModule::add_balance_to_coldkey_account(&coldkey, stake_amount); - SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey, &hotkey, stake_amount); + SubtensorModule::increase_subnet_token_on_coldkey_hotkey_account( + &coldkey, + &hotkey, + netuid, + stake_amount, + ); SubtensorModule::append_neuron(netuid, &hotkey, 0); assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 1); run_to_block(1); // run to next block to ensure weights are set on nodes after their registration block @@ -567,14 +580,11 @@ fn test_1_graph() { )); // SubtensorModule::set_weights_for_testing( netuid, i as u16, vec![ ( 0, u16::MAX )]); // doesn't set update status // SubtensorModule::set_bonds_for_testing( netuid, uid, vec![ ( 0, u16::MAX )]); // rather, bonds are calculated in epoch - SubtensorModule::set_emission_values(&[netuid], vec![1_000_000_000]).unwrap(); - assert_eq!( - SubtensorModule::get_subnet_emission_value(netuid), - 1_000_000_000 - ); + set_emission_values(netuid, 1_000_000_000); + assert_eq!(SubtensorModule::get_emission_value(netuid), 1_000_000_000); SubtensorModule::epoch(netuid, 1_000_000_000); assert_eq!( - SubtensorModule::get_total_stake_for_hotkey(&hotkey), + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey), stake_amount ); assert_eq!(SubtensorModule::get_rank_for_uid(netuid, uid), 0); @@ -605,9 +615,10 @@ fn test_10_graph() { stake_amount, SubtensorModule::get_subnetwork_n(netuid), ); - SubtensorModule::increase_stake_on_coldkey_hotkey_account( + SubtensorModule::increase_subnet_token_on_coldkey_hotkey_account( &coldkey, &hotkey, + netuid, stake_amount, ); SubtensorModule::append_neuron(netuid, &hotkey, 0); @@ -618,6 +629,7 @@ fn test_10_graph() { let n: usize = 10; let netuid: u16 = 1; add_network(netuid, u16::MAX - 1, 0); // set higher tempo to avoid built-in epoch, then manual epoch instead + SubtensorModule::set_global_stake_weight(0); SubtensorModule::set_max_allowed_uids(netuid, n as u16); for i in 0..10 { add_node(netuid, U256::from(i), U256::from(i), i as u16, 1) @@ -638,7 +650,7 @@ fn test_10_graph() { // Check return values. for i in 0..n { assert_eq!( - SubtensorModule::get_total_stake_for_hotkey(&(U256::from(i))), + SubtensorModule::get_hotkey_global_dynamic_tao(&(U256::from(i))), 1 ); assert_eq!(SubtensorModule::get_rank_for_uid(netuid, i as u16), 0); @@ -693,7 +705,7 @@ fn test_512_graph() { let bonds = SubtensorModule::get_bonds(netuid); for uid in validators { assert_eq!( - SubtensorModule::get_total_stake_for_hotkey(&(U256::from(uid))), + SubtensorModule::get_hotkey_global_dynamic_tao(&(U256::from(uid))), max_stake_per_validator ); assert_eq!(SubtensorModule::get_rank_for_uid(netuid, uid), 0); @@ -708,7 +720,7 @@ fn test_512_graph() { } for uid in servers { assert_eq!( - SubtensorModule::get_total_stake_for_hotkey(&(U256::from(uid))), + SubtensorModule::get_hotkey_global_dynamic_tao(&(U256::from(uid))), 0 ); assert_eq!(SubtensorModule::get_rank_for_uid(netuid, uid), 146); // Note R = floor(1 / (512 - 64) * 65_535) = 146 @@ -755,6 +767,7 @@ fn test_512_graph_random_weights() { // Dense epoch new_test_ext(1).execute_with(|| { + SubtensorModule::set_global_stake_weight(0); init_run_epochs( netuid, network_n, @@ -785,6 +798,7 @@ fn test_512_graph_random_weights() { // Sparse epoch (same random seed as dense) new_test_ext(1).execute_with(|| { + SubtensorModule::set_global_stake_weight(0); init_run_epochs( netuid, network_n, @@ -836,6 +850,7 @@ fn test_4096_graph() { let network_n: u16 = 4096; let validators_n: u16 = 256; let epochs: u16 = 1; + SubtensorModule::set_global_stake_weight(0); let max_stake_per_validator: u64 = 82_031_250_000_000; // 21_000_000_000_000_000 / 256 log::info!("test_{network_n:?}_graph ({validators_n:?} validators)"); for interleave in 0..3 { @@ -865,11 +880,10 @@ fn test_4096_graph() { 0, true, ); - assert_eq!(SubtensorModule::get_total_stake(), 21_000_000_000_000_000); let bonds = SubtensorModule::get_bonds(netuid); for uid in &validators { assert_eq!( - SubtensorModule::get_total_stake_for_hotkey(&(U256::from(*uid as u64))), + SubtensorModule::get_hotkey_global_dynamic_tao(&(U256::from(*uid as u64))), max_stake_per_validator ); assert_eq!(SubtensorModule::get_rank_for_uid(netuid, *uid), 0); @@ -886,7 +900,7 @@ fn test_4096_graph() { } for uid in &servers { assert_eq!( - SubtensorModule::get_total_stake_for_hotkey(&(U256::from(*uid as u64))), + SubtensorModule::get_hotkey_global_dynamic_tao(&(U256::from(*uid as u64))), 0 ); assert_eq!(SubtensorModule::get_rank_for_uid(netuid, *uid), 17); // Note R = floor(1 / (4096 - 256) * 65_535) = 17 @@ -915,6 +929,7 @@ fn test_16384_graph_sparse() { let servers: Vec = (validators_n..n).collect(); let server: u16 = servers[0]; let epochs: u16 = 1; + SubtensorModule::set_global_stake_weight(0); log::info!("test_{n:?}_graph ({validators_n:?} validators)"); init_run_epochs( netuid, @@ -935,7 +950,7 @@ fn test_16384_graph_sparse() { let bonds = SubtensorModule::get_bonds(netuid); for uid in validators { assert_eq!( - SubtensorModule::get_total_stake_for_hotkey(&(U256::from(uid))), + SubtensorModule::get_hotkey_global_dynamic_tao(&(U256::from(uid))), 1 ); assert_eq!(SubtensorModule::get_rank_for_uid(netuid, uid), 0); @@ -952,7 +967,7 @@ fn test_16384_graph_sparse() { } for uid in servers { assert_eq!( - SubtensorModule::get_total_stake_for_hotkey(&(U256::from(uid))), + SubtensorModule::get_hotkey_global_dynamic_tao(&(U256::from(uid))), 0 ); assert_eq!(SubtensorModule::get_rank_for_uid(netuid, uid), 4); // Note R = floor(1 / (16384 - 512) * 65_535) = 4 @@ -979,6 +994,7 @@ fn test_bonds() { let stakes: Vec = vec![1, 2, 3, 4, 0, 0, 0, 0]; let block_number = System::block_number(); add_network(netuid, tempo, 0); + SubtensorModule::set_global_stake_weight( 0 ); SubtensorModule::set_max_allowed_uids( netuid, n ); assert_eq!(SubtensorModule::get_max_allowed_uids(netuid), n); SubtensorModule::set_max_registrations_per_block( netuid, n ); @@ -992,7 +1008,7 @@ fn test_bonds() { SubtensorModule::add_balance_to_coldkey_account( &U256::from(key), max_stake ); let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( netuid, block_number, key * 1_000_000, &U256::from(key)); assert_ok!(SubtensorModule::register(<::RuntimeOrigin>::signed(U256::from(key)), netuid, block_number, nonce, work, U256::from(key), U256::from(key))); - SubtensorModule::increase_stake_on_coldkey_hotkey_account( &U256::from(key), &U256::from(key), stakes[key as usize] ); + SubtensorModule::increase_subnet_token_on_coldkey_hotkey_account( &U256::from(key), &U256::from(key), netuid, stakes[key as usize] ); } assert_eq!(SubtensorModule::get_max_allowed_uids(netuid), n); assert_eq!(SubtensorModule::get_subnetwork_n(netuid), n); @@ -1276,6 +1292,7 @@ fn test_active_stake() { add_network(netuid, tempo, 0); SubtensorModule::set_max_allowed_uids(netuid, n); assert_eq!(SubtensorModule::get_max_allowed_uids(netuid), n); + SubtensorModule::set_global_stake_weight(0); SubtensorModule::set_max_registrations_per_block(netuid, n); SubtensorModule::set_target_registrations_per_interval(netuid, n); SubtensorModule::set_min_allowed_weights(netuid, 0); @@ -1299,9 +1316,10 @@ fn test_active_stake() { U256::from(key), U256::from(key) )); - SubtensorModule::increase_stake_on_coldkey_hotkey_account( + SubtensorModule::increase_subnet_token_on_coldkey_hotkey_account( &U256::from(key), &U256::from(key), + netuid, stake, ); } @@ -1480,6 +1498,7 @@ fn test_outdated_weights() { let mut block_number: u64 = System::block_number(); let stake: u64 = 1; add_network(netuid, tempo, 0); + SubtensorModule::set_global_stake_weight(0); SubtensorModule::set_max_allowed_uids(netuid, n); SubtensorModule::set_weights_set_rate_limit(netuid, 0); SubtensorModule::set_max_registrations_per_block(netuid, n); @@ -1506,9 +1525,10 @@ fn test_outdated_weights() { U256::from(key), U256::from(key) )); - SubtensorModule::increase_stake_on_coldkey_hotkey_account( + SubtensorModule::increase_subnet_token_on_coldkey_hotkey_account( &U256::from(key), &U256::from(key), + netuid, stake, ); } @@ -1665,6 +1685,7 @@ fn test_zero_weights() { let mut block_number: u64 = 0; let stake: u64 = 1; add_network(netuid, tempo, 0); + SubtensorModule::set_global_stake_weight(0); SubtensorModule::set_max_allowed_uids(netuid, n); SubtensorModule::set_weights_set_rate_limit(netuid, 0); SubtensorModule::set_max_registrations_per_block(netuid, n); @@ -1692,9 +1713,10 @@ fn test_zero_weights() { } for validator in 0..(n / 2) as u64 { SubtensorModule::add_balance_to_coldkey_account(&U256::from(validator), stake); - SubtensorModule::increase_stake_on_coldkey_hotkey_account( + SubtensorModule::increase_subnet_token_on_coldkey_hotkey_account( &U256::from(validator), &U256::from(validator), + netuid, stake, ); } @@ -1854,6 +1876,9 @@ fn test_validator_permits() { let netuid: u16 = 1; let tempo: u16 = u16::MAX - 1; // high tempo to skip automatic epochs in on_initialize, use manual epochs instead for interleave in 0..3 { + // network_n - total number of neurons in the network + // validators_n - number of validators among these neurons + // servers - neurons that don't have validator permit for (network_n, validators_n) in [(2, 1), (4, 2), (8, 4)] { for assignment in 0..=1 { let (validators, servers) = @@ -1908,9 +1933,10 @@ fn test_validator_permits() { U256::from(key), U256::from(key) )); - SubtensorModule::increase_stake_on_coldkey_hotkey_account( + SubtensorModule::increase_subnet_token_on_coldkey_hotkey_account( &U256::from(key), &U256::from(key), + netuid, stake[key as usize], ); } @@ -1942,9 +1968,10 @@ fn test_validator_permits() { &(U256::from(*server as u64)), 2 * network_n as u64, ); - SubtensorModule::increase_stake_on_coldkey_hotkey_account( + SubtensorModule::increase_subnet_token_on_coldkey_hotkey_account( &(U256::from(*server as u64)), &(U256::from(*server as u64)), + netuid, 2 * network_n as u64, ); } @@ -1972,101 +1999,413 @@ fn test_validator_permits() { } } -// // Map the retention graph for consensus guarantees with an single epoch on a graph with 512 nodes, of which the first 64 are validators, the graph is split into a major and minor set, each setting specific weight on itself and the complement on the other. -// // -// // ```import torch -// // import matplotlib.pyplot as plt -// // from matplotlib.pyplot import cm -// // %matplotlib inline -// // -// // with open('finney_consensus_0.4.txt') as f: # test output saved to finney_consensus.txt -// // retention_map = eval(f.read()) -// // -// // major_ratios = {} -// // avg_weight_devs = {} -// // for major_stake, major_weight, minor_weight, avg_weight_dev, major_ratio in retention_map: -// // major_stake = f'{major_stake:.2f}' -// // maj, min = int(round(50 * major_weight)), int(round(50 * minor_weight)) -// // avg_weight_devs.setdefault(major_stake, torch.zeros((51, 51))) -// // avg_weight_devs[major_stake][maj][min] = avg_weight_dev -// // major_ratios.setdefault(major_stake, torch.zeros((51, 51))) -// // major_ratios[major_stake][maj][min] = major_ratio -// // -// // _x = torch.linspace(0, 1, 51); _y = torch.linspace(0, 1, 51) -// // x, y = torch.meshgrid(_x, _y, indexing='ij') -// // -// // fig = plt.figure(figsize=(6, 6), dpi=70); ax = fig.gca() -// // ax.set_xticks(torch.arange(0, 1, 0.05)); ax.set_yticks(torch.arange(0, 1., 0.05)) -// // ax.set_xticklabels([f'{_:.2f}'[1:] for _ in torch.arange(0, 1., 0.05)]) -// // plt.grid(); plt.rc('grid', linestyle="dotted", color=[0.85, 0.85, 0.85]) -// // -// // isolate = ['0.60']; stakes = [0.51, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 0.99] -// // colors = cm.viridis(torch.linspace(0, 1, len(stakes) + 1)) -// // for i, stake in enumerate(stakes): -// // contours = plt.contour(x, y, major_ratios[f'{stake:.2f}'], levels=[0., stake], colors=[colors[i + 1]]) -// // if f'{stake:.2f}' in isolate: -// // contours.collections[1].set_linewidth(3) -// // plt.clabel(contours, inline=True, fontsize=10) -// // -// // plt.title(f'Major emission [$stake_{{maj}}=emission_{{maj}}$ retention lines]') -// // plt.ylabel('Minor self-weight'); plt.xlabel('Major self-weight'); plt.show() -// // ``` -// // #[test] -// fn _map_consensus_guarantees() { -// let netuid: u16 = 1; -// let network_n: u16 = 512; -// let validators_n: u16 = 64; -// let epochs: u16 = 1; -// let interleave = 0; -// let weight_stddev: I32F32 = fixed(0.4); -// println!("["); -// for _major_stake in vec![0.51, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 0.99] { -// let major_stake: I32F32 = I32F32::from_num(_major_stake); -// for _major_weight in 0..51 { -// let major_weight: I32F32 = I32F32::from_num(50 - _major_weight) / I32F32::from_num(50); -// for _minor_weight in 0..51 { -// let minor_weight: I32F32 = -// I32F32::from_num(50 - _minor_weight) / I32F32::from_num(50); -// let ( -// validators, -// servers, -// major_validators, -// minor_validators, -// major_servers, -// minor_servers, -// stake, -// weights, -// avg_weight_dev, -// ) = split_graph( -// major_stake, -// major_weight, -// minor_weight, -// weight_stddev, -// validators_n as usize, -// network_n as usize, -// interleave as usize, -// ); - -// new_test_ext(1).execute_with(|| { -// init_run_epochs(netuid, network_n, &validators, &servers, epochs, 1, true, &stake, true, &weights, true, false, 0, true); - -// let mut major_emission: I64F64 = I64F64::from_num(0); -// let mut minor_emission: I64F64 = I64F64::from_num(0); -// for set in vec![major_validators, major_servers] { -// for uid in set { -// major_emission += I64F64::from_num(SubtensorModule::get_emission_for_uid( netuid, uid )); -// } -// } -// for set in vec![minor_validators, minor_servers] { -// for uid in set { -// minor_emission += I64F64::from_num(SubtensorModule::get_emission_for_uid( netuid, uid )); -// } -// } -// let major_ratio: I32F32 = I32F32::from_num(major_emission / (major_emission + minor_emission)); -// println!("[{major_stake}, {major_weight:.2}, {minor_weight:.2}, {avg_weight_dev:.3}, {major_ratio:.3}], "); -// }); -// } -// } -// } -// println!("]"); -// } +#[test] +fn test_get_stakes_division_by_zero_is_checked() { + new_test_ext(1).execute_with(|| { + let lock_amount = 100_000_000_000; + setup_dynamic_network(1u16, 1u16, 1u16, lock_amount); + SubtensorModule::set_alpha_outstanding(1u16, 0); + + let hotkey_tuples = vec![(0u16, U256::from(1))]; + let gsw = SubtensorModule::get_global_stake_weights(&hotkey_tuples); + + assert_eq!(gsw.len(), 1); + assert_eq!(gsw[0], 1.0); + }); +} + +#[test] +fn test_gsw_1_subnet_1_hotkey_1_nominator_0_stake() { + new_test_ext(1).execute_with(|| { + let lock_amount = 100_000_000_000; + setup_dynamic_network(1u16, 1u16, 1u16, lock_amount); + + let hotkey_tuples = vec![(0u16, U256::from(1))]; + let gsw = SubtensorModule::get_global_stake_weights(&hotkey_tuples); + + assert_eq!(gsw.len(), 1); + assert_eq!(gsw[0], 1.0); // New network, one stake == TAO == weight is 1 + }); +} + +#[test] +fn test_gsw_2_subnets_2_hotkeys_0_nominators_0_stake() { + new_test_ext(1).execute_with(|| { + let lock_amount = 100_000_000_000; + setup_dynamic_network(1u16, 1u16, 1u16, lock_amount); + setup_dynamic_network(2u16, 2u16, 2u16, lock_amount); + + let hotkey_tuples = vec![(0u16, U256::from(1)), (1u16, U256::from(2))]; + let gsw = SubtensorModule::get_global_stake_weights(&hotkey_tuples); + + assert_eq!(gsw.len(), 2); + assert_eq!(gsw[0], 0.5); + assert_eq!(gsw[1], 0.5); + }); +} + +#[test] +fn test_gsw_1_subnet_1_hotkey_1_nominator_1_stake() { + new_test_ext(1).execute_with(|| { + let lock_amount = 100_000_000_000; + setup_dynamic_network(1u16, 1u16, 1u16, lock_amount); + add_dynamic_stake(1u16, 1u16, 1u16, 1_000_000_000u64); + + let hotkey_tuples = vec![(0u16, U256::from(1))]; + let gsw = SubtensorModule::get_global_stake_weights(&hotkey_tuples); + + assert_eq!(gsw.len(), 1); + assert_eq!(gsw[0], 1.0); // All stake in one hotkey == weight is 1 + }); +} + +#[test] +fn test_gsw_2_subnets_2_hotkeys_2_nominators_100_stake() { + new_test_ext(1).execute_with(|| { + let lock_amount = 100_000_000_000; + setup_dynamic_network(1u16, 1u16, 1u16, lock_amount); + setup_dynamic_network(2u16, 2u16, 2u16, lock_amount); + add_dynamic_stake(1u16, 1u16, 1u16, 100_000_000_000u64); + add_dynamic_stake(2u16, 2u16, 2u16, 100_000_000_000u64); + + let hotkey_tuples = vec![(0u16, U256::from(1)), (1u16, U256::from(2))]; + let gsw = SubtensorModule::get_global_stake_weights(&hotkey_tuples); + + assert_eq!(gsw.len(), 2); + assert_eq!(gsw[0], 0.5); + assert_eq!(gsw[1], 0.5); + }); +} + +#[test] +fn test_gsw_1_subnet_2_hotkeys_2_nominators_uneven_stake() { + new_test_ext(1).execute_with(|| { + let lock_amount = 100_000_000_000; + setup_dynamic_network(1u16, 1u16, 1u16, lock_amount); + add_dynamic_stake(1u16, 1u16, 1u16, 100_000_000_000u64); + add_dynamic_stake(1u16, 1u16, 2u16, 300_000_000_000u64); + + let hotkey_tuples = vec![(0u16, U256::from(1)), (1u16, U256::from(2))]; + let gsw = SubtensorModule::get_global_stake_weights(&hotkey_tuples); + + assert_eq!(gsw.len(), 2); + assert_i64f64_approx_eq!(gsw[0], 0.833333); + assert_i64f64_approx_eq!(gsw[1], 0.166666); + }); +} + +#[test] +fn test_gsw_2_subnets_2_hotkeys_2_nominators_uneven_stake() { + new_test_ext(1).execute_with(|| { + let lock_amount = 100_000_000_000; + setup_dynamic_network(1u16, 1u16, 1u16, lock_amount); + setup_dynamic_network(2u16, 2u16, 2u16, lock_amount); + add_dynamic_stake(1u16, 1u16, 1u16, 100_000_000_000u64); + add_dynamic_stake(2u16, 1u16, 2u16, 300_000_000_000u64); + + let hotkey_tuples = vec![(0u16, U256::from(1)), (1u16, U256::from(2))]; + let gsw = SubtensorModule::get_global_stake_weights(&hotkey_tuples); + + assert_eq!(gsw.len(), 2); + assert_i64f64_approx_eq!(gsw[0], 0.333333); + assert_i64f64_approx_eq!(gsw[1], 0.666666); + }); +} + +#[test] +fn test_gsw_2_subnets_2_hotkeys_2_nominators_uneven_cross_stake() { + new_test_ext(1).execute_with(|| { + let lock_amount = 100_000_000_000; + setup_dynamic_network(1u16, 1u16, 1u16, lock_amount); + setup_dynamic_network(2u16, 2u16, 2u16, lock_amount); + add_dynamic_stake(1u16, 1u16, 1u16, 100_000_000_000u64); + add_dynamic_stake(1u16, 1u16, 2u16, 200_000_000_000u64); + add_dynamic_stake(2u16, 1u16, 1u16, 300_000_000_000u64); + add_dynamic_stake(2u16, 1u16, 2u16, 400_000_000_000u64); + + let hotkey_tuples = vec![(0u16, U256::from(1)), (1u16, U256::from(2))]; + let gsw = SubtensorModule::get_global_stake_weights(&hotkey_tuples); + + assert_eq!(gsw.len(), 2); + assert_i64f64_approx_eq!(gsw[0], 0.552381); + assert_i64f64_approx_eq!(gsw[1], 0.447619); + }); +} + +#[test] +fn test_lsw_1_subnet_1_hotkey_1_nominator_0_stake() { + new_test_ext(1).execute_with(|| { + let lock_amount = 100_000_000_000; + setup_dynamic_network(1u16, 1u16, 1u16, lock_amount); + + let hotkey_tuples = vec![(0u16, U256::from(1))]; + let lsw1 = SubtensorModule::get_local_stake_weights(1, &hotkey_tuples); + + assert_eq!(lsw1.len(), 1); + assert_eq!(lsw1[0], 1.0); + }); +} + +#[test] +fn test_lsw_2_subnets_2_hotkeys_0_nominators_0_stake() { + new_test_ext(1).execute_with(|| { + let lock_amount = 100_000_000_000; + setup_dynamic_network(1u16, 1u16, 1u16, lock_amount); + setup_dynamic_network(2u16, 2u16, 2u16, lock_amount); + + let hotkey_tuples = vec![(0u16, U256::from(1)), (1u16, U256::from(2))]; + let lsw1 = SubtensorModule::get_local_stake_weights(1, &hotkey_tuples); + let lsw2 = SubtensorModule::get_local_stake_weights(2, &hotkey_tuples); + + assert_eq!(lsw1.len(), 2); + assert_eq!(lsw1[0], 1); + assert_eq!(lsw1[1], 0); + assert_eq!(lsw2.len(), 2); + assert_eq!(lsw2[0], 0); + assert_eq!(lsw2[1], 1); + }); +} + +#[test] +fn test_lsw_1_subnet_1_hotkey_1_nominator_1_stake() { + new_test_ext(1).execute_with(|| { + let lock_amount = 100_000_000_000; + setup_dynamic_network(1u16, 1u16, 1u16, lock_amount); + add_dynamic_stake(1u16, 1u16, 1u16, 1_000_000_000u64); + + let hotkey_tuples = vec![(0u16, U256::from(1))]; + let lsw1 = SubtensorModule::get_local_stake_weights(1, &hotkey_tuples); + + assert_eq!(lsw1.len(), 1); + assert_eq!(lsw1[0], 1.0); + }); +} + +#[test] +fn test_lsw_2_subnets_2_hotkeys_2_nominators_100_stake() { + new_test_ext(1).execute_with(|| { + let lock_amount = 100_000_000_000; + setup_dynamic_network(1u16, 1u16, 1u16, lock_amount); + setup_dynamic_network(2u16, 2u16, 2u16, lock_amount); + add_dynamic_stake(1u16, 1u16, 1u16, 100_000_000_000u64); + add_dynamic_stake(2u16, 2u16, 2u16, 100_000_000_000u64); + + let hotkey_tuples = vec![(0u16, U256::from(1)), (1u16, U256::from(2))]; + let lsw1 = SubtensorModule::get_local_stake_weights(1, &hotkey_tuples); + let lsw2 = SubtensorModule::get_local_stake_weights(2, &hotkey_tuples); + + assert_eq!(lsw1.len(), 2); + assert_eq!(lsw1[0], 1); + assert_eq!(lsw1[1], 0); + assert_eq!(lsw2.len(), 2); + assert_eq!(lsw2[0], 0); + assert_eq!(lsw2[1], 1); + }); +} + +#[test] +fn test_lsw_1_subnet_2_hotkeys_2_nominators_uneven_stake() { + new_test_ext(1).execute_with(|| { + let lock_amount = 100_000_000_000; + setup_dynamic_network(1u16, 1u16, 1u16, lock_amount); + add_dynamic_stake(1u16, 1u16, 1u16, 100_000_000_000u64); + add_dynamic_stake(1u16, 1u16, 2u16, 300_000_000_000u64); + + let hotkey_tuples = vec![(0u16, U256::from(1)), (1u16, U256::from(2))]; + let lsw1 = SubtensorModule::get_local_stake_weights(1, &hotkey_tuples); + + assert_eq!(lsw1.len(), 2); + assert_i64f64_approx_eq!(lsw1[0], 0.833333); + assert_i64f64_approx_eq!(lsw1[1], 0.166667); + }); +} + +#[test] +fn test_lsw_2_subnets_2_hotkeys_2_nominators_uneven_stake() { + new_test_ext(1).execute_with(|| { + let lock_amount = 100_000_000_000; + setup_dynamic_network(1u16, 1u16, 1u16, lock_amount); + setup_dynamic_network(2u16, 2u16, 2u16, lock_amount); + add_dynamic_stake(1u16, 1u16, 1u16, 100_000_000_000u64); + add_dynamic_stake(2u16, 1u16, 2u16, 300_000_000_000u64); + + let hotkey_tuples = vec![(0u16, U256::from(1)), (1u16, U256::from(2))]; + let lsw1 = SubtensorModule::get_local_stake_weights(1, &hotkey_tuples); + let lsw2 = SubtensorModule::get_local_stake_weights(2, &hotkey_tuples); + + assert_eq!(lsw1.len(), 2); + assert_eq!(lsw1[0], 1); + assert_eq!(lsw1[1], 0); + assert_eq!(lsw2.len(), 2); + assert_eq!(lsw2[0], 0); + assert_eq!(lsw2[1], 1); + }); +} + +#[test] +fn test_lsw_2_subnets_2_hotkeys_2_nominators_uneven_cross_stake() { + new_test_ext(1).execute_with(|| { + let lock_amount = 100_000_000_000; + setup_dynamic_network(1u16, 1u16, 1u16, lock_amount); + setup_dynamic_network(2u16, 2u16, 2u16, lock_amount); + add_dynamic_stake(1u16, 1u16, 1u16, 100_000_000_000u64); + add_dynamic_stake(1u16, 1u16, 2u16, 200_000_000_000u64); + add_dynamic_stake(2u16, 1u16, 1u16, 300_000_000_000u64); + add_dynamic_stake(2u16, 1u16, 2u16, 400_000_000_000u64); + + let hotkey_tuples = vec![(0u16, U256::from(1)), (1u16, U256::from(2))]; + let lsw1 = SubtensorModule::get_local_stake_weights(1, &hotkey_tuples); + let lsw2 = SubtensorModule::get_local_stake_weights(2, &hotkey_tuples); + + assert_eq!(lsw1.len(), 2); + assert_i64f64_approx_eq!(lsw1[0], 0.857143); + assert_i64f64_approx_eq!(lsw1[1], 0.142857); + assert_eq!(lsw2.len(), 2); + assert_i64f64_approx_eq!(lsw2[0], 0.4); + assert_i64f64_approx_eq!(lsw2[1], 0.6); + }); +} + +#[test] +fn test_get_stakes_subnets_2_hotkeys_2_nominators_uneven_cross_stake_0_global() { + new_test_ext(1).execute_with(|| { + let lock_amount = 100_000_000_000; + setup_dynamic_network(1u16, 1u16, 1u16, lock_amount); + setup_dynamic_network(2u16, 2u16, 2u16, lock_amount); + add_dynamic_stake(1u16, 1u16, 1u16, 100_000_000_000u64); + add_dynamic_stake(1u16, 1u16, 2u16, 200_000_000_000u64); + add_dynamic_stake(2u16, 1u16, 1u16, 300_000_000_000u64); + add_dynamic_stake(2u16, 1u16, 2u16, 400_000_000_000u64); + + let hotkey_tuples = vec![(0u16, U256::from(1)), (1u16, U256::from(2))]; + let stakes1 = SubtensorModule::get_stakes(1, &hotkey_tuples); + let stakes2 = SubtensorModule::get_stakes(2, &hotkey_tuples); + + assert_eq!(stakes1.len(), 2); + assert_i32f32_approx_eq!(stakes1[0], 0.857143); + assert_i32f32_approx_eq!(stakes1[1], 0.142857); + assert_eq!(stakes2.len(), 2); + assert_i32f32_approx_eq!(stakes2[0], 0.4); + assert_i32f32_approx_eq!(stakes2[1], 0.6); + }); +} + +#[test] +fn test_get_stakes_subnets_2_hotkeys_2_nominators_uneven_cross_stake_1_global() { + new_test_ext(1).execute_with(|| { + let lock_amount = 100_000_000_000; + setup_dynamic_network(1u16, 1u16, 1u16, lock_amount); + setup_dynamic_network(2u16, 2u16, 2u16, lock_amount); + SubtensorModule::set_global_stake_weight(u16::MAX); + + add_dynamic_stake(1u16, 1u16, 1u16, 100_000_000_000u64); + add_dynamic_stake(1u16, 1u16, 2u16, 200_000_000_000u64); + add_dynamic_stake(2u16, 1u16, 1u16, 300_000_000_000u64); + add_dynamic_stake(2u16, 1u16, 2u16, 400_000_000_000u64); + + let hotkey_tuples = vec![(0u16, U256::from(1)), (1u16, U256::from(2))]; + let stakes1 = SubtensorModule::get_stakes(1, &hotkey_tuples); + let stakes2 = SubtensorModule::get_stakes(2, &hotkey_tuples); + + assert_eq!(stakes1.len(), 2); + assert_i32f32_approx_eq!(stakes1[0], 0.552380); + assert_i32f32_approx_eq!(stakes1[1], 0.447619); + assert_eq!(stakes2.len(), 2); + assert_i32f32_approx_eq!(stakes2[0], 0.552380); + assert_i32f32_approx_eq!(stakes2[1], 0.447619); + }); +} + +#[test] +fn test_get_stakes_subnets_2_hotkeys_2_nominators_uneven_cross_stake_05_global() { + new_test_ext(1).execute_with(|| { + let lock_amount = 100_000_000_000; + setup_dynamic_network(1u16, 1u16, 1u16, lock_amount); + setup_dynamic_network(2u16, 2u16, 2u16, lock_amount); + SubtensorModule::set_global_stake_weight(u16::MAX / 2); + + add_dynamic_stake(1u16, 1u16, 1u16, 100_000_000_000u64); + add_dynamic_stake(1u16, 1u16, 2u16, 200_000_000_000u64); + add_dynamic_stake(2u16, 1u16, 1u16, 300_000_000_000u64); + add_dynamic_stake(2u16, 1u16, 2u16, 400_000_000_000u64); + + let hotkey_tuples = vec![(0u16, U256::from(1)), (1u16, U256::from(2))]; + let stakes1 = SubtensorModule::get_stakes(1, &hotkey_tuples); + let stakes2 = SubtensorModule::get_stakes(2, &hotkey_tuples); + + assert_eq!(stakes1.len(), 2); + assert_i32f32_approx_eq!(stakes1[0], 0.704762); + assert_i32f32_approx_eq!(stakes1[1], 0.295238); + assert_eq!(stakes2.len(), 2); + assert_i32f32_approx_eq!(stakes2[0], 0.476190); + assert_i32f32_approx_eq!(stakes2[1], 0.523810); + }); +} + +// TODO: Finish this test for 0.5 global stake weight +#[ignore] +#[test] +fn test_stao_dtao_epoch() { + new_test_ext(1).execute_with(|| { + let rootid: u16 = 0; + let netuid: u16 = 1; + let coldkey1 = U256::from(0); + let hotkey1 = U256::from(0); + let coldkey2 = U256::from(1); + // let uid: u16 = 0; + let lock_amount: u64 = 100_000_000_000; + let stake_amount: u64 = 100_000_000_000; + SubtensorModule::set_global_stake_weight(65535); + SubtensorModule::add_balance_to_coldkey_account(&coldkey1, lock_amount); + SubtensorModule::add_balance_to_coldkey_account(&coldkey2, stake_amount); + + // Setup root network + add_network(rootid, u16::MAX - 1, 0); + SubtensorModule::set_max_allowed_uids(rootid, 1); + SubtensorModule::append_neuron(rootid, &hotkey1, 0); + + // Setup a dynamic network + add_dynamic_network(netuid, u16::MAX - 1, 0, 0, lock_amount); + + // Stake from coldkey2 on root network, nominate hotkey1 + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(coldkey2), + hotkey1, + rootid, + stake_amount + )); + + // Distribute emission for root network + let emission_tuples_root = SubtensorModule::epoch(rootid, 1_000_000_000); + emission_tuples_root + .iter() + .for_each(|(hotkey, server, validator)| { + println!( + "emission_tuples (root) = {}, {}, {}", + hotkey, server, validator + ); + SubtensorModule::emit_inflation_through_hotkey_account( + hotkey, rootid, *server, *validator, + ); + }); + + // Distribute emission for dynamic network + let emission_tuples = SubtensorModule::epoch(netuid, 1_000_000_000); + emission_tuples + .iter() + .for_each(|(hotkey, server, validator)| { + println!( + "emission_tuples (net) = {}, {}, {}", + hotkey, server, validator + ); + SubtensorModule::emit_inflation_through_hotkey_account( + hotkey, netuid, *server, *validator, + ); + }); + + // coldkey2 shouldn't expect the substake to increase on netuid because it only staked to root network + assert_substake_eq!(&coldkey2, &hotkey1, netuid, 0); + + // assert_substake_eq!(&coldkey2, &hotkey1, rootid, 100_000_000_000); + }); +} diff --git a/pallets/subtensor/tests/helpers.rs b/pallets/subtensor/tests/helpers.rs new file mode 100644 index 000000000..e57d9f73e --- /dev/null +++ b/pallets/subtensor/tests/helpers.rs @@ -0,0 +1,69 @@ +#[allow(dead_code)] +#[macro_export] +macro_rules! assert_i64f64_approx_eq { + ($left:expr, $right:expr $(,)?) => {{ + const PRECISION: u64 = 10000; + let left = I64F64::from_num($left); + let right = I64F64::from_num($right); + let prec = I64F64::from_num(PRECISION); + + // TODO: Consider using Arithmetic rounding + let l_rounded = (prec * left).round() / prec; + let r_rounded = (prec * right).round() / prec; + + assert_eq!(l_rounded, r_rounded); + }}; +} + +#[allow(dead_code)] +#[macro_export] +macro_rules! assert_i32f32_approx_eq { + ($left:expr, $right:expr $(,)?) => {{ + const PRECISION: u64 = 10000; + let left = I32F32::from_num($left); + let right = I32F32::from_num($right); + let prec = I32F32::from_num(PRECISION); + + let l_rounded = (prec * left).round() / prec; + let r_rounded = (prec * right).round() / prec; + + assert_eq!(l_rounded, r_rounded); + }}; +} + +#[allow(dead_code)] +#[macro_export] +macro_rules! assert_approx_eq { + ($left:expr, $right:expr $(,)?) => {{ + const PRECISION: f64 = 100.; + let left = $left; + let right = $right; + + let l_rounded = (PRECISION * left).round() / PRECISION; + let r_rounded = (PRECISION * right).round() / PRECISION; + + assert_eq!(l_rounded, r_rounded); + }}; +} + +#[allow(dead_code)] +#[macro_export] +macro_rules! assert_substake_eq { + ($coldkey:expr, $hotkey:expr, $netuid:expr, $amount:expr $(,)?) => {{ + assert_eq!( + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey($coldkey, $hotkey, $netuid), + $amount + ); + }}; +} + +#[allow(dead_code)] +#[macro_export] +macro_rules! assert_substake_approx_eq { + ($coldkey:expr, $hotkey:expr, $netuid:expr, $amount:expr $(,)?) => {{ + let subst = + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey($coldkey, $hotkey, $netuid) + as f64; + assert_approx_eq!(subst / 1_000_000_000f64, $amount); + }}; +} diff --git a/pallets/subtensor/tests/migration.rs b/pallets/subtensor/tests/migration.rs index 2f634d7c0..8a976b117 100644 --- a/pallets/subtensor/tests/migration.rs +++ b/pallets/subtensor/tests/migration.rs @@ -1,231 +1,159 @@ mod mock; -use frame_support::assert_ok; -use frame_system::Config; +// use frame_support::assert_ok; +// use frame_system::Config; use mock::*; -use sp_core::U256; - -#[test] -fn test_migration_fix_total_stake_maps() { - new_test_ext(1).execute_with(|| { - let ck1 = U256::from(1); - let ck2 = U256::from(2); - let ck3 = U256::from(3); - - let hk1 = U256::from(1 + 100); - let hk2 = U256::from(2 + 100); - - let mut total_stake_amount = 0; - - // Give each coldkey some stake in the maps - SubtensorModule::increase_stake_on_coldkey_hotkey_account(&ck1, &hk1, 100); - total_stake_amount += 100; - - SubtensorModule::increase_stake_on_coldkey_hotkey_account(&ck2, &hk1, 10_101); - total_stake_amount += 10_101; - - SubtensorModule::increase_stake_on_coldkey_hotkey_account(&ck3, &hk2, 100_000_000); - total_stake_amount += 100_000_000; - - SubtensorModule::increase_stake_on_coldkey_hotkey_account(&ck1, &hk2, 1_123_000_000); - total_stake_amount += 1_123_000_000; - - // Check that the total stake is correct - assert_eq!(SubtensorModule::get_total_stake(), total_stake_amount); - - // Check that the total coldkey stake is correct - assert_eq!( - SubtensorModule::get_total_stake_for_coldkey(&ck1), - 100 + 1_123_000_000 - ); - assert_eq!(SubtensorModule::get_total_stake_for_coldkey(&ck2), 10_101); - assert_eq!( - SubtensorModule::get_total_stake_for_coldkey(&ck3), - 100_000_000 - ); - - // Check that the total hotkey stake is correct - assert_eq!( - SubtensorModule::get_total_stake_for_hotkey(&hk1), - 100 + 10_101 - ); - assert_eq!( - SubtensorModule::get_total_stake_for_hotkey(&hk2), - 100_000_000 + 1_123_000_000 - ); - - // Mess up the total coldkey stake - pallet_subtensor::TotalColdkeyStake::::insert(ck1, 0); - // Verify that the total coldkey stake is now 0 for ck1 - assert_eq!(SubtensorModule::get_total_stake_for_coldkey(&ck1), 0); - - // Mess up the total stake - pallet_subtensor::TotalStake::::put(123_456_789); - // Verify that the total stake is now wrong - assert_ne!(SubtensorModule::get_total_stake(), total_stake_amount); - - // Run the migration to fix the total stake maps - pallet_subtensor::migration::migrate_to_v2_fixed_total_stake::(); - - // Verify that the total stake is now correct - assert_eq!(SubtensorModule::get_total_stake(), total_stake_amount); - // Verify that the total coldkey stake is now correct for each coldkey - assert_eq!( - SubtensorModule::get_total_stake_for_coldkey(&ck1), - 100 + 1_123_000_000 - ); - assert_eq!(SubtensorModule::get_total_stake_for_coldkey(&ck2), 10_101); - assert_eq!( - SubtensorModule::get_total_stake_for_coldkey(&ck3), - 100_000_000 - ); - - // Verify that the total hotkey stake is STILL correct for each hotkey - assert_eq!( - SubtensorModule::get_total_stake_for_hotkey(&hk1), - 100 + 10_101 - ); - assert_eq!( - SubtensorModule::get_total_stake_for_hotkey(&hk2), - 100_000_000 + 1_123_000_000 - ); - - // Verify that the Stake map has no extra entries - assert_eq!(pallet_subtensor::Stake::::iter().count(), 4); // 4 entries total - assert_eq!( - pallet_subtensor::Stake::::iter_key_prefix(hk1).count(), - 2 - ); // 2 stake entries for hk1 - assert_eq!( - pallet_subtensor::Stake::::iter_key_prefix(hk2).count(), - 2 - ); // 2 stake entries for hk2 - }) -} - -#[test] -// To run this test with cargo, use the following command: -// cargo test --package pallet-subtensor --test migration test_migration5_total_issuance -fn test_migration5_total_issuance() { - new_test_ext(1).execute_with(|| { - // Run the migration to check total issuance. - let test: bool = true; - - assert_eq!(SubtensorModule::get_total_issuance(), 0); - pallet_subtensor::migration::migration5_total_issuance::(test); - assert_eq!(SubtensorModule::get_total_issuance(), 0); - - SubtensorModule::add_balance_to_coldkey_account(&U256::from(1), 10000); - assert_eq!(SubtensorModule::get_total_issuance(), 0); - pallet_subtensor::migration::migration5_total_issuance::(test); - assert_eq!(SubtensorModule::get_total_issuance(), 10000); - - SubtensorModule::increase_stake_on_coldkey_hotkey_account( - &U256::from(1), - &U256::from(1), - 30000, - ); - assert_eq!(SubtensorModule::get_total_issuance(), 10000); - pallet_subtensor::migration::migration5_total_issuance::(test); - assert_eq!(SubtensorModule::get_total_issuance(), 10000 + 30000); - }) -} - -#[test] -// To run this test with cargo, use the following command: -// cargo test --package pallet-subtensor --test migration test_total_issuance_global -fn test_total_issuance_global() { - new_test_ext(0).execute_with(|| { - // Initialize network unique identifier and keys for testing. - let netuid: u16 = 1; // Network unique identifier set to 1 for testing. - let coldkey = U256::from(0); // Coldkey initialized to 0, representing an account's public key for non-transactional operations. - let hotkey = U256::from(0); // Hotkey initialized to 0, representing an account's public key for transactional operations. - let owner: U256 = U256::from(0); - - let lockcost: u64 = SubtensorModule::get_network_lock_cost(); - SubtensorModule::add_balance_to_coldkey_account(&owner, lockcost); // Add a balance of 20000 to the coldkey account. - assert_eq!(SubtensorModule::get_total_issuance(), 0); // initial is zero. - assert_ok!(SubtensorModule::register_network( - <::RuntimeOrigin>::signed(owner) - )); - SubtensorModule::set_max_allowed_uids(netuid, 1); // Set the maximum allowed unique identifiers for the network to 1. - assert_eq!(SubtensorModule::get_total_issuance(), 0); // initial is zero. - pallet_subtensor::migration::migration5_total_issuance::(true); // Pick up lock. - assert_eq!(SubtensorModule::get_total_issuance(), lockcost); // Verify the total issuance is updated to 20000 after migration. - assert!(SubtensorModule::if_subnet_exist(netuid)); - - // Test the migration's effect on total issuance after adding balance to a coldkey account. - let account_balance: u64 = 20000; - let _hotkey_account_id_1 = U256::from(1); // Define a hotkey account ID for further operations. - let _coldkey_account_id_1 = U256::from(1); // Define a coldkey account ID for further operations. - assert_eq!(SubtensorModule::get_total_issuance(), lockcost); // Ensure the total issuance starts at 0 before the migration. - SubtensorModule::add_balance_to_coldkey_account(&coldkey, account_balance); // Add a balance of 20000 to the coldkey account. - pallet_subtensor::migration::migration5_total_issuance::(true); // Execute the migration to update total issuance. - assert_eq!( - SubtensorModule::get_total_issuance(), - account_balance + lockcost - ); // Verify the total issuance is updated to 20000 after migration. - - // Test the effect of burning on total issuance. - let burn_cost: u64 = 10000; - SubtensorModule::set_burn(netuid, burn_cost); // Set the burn amount to 10000 for the network. - assert_eq!( - SubtensorModule::get_total_issuance(), - account_balance + lockcost - ); // Confirm the total issuance remains 20000 before burning. - assert_ok!(SubtensorModule::burned_register( - <::RuntimeOrigin>::signed(hotkey), - netuid, - hotkey - )); // Execute the burn operation, reducing the total issuance. - assert_eq!(SubtensorModule::get_subnetwork_n(netuid), 1); // Ensure the subnetwork count increases to 1 after burning - assert_eq!( - SubtensorModule::get_total_issuance(), - account_balance + lockcost - burn_cost - ); // Verify the total issuance is reduced to 10000 after burning. - pallet_subtensor::migration::migration5_total_issuance::(true); // Execute the migration to update total issuance. - assert_eq!( - SubtensorModule::get_total_issuance(), - account_balance + lockcost - burn_cost - ); // Verify the total issuance is updated to 10000 nothing changes - - // Test staking functionality and its effect on total issuance. - let new_stake: u64 = 10000; - assert_eq!( - SubtensorModule::get_total_issuance(), - account_balance + lockcost - burn_cost - ); // Same - SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey, &hotkey, new_stake); // Stake an additional 10000 to the coldkey-hotkey account. This is i - assert_eq!( - SubtensorModule::get_total_issuance(), - account_balance + lockcost - burn_cost - ); // Same - pallet_subtensor::migration::migration5_total_issuance::(true); // Fix issuance - assert_eq!( - SubtensorModule::get_total_issuance(), - account_balance + lockcost - burn_cost + new_stake - ); // New - - // Set emission values for the network and verify. - let emission: u64 = 1_000_000_000; - SubtensorModule::set_tempo(netuid, 1); - SubtensorModule::set_emission_values(&[netuid], vec![emission]).unwrap(); // Set the emission value for the network to 1_000_000_000. - assert_eq!(SubtensorModule::get_subnet_emission_value(netuid), emission); // Verify the emission value is set correctly for the network. - assert_eq!( - SubtensorModule::get_total_issuance(), - account_balance + lockcost - burn_cost + new_stake - ); - run_to_block(2); // Advance to block number 2 to trigger the emission through the subnet. - assert_eq!( - SubtensorModule::get_total_issuance(), - account_balance + lockcost - burn_cost + new_stake + emission - ); // Verify the total issuance reflects the staked amount and emission value that has been put through the epoch. - pallet_subtensor::migration::migration5_total_issuance::(true); // Test migration does not change amount. - assert_eq!( - SubtensorModule::get_total_issuance(), - account_balance + lockcost - burn_cost + new_stake + emission - ); // Verify the total issuance reflects the staked amount and emission value that has been put through the epoch. - }) -} +// use sp_core::U256; + +// #[test] +// // To run this test with cargo, use the following command: +// // cargo test --package pallet-subtensor --test migration test_migration5_total_issuance +// fn test_migration5_total_issuance() { +// new_test_ext(1).execute_with(|| { +// // Run the migration to check total issuance. +// let test: bool = true; + +// assert_eq!(SubtensorModule::get_total_issuance(), 0); +// pallet_subtensor::migration::migration5_total_issuance::(test); +// assert_eq!(SubtensorModule::get_total_issuance(), 0); + +// SubtensorModule::add_balance_to_coldkey_account(&U256::from(1), 10000); +// assert_eq!(SubtensorModule::get_total_issuance(), 0); +// pallet_subtensor::migration::migration5_total_issuance::(test); +// assert_eq!(SubtensorModule::get_total_issuance(), 10000); + +// SubtensorModule::increase_subnet_token_on_coldkey_hotkey_account( +// &U256::from(1), +// &U256::from(1), +// 1, +// 30000, +// ); +// assert_eq!(SubtensorModule::get_total_issuance(), 10000); +// pallet_subtensor::migration::migration5_total_issuance::(test); +// assert_eq!(SubtensorModule::get_total_issuance(), 10000 + 30000); +// }) +// } + +// #[test] +// // To run this test with cargo, use the following command: +// // cargo test --package pallet-subtensor --test migration test_total_issuance_global +// fn test_total_issuance_global() { +// new_test_ext(0).execute_with(|| { +// // Initialize network unique identifier and keys for testing. +// let netuid: u16 = 1; // Network unique identifier set to 1 for testing. +// let coldkey = U256::from(0); // Coldkey initialized to 0, representing an account's public key for non-transactional operations. +// let hotkey = U256::from(0); // Hotkey initialized to 0, representing an account's public key for transactional operations. +// let owner: U256 = U256::from(0); + +// let lockcost: u64 = SubtensorModule::get_network_lock_cost(); +// SubtensorModule::add_balance_to_coldkey_account(&owner, lockcost); // Add a balance of lockcost to the coldkey account. + +// // Pallet balances issuance increases accordingly +// assert_eq!(lockcost, PalletBalances::total_issuance()); + +// assert_eq!(SubtensorModule::get_total_issuance(), 0); // initial is zero. +// assert_ok!(SubtensorModule::register_network( +// <::RuntimeOrigin>::signed(owner), +// hotkey +// )); + +// // We register by withdrawing, balances total issuance goes back to one ED +// assert_eq!(ExistentialDeposit::get(), PalletBalances::total_issuance()); + +// SubtensorModule::set_max_allowed_uids(netuid, 2); // Set the maximum allowed neuron count for the network to 2. +// assert_eq!(SubtensorModule::get_total_issuance(), 0); // initial is zero. +// pallet_subtensor::migration::migration5_total_issuance::(true); // Pick up lock. +// assert_eq!( +// SubtensorModule::get_total_issuance(), +// lockcost + PalletBalances::total_issuance() +// ); +// assert!(SubtensorModule::if_subnet_exist(netuid)); + +// // Test the migration's effect on total issuance after adding balance to a coldkey account. +// let account_balance: u64 = 20000; +// assert_eq!( +// SubtensorModule::get_total_issuance(), +// lockcost + ExistentialDeposit::get() +// ); // Ensure the total issuance starts at 0 before the migration. +// SubtensorModule::add_balance_to_coldkey_account(&coldkey, account_balance); +// pallet_subtensor::migration::migration5_total_issuance::(true); // Execute the migration to update total issuance. +// assert_eq!( +// SubtensorModule::get_total_issuance(), +// account_balance + lockcost + ExistentialDeposit::get() +// ); + +// // Test the effect of burning on total issuance. +// let coldkey2 = U256::from(1); +// let hotkey2 = U256::from(1); +// SubtensorModule::add_balance_to_coldkey_account(&coldkey2, account_balance); + +// let burn_cost: u64 = 10_000; +// SubtensorModule::set_burn(netuid, burn_cost); // Set the burn amount to 10_000 for the network. +// assert_eq!( +// SubtensorModule::get_total_issuance(), +// account_balance + lockcost + ExistentialDeposit::get() +// ); // Confirm the total issuance remains 20000 before burning. +// let neuron_count_before_burning = SubtensorModule::get_subnetwork_n(netuid); +// assert_ok!(SubtensorModule::burned_register( +// <::RuntimeOrigin>::signed(hotkey2), +// netuid, +// hotkey2 +// )); // Execute the burn operation, reducing the total issuance. +// let neuron_count_after_burning = SubtensorModule::get_subnetwork_n(netuid); +// assert_eq!(neuron_count_after_burning - neuron_count_before_burning, 1); // Ensure the subnetwork count increases by 1 after burning +// assert_eq!( +// SubtensorModule::get_total_issuance(), +// account_balance + lockcost - burn_cost + ExistentialDeposit::get() +// ); // Verify the total issuance is reduced to 10000 after burning. +// pallet_subtensor::migration::migration5_total_issuance::(true); // Execute the migration to update total issuance. +// assert_eq!( +// SubtensorModule::get_total_issuance(), +// 2 * account_balance + lockcost - burn_cost + ExistentialDeposit::get() +// ); // Verify the total issuance is updated to 10000 nothing changes + +// // Test staking functionality and its effect on total issuance. +// let new_stake: u64 = 10000; +// assert_eq!( +// SubtensorModule::get_total_issuance(), +// 2 * account_balance + lockcost - burn_cost + ExistentialDeposit::get() +// ); // Same +// SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey, &hotkey, 1, new_stake); // Stake an additional 10000 to the coldkey-hotkey account. This is i +// assert_eq!( +// SubtensorModule::get_total_issuance(), +// 2 * account_balance + lockcost - burn_cost + ExistentialDeposit::get() +// ); // Same +// pallet_subtensor::migration::migration5_total_issuance::(true); // Fix issuance +// assert_eq!( +// SubtensorModule::get_total_issuance(), +// 2 * account_balance + lockcost - burn_cost + new_stake + ExistentialDeposit::get() +// ); // New + +// // Set emission values for the network and verify. +// let emission: u64 = 1_000_000_000; +// SubtensorModule::set_tempo(netuid, 1); +// set_emission_values(netuid, emission); +// assert_eq!(SubtensorModule::get_emission_value(netuid), emission); // Verify the emission value is set correctly for the network. +// assert_eq!( +// SubtensorModule::get_total_issuance(), +// 2 * account_balance + lockcost - burn_cost + new_stake + ExistentialDeposit::get() +// ); +// run_to_block(2); // Advance to block number 2 to trigger the emission through the subnet. +// assert_eq!( +// SubtensorModule::get_total_issuance(), +// 2 * account_balance + lockcost - burn_cost +// + new_stake +// + emission +// + ExistentialDeposit::get() +// ); // Verify the total issuance reflects the staked amount and emission value that has been put through the epoch. +// pallet_subtensor::migration::migration5_total_issuance::(true); // Test migration does not change amount. +// assert_eq!( +// SubtensorModule::get_total_issuance(), +// 2 * account_balance + lockcost - burn_cost +// + new_stake +// + emission +// + ExistentialDeposit::get() +// ); // Verify the total issuance reflects the staked amount and emission value that has been put through the epoch. +// }) +// } #[test] fn test_migration_transfer_nets_to_foundation() { @@ -274,3 +202,83 @@ fn test_migration_delete_subnet_21() { assert!(!SubtensorModule::if_subnet_exist(21)); }) } + +// #[test] +// fn test_migration_stake_to_substake() { +// new_test_ext(1).execute_with(|| { +// // We need to create the root network for this test +// let root: u16 = 0; +// let netuid: u16 = 1; +// let tempo: u16 = 13; +// let hotkey1 = U256::from(1); +// let coldkey1 = U256::from(100); +// let stake_amount1 = 1000u64; + +// let hotkey2 = U256::from(2); +// let coldkey2 = U256::from(200); +// let stake_amount2 = 2000u64; + +// //add root network +// add_network(root, tempo, 0); +// //add subnet 1 +// add_network(netuid, tempo, 0); + +// SubtensorModule::add_balance_to_coldkey_account(&coldkey1, stake_amount1); +// SubtensorModule::add_balance_to_coldkey_account(&coldkey2, stake_amount2); + +// // Register neuron 1 +// register_ok_neuron(netuid, hotkey1, coldkey1, 0); +// // Register neuron 2 +// register_ok_neuron(netuid, hotkey2, coldkey2, 0); + +// // Due to the way update stake work , we need to isolate just adding stake to the +// // Stake StorageMap. We therefore need to manipulate the Stake StorageMap directly. +// set_stake_value(coldkey1, hotkey1, stake_amount1); +// assert_eq!( +// pallet_subtensor::Stake::::get(coldkey1, hotkey1), +// stake_amount1 +// ); + +// set_stake_value(coldkey2, hotkey2, stake_amount2); +// assert_eq!( +// pallet_subtensor::Stake::::get(coldkey2, hotkey2), +// stake_amount2 +// ); + +// assert_eq!( +// pallet_subtensor::SubStake::::get((&coldkey1, &hotkey1, &0u16)), +// 0 +// ); +// assert_eq!( +// pallet_subtensor::SubStake::::get((&coldkey2, &hotkey2, &0u16)), +// 0 +// ); +// // Run the migration +// pallet_subtensor::migration::migrate_stake_to_substake::(); + +// // Verify that Stake entries have been migrated to SubStake +// assert_eq!( +// pallet_subtensor::SubStake::::get((&coldkey1, &hotkey1, &0u16)), +// stake_amount1 +// ); +// assert_eq!( +// pallet_subtensor::SubStake::::get((&coldkey2, &hotkey2, &0u16)), +// stake_amount2 +// ); + +// // Verify TotalHotkeySubStake has been updated +// assert_eq!( +// SubtensorModule::get_total_stake_for_hotkey_and_subnet(&hotkey1, 0), +// stake_amount1 +// ); +// assert_eq!( +// SubtensorModule::get_total_stake_for_hotkey_and_subnet(&hotkey2, 0), +// stake_amount2 +// ); +// }); +// } + +// // Helper function to set a value in the Stake StorageMap +// fn set_stake_value(coldkey: U256, hotkey: U256, stake_amount: u64) { +// pallet_subtensor::Stake::::insert(coldkey, hotkey, stake_amount); +// } diff --git a/pallets/subtensor/tests/mock.rs b/pallets/subtensor/tests/mock.rs index 9995acf84..e8ded440c 100644 --- a/pallets/subtensor/tests/mock.rs +++ b/pallets/subtensor/tests/mock.rs @@ -1,12 +1,14 @@ use frame_support::derive_impl; use frame_support::dispatch::DispatchResultWithPostInfo; +use frame_support::weights::constants::RocksDbWeight; use frame_support::{ assert_ok, parameter_types, traits::{Everything, Hooks}, weights, }; -use frame_system as system; +use frame_system::{self as system, Config}; use frame_system::{limits, EnsureNever, EnsureRoot, RawOrigin}; +use pallet_subtensor::types::SubnetType; use sp_core::{Get, H256, U256}; use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup}, @@ -44,6 +46,9 @@ pub type BalanceCall = pallet_balances::Call; #[allow(dead_code)] pub type TestRuntimeCall = frame_system::Call; +#[allow(dead_code)] +pub type PalletBalances = pallet_balances::Pallet; + parameter_types! { pub const BlockHashCount: u64 = 250; pub const SS58Prefix: u8 = 42; @@ -86,7 +91,7 @@ impl system::Config for Test { type BaseCallFilter = Everything; type BlockWeights = (); type BlockLength = (); - type DbWeight = (); + type DbWeight = RocksDbWeight; type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; type Hash = H256; @@ -113,12 +118,14 @@ parameter_types! { pub const InitialEmissionValue: u16 = 0; pub const InitialMaxWeightsLimit: u16 = u16::MAX; pub BlockWeights: limits::BlockWeights = limits::BlockWeights::simple_max(weights::Weight::from_parts(1024, 0)); - pub const ExistentialDeposit: Balance = 1; + pub const ExistentialDeposit: Balance = 500; // use value that's currently on Finney pub const TransactionByteFee: Balance = 100; pub const SDebug:u64 = 1; pub const InitialRho: u16 = 30; pub const InitialKappa: u16 = 32_767; pub const InitialTempo: u16 = 0; + pub const MinTempo: u16 = 2; + pub const MaxTempo: u16 = u16::MAX; pub const SelfOwnership: u64 = 2; pub const InitialImmunityPeriod: u16 = 2; pub const InitialMaxAllowedUids: u16 = 2; @@ -158,6 +165,7 @@ parameter_types! { pub const InitialSubnetLimit: u16 = 10; // Max 10 subnets. pub const InitialNetworkRateLimit: u64 = 0; pub const InitialTargetStakesPerInterval: u16 = 2; + pub const InitialSubnetOwnerLockPeriod: u64 = 7 * 7200 * 3; } // Configure collective pallet for council @@ -189,6 +197,7 @@ impl CanVote for CanVoteToTriumvirate { } use pallet_subtensor::{CollectiveInterface, MemberManagement}; +use substrate_fixed::types::I64F64; pub struct ManageSenateMembers; impl MemberManagement for ManageSenateMembers { fn add_member(account: &AccountId) -> DispatchResultWithPostInfo { @@ -317,11 +326,14 @@ impl pallet_subtensor::Config for Test { type CouncilOrigin = frame_system::EnsureSigned; type SenateMembers = ManageSenateMembers; type TriumvirateInterface = TriumvirateVotes; + type EpochConfig = (); type InitialMinAllowedWeights = InitialMinAllowedWeights; type InitialEmissionValue = InitialEmissionValue; type InitialMaxWeightsLimit = InitialMaxWeightsLimit; type InitialTempo = InitialTempo; + type MinTempo = MinTempo; + type MaxTempo = MaxTempo; type InitialDifficulty = InitialDifficulty; type InitialAdjustmentInterval = InitialAdjustmentInterval; type InitialAdjustmentAlpha = InitialAdjustmentAlpha; @@ -358,6 +370,7 @@ impl pallet_subtensor::Config for Test { type InitialSubnetLimit = InitialSubnetLimit; type InitialNetworkRateLimit = InitialNetworkRateLimit; type InitialTargetStakesPerInterval = InitialTargetStakesPerInterval; + type InitialSubnetOwnerLockPeriod = InitialSubnetOwnerLockPeriod; } impl pallet_utility::Config for Test { @@ -472,3 +485,132 @@ pub fn add_network(netuid: u16, tempo: u16, _modality: u16) { SubtensorModule::set_network_registration_allowed(netuid, true); SubtensorModule::set_network_pow_registration_allowed(netuid, true); } + +/// Creates a staked STAO subnet +/// - SubnetLocked is set to lock_amount, which doesn't go to SubStake map +/// - SubStake is set to contains stake amount for coldkey 2 +/// - Both amounts are added to TotalSubnetTAO +/// +#[allow(dead_code)] +pub fn create_staked_stao_network(netuid: u16, lock_amount: u64, stake: u64) { + let coldkey1 = U256::from(1); + let hotkey1 = U256::from(1); + let coldkey2 = U256::from(2); + let hotkey2 = U256::from(2); + SubtensorModule::add_balance_to_coldkey_account( + &coldkey1, + lock_amount + ExistentialDeposit::get(), + ); + SubtensorModule::add_balance_to_coldkey_account(&coldkey2, stake + ExistentialDeposit::get()); + SubtensorModule::set_max_registrations_per_block(netuid, 4); + SubtensorModule::set_max_allowed_uids(netuid, 10); + + add_network(netuid, 0, 0); + pallet_subtensor::SubnetCreator::::insert(netuid, hotkey1); + pallet_subtensor::SubnetOwner::::insert(netuid, coldkey1); + + register_ok_neuron(netuid, hotkey1, coldkey1, 124124); + register_ok_neuron(netuid, hotkey2, coldkey2, 987907); + + pallet_subtensor::TotalSubnetTAO::::insert(netuid, lock_amount); + pallet_subtensor::SubnetLocked::::insert( + netuid, + lock_amount + ); + + if stake > 0 { + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(coldkey2), + hotkey1, + netuid, + stake + )); + } +} + +#[allow(dead_code)] +pub fn add_dynamic_network(netuid: u16, tempo: u16, cold_id: u16, hot_id: u16, lock_amount: u64) { + let coldkey = U256::from(cold_id); + let hotkey = U256::from(hot_id); + + SubtensorModule::user_add_network_no_checks( + SubnetType::DTAO, + coldkey, + hotkey, + netuid, + lock_amount, + lock_amount, + tempo, + ) +} + +#[allow(dead_code)] +pub fn setup_dynamic_network(netuid: u16, cold_id: u16, hot_id: u16, lock_amount: u64) { + SubtensorModule::set_global_stake_weight(0); + add_dynamic_network(netuid, 10, cold_id, hot_id, lock_amount); + SubtensorModule::set_max_allowed_uids(netuid, 1); +} + +#[allow(dead_code)] +pub fn add_dynamic_stake(netuid: u16, cold_id: u16, hot_id: u16, amount: u64) { + let coldkey = U256::from(cold_id); + let hotkey = U256::from(hot_id); + + SubtensorModule::add_balance_to_coldkey_account(&coldkey, amount); + + let dynamic_stake = SubtensorModule::compute_dynamic_stake(netuid, amount); + SubtensorModule::increase_subnet_token_on_coldkey_hotkey_account( + &coldkey, + &hotkey, + netuid, + dynamic_stake, + ); +} + +#[allow(dead_code)] +pub fn remove_dynamic_stake(netuid: u16, cold_id: u16, hot_id: u16, amount: u64) { + let coldkey = U256::from(cold_id); + let hotkey = U256::from(hot_id); + + let dynamic_unstake_amount_tao = SubtensorModule::compute_dynamic_unstake(netuid, amount); + SubtensorModule::decrease_subnet_token_on_coldkey_hotkey_account( + &coldkey, + &hotkey, + netuid, + dynamic_unstake_amount_tao, + ); +} + +#[allow(dead_code)] +pub fn set_emission_values(netuid: u16, amount: u64) { + pallet_subtensor::EmissionValues::::insert(netuid, amount); +} + +#[allow(dead_code)] +pub fn get_total_stake_for_coldkey(coldkey: &U256) -> u64 { + pallet_subtensor::SubStake::::iter() + .filter(|((cold, _, _), _)| *cold == *coldkey) + .map(|((_, _, _), stake)| stake) + .sum() +} + +/// Helper function to calculate alpha-tao emission price threshold for DTAO subnets +/// This is supposed to be the same threshold that is used by block_step function +/// when it decides whether to issue alpha or tao in the block. +/// +#[allow(dead_code)] +pub fn get_price_threshold() -> f64 { + // Iterate all subnets and + let (dtao, all) = SubtensorModule::get_all_subnet_netuids().iter().map(|&netuid| { + ( + if SubtensorModule::is_subnet_dynamic(netuid) { + pallet_subtensor::TotalSubnetTAO::::get(netuid) + } else { + 0 + }, + pallet_subtensor::TotalSubnetTAO::::get(netuid) + ) + }).fold((0, 0), |(total_dtao, total_all), (dtao, all)| (total_dtao + dtao, total_all + all)); + + (I64F64::from_num(dtao) / I64F64::from_num(all)).to_num::() +} diff --git a/pallets/subtensor/tests/networks.rs b/pallets/subtensor/tests/networks.rs index 93e563683..f45ca024f 100644 --- a/pallets/subtensor/tests/networks.rs +++ b/pallets/subtensor/tests/networks.rs @@ -49,9 +49,6 @@ // let modality = 0; // let tempo: u16 = 13; // add_network(10, tempo, modality); -// assert_eq!(SubtensorModule::get_number_of_subnets(), 1); -// add_network(20, tempo, modality); -// assert_eq!(SubtensorModule::get_number_of_subnets(), 2); // }); // } diff --git a/pallets/subtensor/tests/neuron_info.rs b/pallets/subtensor/tests/neuron_info.rs index 10df1c07d..2dfcd6ddb 100644 --- a/pallets/subtensor/tests/neuron_info.rs +++ b/pallets/subtensor/tests/neuron_info.rs @@ -1,6 +1,8 @@ mod mock; +use codec::Compact; +use frame_support::assert_ok; +use frame_system::Config; use mock::*; - use sp_core::U256; #[test] @@ -57,6 +59,7 @@ fn test_get_neurons_list() { } let neurons = SubtensorModule::get_neurons(netuid); + log::info!("neurons: {:?}", neurons); assert_eq!(neurons.len(), neuron_count as usize); }); } @@ -68,6 +71,411 @@ fn test_get_neurons_empty() { let neuron_count = 0; let neurons = SubtensorModule::get_neurons(netuid); + log::info!("neurons: {:?}", neurons); assert_eq!(neurons.len(), neuron_count as usize); }); } + +#[test] +fn test_get_neuron_subnet_staking_info() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + + let tempo: u16 = 2; + let modality: u16 = 2; + + let uid: u16 = 0; + let hotkey0 = U256::from(1); + let coldkey0 = U256::from(12); + let stake_amount = 1000; + let stake_weight = u16::MAX as u64; + + add_network(netuid, tempo, modality); + register_ok_neuron(netuid, hotkey0, coldkey0, 39420842); + SubtensorModule::add_balance_to_coldkey_account(&coldkey0, stake_amount); + + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(coldkey0), + hotkey0, + netuid, + stake_amount, + )); + + step_block(tempo); + + let neuron = SubtensorModule::get_neuron_lite(netuid, uid); + log::info!("neuron: {:?}", neuron); + assert_eq!( + neuron.unwrap().stake, + vec![(coldkey0, Compact(stake_weight))] + ); + }); +} + +#[test] +fn test_get_neuron_subnet_staking_info_multiple() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + + let tempo: u16 = 2; + let modality: u16 = 2; + + add_network(netuid, tempo, modality); + + let stake_amounts: [u64; 5] = [1000, 2000, 3000, 4000, 5000]; + let total_stake = 15000; + + SubtensorModule::set_max_registrations_per_block(netuid, 10); + SubtensorModule::set_target_registrations_per_interval(netuid, 10); + + let expected_stakes: Vec<(U256, Compact)> = stake_amounts + .iter() + .enumerate() + .map(|(index, &stake_amount)| { + let hotkey = U256::from(index as u64); + let coldkey = U256::from((index + 10) as u64); + + register_ok_neuron(netuid, hotkey, coldkey, 39420842 + index as u64); + // Adding more because of existential deposit + SubtensorModule::add_balance_to_coldkey_account(&coldkey, stake_amount + 5); + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(coldkey), + hotkey, + netuid, + stake_amount, + )); + let stake_weight = + (u16::MAX as f32 * stake_amount as f32 / total_stake as f32) as u64; + + (coldkey, Compact(stake_weight)) + }) + .collect(); + log::info!("expected_stakes: {:?}", expected_stakes); + + step_block(2); + + // Retrieve and assert for each neuron + expected_stakes.iter().enumerate().for_each( + |(index, &(expected_coldkey, Compact(expected_stake_weight)))| { + let uid: u16 = index as u16; + let neuron = + SubtensorModule::get_neuron_lite(netuid, uid).expect("Neuron should exist"); + + let (coldkey, Compact(stake_weight)) = neuron.stake[0]; + + assert_eq!(expected_coldkey, coldkey,); + // Divide by 10 to mask rounding errors + assert_eq!(expected_stake_weight / 10, stake_weight / 10,); + }, + ); + }); +} + +#[test] +fn test_get_neuron_stake_based_on_netuid() { + new_test_ext(1).execute_with(|| { + let netuid_root: u16 = 0; // Root network + let netuid_sub: u16 = 1; // Subnetwork + let tempo = 2; + + let uid_0: u16 = 0; + + let hotkey_root = U256::from(0); + let coldkey_root = U256::from(0); + let stake_amount_root: u64 = 1000; + + let hotkey_sub = U256::from(1); + let coldkey_sub = U256::from(1); + let stake_amount_sub: u64 = 2000; + + // Setup for root network + add_network(netuid_root, tempo, 2); + SubtensorModule::create_account_if_non_existent(&coldkey_root, &hotkey_root); + SubtensorModule::add_balance_to_coldkey_account(&coldkey_root, stake_amount_root); + assert_ok!(SubtensorModule::add_stake( + <::RuntimeOrigin>::signed(coldkey_root), + hotkey_root, + stake_amount_root, + )); + + // Setup for subnetwork + SubtensorModule::add_balance_to_coldkey_account(&coldkey_sub, stake_amount_sub); + add_network(netuid_sub, tempo, 2); + register_ok_neuron(netuid_sub, hotkey_sub, coldkey_sub, 39420843); + // assert_ok!(SubtensorModule::add_subnet_stake( + // <::RuntimeOrigin>::signed(coldkey_sub), + // hotkey_sub, + // netuid_sub, + // stake_amount_sub, + // )); + + // Test for main network + let neuron_main = SubtensorModule::get_neuron(netuid_sub, uid_0) + .expect("Neuron should exist for main network"); + assert_eq!( + neuron_main.stake.len(), + 1, + "Main network should have 1 stake entry" + ); + + // Test for subnetwork + let neuron_sub = SubtensorModule::get_neuron(netuid_sub, uid_0) + .expect("Neuron should exist for subnetwork"); + assert_eq!( + neuron_sub.stake.len(), + 1, + "Subnetwork should have 1 stake entry" + ); + + step_block(tempo); + let total_stake = (stake_amount_sub + stake_amount_root) as f32; + + let (_, Compact(stake_weight)) = neuron_sub.stake[0]; + let expected_stake_weight = (stake_amount_sub as f32 / total_stake) as u64; + assert_eq!( + expected_stake_weight, stake_weight, + "Stake amount for subnetwork does not match" + ); + }); +} + +#[test] +fn test_adding_substake_affects_only_targeted_neuron() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let tempo: u16 = 2; + let modality: u16 = 2; + + // Setup the network and neurons + add_network(netuid, tempo, modality); + let neuron_count = 5; + let total_stake: u64 = neuron_count as u64 * 1000; + let initial_stake: u64 = 1000; + + SubtensorModule::set_target_stakes_per_interval(10000); + SubtensorModule::set_max_registrations_per_block(netuid, neuron_count); + SubtensorModule::set_target_registrations_per_interval(netuid, neuron_count); + + // Register neurons and add initial stake + for i in 0..neuron_count { + let hotkey = U256::from(i); + let coldkey = U256::from(i); + register_ok_neuron(netuid, hotkey, coldkey, 39420842 + i as u64); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, total_stake); + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(coldkey), + hotkey, + netuid, + initial_stake, + )); + } + + // Add sub-stake to the first neuron + let target_neuron_index: u16 = 0; + let additional_stake: u64 = 500; + let target_hotkey = U256::from(target_neuron_index); + let target_coldkey = U256::from(target_neuron_index); + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(target_coldkey), + target_hotkey, + netuid, + additional_stake, + )); + + // Check that only the targeted neuron's stake has increased + for i in 0..neuron_count { + let hotkey = U256::from(i); + let coldkey = U256::from(i); + let expected_stake = if i == target_neuron_index { + initial_stake + additional_stake + } else { + initial_stake + }; + let neuron_stake = + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey, &hotkey, netuid); + assert_eq!( + neuron_stake, expected_stake, + "Neuron {} stake does not match expected value. Expected: {}, Got: {}", + i, expected_stake, neuron_stake + ); + } + }); +} + +#[test] +fn test_adding_substake_affects_only_targeted_neuron_with_get_neurons_lite() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let tempo: u16 = 2; + let modality: u16 = 2; + + log::info!("Setting up the network and neurons"); + add_network(netuid, tempo, modality); + let neuron_count = 5; + let initial_stake: u64 = 1000; + + SubtensorModule::set_target_stakes_per_interval(10000); + SubtensorModule::set_max_registrations_per_block(netuid, neuron_count); + SubtensorModule::set_target_registrations_per_interval(netuid, neuron_count); + + // Register neurons and add initial stake + for i in 0..neuron_count { + let hotkey = U256::from(i); + let coldkey = U256::from(i); + log::info!( + "Registering neuron {} with hotkey {:?} and coldkey {:?}", + i, + hotkey, + coldkey + ); + register_ok_neuron(netuid, hotkey, coldkey, 0); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, initial_stake * 5); + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(coldkey), + hotkey, + netuid, + initial_stake, + )); + } + + // Add sub-stake to the targeted neuron + let target_neuron_index: u16 = 2; + let additional_stake: u64 = 500; + log::info!("Adding additional stake to neuron {}", target_neuron_index); + let target_hotkey = U256::from(target_neuron_index); + let target_coldkey = U256::from(target_neuron_index); + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(target_coldkey), + target_hotkey, + netuid, + additional_stake, + )); + + // Cause epoch to run so that it sets StakeWeight + step_block(tempo); + + // Retrieve all neurons using get_neurons_lite and check stakes + let total_stake = (neuron_count as u64 * initial_stake + additional_stake) as f32; + let neurons_lite = SubtensorModule::get_neurons_lite(netuid); + log::info!( + "Retrieved {} neurons using get_neurons_lite", + neurons_lite.len() + ); + assert_eq!( + neurons_lite.len(), + neuron_count as usize, + "There should be {} neurons", + neuron_count + ); + + // Check that only the targeted neuron's stake has increased + for neuron in neurons_lite.into_iter() { + // Find the stake for the neuron based on its identifier (assuming the identifier is the first element in the tuple) + let (_, Compact(neuron_stake)) = neuron.stake.iter().find(|(id, _)| *id == neuron.hotkey).expect("Neuron stake not found"); + + let expected_stake_weight = (if neuron.hotkey == U256::from(target_neuron_index) { + (initial_stake + additional_stake) as f32 / total_stake + } else { + initial_stake as f32 / total_stake + } * (u16::MAX as f32)) as u64; + log::info!("Stake in all neurons: {:?}", neuron.stake); + log::info!("Neurons: {:?}", neuron); + log::info!("Neurons UID: {:?}", neuron.uid); + log::info!("Checking stake for neuron with hotkey {:?}: Expected: {:?}, Got: {:?}", neuron.hotkey, expected_stake_weight, neuron_stake); + assert_eq!( + *neuron_stake, expected_stake_weight, + "Stake does not match expected value for neuron with hotkey {:?}. Expected: {:?}, Got: {:?}", + neuron.hotkey, expected_stake_weight, *neuron_stake + ); + } + }); +} + +#[test] +fn test_adding_substake_affects_only_targeted_neuron_with_get_neuron_lite() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let tempo: u16 = 2; + let modality: u16 = 2; + + log::info!("Setting up the network and neurons"); + add_network(netuid, tempo, modality); + let neuron_count = 5; + let initial_stake: u64 = 1000; + + SubtensorModule::set_target_stakes_per_interval(10000); + SubtensorModule::set_max_registrations_per_block(netuid, neuron_count); + SubtensorModule::set_target_registrations_per_interval(netuid, neuron_count); + + // Append neurons and add initial stake + for i in 0..neuron_count { + let hotkey = U256::from(i); + let coldkey = U256::from(i); + log::info!( + "Appending neuron {} with hotkey {:?} and coldkey {:?}", + i, + hotkey, + coldkey + ); + register_ok_neuron(netuid, hotkey, coldkey, 0); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, initial_stake * 5); + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(coldkey), + hotkey, + netuid, + initial_stake, + )); + } + + // Add sub-stake to the targeted neuron + let target_neuron_index: u16 = 0; + let additional_stake: u64 = 500; + let target_hotkey = U256::from(target_neuron_index); + let target_coldkey = U256::from(target_neuron_index); + log::info!("Adding additional stake to neuron {}", target_neuron_index); + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(target_coldkey), + target_hotkey, + netuid, + additional_stake, + )); + + // Cause epoch to run so that it sets StakeWeight + step_block(tempo); + + // Retrieve and check all neurons to ensure only the targeted neuron's stake has increased + let total_stake = (neuron_count as u64 * initial_stake + additional_stake) as f32; + for i in 0..neuron_count { + let neuron_index = i; + if let Some(neuron_lite) = SubtensorModule::get_neuron_lite(netuid, neuron_index) { + let neuron_hotkey = U256::from(i); + let found_stake_tuple = neuron_lite + .stake + .iter() + .find(|(hotkey, _)| *hotkey == neuron_hotkey); + if let Some((_, Compact(stake_weight))) = found_stake_tuple { + let expected_stake_weight = (if neuron_index == target_neuron_index { + (initial_stake + additional_stake) as f32 / total_stake + } else { + initial_stake as f32 / total_stake + } * (u16::MAX as f32)) as u64; + log::info!( + "Checking stake for neuron {}: Expected: {}, Got: {}", + i, + expected_stake_weight, + stake_weight + ); + assert_eq!( + *stake_weight, expected_stake_weight, + "Stake does not match expected value for neuron {}. Expected: {}, Got: {}", + i, expected_stake_weight, *stake_weight + ); + } else { + panic!("Stake for neuron with hotkey {:?} not found", neuron_hotkey); + } + } else { + panic!("Neuron with index {} not found", neuron_index); + } + } + }); +} diff --git a/pallets/subtensor/tests/registration.rs b/pallets/subtensor/tests/registration.rs index 5ee941f26..454fb5bcc 100644 --- a/pallets/subtensor/tests/registration.rs +++ b/pallets/subtensor/tests/registration.rs @@ -11,6 +11,9 @@ use sp_runtime::traits::{DispatchInfoOf, SignedExtension}; mod mock; +// To run just the tests in this file, use the following command: +// cargo test -p pallet-subtensor --test registration + /******************************************** subscribing::subscribe() tests *********************************************/ @@ -33,14 +36,10 @@ fn test_registration_subscribe_ok_dispatch_info_ok() { hotkey, coldkey, }); - assert_eq!( - call.get_dispatch_info(), - DispatchInfo { - weight: frame_support::weights::Weight::from_parts(192_000_000, 0), - class: DispatchClass::Normal, - pays_fee: Pays::No - } - ); + let disp_info = call.get_dispatch_info(); + assert!(disp_info.weight.ref_time() != 0); + assert_eq!(disp_info.class, DispatchClass::Normal,); + assert_eq!(disp_info.pays_fee, Pays::No,); }); } @@ -148,7 +147,7 @@ fn test_registration_ok() { // Check if the balance of this hotkey account for this subnetwork == 0 assert_eq!( - SubtensorModule::get_stake_for_uid_and_subnetwork(netuid, neuron_uid), + SubtensorModule::get_total_stake_for_hotkey_and_subnet(&hotkey_account_id, netuid), 0 ); }); @@ -458,7 +457,7 @@ fn test_burned_registration_ok() { assert_eq!(neuro_uid, neuron_uid); // Check if the balance of this hotkey account for this subnetwork == 0 assert_eq!( - SubtensorModule::get_stake_for_uid_and_subnetwork(netuid, neuron_uid), + SubtensorModule::get_total_stake_for_hotkey_and_subnet(&hotkey_account_id, netuid), 0 ); }); @@ -471,8 +470,10 @@ fn test_burn_registration_without_neuron_slot() { let tempo: u16 = 13; let hotkey_account_id = U256::from(1); let burn_cost = 1000; - let coldkey_account_id = U256::from(667); // Neighbour of the beast, har har - //add network + // Neighbour of the beast, har har + let coldkey_account_id = U256::from(667); + + //add network SubtensorModule::set_burn(netuid, burn_cost); add_network(netuid, tempo, 0); // Give it some $$$ in his coldkey balance diff --git a/pallets/subtensor/tests/root.rs b/pallets/subtensor/tests/root.rs index 7958c9c81..0395eed61 100644 --- a/pallets/subtensor/tests/root.rs +++ b/pallets/subtensor/tests/root.rs @@ -2,12 +2,14 @@ use crate::mock::*; use frame_support::{assert_err, assert_ok}; use frame_system::Config; use frame_system::{EventRecord, Phase}; -use pallet_subtensor::migration; -use pallet_subtensor::Error; +use pallet_subtensor::{migration, Error, PendingEmission, SubnetInTransition, TotalSubnetTAO}; use sp_core::{Get, H256, U256}; mod mock; +// To run just the tests in this file, use the following command: +// cargo test -p pallet-subtensor --test ro + #[allow(dead_code)] fn record(event: RuntimeEvent) -> EventRecord { EventRecord { @@ -132,15 +134,14 @@ fn test_root_register_stake_based_pruning_works() { hot )); // Add stake on other network - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(cold), hot, + other_netuid, 1000 + (i as u64) )); // Check successful registration. assert!(SubtensorModule::get_uid_for_net_and_hotkey(other_netuid, &hot).is_ok()); - // Check that they are NOT all delegates - assert!(!SubtensorModule::hotkey_is_delegate(&hot)); } // Register the first 64 accounts with stake to the root network. @@ -153,8 +154,6 @@ fn test_root_register_stake_based_pruning_works() { )); // Check successful registration. assert!(SubtensorModule::get_uid_for_net_and_hotkey(root_netuid, &hot).is_ok()); - // Check that they are all delegates - assert!(SubtensorModule::hotkey_is_delegate(&hot)); } // Register the second 64 accounts with stake to the root network. @@ -190,268 +189,6 @@ fn test_root_register_stake_based_pruning_works() { }); } -#[test] -fn test_root_set_weights() { - new_test_ext(1).execute_with(|| { - System::set_block_number(0); - migration::migrate_create_root_network::(); - - let n: usize = 10; - let root_netuid: u16 = 0; - SubtensorModule::set_max_registrations_per_block(root_netuid, n as u16); - SubtensorModule::set_target_registrations_per_interval(root_netuid, n as u16); - SubtensorModule::set_max_allowed_uids(root_netuid, n as u16); - for i in 0..n { - let hotkey_account_id: U256 = U256::from(i); - let coldkey_account_id: U256 = U256::from(i + 456); - SubtensorModule::add_balance_to_coldkey_account( - &coldkey_account_id, - 1_000_000_000_000_000, - ); - assert_ok!(SubtensorModule::root_register( - <::RuntimeOrigin>::signed(coldkey_account_id), - hotkey_account_id, - )); - assert_ok!(SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey_account_id), - hotkey_account_id, - 1000 - )); - } - - log::info!("subnet limit: {:?}", SubtensorModule::get_max_subnets()); - log::info!( - "current subnet count: {:?}", - SubtensorModule::get_num_subnets() - ); - - // Lets create n networks - for netuid in 1..n { - log::debug!("Adding network with netuid: {}", netuid); - assert_ok!(SubtensorModule::register_network( - <::RuntimeOrigin>::signed(U256::from(netuid + 456)) - )); - } - - // Test that signing with hotkey will fail. - for i in 0..n { - let hotkey = U256::from(i); - let uids: Vec = vec![i as u16]; - let values: Vec = vec![1]; - assert_err!( - SubtensorModule::set_root_weights( - <::RuntimeOrigin>::signed(hotkey), - root_netuid, - hotkey, - uids, - values, - 0, - ), - Error::::NonAssociatedColdKey - ); - } - - // Test that signing an unassociated coldkey will fail. - let unassociated_coldkey = U256::from(612); - for i in 0..n { - let hotkey = U256::from(i); - let uids: Vec = vec![i as u16]; - let values: Vec = vec![1]; - assert_err!( - SubtensorModule::set_root_weights( - <::RuntimeOrigin>::signed(unassociated_coldkey), - root_netuid, - hotkey, - uids, - values, - 0, - ), - Error::::NonAssociatedColdKey - ); - } - - // Set weights into diagonal matrix. - for i in 0..n { - let hotkey = U256::from(i); - let coldkey = U256::from(i + 456); - let uids: Vec = vec![i as u16]; - let values: Vec = vec![1]; - assert_ok!(SubtensorModule::set_root_weights( - <::RuntimeOrigin>::signed(coldkey), - root_netuid, - hotkey, - uids, - values, - 0, - )); - } - // Run the root epoch - log::debug!("Running Root epoch"); - SubtensorModule::set_tempo(root_netuid, 1); - assert_ok!(SubtensorModule::root_epoch(1_000_000_000)); - // Check that the emission values have been set. - for netuid in 1..n { - log::debug!("check emission for netuid: {}", netuid); - assert_eq!( - SubtensorModule::get_subnet_emission_value(netuid as u16), - 99_999_999 - ); - } - step_block(2); - // Check that the pending emission values have been set. - for netuid in 1..n { - log::debug!( - "check pending emission for netuid {} has pending {}", - netuid, - SubtensorModule::get_pending_emission(netuid as u16) - ); - assert_eq!( - SubtensorModule::get_pending_emission(netuid as u16), - 199_999_998 - ); - } - step_block(1); - for netuid in 1..n { - log::debug!( - "check pending emission for netuid {} has pending {}", - netuid, - SubtensorModule::get_pending_emission(netuid as u16) - ); - assert_eq!( - SubtensorModule::get_pending_emission(netuid as u16), - 299_999_997 - ); - } - let step = SubtensorModule::blocks_until_next_epoch( - 10, - 1000, - SubtensorModule::get_current_block_as_u64(), - ); - step_block(step as u16); - assert_eq!(SubtensorModule::get_pending_emission(10), 0); - }); -} - -#[test] -fn test_root_set_weights_out_of_order_netuids() { - new_test_ext(1).execute_with(|| { - System::set_block_number(0); - migration::migrate_create_root_network::(); - - let n: usize = 10; - let root_netuid: u16 = 0; - SubtensorModule::set_max_registrations_per_block(root_netuid, n as u16); - SubtensorModule::set_target_registrations_per_interval(root_netuid, n as u16); - SubtensorModule::set_max_allowed_uids(root_netuid, n as u16); - for i in 0..n { - let hotkey_account_id: U256 = U256::from(i); - let coldkey_account_id: U256 = U256::from(i); - SubtensorModule::add_balance_to_coldkey_account( - &coldkey_account_id, - 1_000_000_000_000_000, - ); - assert_ok!(SubtensorModule::root_register( - <::RuntimeOrigin>::signed(coldkey_account_id), - hotkey_account_id, - )); - assert_ok!(SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey_account_id), - hotkey_account_id, - 1000 - )); - } - - log::info!("subnet limit: {:?}", SubtensorModule::get_max_subnets()); - log::info!( - "current subnet count: {:?}", - SubtensorModule::get_num_subnets() - ); - - // Lets create n networks - for netuid in 1..n { - log::debug!("Adding network with netuid: {}", netuid); - - if netuid % 2 == 0 { - assert_ok!(SubtensorModule::register_network( - <::RuntimeOrigin>::signed(U256::from(netuid)) - )); - } else { - add_network(netuid as u16 * 10, 1000, 0) - } - } - - log::info!("netuids: {:?}", SubtensorModule::get_all_subnet_netuids()); - log::info!( - "root network count: {:?}", - SubtensorModule::get_subnetwork_n(0) - ); - - let subnets = SubtensorModule::get_all_subnet_netuids(); - // Set weights into diagonal matrix. - for (i, netuid) in subnets.iter().enumerate() { - let uids: Vec = vec![*netuid]; - let values: Vec = vec![1]; - - let coldkey = U256::from(i); - let hotkey = U256::from(i); - assert_ok!(SubtensorModule::set_root_weights( - <::RuntimeOrigin>::signed(coldkey), - root_netuid, - hotkey, - uids, - values, - 0, - )); - } - // Run the root epoch - log::debug!("Running Root epoch"); - SubtensorModule::set_tempo(root_netuid, 1); - assert_ok!(SubtensorModule::root_epoch(1_000_000_000)); - // Check that the emission values have been set. - for netuid in subnets.iter() { - log::debug!("check emission for netuid: {}", netuid); - assert_eq!( - SubtensorModule::get_subnet_emission_value(*netuid), - 99_999_999 - ); - } - step_block(2); - // Check that the pending emission values have been set. - for netuid in subnets.iter() { - if *netuid == 0 { - continue; - } - - log::debug!( - "check pending emission for netuid {} has pending {}", - netuid, - SubtensorModule::get_pending_emission(*netuid) - ); - assert_eq!(SubtensorModule::get_pending_emission(*netuid), 199_999_998); - } - step_block(1); - for netuid in subnets.iter() { - if *netuid == 0 { - continue; - } - - log::debug!( - "check pending emission for netuid {} has pending {}", - netuid, - SubtensorModule::get_pending_emission(*netuid) - ); - assert_eq!(SubtensorModule::get_pending_emission(*netuid), 299_999_997); - } - let step = SubtensorModule::blocks_until_next_epoch( - 9, - 1000, - SubtensorModule::get_current_block_as_u64(), - ); - step_block(step as u16); - assert_eq!(SubtensorModule::get_pending_emission(9), 0); - }); -} - #[test] fn test_root_subnet_creation_deletion() { new_test_ext(1).execute_with(|| { @@ -459,19 +196,22 @@ fn test_root_subnet_creation_deletion() { migration::migrate_create_root_network::(); // Owner of subnets. let owner: U256 = U256::from(0); + let hotkey: U256 = U256::from(1); // Add a subnet. SubtensorModule::add_balance_to_coldkey_account(&owner, 1_000_000_000_000_000); // last_lock: 100000000000, min_lock: 100000000000, last_lock_block: 0, lock_reduction_interval: 2, current_block: 0, mult: 1 lock_cost: 100000000000 assert_ok!(SubtensorModule::register_network( - <::RuntimeOrigin>::signed(owner) + <::RuntimeOrigin>::signed(owner), + hotkey )); // last_lock: 100000000000, min_lock: 100000000000, last_lock_block: 0, lock_reduction_interval: 2, current_block: 0, mult: 1 lock_cost: 100000000000 assert_eq!(SubtensorModule::get_network_lock_cost(), 100_000_000_000); step_block(1); // last_lock: 100000000000, min_lock: 100000000000, last_lock_block: 0, lock_reduction_interval: 2, current_block: 1, mult: 1 lock_cost: 100000000000 assert_ok!(SubtensorModule::register_network( - <::RuntimeOrigin>::signed(owner) + <::RuntimeOrigin>::signed(owner), + hotkey )); // last_lock: 100000000000, min_lock: 100000000000, last_lock_block: 1, lock_reduction_interval: 2, current_block: 1, mult: 2 lock_cost: 200000000000 assert_eq!(SubtensorModule::get_network_lock_cost(), 200_000_000_000); // Doubles from previous subnet creation @@ -485,38 +225,44 @@ fn test_root_subnet_creation_deletion() { // last_lock: 100000000000, min_lock: 100000000000, last_lock_block: 1, lock_reduction_interval: 2, current_block: 4, mult: 2 lock_cost: 100000000000 assert_eq!(SubtensorModule::get_network_lock_cost(), 100_000_000_000); // Reaches min value assert_ok!(SubtensorModule::register_network( - <::RuntimeOrigin>::signed(owner) + <::RuntimeOrigin>::signed(owner), + hotkey )); // last_lock: 100000000000, min_lock: 100000000000, last_lock_block: 4, lock_reduction_interval: 2, current_block: 4, mult: 2 lock_cost: 200000000000 assert_eq!(SubtensorModule::get_network_lock_cost(), 200_000_000_000); // Doubles from previous subnet creation step_block(1); // last_lock: 100000000000, min_lock: 100000000000, last_lock_block: 4, lock_reduction_interval: 2, current_block: 5, mult: 2 lock_cost: 150000000000 assert_ok!(SubtensorModule::register_network( - <::RuntimeOrigin>::signed(owner) + <::RuntimeOrigin>::signed(owner), + hotkey )); // last_lock: 150000000000, min_lock: 100000000000, last_lock_block: 5, lock_reduction_interval: 2, current_block: 5, mult: 2 lock_cost: 300000000000 assert_eq!(SubtensorModule::get_network_lock_cost(), 300_000_000_000); // Doubles from previous subnet creation step_block(1); // last_lock: 150000000000, min_lock: 100000000000, last_lock_block: 5, lock_reduction_interval: 2, current_block: 6, mult: 2 lock_cost: 225000000000 assert_ok!(SubtensorModule::register_network( - <::RuntimeOrigin>::signed(owner) + <::RuntimeOrigin>::signed(owner), + hotkey )); // last_lock: 225000000000, min_lock: 100000000000, last_lock_block: 6, lock_reduction_interval: 2, current_block: 6, mult: 2 lock_cost: 450000000000 assert_eq!(SubtensorModule::get_network_lock_cost(), 450_000_000_000); // Increasing step_block(1); // last_lock: 225000000000, min_lock: 100000000000, last_lock_block: 6, lock_reduction_interval: 2, current_block: 7, mult: 2 lock_cost: 337500000000 assert_ok!(SubtensorModule::register_network( - <::RuntimeOrigin>::signed(owner) + <::RuntimeOrigin>::signed(owner), + hotkey )); // last_lock: 337500000000, min_lock: 100000000000, last_lock_block: 7, lock_reduction_interval: 2, current_block: 7, mult: 2 lock_cost: 675000000000 assert_eq!(SubtensorModule::get_network_lock_cost(), 675_000_000_000); // Increasing. assert_ok!(SubtensorModule::register_network( - <::RuntimeOrigin>::signed(owner) + <::RuntimeOrigin>::signed(owner), + hotkey )); // last_lock: 337500000000, min_lock: 100000000000, last_lock_block: 7, lock_reduction_interval: 2, current_block: 7, mult: 2 lock_cost: 675000000000 assert_eq!(SubtensorModule::get_network_lock_cost(), 1_350_000_000_000); // Double increasing. assert_ok!(SubtensorModule::register_network( - <::RuntimeOrigin>::signed(owner) + <::RuntimeOrigin>::signed(owner), + hotkey )); assert_eq!(SubtensorModule::get_network_lock_cost(), 2_700_000_000_000); // Double increasing again. @@ -533,244 +279,69 @@ fn test_root_subnet_creation_deletion() { } #[test] -fn test_network_pruning() { - new_test_ext(1).execute_with(|| { - System::set_block_number(0); - migration::migrate_create_root_network::(); - - assert_eq!(SubtensorModule::get_total_issuance(), 0); - - let n: usize = 10; - let root_netuid: u16 = 0; - SubtensorModule::set_max_registrations_per_block(root_netuid, n as u16); - SubtensorModule::set_target_registrations_per_interval(root_netuid, n as u16); - SubtensorModule::set_max_allowed_uids(root_netuid, n as u16 + 1); - SubtensorModule::set_tempo(root_netuid, 1); - // No validators yet. - assert_eq!(SubtensorModule::get_subnetwork_n(root_netuid), 0); - - for i in 0..n { - let hot: U256 = U256::from(i); - let cold: U256 = U256::from(i); - let uids: Vec = (0..i as u16).collect(); - let values: Vec = vec![1; i]; - SubtensorModule::add_balance_to_coldkey_account(&cold, 1_000_000_000_000_000); - assert_ok!(SubtensorModule::root_register( - <::RuntimeOrigin>::signed(cold), - hot - )); - assert_ok!(SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(cold), - hot, - 1_000 - )); - assert_ok!(SubtensorModule::register_network( - <::RuntimeOrigin>::signed(cold) - )); - log::debug!("Adding network with netuid: {}", (i as u16) + 1); - assert!(SubtensorModule::if_subnet_exist((i as u16) + 1)); - assert!(SubtensorModule::is_hotkey_registered_on_network( - root_netuid, - &hot - )); - assert!(SubtensorModule::get_uid_for_net_and_hotkey(root_netuid, &hot).is_ok()); - assert_ok!(SubtensorModule::set_root_weights( - <::RuntimeOrigin>::signed(cold), - root_netuid, - hot, - uids, - values, - 0 - )); - SubtensorModule::set_tempo((i as u16) + 1, 1); - SubtensorModule::set_burn((i as u16) + 1, 0); - assert_ok!(SubtensorModule::burned_register( - <::RuntimeOrigin>::signed(cold), - (i as u16) + 1, - hot - )); - assert_eq!( - SubtensorModule::get_subnetwork_n(root_netuid), - (i as u16) + 1 - ); - } - // Stakes - // 0 : 10_000 - // 1 : 9_000 - // 2 : 8_000 - // 3 : 7_000 - // 4 : 6_000 - // 5 : 5_000 - // 6 : 4_000 - // 7 : 3_000 - // 8 : 2_000 - // 9 : 1_000 - - step_block(1); - assert_ok!(SubtensorModule::root_epoch(1_000_000_000)); - assert_eq!(SubtensorModule::get_subnet_emission_value(0), 385_861_815); - assert_eq!(SubtensorModule::get_subnet_emission_value(1), 249_435_914); - assert_eq!(SubtensorModule::get_subnet_emission_value(2), 180_819_837); - assert_eq!(SubtensorModule::get_subnet_emission_value(3), 129_362_980); - assert_eq!(SubtensorModule::get_subnet_emission_value(4), 50_857_187); - assert_eq!(SubtensorModule::get_subnet_emission_value(5), 3_530_356); - step_block(1); - assert_eq!(SubtensorModule::get_pending_emission(0), 0); // root network gets no pending emission. - assert_eq!(SubtensorModule::get_pending_emission(1), 249_435_914); - assert_eq!(SubtensorModule::get_pending_emission(2), 0); // This has been drained. - assert_eq!(SubtensorModule::get_pending_emission(3), 129_362_980); - assert_eq!(SubtensorModule::get_pending_emission(4), 0); // This network has been drained. - assert_eq!(SubtensorModule::get_pending_emission(5), 3_530_356); - step_block(1); - }); -} - -#[test] -fn test_network_prune_results() { - new_test_ext(1).execute_with(|| { - migration::migrate_create_root_network::(); - - SubtensorModule::set_network_immunity_period(3); - SubtensorModule::set_network_min_lock(0); - SubtensorModule::set_network_rate_limit(0); - - let owner: U256 = U256::from(0); - SubtensorModule::add_balance_to_coldkey_account(&owner, 1_000_000_000_000_000); - - assert_ok!(SubtensorModule::register_network( - <::RuntimeOrigin>::signed(owner) - )); - step_block(3); - - assert_ok!(SubtensorModule::register_network( - <::RuntimeOrigin>::signed(owner) - )); - step_block(3); - - assert_ok!(SubtensorModule::register_network( - <::RuntimeOrigin>::signed(owner) - )); - step_block(3); - - // lowest emission - SubtensorModule::set_emission_values(&[1u16, 2u16, 3u16], vec![5u64, 4u64, 4u64]).unwrap(); - assert_eq!(SubtensorModule::get_subnet_to_prune(), 2u16); - - // equal emission, creation date - SubtensorModule::set_emission_values(&[1u16, 2u16, 3u16], vec![5u64, 5u64, 4u64]).unwrap(); - assert_eq!(SubtensorModule::get_subnet_to_prune(), 3u16); - - // equal emission, creation date - SubtensorModule::set_emission_values(&[1u16, 2u16, 3u16], vec![4u64, 5u64, 5u64]).unwrap(); - assert_eq!(SubtensorModule::get_subnet_to_prune(), 1u16); - }); -} - -#[test] -fn test_weights_after_network_pruning() { +fn test_subnet_staking_cleared_and_refunded_on_network_removal() { new_test_ext(1).execute_with(|| { migration::migrate_create_root_network::(); + let netuid: u16 = 1; + let hotkey_account_id = U256::from(1); + let coldkey_account_id = U256::from(667); + let initial_balance = 100_000_000; + let burn_amount: u64 = 10; + let stake_amount = 1_000; - assert_eq!(SubtensorModule::get_total_issuance(), 0); - - // Set up N subnets, with max N + 1 allowed UIDs - let n: usize = 2; - let root_netuid: u16 = 0; - SubtensorModule::set_network_immunity_period(3); - SubtensorModule::set_max_registrations_per_block(root_netuid, n as u16); - SubtensorModule::set_max_subnets(n as u16); - SubtensorModule::set_weights_set_rate_limit(root_netuid, 0_u64); - - // No validators yet. - assert_eq!(SubtensorModule::get_subnetwork_n(root_netuid), 0); - - for i in 0..n { - // Register a validator - let cold: U256 = U256::from(i); - - SubtensorModule::add_balance_to_coldkey_account(&cold, 1_000_000_000_000); - - // Register a network - assert_ok!(SubtensorModule::register_network( - <::RuntimeOrigin>::signed(cold) - )); - - log::debug!("Adding network with netuid: {}", (i as u16) + 1); - assert!(SubtensorModule::if_subnet_exist((i as u16) + 1)); - step_block(3); - } - - // Register a validator in subnet 0 - let hot: U256 = U256::from((n as u64) - 1); - let cold: U256 = U256::from((n as u64) - 1); - - assert_ok!(SubtensorModule::root_register( - <::RuntimeOrigin>::signed(cold), - hot - )); - assert_ok!(SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(cold), - hot, - 1_000 - )); - - // Let's give these subnets some weights - let uids: Vec = (0..(n as u16) + 1).collect(); - let values: Vec = vec![4u16, 2u16, 6u16]; - log::info!("uids set: {:?}", uids); - log::info!("values set: {:?}", values); - log::info!("In netuid: {:?}", root_netuid); - assert_ok!(SubtensorModule::set_root_weights( - <::RuntimeOrigin>::signed(cold), - root_netuid, - hot, - uids, - values, - 0 - )); + add_network(netuid, 0, 0); + // Add initial balance to the coldkey account + SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, initial_balance); log::info!( - "Root network weights before extra network registration: {:?}", - SubtensorModule::get_root_weights() + "Initial balance added to coldkey account: {}", + initial_balance ); - log::info!("Max subnets: {:?}", SubtensorModule::get_max_subnets()); - let i = (n as u16) + 1; - // let _hot: U256 = U256::from(i); - let cold: U256 = U256::from(i); - - SubtensorModule::add_balance_to_coldkey_account(&cold, 1_000_000_000_000_000_000); - let subnet_to_prune = SubtensorModule::get_subnet_to_prune(); - // Subnet 1 should be pruned here. - assert_eq!(subnet_to_prune, 1); - log::info!("Removing subnet: {:?}", subnet_to_prune); + // Set up the network with a specific burn cost (if applicable) + SubtensorModule::set_burn(netuid, burn_amount); + log::info!("Burn set to {}", burn_amount); - // Check that the weights have been set appropriately. - let latest_weights = SubtensorModule::get_root_weights(); - log::info!("Weights before register network: {:?}", latest_weights); - // We expect subnet 1 to be deregistered as it is oldest and has lowest emissions - assert_eq!(latest_weights[0][1], 21845); - - assert_ok!(SubtensorModule::register_network( - <::RuntimeOrigin>::signed(cold) + // Register the hotkey with the network and stake + assert_ok!(SubtensorModule::burned_register( + <::RuntimeOrigin>::signed(coldkey_account_id), + netuid, + hotkey_account_id, )); + log::info!("Hotkey registered"); - // Subnet should not exist, as it would replace a previous subnet. - assert!(!SubtensorModule::if_subnet_exist(i + 1)); - - log::info!( - "Root network weights: {:?}", - SubtensorModule::get_root_weights() - ); - - let latest_weights = SubtensorModule::get_root_weights(); + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(coldkey_account_id), + hotkey_account_id, + netuid, + stake_amount, + )); + log::info!("Stake added"); log::info!( - "Weights after register network: {:?}", - SubtensorModule::get_root_weights() + "Balance after adding stake: {}", + SubtensorModule::get_coldkey_balance(&coldkey_account_id) ); - - // Subnet 0 should be kicked, and thus its weight should be 0 - assert_eq!(latest_weights[0][1], 0); + // Verify the stake has been added + let stake_before_removal = + SubtensorModule::get_total_stake_for_hotkey_and_subnet(&hotkey_account_id, netuid); + log::info!("Stake before removal: {}", stake_before_removal); + assert_eq!(stake_before_removal, stake_amount); + + // TODO: Do we have the network removal removed on purpose? + // Remove the network, triggering stake removal and refund + // SubtensorModule::remove_network(netuid); + // log::info!("Network removed"); + + // // Verify the stake has been cleared + // let stake_after_removal = + // SubtensorModule::get_total_stake_for_hotkey_and_subnet(&hotkey_account_id, netuid); + // log::info!("Stake after removal: {}", stake_after_removal); + // assert_eq!(stake_after_removal, 0); + + // // Verify the balance has been refunded to the coldkey account + // let balance_after_refund = SubtensorModule::get_coldkey_balance(&coldkey_account_id); + // log::info!("Balance after refund: {}", balance_after_refund); + // assert_eq!(balance_after_refund, initial_balance - burn_amount); }); } @@ -783,13 +354,11 @@ fn test_issuance_bounds() { // Simulate 100 halvings convergence to 21M. Note that the total issuance never reaches 21M because of rounding errors. // We converge to 20_999_999_989_500_000 (< 1 TAO away). let n_halvings: usize = 100; - let mut total_issuance: u64 = 0; - for _ in 0..n_halvings { + let total_issuance = (0..n_halvings).fold(0, |total, _| { let block_emission_10_500_000x: u64 = - SubtensorModule::get_block_emission_for_issuance(total_issuance).unwrap() - * 10_500_000; - total_issuance += block_emission_10_500_000x; - } + SubtensorModule::get_block_emission_for_issuance(total).unwrap() * 10_500_000; + total + block_emission_10_500_000x + }); assert_eq!(total_issuance, 20_999_999_989_500_000); }) } @@ -972,3 +541,489 @@ fn test_dissolve_network_does_not_exist_err() { ); }); } + +#[test] +fn test_stao_dtao_transition_basic() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let coldkey1 = U256::from(1); + let coldkey2 = U256::from(2); + let hotkey1 = U256::from(1); + let lock_cost = 100_000_000_000; + let stake = 100_000_000_000; + create_staked_stao_network(netuid, lock_cost, stake); + + // Make sure TotalSubnetTAO and SubStake were initialized + assert_eq!( + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1, netuid), + 0, + ); + assert_eq!( + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey2, &hotkey1, netuid), + stake, + ); + assert_eq!(TotalSubnetTAO::::get(netuid), lock_cost + stake); + + let coldkey2_balance_before = SubtensorModule::get_coldkey_balance(&coldkey2); + + // Start transition + assert_ok!(SubtensorModule::do_start_stao_dtao_transition(netuid,)); + + // Let transition run + SubtensorModule::do_continue_stao_dtao_transition(); + + // Check that everyone but owner got unstaked + assert_eq!( + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey2, &hotkey1, netuid), + 0 + ); + + // TotalSubnetTAO updated + assert_eq!( + TotalSubnetTAO::::get(netuid), + SubtensorModule::get_initial_lock_on_transition() + ); + + // Re-staked balance of owner and delegators is not available as balance + let coldkey2_balance_after = SubtensorModule::get_coldkey_balance(&coldkey2); + assert_eq!(coldkey2_balance_after, coldkey2_balance_before + stake); + }); +} + +// TODOSDT: Unignore and fix +#[ignore] +#[test] +fn test_stao_dtao_transition_non_owner_fail() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let lock_cost = 100_000_000_000; + let stake = 100_000_000_000; + create_staked_stao_network(netuid, lock_cost, stake); + + // Start transition using non-owner coldkey + assert_err!( + SubtensorModule::do_start_stao_dtao_transition(netuid), + Error::::NotSubnetOwner + ); + }); +} + +#[test] +fn test_stao_dtao_transition_waits_for_drain() { + new_test_ext(1).execute_with(|| { + let netuid1: u16 = 1; + let coldkey2 = U256::from(2); + let hotkey1 = U256::from(1); + let lock_cost = 100_000_000_000; + let stake = 100_000_000_000; + + // We'll need two subnets so that new alpha stakes are different from old tao stakes + create_staked_stao_network(netuid1, lock_cost, stake); + + // Set emission values for this subnet + PendingEmission::::insert(netuid1, 123); + + // Start transition + assert_ok!(SubtensorModule::do_start_stao_dtao_transition(netuid1)); + + // Let transition run (pending emission is non-zero) + SubtensorModule::do_continue_stao_dtao_transition(); + + // Check that everybody's but owner SubStake is the same + assert_eq!( + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey2, &hotkey1, netuid1), + stake, + ); + + // Check that total TAO subnet didn't change + assert_eq!(TotalSubnetTAO::::get(netuid1), lock_cost + stake); + + // Drain emission + PendingEmission::::insert(netuid1, 0); + + // Let transition run (pending emission is zero) + SubtensorModule::do_continue_stao_dtao_transition(); + + // Check that everybody's SubStake is now cleared + assert_eq!( + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey2, &hotkey1, netuid1), + 0 + ); + + // TAO amount is also updated + let initial_total_tao = SubtensorModule::get_initial_lock_on_transition(); + assert_eq!(TotalSubnetTAO::::get(netuid1), initial_total_tao); + }); +} + +#[test] +fn test_staking_during_dtao_transition_fails() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let coldkey2 = U256::from(2); + let hotkey1 = U256::from(1); + let lock_cost = 100_000_000_000; + let stake = 100_000_000_000; + create_staked_stao_network(netuid, lock_cost, stake); + SubtensorModule::add_balance_to_coldkey_account(&coldkey2, stake); + + // Start transition + assert_ok!(SubtensorModule::do_start_stao_dtao_transition(netuid)); + + // Check that staking fails + assert_err!( + SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(coldkey2), + hotkey1, + netuid, + stake + ), + Error::::TemporarilyNotAllowed + ); + }); +} + +#[test] +fn test_staking_after_dtao_transition_ok() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let coldkey2 = U256::from(2); + let hotkey1 = U256::from(1); + let lock_cost = 100_000_000_000; + let stake = 100_000_000_000; + create_staked_stao_network(netuid, lock_cost, stake); + SubtensorModule::add_balance_to_coldkey_account( + &coldkey2, + stake + ExistentialDeposit::get(), + ); + + // Start transition + assert_ok!(SubtensorModule::do_start_stao_dtao_transition(netuid)); + + // Let transition run + SubtensorModule::do_continue_stao_dtao_transition(); + + // Check that everybody got their stakes cleared + assert_eq!( + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey2, &hotkey1, netuid), + 0 + ); + assert_eq!( + TotalSubnetTAO::::get(netuid), + SubtensorModule::get_initial_lock_on_transition() + ); + + // Check that staking succeeds + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(coldkey2), + hotkey1, + netuid, + stake + )); + }); +} + +#[test] +fn test_run_coinbase_during_dtao_transition_no_effect() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let lock_cost = 100_000_000_000; + let stake = 100_000_000_000; + create_staked_stao_network(netuid, lock_cost, stake); + + // Start transition + assert_ok!(SubtensorModule::do_start_stao_dtao_transition(netuid)); + + // Check that run_coinbase doesn't increase PendingEmission or TotalSubnetTAO for this subnet + SubtensorModule::run_coinbase(2); + assert_eq!(PendingEmission::::get(netuid), 0); + assert_eq!(TotalSubnetTAO::::get(netuid), lock_cost + stake); + }); +} + +#[test] +fn test_run_coinbase_after_dtao_transition_ok() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let lock_cost = 100_000_000_000; + let stake = 100_000_000_000; + create_staked_stao_network(netuid, lock_cost, stake); + + // Start transition + assert_ok!(SubtensorModule::do_start_stao_dtao_transition(netuid)); + + // Let transition run + SubtensorModule::do_continue_stao_dtao_transition(); + + // Check that run_coinbase increases PendingEmission or TotalSubnetTAO for this subnet + let total_tao_before = TotalSubnetTAO::::get(netuid); + SubtensorModule::run_coinbase(2); + let total_tao_after = TotalSubnetTAO::::get(netuid); + assert_eq!( + PendingEmission::::get(netuid), + SubtensorModule::get_block_emission().unwrap(), + ); + assert!(total_tao_before < total_tao_after); + }); +} + +// The dynamic pool is initialized as (tao_in: 1, alpha_in: 1, alpha_out: 1) +#[test] +fn test_stao_dtao_transition_dynamic_variables() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let hotkey1 = U256::from(1); + let lock_cost = 100_000_000_000; + let stake = 100_000_000_000; + let tao_in = SubtensorModule::get_initial_lock_on_transition(); + create_staked_stao_network(netuid, lock_cost, stake); + + // Start transition + assert_ok!(SubtensorModule::do_start_stao_dtao_transition(netuid)); + + // Let transition run + SubtensorModule::do_continue_stao_dtao_transition(); + + // Check dynamic variables + assert_eq!( + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey1), + tao_in, + ); + assert_eq!( + pallet_subtensor::DynamicTAOReserve::::get(netuid), + tao_in, + ); + assert_eq!( + pallet_subtensor::DynamicAlphaReserve::::get(netuid), + tao_in, + ); + assert_eq!( + pallet_subtensor::DynamicAlphaOutstanding::::get(netuid), + tao_in, + ); + assert_eq!( + pallet_subtensor::DynamicK::::get(netuid), + tao_in as u128 * tao_in as u128, + ); + assert!(pallet_subtensor::IsDynamic::::get(netuid)); + + // DynamicTAOReserve will be set to equal the new value of TotalSubnetTAO (test) + assert_eq!( + pallet_subtensor::DynamicTAOReserve::::get(netuid), + TotalSubnetTAO::::get(netuid), + ); + }); +} + +#[test] +fn test_stao_dtao_transition_updates_staker() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let coldkey1 = U256::from(1); + let coldkey2 = U256::from(2); + let hotkey1 = U256::from(1); + let lock_cost = 100_000_000_000; + let stake = 100_000_000_000; + create_staked_stao_network(netuid, lock_cost, stake); + + // Start transition + assert_ok!(SubtensorModule::do_start_stao_dtao_transition(netuid)); + + // Let transition run + SubtensorModule::do_continue_stao_dtao_transition(); + + // Check staker map for owner (should be set) and for delegator (should be cleared) + assert!(pallet_subtensor::Staker::::get(hotkey1, coldkey1)); + assert!(!pallet_subtensor::Staker::::get(hotkey1, coldkey2)); + }); +} + +// Subnet tempo is set to default value +#[test] +fn test_stao_dtao_transition_resets_tempo() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let lock_cost = 100_000_000_000; + let stake = 100_000_000_000; + create_staked_stao_network(netuid, lock_cost, stake); + + // Start transition + assert_ok!(SubtensorModule::do_start_stao_dtao_transition(netuid)); + + // Let transition run + SubtensorModule::do_continue_stao_dtao_transition(); + + // Check that tempo went default + assert_eq!( + pallet_subtensor::Tempo::::get(netuid), + ::InitialTempo::get(), + ); + }); +} + +// High weight test - many SubStake records, so that do_continue_stao_dtao_transition runs multiple times +#[test] +fn test_stao_dtao_transition_high_weight_ok() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let hotkey1 = U256::from(1); + let lock_cost = 100_000_000_000; + let stake = 100_000_000_000; + create_staked_stao_network(netuid, lock_cost, stake); + + let items = 10000; + + for i in 3..=items + 2 { + let coldkey = U256::from(i); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, stake); + SubtensorModule::increase_subnet_token_on_coldkey_hotkey_account( + &coldkey, &hotkey1, netuid, stake, + ); + TotalSubnetTAO::::mutate(netuid, |locked| *locked = locked.saturating_add(stake)); + } + + // Start transition + assert_ok!(SubtensorModule::do_start_stao_dtao_transition(netuid)); + + // Let transition run one time + SubtensorModule::do_continue_stao_dtao_transition(); + + // Check that transition hasn't finished yet + assert!(SubnetInTransition::::get(netuid).is_some()); + + // Check that transition finishes eventually, but takes more than 10 iterations + let mut counter = 0; + loop { + counter += 1; + SubtensorModule::do_continue_stao_dtao_transition(); + + if SubnetInTransition::::get(netuid).is_none() { + break; + } + } + assert!(counter > 10); + }); +} + +#[test] +fn test_stao_dtao_transition_multi_network() { + new_test_ext(1).execute_with(|| { + let netuid1: u16 = 1; + let netuid2: u16 = 2; + let lock_cost = 100_000_000_000; + let stake = 100_000_000_000; + create_staked_stao_network(netuid1, lock_cost, stake); + create_staked_stao_network(netuid2, lock_cost, stake); + + // Start transition + assert_ok!(SubtensorModule::do_start_stao_dtao_transition_for_all()); + + // Check that transition started for all networks + assert_eq!(pallet_subtensor::SubnetLocked::::get(netuid1), 0); + assert_eq!(pallet_subtensor::SubnetLocked::::get(netuid2), 0); + assert!(SubnetInTransition::::get(netuid1).is_some()); + assert!(SubnetInTransition::::get(netuid2).is_some()); + + // Let transition run (two times) + SubtensorModule::do_continue_stao_dtao_transition(); + SubtensorModule::do_continue_stao_dtao_transition(); + + // Check that all transitions finished + assert!(SubnetInTransition::::get(netuid1).is_none()); + assert!(SubnetInTransition::::get(netuid2).is_none()); + }); +} + +#[test] +fn test_stao_dtao_transition_multi_network_no_stake_ok() { + new_test_ext(1).execute_with(|| { + let netuid1: u16 = 1; + let netuid2: u16 = 2; + let coldkey1 = U256::from(1); + let hotkey1 = U256::from(1); + let coldkey2 = U256::from(2); + let lock_cost = 100_000_000_000; + let stake = 100_000_000_000; + create_staked_stao_network(netuid1, lock_cost, stake); + create_staked_stao_network(netuid2, lock_cost, stake); + + // Remove stake from netuid 2 + pallet_subtensor::TotalSubnetTAO::::insert(netuid2, 0); + pallet_subtensor::SubStake::::insert((&coldkey1, &hotkey1, netuid2), 0); + pallet_subtensor::SubStake::::insert((&coldkey2, &hotkey1, netuid2), 0); + + // Start transition + assert_ok!( + SubtensorModule::do_start_stao_dtao_transition_for_all() + ); + }); +} + +#[test] +fn test_transition_zero_subnet_lock_fail() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let lock_cost = 100_000_000_000; + let stake = 100_000_000_000; + create_staked_stao_network(netuid, lock_cost, stake); + pallet_subtensor::SubnetLocked::::insert(netuid, 0); + + // Start transition + assert_err!( + SubtensorModule::do_start_stao_dtao_transition_for_all(), + Error::::NoStakeInSubnet + ); + }); +} + +#[test] +fn test_transition_lock_release_ok() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let coldkey1 = U256::from(1); + let coldkey2 = U256::from(2); + let hotkey1 = U256::from(1); + let lock_cost = 100_000_000_000; + let stake = 100_000_000_000; + create_staked_stao_network(netuid, lock_cost, stake); + + // Make sure SubnetLocked was initialized + assert_eq!( + pallet_subtensor::SubnetLocked::::get(netuid), + lock_cost, + ); + assert_eq!( + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey2, &hotkey1, netuid), + stake, + ); + assert_eq!(TotalSubnetTAO::::get(netuid), lock_cost + stake); + + let coldkey1_balance_before = SubtensorModule::get_coldkey_balance(&coldkey1); + + // Start transition + assert_ok!(SubtensorModule::do_start_stao_dtao_transition(netuid,)); + + // Let transition run + SubtensorModule::do_continue_stao_dtao_transition(); + + // Check that owner has the stake equal to initial lock on transition (1 TAO) + let initial_total_tao = SubtensorModule::get_initial_lock_on_transition(); + assert_eq!( + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1, netuid), + initial_total_tao, + ); + + // SubnetLocked is cleared + assert_eq!( + pallet_subtensor::SubnetLocked::::get(netuid), + 0 + ); + + // Owner received the previously locked balance back (less initial lock amount) + let coldkey1_balance_after = SubtensorModule::get_coldkey_balance(&coldkey1); + assert_eq!( + coldkey1_balance_after - coldkey1_balance_before, + lock_cost - initial_total_tao + ); + }); +} \ No newline at end of file diff --git a/pallets/subtensor/tests/senate.rs b/pallets/subtensor/tests/senate.rs index a21fbce01..8f8eba721 100644 --- a/pallets/subtensor/tests/senate.rs +++ b/pallets/subtensor/tests/senate.rs @@ -16,6 +16,9 @@ use pallet_collective::Event as CollectiveEvent; use pallet_subtensor::migration; use pallet_subtensor::Error; +// To run just the tests in this file, use the following command: +// cargo test -p pallet-subtensor --test senate + pub fn new_test_ext() -> sp_io::TestExternalities { sp_tracing::try_init_simple(); @@ -89,27 +92,31 @@ fn test_senate_join_works() { ); // Lets make this new key a delegate with a 10% take. - assert_ok!(SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(coldkey_account_id), - hotkey_account_id, - u16::MAX / 10 - )); + assert_eq!( + SubtensorModule::get_delegate_take(&hotkey_account_id, netuid), + InitialDefaultTake::get() + ); let staker_coldkey = U256::from(7); SubtensorModule::add_balance_to_coldkey_account(&staker_coldkey, 100_000); - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(staker_coldkey), hotkey_account_id, + netuid, 100_000 )); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&staker_coldkey, &hotkey_account_id), - 99_999 + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey( + &staker_coldkey, + &hotkey_account_id, + netuid + ), + 100_000 ); assert_eq!( - SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), - 99_999 + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey_account_id), + 100_000 ); assert_ok!(SubtensorModule::root_register( @@ -158,27 +165,31 @@ fn test_senate_vote_works() { ); // Lets make this new key a delegate with a 10% take. - assert_ok!(SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(coldkey_account_id), - hotkey_account_id, - u16::MAX / 10 - )); + assert_eq!( + SubtensorModule::get_delegate_take(&hotkey_account_id, netuid), + InitialDefaultTake::get() + ); let staker_coldkey = U256::from(7); SubtensorModule::add_balance_to_coldkey_account(&staker_coldkey, 100_000); - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(staker_coldkey), hotkey_account_id, + netuid, 100_000 )); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&staker_coldkey, &hotkey_account_id), - 99_999 + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey( + &staker_coldkey, + &hotkey_account_id, + netuid + ), + 100_000 ); assert_eq!( - SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), - 99_999 + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey_account_id), + 100_000 ); assert_ok!(SubtensorModule::root_register( @@ -325,28 +336,26 @@ fn test_senate_leave_works() { coldkey_account_id ); - // Lets make this new key a delegate with a 10% take. - assert_ok!(SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(coldkey_account_id), - hotkey_account_id, - u16::MAX / 10 - )); - let staker_coldkey = U256::from(7); SubtensorModule::add_balance_to_coldkey_account(&staker_coldkey, 100_000); - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(staker_coldkey), hotkey_account_id, + netuid, 100_000 )); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&staker_coldkey, &hotkey_account_id), - 99_999 + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey( + &staker_coldkey, + &hotkey_account_id, + netuid + ), + 100_000 ); assert_eq!( - SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), - 99_999 + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey_account_id), + 100_000 ); assert_ok!(SubtensorModule::root_register( @@ -395,28 +404,26 @@ fn test_senate_leave_vote_removal() { coldkey_account_id ); - // Lets make this new key a delegate with a 10% take. - assert_ok!(SubtensorModule::do_become_delegate( - coldkey_origin.clone(), - hotkey_account_id, - u16::MAX / 10 - )); - let staker_coldkey = U256::from(7); SubtensorModule::add_balance_to_coldkey_account(&staker_coldkey, 100_000); - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(staker_coldkey), hotkey_account_id, + netuid, 100_000 )); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&staker_coldkey, &hotkey_account_id), - 99_999 + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey( + &staker_coldkey, + &hotkey_account_id, + netuid + ), + 100_000 ); assert_eq!( - SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), - 99_999 + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey_account_id), + 100_000 ); assert_ok!(SubtensorModule::root_register( @@ -466,9 +473,10 @@ fn test_senate_leave_vote_removal() { hot )); // Add stake on other network - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(cold), hot, + netuid, 100_000_000 + (i as u64) )); // Register them on the root network. @@ -479,8 +487,6 @@ fn test_senate_leave_vote_removal() { // Check succesfull registration. assert!(SubtensorModule::get_uid_for_net_and_hotkey(other_netuid, &hot).is_ok()); assert!(SubtensorModule::get_uid_for_net_and_hotkey(root_netuid, &hot).is_ok()); - // Check that they are all delegates - assert!(SubtensorModule::hotkey_is_delegate(&hot)); } // No longer a root member assert!( @@ -531,29 +537,27 @@ fn test_senate_not_leave_when_stake_removed() { coldkey_account_id ); - // Lets make this new key a delegate with a 10% take. - assert_ok!(SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(coldkey_account_id), - hotkey_account_id, - u16::MAX / 10 - )); - let staker_coldkey = U256::from(7); let stake_amount: u64 = 100_000; SubtensorModule::add_balance_to_coldkey_account(&staker_coldkey, stake_amount); - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(staker_coldkey), hotkey_account_id, + netuid, stake_amount )); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&staker_coldkey, &hotkey_account_id), - stake_amount - 1 // Need to account for ED + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey( + &staker_coldkey, + &hotkey_account_id, + netuid + ), + stake_amount ); assert_eq!( - SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), - stake_amount - 1 // Need to account for ED + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey_account_id), + stake_amount ); assert_ok!(SubtensorModule::root_register( @@ -561,13 +565,26 @@ fn test_senate_not_leave_when_stake_removed() { hotkey_account_id )); assert!(Senate::is_member(&hotkey_account_id)); + assert_eq!( + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey( + &staker_coldkey, + &hotkey_account_id, + netuid + ), + stake_amount + ); + assert_eq!( + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey_account_id), + stake_amount + ); - step_block(100); + // step_block(100); - assert_ok!(SubtensorModule::remove_stake( + assert_ok!(SubtensorModule::remove_subnet_stake( <::RuntimeOrigin>::signed(staker_coldkey), hotkey_account_id, - stake_amount - 1 + netuid, + stake_amount )); assert!(Senate::is_member(&hotkey_account_id)); }); diff --git a/pallets/subtensor/tests/serving.rs b/pallets/subtensor/tests/serving.rs index 851edeee2..44bac5429 100644 --- a/pallets/subtensor/tests/serving.rs +++ b/pallets/subtensor/tests/serving.rs @@ -2,12 +2,15 @@ use crate::mock::*; mod mock; use frame_support::{ assert_ok, - dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays}, + dispatch::{DispatchClass, GetDispatchInfo, Pays}, }; use frame_system::Config; use pallet_subtensor::Error; use sp_core::U256; +// To run just the tests in this file, use the following command: +// cargo test -p pallet-subtensor --test serving + mod test { use std::net::{Ipv4Addr, Ipv6Addr}; @@ -47,14 +50,10 @@ fn test_serving_subscribe_ok_dispatch_info_ok() { placeholder1, placeholder2, }); - assert_eq!( - call.get_dispatch_info(), - DispatchInfo { - weight: frame_support::weights::Weight::from_parts(46_000_000, 0), - class: DispatchClass::Normal, - pays_fee: Pays::No - } - ); + let disp_info = call.get_dispatch_info(); + assert!(disp_info.weight.ref_time() != 0); + assert_eq!(disp_info.class, DispatchClass::Normal,); + assert_eq!(disp_info.pays_fee, Pays::No,); }); } @@ -292,14 +291,10 @@ fn test_prometheus_serving_subscribe_ok_dispatch_info_ok() { port, ip_type, }); - assert_eq!( - call.get_dispatch_info(), - DispatchInfo { - weight: frame_support::weights::Weight::from_parts(45_000_000, 0), - class: DispatchClass::Normal, - pays_fee: Pays::No - } - ); + let disp_info = call.get_dispatch_info(); + assert!(disp_info.weight.ref_time() != 0); + assert_eq!(disp_info.class, DispatchClass::Normal,); + assert_eq!(disp_info.pays_fee, Pays::No,); }); } diff --git a/pallets/subtensor/tests/stake_info.rs b/pallets/subtensor/tests/stake_info.rs new file mode 100644 index 000000000..487e6a3dd --- /dev/null +++ b/pallets/subtensor/tests/stake_info.rs @@ -0,0 +1,432 @@ +mod mock; +use codec::Compact; +use codec::Encode; +use frame_support::assert_ok; +use frame_system::Config; +use mock::*; +use pallet_subtensor::types::TensorBytes; +use sp_core::U256; + +#[test] +fn test_get_stake_info_for_coldkey() { + new_test_ext(1).execute_with(|| { + let hotkey = U256::from(0); + let coldkey = U256::from(0); + let netuid: u16 = 1; + let tempo: u16 = 13; + add_network(netuid, tempo, 0); + register_ok_neuron(netuid, hotkey, coldkey, 39420842); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, 10000); + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(coldkey), + hotkey, + netuid, + 10000 + )); + assert_eq!( + SubtensorModule::get_subnet_stake_info_for_coldkey( + TensorBytes::from(coldkey.encode()), + netuid + ) + .iter() + .map(|info| info.stake.0) + .sum::(), + 10000 + ); + }); +} + +#[test] +fn test_get_stake_info_for_coldkeys() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let tempo: u16 = 13; + let coldkey = U256::from(0); + let hotkey = U256::from(0); + add_network(netuid, tempo, 0); + register_ok_neuron(netuid, hotkey, coldkey, 39420842); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, 10000); + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(coldkey), + hotkey, + netuid, + 10000 + )); + assert_eq!( + SubtensorModule::get_subnet_stake_info_for_coldkey( + TensorBytes::from(coldkey.encode()), + netuid + ) + .iter() + .map(|info| info.stake.0) + .sum::(), + 10000 + ); + }); +} + +#[test] +fn test_get_stake_info_for_multiple_coldkeys() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let tempo: u16 = 13; + + // Create multiple coldkeys and hotkeys + let coldkey1 = U256::from(1); + let hotkey1 = U256::from(1); + let coldkey2 = U256::from(2); + let hotkey2 = U256::from(2); + + add_network(netuid, tempo, 0); + + // Register neurons and add balance for each coldkey + register_ok_neuron(netuid, hotkey1, coldkey1, 39420842); + SubtensorModule::add_balance_to_coldkey_account(&coldkey1, 10000); + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(coldkey1), + hotkey1, + netuid, + 5000 + )); + + register_ok_neuron(netuid, hotkey2, coldkey2, 39420843); + SubtensorModule::add_balance_to_coldkey_account(&coldkey2, 10000); + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(coldkey2), + hotkey2, + netuid, + 3000 + )); + + // Assert individual stakes + assert_eq!( + SubtensorModule::get_subnet_stake_info_for_coldkey( + TensorBytes::from(coldkey1.encode()), + netuid + ) + .iter() + .map(|info| info.stake.0) + .sum::(), + 5000 + ); + + assert_eq!( + SubtensorModule::get_subnet_stake_info_for_coldkey( + TensorBytes::from(coldkey2.encode()), + netuid + ) + .iter() + .map(|info| info.stake.0) + .sum::(), + 3000 + ); + }); +} + +#[test] +fn test_get_total_subnet_stake() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let tempo: u16 = 13; + let coldkey = U256::from(0); + let hotkey = U256::from(0); + add_network(netuid, tempo, 0); + register_ok_neuron(netuid, hotkey, coldkey, 39420842); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, 10000); + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(coldkey), + hotkey, + netuid, + 10000 + )); + assert_eq!( + SubtensorModule::get_total_subnet_stake(Compact(netuid).into()), + Compact(10000) + ); + }); +} + +#[test] +fn test_get_all_stake_info_for_coldkey() { + new_test_ext(1).execute_with(|| { + let netuid1: u16 = 1; + let netuid2: u16 = 2; + let tempo: u16 = 13; + // Create coldkey and multiple hotkeys + let coldkey = U256::from(0); + let hotkey1 = U256::from(1); + let hotkey2 = U256::from(2); + + add_network(netuid1, tempo, 0); + add_network(netuid2, tempo, 0); + + // Register neurons and add balance for the coldkey in different subnets + register_ok_neuron(netuid1, hotkey1, coldkey, 39420842); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, 20000); + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(coldkey), + hotkey1, + netuid1, + 10000 + )); + + register_ok_neuron(netuid2, hotkey2, coldkey, 39420843); + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(coldkey), + hotkey2, + netuid2, + 5000 + )); + + // Retrieve all stake info for the coldkey and assert the results + let all_stake_info = + SubtensorModule::get_all_stake_info_for_coldkey(TensorBytes::from(coldkey.encode())); + log::info!("all_stake_info: {:?}", all_stake_info); + // Assuming the function returns a Vec<(AccountId, u16, Compact)> + assert_eq!(all_stake_info.len(), 2); // Ensure we have two entries + + let total_stake: u64 = all_stake_info.iter().map(|info| info.2 .0).sum(); + assert_eq!(total_stake, 15000); // Total stake should be the sum of stakes in both subnets + }); +} + +#[test] +fn test_get_all_stake_info_for_coldkey_2() { + new_test_ext(1).execute_with(|| { + let netuid1: u16 = 1; + let netuid2: u16 = 2; + let tempo: u16 = 13; + + // Create coldkey and multiple hotkeys + let coldkey = U256::from(0); + let hotkey1 = U256::from(1); + let hotkey2 = U256::from(2); + + add_network(netuid1, tempo, 0); + add_network(netuid2, tempo, 0); + + // Assert that stake info is 0 before adding stake + let initial_stake_info = + SubtensorModule::get_all_stake_info_for_coldkey(TensorBytes::from(coldkey.encode())); + log::info!("initial_stake_info: {:?}", initial_stake_info); + let initial_total_stake: u64 = initial_stake_info.iter().map(|info| info.2 .0).sum(); + assert_eq!(initial_total_stake, 0, "Initial total stake should be 0"); + + // Register neurons and add balance for the coldkey in different subnets + register_ok_neuron(netuid1, hotkey1, coldkey, 39420842); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, 20000); + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(coldkey), + hotkey1, + netuid1, + 10000 + )); + + register_ok_neuron(netuid2, hotkey2, coldkey, 39420843); + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(coldkey), + hotkey2, + netuid2, + 5000 + )); + + // Retrieve all stake info for the coldkey and assert the results + let all_stake_info = + SubtensorModule::get_all_stake_info_for_coldkey(TensorBytes::from(coldkey.encode())); + log::info!("all_stake_info: {:?}", all_stake_info); + assert_eq!(all_stake_info.len(), 2); // Ensure we have two entries + + let total_stake: u64 = all_stake_info.iter().map(|info| info.2 .0).sum(); + assert_eq!(total_stake, 15000); + }); +} + +#[test] +fn test_get_all_subnet_stake_info_for_coldkey() { + new_test_ext(1).execute_with(|| { + let netuid1: u16 = 1; + let netuid2: u16 = 2; + let tempo: u16 = 13; + + // Create coldkey and multiple hotkeys + let coldkey = U256::from(0); + let hotkey1 = U256::from(1); + let hotkey2 = U256::from(2); + + add_network(netuid1, tempo, 0); + add_network(netuid2, tempo, 0); + + // Register neurons and add balance for the coldkey in different subnets + register_ok_neuron(netuid1, hotkey1, coldkey, 39420842); + SubtensorModule::add_balance_to_coldkey_account(&coldkey, 20000); + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(coldkey), + hotkey1, + netuid1, + 10000 + )); + + register_ok_neuron(netuid2, hotkey2, coldkey, 39420843); + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(coldkey), + hotkey2, + netuid2, + 5000 + )); + + // Retrieve all stake info for the coldkey and assert the results + let all_stake_info = SubtensorModule::get_all_subnet_stake_info_for_coldkey( + TensorBytes::from(coldkey.encode()), + ); + assert_eq!(all_stake_info.len(), 2); // Ensure we have two entries + + let total_stake: u64 = all_stake_info.iter().map(|info| info.stake.0).sum(); + assert_eq!(total_stake, 15000); // Total stake should be the sum of stakes in both subnets + }); +} + +#[test] +fn test_get_all_subnet_stake_info_for_coldkey_32_subnets() { + new_test_ext(1).execute_with(|| { + let tempo: u16 = 13; + + // Create coldkey and hotkeys + let coldkey = U256::from(0); + let mut hotkeys = Vec::new(); + + // Create 32 subnets and register neurons + for i in 1..=32 { + let netuid = i; + let hotkey = U256::from(i); + hotkeys.push(hotkey); + + add_network(netuid, tempo, 0); + register_ok_neuron(netuid, hotkey, coldkey, 39420840 + i as u64); + } + + // Add balance to the coldkey account + SubtensorModule::add_balance_to_coldkey_account(&coldkey, 320000); + + // Add subnet stake for each subnet + for (i, hotkey) in hotkeys.iter().enumerate() { + let netuid = (i + 1) as u16; + let stake_amount = 1000; + + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(coldkey), + *hotkey, + netuid, + stake_amount + )); + } + + // Retrieve all stake info for the coldkey and assert the results + let all_stake_info = SubtensorModule::get_all_subnet_stake_info_for_coldkey( + TensorBytes::from(coldkey.encode()), + ); + assert_eq!(all_stake_info.len(), 32); // Ensure we have 32 entries + + let total_stake: u64 = all_stake_info.iter().map(|info| info.stake.0).sum(); + let expected_total_stake = 32 * 1000; // Total stake should be the sum of stakes in all 32 subnets + assert_eq!(total_stake, expected_total_stake); + }); +} + +#[test] +fn test_get_total_stake_for_each_subnet_single_stake() { + new_test_ext(1).execute_with(|| { + let tempo: u16 = 13; + + // Create coldkey and hotkeys + let coldkey = U256::from(0); + let mut hotkeys = Vec::new(); + + // Create 32 subnets and register neurons + for i in 1..=32 { + let netuid = i; + let hotkey = U256::from(i); + hotkeys.push(hotkey); + + add_network(netuid, tempo, 0); + register_ok_neuron(netuid, hotkey, coldkey, 39420840 + i as u64); + } + + // Add balance to the coldkey account + SubtensorModule::add_balance_to_coldkey_account(&coldkey, 320000); + + // Add subnet stake for each subnet + for (i, hotkey) in hotkeys.iter().enumerate() { + let netuid = (i + 1) as u16; + let stake_amount = (1000 + netuid) as u64; + + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(coldkey), + *hotkey, + netuid, + stake_amount + )); + } + + // Retrieve total stake info for each subnet + let total_stake = SubtensorModule::get_total_stake_for_each_subnet(); + assert_eq!(total_stake.len(), 32); // Ensure we have 32 entries + + total_stake.iter().for_each(|&s| { + assert_eq!(s.1, Compact((1000 + s.0) as u64)); + }); + }); +} + +#[test] +fn test_get_total_stake_for_each_subnet_double_stake() { + new_test_ext(1).execute_with(|| { + let tempo: u16 = 13; + + // Create coldkey and hotkeys + let coldkey = U256::from(0); + let mut hotkeys = Vec::new(); + + // Create 32 subnets and register neurons + for i in 1..=32 { + let netuid = i; + let hotkey = U256::from(i); + hotkeys.push(hotkey); + + add_network(netuid, tempo, 0); + register_ok_neuron(netuid, hotkey, coldkey, 39420840 + i as u64); + } + + // Add balance to the coldkey account + SubtensorModule::add_balance_to_coldkey_account(&coldkey, 320000); + + // Add subnet stake for each subnet + for (i, hotkey) in hotkeys.iter().enumerate() { + let netuid = (i + 1) as u16; + let stake_amount = 1000; + + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(coldkey), + *hotkey, + netuid, + stake_amount + )); + + // Add stake to another subnet + let netuid = ((i + 1) % 32 + 1) as u16; + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(coldkey), + *hotkey, + netuid, + stake_amount + )); + } + + // Retrieve total stake info for each subnet + let total_stake = SubtensorModule::get_total_stake_for_each_subnet(); + assert_eq!(total_stake.len(), 32); // Ensure we have 32 entries + + total_stake.iter().for_each(|&s| { + assert_eq!(s.1, Compact(2000u64)); + }); + }); +} diff --git a/pallets/subtensor/tests/staking.rs b/pallets/subtensor/tests/staking.rs index ffe9de27a..9a7fedcde 100644 --- a/pallets/subtensor/tests/staking.rs +++ b/pallets/subtensor/tests/staking.rs @@ -1,38 +1,40 @@ use frame_support::{assert_err, assert_noop, assert_ok, traits::Currency}; use frame_system::Config; mod mock; -use frame_support::dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays}; +use frame_support::dispatch::{DispatchClass, GetDispatchInfo, Pays}; use frame_support::sp_runtime::DispatchError; use mock::*; use pallet_subtensor::*; use sp_core::{H256, U256}; /*********************************************************** - staking::add_stake() tests + staking::add_subnet_stake() tests ************************************************************/ +// To run just the tests in this file, use the following command: +// cargo test -p pallet-subtensor --test staking + #[test] #[cfg(not(tarpaulin))] -fn test_add_stake_dispatch_info_ok() { +fn test_add_subnet_stake_dispatch_info_ok() { new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; let hotkey = U256::from(0); let amount_staked = 5000; - let call = RuntimeCall::SubtensorModule(SubtensorCall::add_stake { + let call = RuntimeCall::SubtensorModule(SubtensorCall::add_subnet_stake { hotkey, + netuid, amount_staked, }); - assert_eq!( - call.get_dispatch_info(), - DispatchInfo { - weight: frame_support::weights::Weight::from_parts(124_000_000, 0), - class: DispatchClass::Normal, - pays_fee: Pays::No - } - ); + let disp_info = call.get_dispatch_info(); + assert!(disp_info.weight.ref_time() != 0); + assert_eq!(disp_info.class, DispatchClass::Normal,); + assert_eq!(disp_info.pays_fee, Pays::No,); }); } + #[test] -fn test_add_stake_ok_no_emission() { +fn test_add_subnet_stake_ok_no_emission() { new_test_ext(1).execute_with(|| { let hotkey_account_id = U256::from(533453); let coldkey_account_id = U256::from(55453); @@ -51,31 +53,29 @@ fn test_add_stake_ok_no_emission() { // Check we have zero staked before transfer assert_eq!( - SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey_account_id), 0 ); - // Also total stake should be zero - assert_eq!(SubtensorModule::get_total_stake(), 0); - // Transfer to hotkey account, and check if the result is ok - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey_account_id), hotkey_account_id, + netuid, 10000 )); // Check if stake has increased assert_eq!( - SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), - 9999 + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey_account_id), + 10000 ); // Check if balance has decreased - assert_eq!(SubtensorModule::get_coldkey_balance(&coldkey_account_id), 1); - - // Check if total stake has increased accordingly. - assert_eq!(SubtensorModule::get_total_stake(), 9999); + assert_eq!( + SubtensorModule::get_coldkey_balance(&coldkey_account_id), + ExistentialDeposit::get() + ); }); } @@ -101,11 +101,15 @@ fn test_dividends_with_run_to_block() { register_ok_neuron(netuid, neuron_dest_hotkey_id, coldkey_account_id, 12323); // Add some stake to the hotkey account, so we can test for emission before the transfer takes place - SubtensorModule::increase_stake_on_hotkey_account(&neuron_src_hotkey_id, initial_stake); + SubtensorModule::increase_subnet_token_on_hotkey_account( + &neuron_src_hotkey_id, + netuid, + initial_stake, + ); // Check if the initial stake has arrived assert_eq!( - SubtensorModule::get_total_stake_for_hotkey(&neuron_src_hotkey_id), + SubtensorModule::get_hotkey_global_dynamic_tao(&neuron_src_hotkey_id), initial_stake ); @@ -117,27 +121,29 @@ fn test_dividends_with_run_to_block() { // Check if the stake is equal to the inital stake + transfer assert_eq!( - SubtensorModule::get_total_stake_for_hotkey(&neuron_src_hotkey_id), + SubtensorModule::get_hotkey_global_dynamic_tao(&neuron_src_hotkey_id), initial_stake ); // Check if the stake is equal to the inital stake + transfer assert_eq!( - SubtensorModule::get_total_stake_for_hotkey(&neuron_dest_hotkey_id), + SubtensorModule::get_hotkey_global_dynamic_tao(&neuron_dest_hotkey_id), 0 ); }); } #[test] -fn test_add_stake_err_signature() { +fn test_add_subnet_stake_err_signature() { new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; let hotkey_account_id = U256::from(654); // bogus let amount = 20000; // Not used - let result = SubtensorModule::add_stake( + let result = SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::none(), hotkey_account_id, + netuid, amount, ); assert_eq!(result, DispatchError::BadOrigin.into()); @@ -145,16 +151,19 @@ fn test_add_stake_err_signature() { } #[test] -fn test_add_stake_not_registered_key_pair() { +fn test_add_subnet_stake_not_registered_key_pair() { new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; let coldkey_account_id = U256::from(435445); let hotkey_account_id = U256::from(54544); let amount = 1337; SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 1800); + add_network(netuid, 0, 0); assert_eq!( - SubtensorModule::add_stake( + SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey_account_id), hotkey_account_id, + netuid, amount ), Err(Error::::HotKeyAccountNotExists.into()) @@ -163,7 +172,7 @@ fn test_add_stake_not_registered_key_pair() { } #[test] -fn test_add_stake_err_neuron_does_not_belong_to_coldkey() { +fn test_add_subnet_stake_neuron_does_not_belong_to_coldkey_ok() { new_test_ext(1).execute_with(|| { let coldkey_id = U256::from(544); let hotkey_id = U256::from(54544); @@ -180,20 +189,51 @@ fn test_add_stake_err_neuron_does_not_belong_to_coldkey() { SubtensorModule::add_balance_to_coldkey_account(&other_cold_key, 100000); // Perform the request which is signed by a different cold key - let result = SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(other_cold_key), hotkey_id, + netuid, 1000, - ); - assert_eq!( - result, - Err(Error::::HotKeyNotDelegateAndSignerNotOwnHotKey.into()) + )); + }); +} + +#[test] +fn test_add_subnet_stake_neuron_not_registered_fail() { + new_test_ext(1).execute_with(|| { + let coldkey_id = U256::from(544); + let hotkey_id = U256::from(54544); + let other_cold_key = U256::from(99498); + let netuid: u16 = 1; + let netuid2: u16 = 2; + let tempo = 10; + let start_nonce: u64 = 0; + + // add network + add_network(netuid, tempo, 0); + add_network(netuid2, tempo, 0); + + // Register on a wrong subnet, so that hotkey exists, but is not registered on the subnet we're staking + register_ok_neuron(netuid2, hotkey_id, coldkey_id, start_nonce); + + // Give it some $$$ in his coldkey balance + SubtensorModule::add_balance_to_coldkey_account(&other_cold_key, 100000); + + // Perform the request which is signed by a different cold key + assert_err!( + SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(other_cold_key), + hotkey_id, + netuid, + 1000, + ), + Error::::HotKeyNotDelegateAndSignerNotOwnHotKey ); }); } #[test] -fn test_add_stake_err_not_enough_belance() { +fn test_add_subnet_stake_err_not_enough_belance() { new_test_ext(1).execute_with(|| { let coldkey_id = U256::from(544); let hotkey_id = U256::from(54544); @@ -208,9 +248,10 @@ fn test_add_stake_err_not_enough_belance() { // Lets try to stake with 0 balance in cold key account assert_eq!(SubtensorModule::get_coldkey_balance(&coldkey_id), 0); - let result = SubtensorModule::add_stake( + let result = SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey_id), hotkey_id, + netuid, 60000, ); @@ -220,7 +261,7 @@ fn test_add_stake_err_not_enough_belance() { #[test] #[ignore] -fn test_add_stake_total_balance_no_change() { +fn test_add_subnet_stake_total_balance_no_change() { // When we add stake, the total balance of the coldkey account should not change // this is because the stake should be part of the coldkey account balance (reserved/locked) new_test_ext(1).execute_with(|| { @@ -241,34 +282,29 @@ fn test_add_stake_total_balance_no_change() { SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, initial_balance); // Check we have zero staked before transfer - let initial_stake = SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id); + let initial_stake = SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey_account_id); assert_eq!(initial_stake, 0); // Check total balance is equal to initial balance let initial_total_balance = Balances::total_balance(&coldkey_account_id); assert_eq!(initial_total_balance, initial_balance); - // Also total stake should be zero - assert_eq!(SubtensorModule::get_total_stake(), 0); - // Stake to hotkey account, and check if the result is ok - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey_account_id), hotkey_account_id, + netuid, 10000 )); // Check if stake has increased - let new_stake = SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id); + let new_stake = SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey_account_id); assert_eq!(new_stake, 10000); // Check if free balance has decreased let new_free_balance = SubtensorModule::get_coldkey_balance(&coldkey_account_id); assert_eq!(new_free_balance, 0); - // Check if total stake has increased accordingly. - assert_eq!(SubtensorModule::get_total_stake(), 10000); - // Check if total balance has remained the same. (no fee, includes reserved/locked balance) let total_balance = Balances::total_balance(&coldkey_account_id); assert_eq!(total_balance, initial_total_balance); @@ -277,7 +313,7 @@ fn test_add_stake_total_balance_no_change() { #[test] #[ignore] -fn test_add_stake_total_issuance_no_change() { +fn test_add_subnet_stake_total_issuance_no_change() { // When we add stake, the total issuance of the balances pallet should not change // this is because the stake should be part of the coldkey account balance (reserved/locked) new_test_ext(1).execute_with(|| { @@ -298,7 +334,7 @@ fn test_add_stake_total_issuance_no_change() { SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, initial_balance); // Check we have zero staked before transfer - let initial_stake = SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id); + let initial_stake = SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey_account_id); assert_eq!(initial_stake, 0); // Check total balance is equal to initial balance @@ -309,27 +345,22 @@ fn test_add_stake_total_issuance_no_change() { let initial_total_issuance = Balances::total_issuance(); assert_eq!(initial_total_issuance, initial_balance); - // Also total stake should be zero - assert_eq!(SubtensorModule::get_total_stake(), 0); - // Stake to hotkey account, and check if the result is ok - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey_account_id), hotkey_account_id, + netuid, 10000 )); // Check if stake has increased - let new_stake = SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id); + let new_stake = SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey_account_id); assert_eq!(new_stake, 10000); // Check if free balance has decreased let new_free_balance = SubtensorModule::get_coldkey_balance(&coldkey_account_id); assert_eq!(new_free_balance, 0); - // Check if total stake has increased accordingly. - assert_eq!(SubtensorModule::get_total_stake(), 10000); - // Check if total issuance has remained the same. (no fee, includes reserved/locked balance) let total_issuance = Balances::total_issuance(); assert_eq!(total_issuance, initial_total_issuance); @@ -381,66 +412,78 @@ fn test_add_stake_under_limit() { add_network(netuid, tempo, 0); register_ok_neuron(netuid, hotkey_account_id, coldkey_account_id, start_nonce); SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 60000); - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey_account_id), hotkey_account_id, + netuid, 1, )); - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey_account_id), hotkey_account_id, + netuid, 1, )); - let current_stakes = SubtensorModule::get_stakes_this_interval_for_coldkey_hotkey( - &coldkey_account_id, - &hotkey_account_id, - ); - assert!(current_stakes <= max_stakes); + // TODO: get_stakes_this_interval_for_hotkey was replaced or removed? + // let current_stakes = + // SubtensorModule::get_stakes_this_interval_for_hotkey(&hotkey_account_id); + // assert!(current_stakes <= max_stakes); }); } -#[test] -fn test_add_stake_rate_limit_exceeded() { - new_test_ext(1).execute_with(|| { - let hotkey_account_id = U256::from(561337); - let coldkey_account_id = U256::from(61337); - let netuid: u16 = 1; - let start_nonce: u64 = 0; - let tempo: u16 = 13; - let max_stakes = 2; - let block_number = 1; - - SubtensorModule::set_target_stakes_per_interval(max_stakes); - SubtensorModule::set_stakes_this_interval_for_coldkey_hotkey( - &coldkey_account_id, - &hotkey_account_id, - max_stakes, - block_number, - ); - - add_network(netuid, tempo, 0); - register_ok_neuron(netuid, hotkey_account_id, coldkey_account_id, start_nonce); - SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 60000); - assert_err!( - SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey_account_id), - hotkey_account_id, - 1, - ), - Error::::StakeRateLimitExceeded - ); - - let current_stakes = SubtensorModule::get_stakes_this_interval_for_coldkey_hotkey( - &coldkey_account_id, - &hotkey_account_id, - ); - assert_eq!(current_stakes, max_stakes); - }); -} +// TODO: set_stakes_this_interval_for_hotkey and get_stakes_this_interval_for_hotkey are removed. Is this test needed? +// #[test] +// fn test_add_stake_rate_limit_exceeded() { +// new_test_ext(1).execute_with(|| { +// let hotkey_account_id = U256::from(561337); +// let coldkey_account_id = U256::from(61337); +// let who: ::AccountId = hotkey_account_id.into(); +// let netuid: u16 = 1; +// let start_nonce: u64 = 0; +// let tempo: u16 = 13; +// let max_stakes = 2; +// let block_number = 1; + +// SubtensorModule::set_target_stakes_per_interval(max_stakes); +// SubtensorModule::set_stakes_this_interval_for_hotkey( +// &hotkey_account_id, +// max_stakes, +// block_number, +// ); + +// let call: pallet_subtensor::Call = pallet_subtensor::Call::add_stake { +// hotkey: hotkey_account_id, +// amount_staked: 1, +// }; +// let info: DispatchInfo = +// DispatchInfoOf::<::RuntimeCall>::default(); +// let extension = SubtensorSignedExtension::::new(); +// let result = extension.validate(&who, &call.into(), &info, 10); + +// assert_err!(result, InvalidTransaction::ExhaustsResources); + +// add_network(netuid, tempo, 0); +// register_ok_neuron(netuid, hotkey_account_id, coldkey_account_id, start_nonce); +// SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 60000); +// assert_err!( +// SubtensorModule::add_subnet_stake( +// <::RuntimeOrigin>::signed(coldkey_account_id), +// hotkey_account_id, +// netuid, +// 1, +// ), +// Error::::StakeRateLimitExceeded +// ); + +// let current_stakes = +// SubtensorModule::get_stakes_this_interval_for_hotkey(&hotkey_account_id); +// assert_eq!(current_stakes, max_stakes); +// }); +// } // /*********************************************************** -// staking::remove_stake() tests +// staking::remove_subnet_stake() tests // ************************************************************/ #[test] fn test_remove_stake_under_limit() { @@ -456,91 +499,108 @@ fn test_remove_stake_under_limit() { add_network(netuid, tempo, 0); register_ok_neuron(netuid, hotkey_account_id, coldkey_account_id, start_nonce); SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 60000); - SubtensorModule::increase_stake_on_hotkey_account(&hotkey_account_id, 2); + SubtensorModule::increase_subnet_token_on_hotkey_account(&hotkey_account_id, netuid, 6000); - assert_ok!(SubtensorModule::remove_stake( + log::info!( + "Stake amount or hotkey: {:?}", + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey( + &coldkey_account_id, + &hotkey_account_id, + netuid + ) + ); + assert_ok!(SubtensorModule::remove_subnet_stake( <::RuntimeOrigin>::signed(coldkey_account_id), hotkey_account_id, + netuid, 1, )); - assert_ok!(SubtensorModule::remove_stake( + assert_ok!(SubtensorModule::remove_subnet_stake( <::RuntimeOrigin>::signed(coldkey_account_id), hotkey_account_id, + netuid, 1, )); - let current_unstakes = SubtensorModule::get_stakes_this_interval_for_coldkey_hotkey( - &coldkey_account_id, - &hotkey_account_id, - ); - assert!(current_unstakes <= max_unstakes); + // TODO: get_stakes_this_interval_for_hotkey is removed. Is this check needed? + // let current_unstakes = + // SubtensorModule::get_stakes_this_interval_for_hotkey(&hotkey_account_id); + // assert!(current_unstakes <= max_unstakes); }); } -#[test] -fn test_remove_stake_rate_limit_exceeded() { - new_test_ext(1).execute_with(|| { - let hotkey_account_id = U256::from(561337); - let coldkey_account_id = U256::from(61337); - let netuid: u16 = 1; - let start_nonce: u64 = 0; - let tempo: u16 = 13; - let max_unstakes = 1; - let block_number = 1; - - SubtensorModule::set_target_stakes_per_interval(max_unstakes); - SubtensorModule::set_stakes_this_interval_for_coldkey_hotkey( - &coldkey_account_id, - &hotkey_account_id, - max_unstakes, - block_number, - ); - - add_network(netuid, tempo, 0); - register_ok_neuron(netuid, hotkey_account_id, coldkey_account_id, start_nonce); - SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 60000); - SubtensorModule::increase_stake_on_hotkey_account(&hotkey_account_id, 2); - assert_err!( - SubtensorModule::remove_stake( - <::RuntimeOrigin>::signed(coldkey_account_id), - hotkey_account_id, - 2, - ), - Error::::UnstakeRateLimitExceeded - ); - - let current_unstakes = SubtensorModule::get_stakes_this_interval_for_coldkey_hotkey( - &coldkey_account_id, - &hotkey_account_id, - ); - assert_eq!(current_unstakes, max_unstakes); - }); -} +// TODO: set_stakes_this_interval_for_hotkey and get_stakes_this_interval_for_hotkey are removed. Is this test needed? +// #[test] +// fn test_remove_stake_rate_limit_exceeded() { +// new_test_ext(1).execute_with(|| { +// let hotkey_account_id = U256::from(561337); +// let coldkey_account_id = U256::from(61337); +// let who: ::AccountId = hotkey_account_id.into(); +// let netuid: u16 = 1; +// let start_nonce: u64 = 0; +// let tempo: u16 = 13; +// let max_unstakes = 1; +// let block_number = 1; + +// SubtensorModule::set_target_stakes_per_interval(max_unstakes); +// SubtensorModule::set_stakes_this_interval_for_hotkey( +// &hotkey_account_id, +// max_unstakes, +// block_number, +// ); + +// let call = pallet_subtensor::Call::remove_stake { +// hotkey: hotkey_account_id, +// amount_unstaked: 1, +// }; +// let info: DispatchInfo = +// DispatchInfoOf::<::RuntimeCall>::default(); +// let extension = SubtensorSignedExtension::::new(); +// let result = extension.validate(&who, &call.into(), &info, 10); + +// assert_err!(result, InvalidTransaction::ExhaustsResources); + +// add_network(netuid, tempo, 0); +// register_ok_neuron(netuid, hotkey_account_id, coldkey_account_id, start_nonce); +// SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 60000); +// SubtensorModule::increase_subnet_token_on_hotkey_account(&hotkey_account_id, netuid, 2); +// assert_err!( +// SubtensorModule::remove_subnet_stake( +// <::RuntimeOrigin>::signed(coldkey_account_id), +// hotkey_account_id, +// netuid, +// 2, +// ), +// Error::::UnstakeRateLimitExceeded +// ); + +// let current_unstakes = +// SubtensorModule::get_stakes_this_interval_for_hotkey(&hotkey_account_id); +// assert_eq!(current_unstakes, max_unstakes); +// }); +// } #[test] #[cfg(not(tarpaulin))] -fn test_remove_stake_dispatch_info_ok() { +fn test_remove_subnet_stake_dispatch_info_ok() { new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; let hotkey = U256::from(0); let amount_unstaked = 5000; - let call = RuntimeCall::SubtensorModule(SubtensorCall::remove_stake { + let call = RuntimeCall::SubtensorModule(SubtensorCall::remove_subnet_stake { hotkey, + netuid, amount_unstaked, }); - assert_eq!( - call.get_dispatch_info(), - DispatchInfo { - weight: frame_support::weights::Weight::from_parts(111_000_000, 0) - .add_proof_size(43991), - class: DispatchClass::Normal, - pays_fee: Pays::No - } - ); + let disp_info = call.get_dispatch_info(); + assert!(disp_info.weight.ref_time() != 0); + assert_eq!(disp_info.class, DispatchClass::Normal,); + assert_eq!(disp_info.pays_fee, Pays::No,); }); } #[test] -fn test_remove_stake_ok_no_emission() { +fn test_remove_subnet_stake_ok_no_emission() { new_test_ext(1).execute_with(|| { let coldkey_account_id = U256::from(4343); let hotkey_account_id = U256::from(4968585); @@ -556,20 +616,24 @@ fn test_remove_stake_ok_no_emission() { register_ok_neuron(netuid, hotkey_account_id, coldkey_account_id, start_nonce); // Some basic assertions - assert_eq!(SubtensorModule::get_total_stake(), 0); assert_eq!( - SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey_account_id), 0 ); assert_eq!(SubtensorModule::get_coldkey_balance(&coldkey_account_id), 0); // Give the neuron some stake to remove - SubtensorModule::increase_stake_on_hotkey_account(&hotkey_account_id, amount); + SubtensorModule::increase_subnet_token_on_hotkey_account( + &hotkey_account_id, + netuid, + amount, + ); // Do the magic - assert_ok!(SubtensorModule::remove_stake( + assert_ok!(SubtensorModule::remove_subnet_stake( <::RuntimeOrigin>::signed(coldkey_account_id), hotkey_account_id, + netuid, amount )); @@ -578,15 +642,14 @@ fn test_remove_stake_ok_no_emission() { amount ); assert_eq!( - SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey_account_id), 0 ); - assert_eq!(SubtensorModule::get_total_stake(), 0); }); } #[test] -fn test_remove_stake_amount_zero() { +fn test_remove_subnet_stake_amount_zero() { new_test_ext(1).execute_with(|| { let coldkey_account_id = U256::from(4343); let hotkey_account_id = U256::from(4968585); @@ -602,21 +665,25 @@ fn test_remove_stake_amount_zero() { register_ok_neuron(netuid, hotkey_account_id, coldkey_account_id, start_nonce); // Some basic assertions - assert_eq!(SubtensorModule::get_total_stake(), 0); assert_eq!( - SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey_account_id), 0 ); assert_eq!(SubtensorModule::get_coldkey_balance(&coldkey_account_id), 0); // Give the neuron some stake to remove - SubtensorModule::increase_stake_on_hotkey_account(&hotkey_account_id, amount); + SubtensorModule::increase_subnet_token_on_hotkey_account( + &hotkey_account_id, + netuid, + amount, + ); // Do the magic assert_noop!( - SubtensorModule::remove_stake( + SubtensorModule::remove_subnet_stake( <::RuntimeOrigin>::signed(coldkey_account_id), hotkey_account_id, + netuid, 0 ), Error::::StakeToWithdrawIsZero @@ -625,14 +692,16 @@ fn test_remove_stake_amount_zero() { } #[test] -fn test_remove_stake_err_signature() { +fn test_remove_subnet_stake_err_signature() { new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; let hotkey_account_id = U256::from(4968585); let amount = 10000; // Amount to be removed - let result = SubtensorModule::remove_stake( + let result = SubtensorModule::remove_subnet_stake( <::RuntimeOrigin>::none(), hotkey_account_id, + netuid, amount, ); assert_eq!(result, DispatchError::BadOrigin.into()); @@ -640,7 +709,7 @@ fn test_remove_stake_err_signature() { } #[test] -fn test_remove_stake_err_hotkey_does_not_belong_to_coldkey() { +fn test_remove_subnet_stake_never_staked_fail() { new_test_ext(1).execute_with(|| { let coldkey_id = U256::from(544); let hotkey_id = U256::from(54544); @@ -655,20 +724,21 @@ fn test_remove_stake_err_hotkey_does_not_belong_to_coldkey() { register_ok_neuron(netuid, hotkey_id, coldkey_id, start_nonce); // Perform the request which is signed by a different cold key - let result = SubtensorModule::remove_stake( + let result = SubtensorModule::remove_subnet_stake( <::RuntimeOrigin>::signed(other_cold_key), hotkey_id, + netuid, 1000, ); - assert_eq!( + assert_err!( result, - Err(Error::::HotKeyNotDelegateAndSignerNotOwnHotKey.into()) + Error::::NotEnoughStakeToWithdraw ); }); } #[test] -fn test_remove_stake_no_enough_stake() { +fn test_remove_subnet_stake_no_enough_stake() { new_test_ext(1).execute_with(|| { let coldkey_id = U256::from(544); let hotkey_id = U256::from(54544); @@ -682,11 +752,15 @@ fn test_remove_stake_no_enough_stake() { register_ok_neuron(netuid, hotkey_id, coldkey_id, start_nonce); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey_id), 0); + assert_eq!( + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey_id), + 0 + ); - let result = SubtensorModule::remove_stake( + let result = SubtensorModule::remove_subnet_stake( <::RuntimeOrigin>::signed(coldkey_id), hotkey_id, + netuid, amount, ); assert_eq!(result, Err(Error::::NotEnoughStakeToWithdraw.into())); @@ -694,7 +768,7 @@ fn test_remove_stake_no_enough_stake() { } #[test] -fn test_remove_stake_total_balance_no_change() { +fn test_remove_subnet_stake_total_balance_no_change() { // When we remove stake, the total balance of the coldkey account should not change // this is because the stake should be part of the coldkey account balance (reserved/locked) // then the removed stake just becomes free balance @@ -713,9 +787,8 @@ fn test_remove_stake_total_balance_no_change() { register_ok_neuron(netuid, hotkey_account_id, coldkey_account_id, start_nonce); // Some basic assertions - assert_eq!(SubtensorModule::get_total_stake(), 0); assert_eq!( - SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey_account_id), 0 ); assert_eq!(SubtensorModule::get_coldkey_balance(&coldkey_account_id), 0); @@ -723,12 +796,17 @@ fn test_remove_stake_total_balance_no_change() { assert_eq!(initial_total_balance, 0); // Give the neuron some stake to remove - SubtensorModule::increase_stake_on_hotkey_account(&hotkey_account_id, amount); + SubtensorModule::increase_subnet_token_on_hotkey_account( + &hotkey_account_id, + netuid, + amount, + ); // Do the magic - assert_ok!(SubtensorModule::remove_stake( + assert_ok!(SubtensorModule::remove_subnet_stake( <::RuntimeOrigin>::signed(coldkey_account_id), hotkey_account_id, + netuid, amount )); @@ -737,10 +815,9 @@ fn test_remove_stake_total_balance_no_change() { amount ); assert_eq!( - SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey_account_id), 0 ); - assert_eq!(SubtensorModule::get_total_stake(), 0); // Check total balance is equal to the added stake. Even after remove stake (no fee, includes reserved/locked balance) let total_balance = Balances::total_balance(&coldkey_account_id); @@ -748,68 +825,6 @@ fn test_remove_stake_total_balance_no_change() { }); } -#[test] -#[ignore] -fn test_remove_stake_total_issuance_no_change() { - // When we remove stake, the total issuance of the balances pallet should not change - // this is because the stake should be part of the coldkey account balance (reserved/locked) - // then the removed stake just becomes free balance - new_test_ext(1).execute_with(|| { - let hotkey_account_id = U256::from(581337); - let coldkey_account_id = U256::from(81337); - let netuid: u16 = 1; - let tempo: u16 = 13; - let start_nonce: u64 = 0; - let amount = 10000; - - //add network - add_network(netuid, tempo, 0); - - // Register neuron - register_ok_neuron(netuid, hotkey_account_id, coldkey_account_id, start_nonce); - - // Some basic assertions - assert_eq!(SubtensorModule::get_total_stake(), 0); - assert_eq!( - SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), - 0 - ); - assert_eq!(SubtensorModule::get_coldkey_balance(&coldkey_account_id), 0); - let initial_total_balance = Balances::total_balance(&coldkey_account_id); - assert_eq!(initial_total_balance, 0); - let inital_total_issuance = Balances::total_issuance(); - assert_eq!(inital_total_issuance, 0); - - // Give the neuron some stake to remove - SubtensorModule::increase_stake_on_hotkey_account(&hotkey_account_id, amount); - - let total_issuance_after_stake = Balances::total_issuance(); - - // Do the magic - assert_ok!(SubtensorModule::remove_stake( - <::RuntimeOrigin>::signed(coldkey_account_id), - hotkey_account_id, - amount - )); - - assert_eq!( - SubtensorModule::get_coldkey_balance(&coldkey_account_id), - amount - ); - assert_eq!( - SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), - 0 - ); - assert_eq!(SubtensorModule::get_total_stake(), 0); - - // Check if total issuance is equal to the added stake, even after remove stake (no fee, includes reserved/locked balance) - // Should also be equal to the total issuance after adding stake - let total_issuance = Balances::total_issuance(); - assert_eq!(total_issuance, total_issuance_after_stake); - assert_eq!(total_issuance, amount); - }); -} - /*********************************************************** staking::get_coldkey_balance() tests ************************************************************/ @@ -841,10 +856,10 @@ fn test_get_coldkey_balance_with_balance() { } // /*********************************************************** -// staking::add_stake_to_hotkey_account() tests +// staking::add_subnet_stake_to_hotkey_account() tests // ************************************************************/ #[test] -fn test_add_stake_to_hotkey_account_ok() { +fn test_add_subnet_stake_to_hotkey_account_ok() { new_test_ext(1).execute_with(|| { let hotkey_id = U256::from(5445); let coldkey_id = U256::from(5443433); @@ -858,27 +873,21 @@ fn test_add_stake_to_hotkey_account_ok() { register_ok_neuron(netuid, hotkey_id, coldkey_id, start_nonce); - // There is not stake in the system at first, so result should be 0; - assert_eq!(SubtensorModule::get_total_stake(), 0); - - SubtensorModule::increase_stake_on_hotkey_account(&hotkey_id, amount); + SubtensorModule::increase_subnet_token_on_hotkey_account(&hotkey_id, netuid, amount); // The stake that is now in the account, should equal the amount assert_eq!( - SubtensorModule::get_total_stake_for_hotkey(&hotkey_id), + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey_id), amount ); - - // The total stake should have been increased by the amount -> 0 + amount = amount - assert_eq!(SubtensorModule::get_total_stake(), amount); }); } /************************************************************ - staking::remove_stake_from_hotkey_account() tests + staking::remove_subnet_stake_from_hotkey_account() tests ************************************************************/ #[test] -fn test_remove_stake_from_hotkey_account() { +fn test_remove_subnet_stake_from_hotkey_account() { new_test_ext(1).execute_with(|| { let hotkey_id = U256::from(5445); let coldkey_id = U256::from(5443433); @@ -893,28 +902,27 @@ fn test_remove_stake_from_hotkey_account() { register_ok_neuron(netuid, hotkey_id, coldkey_id, start_nonce); // Add some stake that can be removed - SubtensorModule::increase_stake_on_hotkey_account(&hotkey_id, amount); + SubtensorModule::increase_subnet_token_on_hotkey_account(&hotkey_id, netuid, amount); // Prelimiary checks - assert_eq!(SubtensorModule::get_total_stake(), amount); assert_eq!( - SubtensorModule::get_total_stake_for_hotkey(&hotkey_id), + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey_id), amount ); // Remove stake - SubtensorModule::decrease_stake_on_hotkey_account(&hotkey_id, amount); + SubtensorModule::decrease_subnet_token_on_hotkey_account(&hotkey_id, netuid, amount); // The stake on the hotkey account should be 0 - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey_id), 0); - - // The total amount of stake should be 0 - assert_eq!(SubtensorModule::get_total_stake(), 0); + assert_eq!( + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey_id), + 0 + ); }); } #[test] -fn test_remove_stake_from_hotkey_account_registered_in_various_networks() { +fn test_remove_subnet_stake_from_hotkey_account_registered_in_various_networks() { new_test_ext(1).execute_with(|| { let hotkey_id = U256::from(5445); let coldkey_id = U256::from(5443433); @@ -944,7 +952,7 @@ fn test_remove_stake_from_hotkey_account_registered_in_various_networks() { Err(e) => panic!("Error: {:?}", e), }; //Add some stake that can be removed - SubtensorModule::increase_stake_on_hotkey_account(&hotkey_id, amount); + SubtensorModule::increase_subnet_token_on_hotkey_account(&hotkey_id, netuid, amount); assert_eq!( SubtensorModule::get_stake_for_uid_and_subnetwork(netuid, neuron_uid), @@ -952,11 +960,15 @@ fn test_remove_stake_from_hotkey_account_registered_in_various_networks() { ); assert_eq!( SubtensorModule::get_stake_for_uid_and_subnetwork(netuid_ex, neuron_uid_ex), + 0 + ); + assert_eq!( + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey_id), amount ); // Remove stake - SubtensorModule::decrease_stake_on_hotkey_account(&hotkey_id, amount); + SubtensorModule::decrease_subnet_token_on_hotkey_account(&hotkey_id, netuid, amount); // assert_eq!( SubtensorModule::get_stake_for_uid_and_subnetwork(netuid, neuron_uid), @@ -966,38 +978,9 @@ fn test_remove_stake_from_hotkey_account_registered_in_various_networks() { SubtensorModule::get_stake_for_uid_and_subnetwork(netuid_ex, neuron_uid_ex), 0 ); - }); -} - -// /************************************************************ -// staking::increase_total_stake() tests -// ************************************************************/ -#[test] -fn test_increase_total_stake_ok() { - new_test_ext(1).execute_with(|| { - let increment = 10000; - assert_eq!(SubtensorModule::get_total_stake(), 0); - SubtensorModule::increase_total_stake(increment); - assert_eq!(SubtensorModule::get_total_stake(), increment); - }); -} - -// /************************************************************ -// staking::decrease_total_stake() tests -// ************************************************************/ -#[test] -fn test_decrease_total_stake_ok() { - new_test_ext(1).execute_with(|| { - let initial_total_stake = 10000; - let decrement = 5000; - - SubtensorModule::increase_total_stake(initial_total_stake); - SubtensorModule::decrease_total_stake(decrement); - - // The total stake remaining should be the difference between the initial stake and the decrement assert_eq!( - SubtensorModule::get_total_stake(), - initial_total_stake - decrement + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey_id), + 0 ); }); } @@ -1113,20 +1096,25 @@ fn test_has_enough_stake_yes() { let start_nonce: u64 = 0; add_network(netuid, tempo, 0); register_ok_neuron(netuid, hotkey_id, coldkey_id, start_nonce); - SubtensorModule::increase_stake_on_hotkey_account(&hotkey_id, intial_amount); + SubtensorModule::increase_subnet_token_on_hotkey_account(&hotkey_id, netuid, intial_amount); assert_eq!( - SubtensorModule::get_total_stake_for_hotkey(&hotkey_id), + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey_id), 10000 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey_id, &hotkey_id), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey( + &coldkey_id, + &hotkey_id, + netuid + ), 10000 ); assert!(SubtensorModule::has_enough_stake( &coldkey_id, &hotkey_id, + netuid, 5000 - )); + ),); }); } @@ -1141,10 +1129,11 @@ fn test_has_enough_stake_no() { let start_nonce: u64 = 0; add_network(netuid, tempo, 0); register_ok_neuron(netuid, hotkey_id, coldkey_id, start_nonce); - SubtensorModule::increase_stake_on_hotkey_account(&hotkey_id, intial_amount); + SubtensorModule::increase_subnet_token_on_hotkey_account(&hotkey_id, netuid, intial_amount); assert!(!SubtensorModule::has_enough_stake( &coldkey_id, &hotkey_id, + netuid, 5000 )); }); @@ -1153,19 +1142,22 @@ fn test_has_enough_stake_no() { #[test] fn test_non_existent_account() { new_test_ext(1).execute_with(|| { - SubtensorModule::increase_stake_on_coldkey_hotkey_account( + let netuid: u16 = 1; + SubtensorModule::increase_subnet_token_on_coldkey_hotkey_account( &U256::from(0), &(U256::from(0)), + netuid, 10, ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&U256::from(0), &U256::from(0)), - 10 - ); - assert_eq!( - SubtensorModule::get_total_stake_for_coldkey(&(U256::from(0))), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey( + &U256::from(0), + &U256::from(0), + netuid + ), 10 ); + assert_eq!(get_total_stake_for_coldkey(&(U256::from(0))), 10); }); } @@ -1182,11 +1174,7 @@ fn test_delegate_stake_division_by_zero_check() { let coldkey = U256::from(3); add_network(netuid, tempo, 0); register_ok_neuron(netuid, hotkey, coldkey, 2341312); - assert_ok!(SubtensorModule::become_delegate( - <::RuntimeOrigin>::signed(coldkey), - hotkey - )); - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey, 0, 1000); + SubtensorModule::emit_inflation_through_hotkey_account(&hotkey, netuid, 0, 1000); }); } @@ -1207,41 +1195,26 @@ fn test_full_with_delegating() { SubtensorModule::set_max_allowed_uids(netuid, 4); // Allow all 4 to be registered at once SubtensorModule::set_target_stakes_per_interval(10); // Increase max stakes per interval - // Neither key can add stake because they dont have fundss. - assert_eq!( - SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey0), - hotkey0, - 60000 - ), - Err(Error::::NotEnoughBalanceToStake.into()) - ); - assert_eq!( - SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey1), - hotkey1, - 60000 - ), - Err(Error::::NotEnoughBalanceToStake.into()) - ); - // Add balances. SubtensorModule::add_balance_to_coldkey_account(&coldkey0, 60000); SubtensorModule::add_balance_to_coldkey_account(&coldkey1, 60000); + // Neither key can add stake because they are not registered (registration check comes before balance check) // We have enough, but the keys are not registered. assert_eq!( - SubtensorModule::add_stake( + SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey0), hotkey0, + netuid, 100 ), Err(Error::::HotKeyAccountNotExists.into()) ); assert_eq!( - SubtensorModule::add_stake( + SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey0), hotkey0, + netuid, 100 ), Err(Error::::HotKeyAccountNotExists.into()) @@ -1249,56 +1222,42 @@ fn test_full_with_delegating() { // Cant remove either. assert_eq!( - SubtensorModule::remove_stake( + SubtensorModule::remove_subnet_stake( <::RuntimeOrigin>::signed(coldkey0), hotkey0, + netuid, 10 ), Err(Error::::HotKeyAccountNotExists.into()) ); assert_eq!( - SubtensorModule::remove_stake( + SubtensorModule::remove_subnet_stake( <::RuntimeOrigin>::signed(coldkey1), hotkey1, + netuid, 10 ), Err(Error::::HotKeyAccountNotExists.into()) ); assert_eq!( - SubtensorModule::remove_stake( + SubtensorModule::remove_subnet_stake( <::RuntimeOrigin>::signed(coldkey0), hotkey1, + netuid, 10 ), Err(Error::::HotKeyAccountNotExists.into()) ); assert_eq!( - SubtensorModule::remove_stake( + SubtensorModule::remove_subnet_stake( <::RuntimeOrigin>::signed(coldkey1), hotkey0, + netuid, 10 ), Err(Error::::HotKeyAccountNotExists.into()) ); - // Neither key can become a delegate either because we are not registered. - assert_eq!( - SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(coldkey0), - hotkey0, - 100 - ), - Err(Error::::HotKeyAccountNotExists.into()) - ); - assert_eq!( - SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(coldkey0), - hotkey0, - 100 - ), - Err(Error::::HotKeyAccountNotExists.into()) - ); - // Register the 2 neurons to a new network. register_ok_neuron(netuid, hotkey0, coldkey0, 124124); register_ok_neuron(netuid, hotkey1, coldkey1, 987907); @@ -1313,301 +1272,293 @@ fn test_full_with_delegating() { assert!(SubtensorModule::coldkey_owns_hotkey(&coldkey0, &hotkey0)); assert!(SubtensorModule::coldkey_owns_hotkey(&coldkey1, &hotkey1)); - // We try to delegate stake but niether are allowing delegation. - assert!(!SubtensorModule::hotkey_is_delegate(&hotkey0)); - assert!(!SubtensorModule::hotkey_is_delegate(&hotkey1)); - assert_eq!( - SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey0), - hotkey1, - 100 - ), - Err(Error::::HotKeyNotDelegateAndSignerNotOwnHotKey.into()) - ); - assert_eq!( - SubtensorModule::add_stake( - <::RuntimeOrigin>::signed(coldkey1), - hotkey0, - 100 - ), - Err(Error::::HotKeyNotDelegateAndSignerNotOwnHotKey.into()) - ); - // We stake and all is ok. assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0, netuid), 0 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0, netuid), 0 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0, netuid), 0 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0, netuid), 0 ); - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey0), hotkey0, + netuid, 100 )); - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey1), hotkey1, + netuid, 100 )); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0, netuid), 100 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey1), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey1, netuid), 0 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0, netuid), 0 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1, netuid), + 100 + ); + assert_eq!( + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey0), + 100 + ); + assert_eq!( + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey1), 100 ); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey0), 100); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey1), 100); //assert_eq!( SubtensorModule::get_total_stake_for_coldkey( &coldkey0 ), 100 ); //assert_eq!( SubtensorModule::get_total_stake_for_coldkey( &coldkey1 ), 100 ); - assert_eq!(SubtensorModule::get_total_stake(), 200); - // Cant remove these funds because we are not delegating. - assert_eq!( - SubtensorModule::remove_stake( + // Cant remove these funds because we didn't stake + assert_err!( + SubtensorModule::remove_subnet_stake( <::RuntimeOrigin>::signed(coldkey0), hotkey1, + netuid, 10 ), - Err(Error::::HotKeyNotDelegateAndSignerNotOwnHotKey.into()) + Error::::NotEnoughStakeToWithdraw ); - assert_eq!( - SubtensorModule::remove_stake( + assert_err!( + SubtensorModule::remove_subnet_stake( <::RuntimeOrigin>::signed(coldkey1), hotkey0, + netuid, 10 ), - Err(Error::::HotKeyNotDelegateAndSignerNotOwnHotKey.into()) + Error::::NotEnoughStakeToWithdraw ); // Emit inflation through non delegates. - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey0, 0, 100); - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey1, 0, 100); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey0), 200); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey1), 200); - - // Try allowing the keys to become delegates, fails because of incorrect coldkeys. - // Set take to be 0. + SubtensorModule::emit_inflation_through_hotkey_account(&hotkey0, netuid, 0, 100); + SubtensorModule::emit_inflation_through_hotkey_account(&hotkey1, netuid, 0, 100); assert_eq!( - SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(coldkey0), - hotkey1, - 0 - ), - Err(Error::::NonAssociatedColdKey.into()) - ); - assert_eq!( - SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(coldkey1), - hotkey0, - 0 - ), - Err(Error::::NonAssociatedColdKey.into()) - ); - - // Become delegates all is ok. - assert_ok!(SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(coldkey0), - hotkey0, - SubtensorModule::get_min_take() - )); - assert_ok!(SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(coldkey1), - hotkey1, - SubtensorModule::get_min_take() - )); - assert!(SubtensorModule::hotkey_is_delegate(&hotkey0)); - assert!(SubtensorModule::hotkey_is_delegate(&hotkey1)); - - // Cant become a delegate twice. - assert_eq!( - SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(coldkey0), - hotkey0, - SubtensorModule::get_min_take() - ), - Err(Error::::HotKeyAlreadyDelegate.into()) + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey0), + 200 ); assert_eq!( - SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(coldkey1), - hotkey1, - u16::MAX / 10 - ), - Err(Error::::HotKeyAlreadyDelegate.into()) + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey1), + 200 ); // This add stake works for delegates. assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0, netuid), 200 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey1), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey1, netuid), 0 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0, netuid), 0 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1, netuid), 200 ); - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey0), hotkey1, + netuid, 200 )); - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey1), hotkey0, + netuid, 300 )); + + let mut substake_cold0_hot0 = 200; + let mut substake_cold0_hot1 = 200; + let mut substake_cold1_hot0 = 300; + let mut substake_cold1_hot1 = 200; + assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), - 200 + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0, netuid), + substake_cold0_hot0 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey1), - 200 + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey1, netuid), + substake_cold0_hot1 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0), - 300 + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0, netuid), + substake_cold1_hot0 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1), - 200 + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1, netuid), + substake_cold1_hot1 + ); + assert_eq!( + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey0), + substake_cold0_hot0 + substake_cold1_hot0 + ); + assert_eq!( + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey1), + substake_cold0_hot1 + substake_cold1_hot1 + ); + assert_eq!( + get_total_stake_for_coldkey(&coldkey0), + substake_cold0_hot0 + substake_cold0_hot1 + ); + assert_eq!( + get_total_stake_for_coldkey(&coldkey1), + substake_cold1_hot0 + substake_cold1_hot1 ); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey0), 500); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey1), 400); - //assert_eq!( SubtensorModule::get_total_stake_for_coldkey( &coldkey0 ), 400 ); - //assert_eq!( SubtensorModule::get_total_stake_for_coldkey( &coldkey1 ), 500 ); - assert_eq!(SubtensorModule::get_total_stake(), 900); // Lets emit inflation through the hot and coldkeys. - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey0, 0, 1000); - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey1, 0, 1000); + SubtensorModule::emit_inflation_through_hotkey_account(&hotkey0, netuid, 0, 1000); + SubtensorModule::emit_inflation_through_hotkey_account(&hotkey1, netuid, 0, 1000); + + let take0 = SubtensorModule::get_delegate_take(&hotkey0, netuid) as f32 / u16::MAX as f32; + let take1 = SubtensorModule::get_delegate_take(&hotkey1, netuid) as f32 / u16::MAX as f32; + + let cold0hot0weight = + substake_cold0_hot0 as f32 / (substake_cold0_hot0 + substake_cold1_hot0) as f32; + let cold0hot1weight = + substake_cold0_hot1 as f32 / (substake_cold0_hot1 + substake_cold1_hot1) as f32; + let cold1hot0weight = + substake_cold1_hot0 as f32 / (substake_cold0_hot0 + substake_cold1_hot0) as f32; + let cold1hot1weight = + substake_cold1_hot1 as f32 / (substake_cold0_hot1 + substake_cold1_hot1) as f32; + let delegate_take_hot0 = 1000. * take0; + let delegate_take_hot1 = 1000. * take1; + let emission0_remainder = 1000. - delegate_take_hot0; + let emission1_remainder = 1000. - delegate_take_hot1; + + // cold0 owns hot0, hence delegate_take_hot0 goes to cold0 substake. +1 for rounding errors + substake_cold0_hot0 += + (delegate_take_hot0 + emission0_remainder * cold0hot0weight) as u64 + 1; + substake_cold1_hot0 += (emission0_remainder * cold1hot0weight) as u64; + substake_cold0_hot1 += (emission1_remainder * cold0hot1weight) as u64; + substake_cold1_hot1 += + (delegate_take_hot1 + emission1_remainder * cold1hot1weight) as u64 + 1; + // initial + rewards, server emission goes to cold0 in dtao - // validator_take = take * validator_emission = 10% * 1000 = 100 - // old_stake + (validator_emission - validator_take) * stake_for_coldkey_and_hotkey / total_stake_for_hotkey + validator_take - // = - // 200 + 900 * 200 / 500 + 100 = 660 assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), - 654 + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0, netuid), + substake_cold0_hot0 ); - // validator_take = take * validator_emission = 9% * 1000 = 90 - // old_stake + (validator_emission - validator_take) * stake_for_coldkey_and_hotkey / total_stake_for_hotkey - // = - // 200 + (1000 - 90) * 200 / 400 = 655 ~ 654 assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey1), - 655 + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey1, netuid), + substake_cold0_hot1 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0), - 846 - ); // 300 + 910 x ( 300 / 500 ) = 300 + 546 = 846 + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0, netuid), + substake_cold1_hot0 + ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1), - 745 - ); // 200 + 1090 x ( 200 / 400 ) = 300 + 545 = 745 - assert_eq!(SubtensorModule::get_total_stake(), 2900); // 600 + 700 + 900 + 750 = 2900 + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1, netuid), + substake_cold1_hot1 + ); // // Try unstaking too much. assert_eq!( - SubtensorModule::remove_stake( + SubtensorModule::remove_subnet_stake( <::RuntimeOrigin>::signed(coldkey0), hotkey0, + netuid, 100000 ), Err(Error::::NotEnoughStakeToWithdraw.into()) ); assert_eq!( - SubtensorModule::remove_stake( + SubtensorModule::remove_subnet_stake( <::RuntimeOrigin>::signed(coldkey1), hotkey1, + netuid, 100000 ), Err(Error::::NotEnoughStakeToWithdraw.into()) ); assert_eq!( - SubtensorModule::remove_stake( + SubtensorModule::remove_subnet_stake( <::RuntimeOrigin>::signed(coldkey0), hotkey1, + netuid, 100000 ), Err(Error::::NotEnoughStakeToWithdraw.into()) ); assert_eq!( - SubtensorModule::remove_stake( + SubtensorModule::remove_subnet_stake( <::RuntimeOrigin>::signed(coldkey1), hotkey0, + netuid, 100000 ), Err(Error::::NotEnoughStakeToWithdraw.into()) ); // unstaking is ok. - assert_ok!(SubtensorModule::remove_stake( + assert_ok!(SubtensorModule::remove_subnet_stake( <::RuntimeOrigin>::signed(coldkey0), hotkey0, + netuid, 100 )); - assert_ok!(SubtensorModule::remove_stake( + assert_ok!(SubtensorModule::remove_subnet_stake( <::RuntimeOrigin>::signed(coldkey1), hotkey1, + netuid, 100 )); - assert_ok!(SubtensorModule::remove_stake( + assert_ok!(SubtensorModule::remove_subnet_stake( <::RuntimeOrigin>::signed(coldkey0), hotkey1, + netuid, 100 )); - assert_ok!(SubtensorModule::remove_stake( + assert_ok!(SubtensorModule::remove_subnet_stake( <::RuntimeOrigin>::signed(coldkey1), hotkey0, + netuid, 100 )); // All the amounts have been decreased. + substake_cold0_hot0 -= 100; + substake_cold1_hot0 -= 100; + substake_cold0_hot1 -= 100; + substake_cold1_hot1 -= 100; + assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), - 554 + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0, netuid), + substake_cold0_hot0 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey1), - 555 + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey1, netuid), + substake_cold0_hot1 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0), - 746 + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0, netuid), + substake_cold1_hot0 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1), - 645 + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1, netuid), + substake_cold1_hot1 ); // Lets register and stake a new key. @@ -1622,90 +1573,91 @@ fn test_full_with_delegating() { )); SubtensorModule::add_balance_to_coldkey_account(&coldkey2, 60_000); - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey2), hotkey2, + netuid, 1000 )); - assert_ok!(SubtensorModule::remove_stake( + assert_ok!(SubtensorModule::remove_subnet_stake( <::RuntimeOrigin>::signed(coldkey2), hotkey2, + netuid, 100 )); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey2, &hotkey2), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey2, &hotkey2, netuid), 900 ); - assert_eq!( - SubtensorModule::remove_stake( + assert_err!( + SubtensorModule::remove_subnet_stake( <::RuntimeOrigin>::signed(coldkey0), hotkey2, + netuid, 10 ), - Err(Error::::HotKeyNotDelegateAndSignerNotOwnHotKey.into()) + Error::::NotEnoughStakeToWithdraw ); - assert_eq!( - SubtensorModule::remove_stake( + assert_err!( + SubtensorModule::remove_subnet_stake( <::RuntimeOrigin>::signed(coldkey1), hotkey2, + netuid, 10 ), - Err(Error::::HotKeyNotDelegateAndSignerNotOwnHotKey.into()) + Error::::NotEnoughStakeToWithdraw ); - // Lets make this new key a delegate with a 10% take. - assert_ok!(SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(coldkey2), - hotkey2, - SubtensorModule::get_min_take() - )); - // Add nominate some stake. - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey0), hotkey2, + netuid, 1_000 )); - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey1), hotkey2, + netuid, 1_000 )); - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey2), hotkey2, + netuid, 100 )); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey2, &hotkey2), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey2, &hotkey2, netuid), 1_000 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey2), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey2, netuid), 1_000 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey2), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey2, netuid), 1_000 ); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey2), 3_000); - assert_eq!(SubtensorModule::get_total_stake(), 5_500); + assert_eq!( + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey2), + 3_000 + ); // Lets emit inflation through this new key with distributed ownership. - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey2, 0, 1000); + SubtensorModule::emit_inflation_through_hotkey_account(&hotkey2, netuid, 0, 1000); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey2, &hotkey2), - 1_394 - ); // 1000 + 94 + 900 * (1000/3000) = 1400 + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey2, &hotkey2, netuid), + 1_454 + ); // 1000 + 180 + 820 * (1000/3000) = 1500 + 453.3 ~ 1454 assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey2), - 1_303 - ); // 1000 + 900 * (1000/3000) = 1300 + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey2, netuid), + 1_273 + ); // 1000 + 820 * (1000/3000) = 1000 + 273.3 = 1273 assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey2), - 1_303 - ); // 1000 + 900 * (1000/3000) = 1300 - assert_eq!(SubtensorModule::get_total_stake(), 6_500); // before + 1_000 = 5_500 + 1_000 = 6_500 + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey2, netuid), + 1_273 + ); // 1000 + 820 * (1000/3000) = 1000 + 273.3 = 1273 step_block(1); @@ -1714,70 +1666,70 @@ fn test_full_with_delegating() { let coldkey3 = U256::from(8); register_ok_neuron(netuid, hotkey3, coldkey3, 4124124); SubtensorModule::add_balance_to_coldkey_account(&coldkey3, 60000); - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey3), hotkey3, + netuid, 1000 )); step_block(3); - assert_ok!(SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(coldkey3), - hotkey3, - SubtensorModule::get_min_take() - )); // Full take. - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey0), hotkey3, + netuid, 1000 )); - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey1), hotkey3, + netuid, 1000 )); - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey2), hotkey3, + netuid, 1000 )); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey3), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey3, netuid), 1000 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey3), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey3, netuid), 1000 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey2, &hotkey3), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey2, &hotkey3, netuid), 1000 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey3, &hotkey3), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey3, &hotkey3, netuid), 1000 ); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey3), 4000); - assert_eq!(SubtensorModule::get_total_stake(), 10_500); - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey3, 0, 1000); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey3), - 1227 - ); // 1000 + 90% * 1000 * 1000/4000 = 1225 + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey3), + 4000 + ); + SubtensorModule::emit_inflation_through_hotkey_account(&hotkey3, netuid, 0, 1000); + assert_eq!( + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey3, netuid), + 1205 + ); // 1000 + 82% * 1000 * 1000/4000 = 1205 assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey3), - 1227 - ); // 1000 + 90% * 1000 * 1000/4000 = 1225 + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey3, netuid), + 1205 + ); // 1000 + 82% * 1000 * 1000/4000 = 1205 assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey2, &hotkey3), - 1227 - ); // 1000 + 90% * 1000 * 1000/4000 = 1225 + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey2, &hotkey3, netuid), + 1205 + ); // 1000 + 82% * 1000 * 1000/4000 = 1205 assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey3, &hotkey3), - 1319 - ); // 1000 + 25 * 3 + 1000 * 1000/4000 = 1325 - assert_eq!(SubtensorModule::get_total_stake(), 11_500); // before + 1_000 = 10_500 + 1_000 = 11_500 + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey3, &hotkey3, netuid), + 1385 + ); // 1000 + 180 + 820 * 1000/4000 = 1385 }); } @@ -1794,21 +1746,24 @@ fn test_full_with_delegating_some_servers() { let coldkey1 = U256::from(4); SubtensorModule::set_max_registrations_per_block(netuid, 4); SubtensorModule::set_max_allowed_uids(netuid, 10); // Allow at least 10 to be registered at once, so no unstaking occurs + add_network(netuid, 0, 0); SubtensorModule::set_target_stakes_per_interval(10); // Increase max stakes per interval - // Neither key can add stake because they dont have fundss. + // Neither key can add stake because they are not registered (registration check is now done before balance check). assert_eq!( - SubtensorModule::add_stake( + SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey0), hotkey0, + netuid, 60000 ), Err(Error::::NotEnoughBalanceToStake.into()) ); assert_eq!( - SubtensorModule::add_stake( + SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey1), hotkey1, + netuid, 60000 ), Err(Error::::NotEnoughBalanceToStake.into()) @@ -1819,8 +1774,6 @@ fn test_full_with_delegating_some_servers() { SubtensorModule::add_balance_to_coldkey_account(&coldkey1, 60000); // Register the 2 neurons to a new network. - let netuid = 1; - add_network(netuid, 0, 0); register_ok_neuron(netuid, hotkey0, coldkey0, 124124); register_ok_neuron(netuid, hotkey1, coldkey1, 987907); assert_eq!( @@ -1836,280 +1789,433 @@ fn test_full_with_delegating_some_servers() { // We stake and all is ok. assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0, netuid), 0 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0, netuid), 0 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0, netuid), 0 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0, netuid), 0 ); - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey0), hotkey0, + netuid, 100 )); - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey1), hotkey1, + netuid, 100 )); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0, netuid), 100 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey1), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey1, netuid), 0 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0, netuid), 0 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1, netuid), + 100 + ); + assert_eq!( + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey0), + 100 + ); + assert_eq!( + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey1), 100 ); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey0), 100); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey1), 100); - assert_eq!(SubtensorModule::get_total_stake(), 200); // Emit inflation through non delegates. - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey0, 0, 100); - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey1, 0, 100); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey0), 200); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey1), 200); + SubtensorModule::emit_inflation_through_hotkey_account(&hotkey0, netuid, 0, 100); + SubtensorModule::emit_inflation_through_hotkey_account(&hotkey1, netuid, 0, 100); + assert_eq!( + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey0), + 200 + ); + assert_eq!( + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey1), + 200 + ); - // Become delegates all is ok. - assert_ok!(SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(coldkey0), - hotkey0, - SubtensorModule::get_min_take() - )); - assert_ok!(SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(coldkey1), - hotkey1, - SubtensorModule::get_min_take() - )); - assert!(SubtensorModule::hotkey_is_delegate(&hotkey0)); - assert!(SubtensorModule::hotkey_is_delegate(&hotkey1)); + let take0 = SubtensorModule::get_delegate_take(&hotkey0, netuid) as f32 / u16::MAX as f32; + let take1 = SubtensorModule::get_delegate_take(&hotkey1, netuid) as f32 / u16::MAX as f32; // This add stake works for delegates. assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0, netuid), 200 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey1), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey1, netuid), 0 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0, netuid), 0 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1, netuid), 200 ); - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey0), hotkey1, + netuid, 200 )); - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey1), hotkey0, + netuid, 300 )); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0, netuid), 200 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey1), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey1, netuid), 200 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0, netuid), 300 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1, netuid), 200 ); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey0), 500); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey1), 400); - assert_eq!(SubtensorModule::get_total_stake(), 900); + assert_eq!( + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey0), + 500 + ); + assert_eq!( + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey1), + 400 + ); + + // Set global stake weight to be 1 + SubtensorModule::set_global_stake_weight(u16::MAX); // Lets emit inflation through the hot and coldkeys. // fist emission arg is for a server. This should only go to the owner of the hotkey. - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey0, 200, 1_000); // 1_200 total emission. - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey1, 123, 2_000); // 2_123 total emission. + SubtensorModule::emit_inflation_through_hotkey_account(&hotkey0, netuid, 200, 1_000); // 1_200 total emission. + SubtensorModule::emit_inflation_through_hotkey_account(&hotkey1, netuid, 123, 2_000); // 2_123 total emission. + + // Global stake weights = 0 for now, so all nominator rewards are calculated off their global stake proportion + // which is (for non-dynamic networks) the sum of all nominator stakes to this delegate in all subnets divided + // by sum of all delegate stakes in all subnets + let cold0hot0weight = 200. / 500.; + let cold0hot1weight = 200. / 400.; + let cold1hot0weight = 300. / 500.; + let cold1hot1weight = 200. / 400.; + let delegate_take_hot0 = 1000. * take0; + let delegate_take_hot1 = 2000. * take1; + let emission0_remainder = 1000. - delegate_take_hot0; + let emission1_remainder = 2000. - delegate_take_hot1; + + // cold0 owns hot0, hence delegate_take_hot0 goes to cold0 substake. +1 for rounding errors + let substake_cold0_hot0 = + 200 + (delegate_take_hot0 + emission0_remainder * cold0hot0weight) as u64 + 1; + let substake_cold1_hot0 = 300 + (emission0_remainder * cold1hot0weight) as u64; + let substake_cold0_hot1 = 200 + (emission1_remainder * cold0hot1weight) as u64; + let substake_cold1_hot1 = + 200 + (delegate_take_hot1 + emission1_remainder * cold1hot1weight) as u64 + 1; + // initial + rewards, server emission goes to cold0 in dtao + let total_hot0 = 500 + (delegate_take_hot0 + emission0_remainder) as u64; + let total_hot1 = 400 + (delegate_take_hot1 + emission1_remainder) as u64; + assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), - 854 - ); // 200 + (200 + 910 x ( 200 / 500 )) = 200 + (200 + 400) + 60 = 854 + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0, netuid), + substake_cold0_hot0 + ); + assert_eq!( + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0, netuid), + substake_cold1_hot0 + ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0), - 846 - ); // 300 + 910 x ( 300 / 500 ) = 300 + 546 = 846 - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey0), 1_700); // initial + server emission + validator emission = 799 + 899 = 1_698 + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey0), + total_hot0 + ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey1), - 1_110 - ); // 200 + (0 + 2000 x ( 200 / 400 )) - 100 = 200 + (1000) - 100= 1_110 + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey1, netuid), + substake_cold0_hot1 + ); + assert_eq!( + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1, netuid), + substake_cold1_hot1 + ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1), - 1_413 - ); // 200 + (123 + 2000 x ( 200 / 400 )) + 100 = 200 + (1_200)+ 100 = 1_423 - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey1), 2_523); // 400 + 2_123 - assert_eq!(SubtensorModule::get_total_stake(), 4_223); // 2_100 + 2_123 = 4_223 + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey1), + total_hot1 + ); // Lets emit MORE inflation through the hot and coldkeys. // This time only server emission. This should go to the owner of the hotkey. - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey0, 350, 0); - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey1, 150, 0); + SubtensorModule::emit_inflation_through_hotkey_account(&hotkey0, netuid, 350, 0); + SubtensorModule::emit_inflation_through_hotkey_account(&hotkey1, netuid, 150, 0); + + // No change assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), - 1_204 - ); // + 350 + 54 = 1_204 + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0, netuid), + substake_cold0_hot0 + ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey1), - 1_110 - ); // No change. + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey1, netuid), + substake_cold0_hot1 + ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0), - 846 - ); // No change. + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0, netuid), + substake_cold1_hot0 + ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1), - 1_563 - ); // 1_323 + 150 + 90 = 1_573 - assert_eq!(SubtensorModule::get_total_stake(), 4_723); // 4_223 + 500 = 4_823 + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1, netuid), + substake_cold1_hot1 + ); // Lets register and stake a new key. let hotkey2 = U256::from(5); let coldkey2 = U256::from(6); register_ok_neuron(netuid, hotkey2, coldkey2, 248123); SubtensorModule::add_balance_to_coldkey_account(&coldkey2, 60_000); - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey2), hotkey2, + netuid, 1_000 )); - assert_ok!(SubtensorModule::remove_stake( + assert_ok!(SubtensorModule::remove_subnet_stake( <::RuntimeOrigin>::signed(coldkey2), hotkey2, + netuid, 100 )); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey2, &hotkey2), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey2, &hotkey2, netuid), 900 ); - assert_eq!( - SubtensorModule::remove_stake( - <::RuntimeOrigin>::signed(coldkey0), - hotkey2, - 10 - ), - Err(Error::::HotKeyNotDelegateAndSignerNotOwnHotKey.into()) - ); - assert_eq!( - SubtensorModule::remove_stake( - <::RuntimeOrigin>::signed(coldkey1), - hotkey2, - 10 - ), - Err(Error::::HotKeyNotDelegateAndSignerNotOwnHotKey.into()) - ); - assert_eq!(SubtensorModule::get_total_stake(), 5_623); // 4_723 + 900 = 5_623 - - // Lets make this new key a delegate with a 9% take. - assert_ok!(SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(coldkey2), - hotkey2, - SubtensorModule::get_min_take() - )); + let take2 = SubtensorModule::get_delegate_take(&hotkey2, netuid) as f32 / u16::MAX as f32; // Add nominate some stake. - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey0), hotkey2, + netuid, 1000 )); - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey1), hotkey2, + netuid, 1000 )); - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey2), hotkey2, + netuid, 100 )); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey2, &hotkey2), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey2, &hotkey2, netuid), 1000 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey2), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey2, netuid), 1000 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey2), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey2, netuid), 1000 ); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey2), 3_000); - assert_eq!(SubtensorModule::get_total_stake(), 7_723); // 5_623 + (1_000 + 1_000 + 100) = 7_723 + assert_eq!( + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey2), + 3_000 + ); // Lets emit inflation through this new key with distributed ownership. // We will emit 100 server emission, which should go in-full to the owner of the hotkey. // We will emit 1000 validator emission, which should be distributed in-part to the nominators. - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey2, 100, 1000); + SubtensorModule::emit_inflation_through_hotkey_account(&hotkey2, netuid, 100, 1000); + + let delegate_take_hot2 = 1000. * take2; + let emission2_remainder = 1000. - delegate_take_hot2; + let cold0hot2weight = 1000. / 3000.; + let cold1hot2weight = 1000. / 3000.; + let cold2hot2weight = 1000. / 3000.; + let substake_cold0_hot2 = 1000 + (emission2_remainder * cold0hot2weight) as u64; + let substake_cold1_hot2 = 1000 + (emission2_remainder * cold1hot2weight) as u64; + let substake_cold2_hot2 = + 1000 + (delegate_take_hot2 + emission2_remainder * cold2hot2weight) as u64 + 1; + assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey2, &hotkey2), - 1_494 - ); // 1000 + 100 + 94 + 900 * (1000/3000) = 1000 + 200 + 300 = 1_494 + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey2, &hotkey2, netuid), + substake_cold2_hot2 + ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey2), - 1_303 - ); // 1000 + 900 * (1000/3000) = 1000 + 300 = 1_303 + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey2, netuid), + substake_cold1_hot2 + ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey2), - 1_303 - ); // 1000 + 900 * (1000/3000) = 1000 + 300 = 1300 - assert_eq!(SubtensorModule::get_total_stake(), 8_823); // 7_723 + 1_100 = 8_823 + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey2, netuid), + substake_cold0_hot2 + ); + let cold2balance_before = SubtensorModule::get_coldkey_balance(&coldkey2); // Lets emit MORE inflation through this new key with distributed ownership. // This time we do ONLY server emission // We will emit 123 server emission, which should go in-full to the owner of the hotkey. // We will emit *0* validator emission. - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey2, 123, 0); + SubtensorModule::emit_inflation_through_hotkey_account(&hotkey2, netuid, 123, 0); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey2, &hotkey2), - 1_617 - ); // 1_500 + 117 = 1_617 + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey2, &hotkey2, netuid), + substake_cold2_hot2 + ); // No change. assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey2), - 1_303 + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey2, netuid), + substake_cold1_hot2 ); // No change. assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey2), - 1_303 + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey2, netuid), + substake_cold0_hot2 ); // No change. - assert_eq!(SubtensorModule::get_total_stake(), 8_946); // 8_823 + 123 = 8_946 + + let cold2balance_after = SubtensorModule::get_coldkey_balance(&coldkey2); + assert_eq!(cold2balance_after - cold2balance_before, 123); }); } +#[test] +fn test_stao_delegation() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + let delegate = U256::from(1); + let nominator1 = U256::from(2); + let nominator2 = U256::from(3); + + add_network(netuid, 0, 0); + register_ok_neuron(netuid, delegate, delegate, 124124); + SubtensorModule::set_target_stakes_per_interval(10000); + SubtensorModule::add_balance_to_coldkey_account(&delegate, 100000); + SubtensorModule::add_balance_to_coldkey_account(&nominator1, 100000); + SubtensorModule::add_balance_to_coldkey_account(&nominator2, 100000); + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(delegate), + delegate, + netuid, + 100000 + )); + let take = SubtensorModule::get_delegate_take(&delegate, netuid) as f32 / u16::MAX as f32; + + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(nominator1), + delegate, + netuid, + 100000 + )); + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(nominator2), + delegate, + netuid, + 100000 + )); + assert_eq!( + SubtensorModule::get_hotkey_global_dynamic_tao(&delegate), + 100000 * 3 + ); + assert_eq!( + SubtensorModule::get_total_stake_for_subnet(netuid), + 100000 * 3 + ); + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey_and_subnet(&delegate, netuid), + 100000 * 3 + ); + assert_eq!(get_total_stake_for_coldkey(&delegate), 100_000); + assert_eq!(get_total_stake_for_coldkey(&nominator1), 100_000); + assert_eq!(get_total_stake_for_coldkey(&nominator2), 100_000); + assert_eq!( + SubtensorModule::get_owning_coldkey_for_hotkey(&delegate), + delegate + ); + assert!(SubtensorModule::hotkey_account_exists(&delegate)); + assert!(!SubtensorModule::hotkey_account_exists(&nominator1)); + assert!(!SubtensorModule::hotkey_account_exists(&nominator2)); + assert_eq!( + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&delegate, &delegate, netuid), + 100_000 + ); + assert_eq!( + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey( + &nominator1, + &delegate, + netuid + ), + 100_000 + ); + assert_eq!( + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey( + &nominator2, + &delegate, + netuid + ), + 100_000 + ); + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey_and_coldkey(&delegate, &delegate), + 100_000 + ); + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey_and_coldkey(&delegate, &nominator1), + 100_000 + ); + assert_eq!( + SubtensorModule::get_total_stake_for_hotkey_and_coldkey(&delegate, &nominator1), + 100_000 + ); + SubtensorModule::emit_inflation_through_hotkey_account(&delegate, netuid, 0, 1000); + let nominator_reward = ((1000. * (1. - take)) as u64) / 3; + let delegate_take = 1000 - nominator_reward * 3; + assert_eq!( + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&delegate, &delegate, netuid), + 100000 + delegate_take + nominator_reward + ); + assert_eq!( + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey( + &nominator1, + &delegate, + netuid + ), + 100000 + nominator_reward + ); + assert_eq!( + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey( + &nominator2, + &delegate, + netuid + ), + 100000 + nominator_reward + ); + }) +} + #[test] fn test_full_block_emission_occurs() { new_test_ext(1).execute_with(|| { @@ -2120,23 +2226,27 @@ fn test_full_block_emission_occurs() { let coldkey0 = U256::from(3); let coldkey1 = U256::from(4); + + add_network(netuid, 0, 0); SubtensorModule::set_max_registrations_per_block(netuid, 4); SubtensorModule::set_max_allowed_uids(netuid, 10); // Allow at least 10 to be registered at once, so no unstaking occurs SubtensorModule::set_target_stakes_per_interval(10); // Increase max stakes per interval - // Neither key can add stake because they dont have fundss. + // Neither key can add stake because they are not registered assert_eq!( - SubtensorModule::add_stake( + SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey0), hotkey0, + netuid, 60000 ), Err(Error::::NotEnoughBalanceToStake.into()) ); assert_eq!( - SubtensorModule::add_stake( + SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey1), hotkey1, + netuid, 60000 ), Err(Error::::NotEnoughBalanceToStake.into()) @@ -2147,8 +2257,6 @@ fn test_full_block_emission_occurs() { SubtensorModule::add_balance_to_coldkey_account(&coldkey1, 60000); // Register the 2 neurons to a new network. - let netuid = 1; - add_network(netuid, 0, 0); register_ok_neuron(netuid, hotkey0, coldkey0, 124124); register_ok_neuron(netuid, hotkey1, coldkey1, 987907); assert_eq!( @@ -2164,104 +2272,88 @@ fn test_full_block_emission_occurs() { // We stake and all is ok. assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0, netuid), 0 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0, netuid), 0 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0, netuid), 0 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0, netuid), 0 ); - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey0), hotkey0, + netuid, 100 )); - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey1), hotkey1, + netuid, 100 )); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0, netuid), 100 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey1), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey1, netuid), 0 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0, netuid), 0 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey1, netuid), + 100 + ); + assert_eq!( + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey0), + 100 + ); + assert_eq!( + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey1), 100 ); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey0), 100); - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey1), 100); - assert_eq!(SubtensorModule::get_total_stake(), 200); // Emit inflation through non delegates. - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey0, 0, 111); - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey1, 0, 234); - // Verify the full emission occurs. - assert_eq!(SubtensorModule::get_total_stake(), 200 + 111 + 234); // 200 + 111 + 234 = 545 - - // Become delegates all is ok. - assert_ok!(SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(coldkey0), - hotkey0, - SubtensorModule::get_min_take() - )); - assert_ok!(SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(coldkey1), - hotkey1, - SubtensorModule::get_min_take() - )); - assert!(SubtensorModule::hotkey_is_delegate(&hotkey0)); - assert!(SubtensorModule::hotkey_is_delegate(&hotkey1)); + SubtensorModule::emit_inflation_through_hotkey_account(&hotkey0, netuid, 0, 111); + SubtensorModule::emit_inflation_through_hotkey_account(&hotkey1, netuid, 0, 234); // Add some delegate stake - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey0), hotkey1, + netuid, 200 )); - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey1), hotkey0, + netuid, 300 )); - assert_eq!(SubtensorModule::get_total_stake(), 545 + 500); // 545 + 500 = 1045 - // Lets emit inflation with delegatees, with both validator and server emission - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey0, 200, 1_000); // 1_200 total emission. - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey1, 123, 2_000); // 2_123 total emission. - - assert_eq!(SubtensorModule::get_total_stake(), 1045 + 1_200 + 2_123); // before + 1_200 + 2_123 = 4_368 + SubtensorModule::emit_inflation_through_hotkey_account(&hotkey0, netuid, 200, 1_000); // 1_200 total emission. + SubtensorModule::emit_inflation_through_hotkey_account(&hotkey1, netuid, 123, 2_000); // 2_123 total emission. // Lets emit MORE inflation through the hot and coldkeys. // This time JUSt server emission - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey0, 350, 0); - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey1, 150, 0); - - assert_eq!(SubtensorModule::get_total_stake(), 4_368 + 350 + 150); // before + 350 + 150 = 4_868 + SubtensorModule::emit_inflation_through_hotkey_account(&hotkey0, netuid, 350, 0); + SubtensorModule::emit_inflation_through_hotkey_account(&hotkey1, netuid, 150, 0); // Lastly, do only validator emission - - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey0, 0, 12_948); - SubtensorModule::emit_inflation_through_hotkey_account(&hotkey1, 0, 1_874); - - assert_eq!(SubtensorModule::get_total_stake(), 4_868 + 12_948 + 1_874); // before + 12_948 + 1_874 = 19_690 + SubtensorModule::emit_inflation_through_hotkey_account(&hotkey0, netuid, 0, 12_948); + SubtensorModule::emit_inflation_through_hotkey_account(&hotkey1, netuid, 0, 1_874); }); } @@ -2296,20 +2388,28 @@ fn test_unstake_all_coldkeys_from_hotkey_account() { } //Add some stake that can be removed - SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey0_id, &hotkey_id, amount); - SubtensorModule::increase_stake_on_coldkey_hotkey_account( + SubtensorModule::increase_subnet_token_on_coldkey_hotkey_account( + &coldkey0_id, + &hotkey_id, + netuid, + amount, + ); + SubtensorModule::increase_subnet_token_on_coldkey_hotkey_account( &coldkey1_id, &hotkey_id, + netuid, amount + 2, ); - SubtensorModule::increase_stake_on_coldkey_hotkey_account( + SubtensorModule::increase_subnet_token_on_coldkey_hotkey_account( &coldkey2_id, &hotkey_id, + netuid, amount + 3, ); - SubtensorModule::increase_stake_on_coldkey_hotkey_account( + SubtensorModule::increase_subnet_token_on_coldkey_hotkey_account( &coldkey3_id, &hotkey_id, + netuid, amount + 4, ); @@ -2321,7 +2421,7 @@ fn test_unstake_all_coldkeys_from_hotkey_account() { // Verify total stake is correct assert_eq!( - SubtensorModule::get_total_stake_for_hotkey(&hotkey_id), + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey_id), amount * 4 + (2 + 3 + 4) ); @@ -2329,23 +2429,42 @@ fn test_unstake_all_coldkeys_from_hotkey_account() { SubtensorModule::unstake_all_coldkeys_from_hotkey_account(&hotkey_id); // Verify total stake is 0 - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey_id), 0); + assert_eq!( + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey_id), + 0 + ); // Vefify stake for all coldkeys is 0 assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0_id, &hotkey_id), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey( + &coldkey0_id, + &hotkey_id, + netuid + ), 0 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey1_id, &hotkey_id), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey( + &coldkey1_id, + &hotkey_id, + netuid + ), 0 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey2_id, &hotkey_id), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey( + &coldkey2_id, + &hotkey_id, + netuid + ), 0 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey3_id, &hotkey_id), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey( + &coldkey3_id, + &hotkey_id, + netuid + ), 0 ); @@ -2380,14 +2499,19 @@ fn test_unstake_all_coldkeys_from_hotkey_account_single_staker() { } //Add some stake that can be removed - SubtensorModule::increase_stake_on_coldkey_hotkey_account(&coldkey0_id, &hotkey_id, amount); + SubtensorModule::increase_subnet_token_on_coldkey_hotkey_account( + &coldkey0_id, + &hotkey_id, + netuid, + amount, + ); // Verify free balance is 0 for coldkey assert_eq!(Balances::free_balance(coldkey0_id), 0); // Verify total stake is correct assert_eq!( - SubtensorModule::get_total_stake_for_hotkey(&hotkey_id), + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey_id), amount ); @@ -2395,11 +2519,18 @@ fn test_unstake_all_coldkeys_from_hotkey_account_single_staker() { SubtensorModule::unstake_all_coldkeys_from_hotkey_account(&hotkey_id); // Verify total stake is 0 - assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey_id), 0); + assert_eq!( + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey_id), + 0 + ); // Vefify stake for single coldkey is 0 assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey0_id, &hotkey_id), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey( + &coldkey0_id, + &hotkey_id, + netuid + ), 0 ); @@ -2467,148 +2598,118 @@ fn test_clear_small_nominations() { // Register hot1. register_ok_neuron(netuid, hot1, cold1, 0); - assert_ok!(SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(cold1), - hot1, - SubtensorModule::get_min_take() - )); assert_eq!(SubtensorModule::get_owning_coldkey_for_hotkey(&hot1), cold1); // Register hot2. register_ok_neuron(netuid, hot2, cold2, 0); - assert_ok!(SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(cold2), - hot2, - SubtensorModule::get_min_take() - )); assert_eq!(SubtensorModule::get_owning_coldkey_for_hotkey(&hot2), cold2); // Add stake cold1 --> hot1 (non delegation.) - SubtensorModule::add_balance_to_coldkey_account(&cold1, 5); - assert_ok!(SubtensorModule::add_stake( + SubtensorModule::add_balance_to_coldkey_account(&cold1, 5 + ExistentialDeposit::get()); + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(cold1), hot1, + netuid, 1 )); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&cold1, &hot1), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&cold1, &hot1, netuid), 1 ); - assert_eq!(Balances::free_balance(cold1), 4); + assert_eq!(Balances::free_balance(cold1), 4 + ExistentialDeposit::get()); // Add stake cold2 --> hot1 (is delegation.) - SubtensorModule::add_balance_to_coldkey_account(&cold2, 5); - assert_ok!(SubtensorModule::add_stake( + SubtensorModule::add_balance_to_coldkey_account(&cold2, 5 + ExistentialDeposit::get()); + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(cold2), hot1, + netuid, 1 )); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&cold2, &hot1), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&cold2, &hot1, netuid), 1 ); - assert_eq!(Balances::free_balance(cold2), 4); + assert_eq!(Balances::free_balance(cold2), 4 + ExistentialDeposit::get()); // Add stake cold1 --> hot2 (non delegation.) SubtensorModule::add_balance_to_coldkey_account(&cold1, 5); - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(cold1), hot2, + netuid, 1 )); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&cold1, &hot2), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&cold1, &hot2, netuid), 1 ); - assert_eq!(Balances::free_balance(cold1), 8); + assert_eq!(Balances::free_balance(cold1), 8 + ExistentialDeposit::get()); // Add stake cold2 --> hot2 (is delegation.) SubtensorModule::add_balance_to_coldkey_account(&cold2, 5); - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(cold2), hot2, + netuid, 1 )); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&cold2, &hot2), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&cold2, &hot2, netuid), 1 ); - assert_eq!(Balances::free_balance(cold2), 8); + assert_eq!(Balances::free_balance(cold2), 8 + ExistentialDeposit::get()); // Run clear all small nominations when min stake is zero (noop) SubtensorModule::set_nominator_min_required_stake(0); SubtensorModule::clear_small_nominations(); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&cold1, &hot1), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&cold1, &hot1, netuid), 1 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&cold1, &hot2), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&cold1, &hot2, netuid), 1 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&cold2, &hot1), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&cold2, &hot1, netuid), 1 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&cold2, &hot2), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&cold2, &hot2, netuid), 1 ); // Set min nomination to 10 - let total_cold1_stake_before = TotalColdkeyStake::::get(cold1); - let total_cold2_stake_before = TotalColdkeyStake::::get(cold2); - let total_hot1_stake_before = TotalHotkeyStake::::get(hot1); - let total_hot2_stake_before = TotalHotkeyStake::::get(hot2); - let _ = Stake::::try_get(hot2, cold1).unwrap(); // ensure exists before - let _ = Stake::::try_get(hot1, cold2).unwrap(); // ensure exists before - let total_stake_before = TotalStake::::get(); + let _ = Staker::::try_get(hot2, cold1).unwrap(); // ensure exists before + let _ = Staker::::try_get(hot1, cold2).unwrap(); // ensure exists before SubtensorModule::set_nominator_min_required_stake(10); // Run clear all small nominations (removes delegations under 10) SubtensorModule::clear_small_nominations(); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&cold1, &hot1), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&cold1, &hot1, netuid), 1 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&cold1, &hot2), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&cold1, &hot2, netuid), 0 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&cold2, &hot1), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&cold2, &hot1, netuid), 0 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&cold2, &hot2), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&cold2, &hot2, netuid), 1 ); // Balances have been added back into accounts. - assert_eq!(Balances::free_balance(cold1), 9); - assert_eq!(Balances::free_balance(cold2), 9); + assert_eq!(Balances::free_balance(cold1), 9 + ExistentialDeposit::get()); + assert_eq!(Balances::free_balance(cold2), 9 + ExistentialDeposit::get()); // Internal storage is updated - assert_eq!( - TotalColdkeyStake::::get(cold2), - total_cold2_stake_before - 1 - ); - assert_eq!( - TotalHotkeyStake::::get(hot2), - total_hot2_stake_before - 1 - ); - Stake::::try_get(hot2, cold1).unwrap_err(); - Stake::::try_get(hot1, cold2).unwrap_err(); - assert_eq!( - TotalColdkeyStake::::get(cold1), - total_cold1_stake_before - 1 - ); - assert_eq!( - TotalHotkeyStake::::get(hot1), - total_hot1_stake_before - 1 - ); - Stake::::try_get(hot2, cold1).unwrap_err(); - assert_eq!(TotalStake::::get(), total_stake_before - 2); + Staker::::try_get(hot2, cold1).unwrap_err(); }); } @@ -2634,23 +2735,21 @@ fn test_add_stake_below_minimum_threshold() { // Register the neuron to a new network. register_ok_neuron(netuid, hotkey1, coldkey1, 0); - assert_ok!(SubtensorModule::become_delegate( - <::RuntimeOrigin>::signed(coldkey1), - hotkey1 - )); // Coldkey staking on its own hotkey can stake below min threshold. - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey1), hotkey1, + netuid, amount_below )); // Nomination stake cannot stake below min threshold. assert_noop!( - SubtensorModule::add_stake( + SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey2), hotkey1, + netuid, amount_below ), pallet_subtensor::Error::::NomStakeBelowMinimumThreshold @@ -2672,8 +2771,14 @@ fn test_remove_stake_below_minimum_threshold() { let stake_amount_to_remove = 51_000; // Add balances. - SubtensorModule::add_balance_to_coldkey_account(&coldkey1, initial_balance); - SubtensorModule::add_balance_to_coldkey_account(&coldkey2, initial_balance); + SubtensorModule::add_balance_to_coldkey_account( + &coldkey1, + initial_balance + ExistentialDeposit::get(), + ); + SubtensorModule::add_balance_to_coldkey_account( + &coldkey2, + initial_balance + ExistentialDeposit::get(), + ); SubtensorModule::set_nominator_min_required_stake(minimum_threshold); SubtensorModule::set_target_stakes_per_interval(10); @@ -2682,67 +2787,65 @@ fn test_remove_stake_below_minimum_threshold() { // Register the neuron to a new network. register_ok_neuron(netuid, hotkey1, coldkey1, 0); - assert_ok!(SubtensorModule::become_delegate( - <::RuntimeOrigin>::signed(coldkey1), - hotkey1 - )); - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey1), hotkey1, + netuid, initial_stake )); - assert_ok!(SubtensorModule::add_stake( + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey2), hotkey1, + netuid, initial_stake )); // Coldkey staking on its own hotkey can unstake below min threshold. - assert_ok!(SubtensorModule::remove_stake( + assert_ok!(SubtensorModule::remove_subnet_stake( <::RuntimeOrigin>::signed(coldkey1), hotkey1, + netuid, stake_amount_to_remove )); // Nomination stake cannot unstake below min threshold, // without unstaking all and removing the nomination. - let total_hotkey_stake_before = SubtensorModule::get_total_stake_for_hotkey(&hotkey1); let bal_before = Balances::free_balance(coldkey2); - let staked_before = SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey2, &hotkey1); - let total_network_stake_before = SubtensorModule::get_total_stake(); + let staked_before = + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey2, &hotkey1, netuid); let total_issuance_before = SubtensorModule::get_total_issuance(); // check the premise of the test is correct assert!(initial_stake - stake_amount_to_remove < minimum_threshold); - assert_ok!(SubtensorModule::remove_stake( + assert_eq!( + SubtensorModule::remove_subnet_stake( + <::RuntimeOrigin>::signed(coldkey2), + hotkey1, + netuid, + stake_amount_to_remove + ), + Err(Error::::NomStakeBelowMinimumThreshold.into()) + ); + + // Unstake all + assert_ok!(SubtensorModule::remove_subnet_stake( <::RuntimeOrigin>::signed(coldkey2), hotkey1, - stake_amount_to_remove + netuid, + initial_stake )); // Has no stake now assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey2, &hotkey1), + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey2, &hotkey1, netuid), 0 ); - let stake_removed = staked_before; // All stake was removed - // Has the full balance + // All stake was removed + let stake_removed = staked_before; + // Has the full balance assert_eq!(Balances::free_balance(coldkey2), bal_before + stake_removed); - // Stake map entry is removed - assert!(Stake::::try_get(hotkey1, coldkey2).is_err(),); - // Stake tracking is updated - assert_eq!( - TotalColdkeyStake::::try_get(coldkey2).unwrap(), - 0 // Did not have any stake before; Entry is NOT removed - ); - assert_eq!( - TotalHotkeyStake::::try_get(hotkey1).unwrap(), - total_hotkey_stake_before - stake_removed // Stake was removed from hotkey1 tracker - ); - assert_eq!( - TotalStake::::try_get().unwrap(), - total_network_stake_before - stake_removed - ); + // Staker map entry is removed + assert!(Staker::::try_get(hotkey1, coldkey2).is_err(),); // Total issuance is the same assert_eq!( @@ -2768,25 +2871,17 @@ fn test_delegate_take_can_be_decreased() { add_network(netuid, 0, 0); register_ok_neuron(netuid, hotkey0, coldkey0, 124124); - // Coldkey / hotkey 0 become delegates with 9% take - assert_ok!(SubtensorModule::do_become_delegate( + // Coldkey / hotkey 0 decreases take + let lower_take = SubtensorModule::get_delegate_take(&hotkey0, netuid) - 1; + assert_ok!(SubtensorModule::do_decrease_take( <::RuntimeOrigin>::signed(coldkey0), hotkey0, - SubtensorModule::get_min_take() + netuid, + lower_take )); assert_eq!( - SubtensorModule::get_hotkey_take(&hotkey0), - SubtensorModule::get_min_take() - ); - - // Coldkey / hotkey 0 decreases take to 5%. This should fail as the minimum take is 9% - assert_err!( - SubtensorModule::do_decrease_take( - <::RuntimeOrigin>::signed(coldkey0), - hotkey0, - u16::MAX / 20 - ), - Error::::DelegateTakeTooLow + SubtensorModule::get_delegate_take(&hotkey0, netuid), + lower_take ); }); } @@ -2807,21 +2902,15 @@ fn test_can_set_min_take_ok() { add_network(netuid, 0, 0); register_ok_neuron(netuid, hotkey0, coldkey0, 124124); - // Coldkey / hotkey 0 become delegates - assert_ok!(SubtensorModule::do_become_delegate( - <::RuntimeOrigin>::signed(coldkey0), - hotkey0, - u16::MAX / 10 - )); - // Coldkey / hotkey 0 decreases take to min assert_ok!(SubtensorModule::do_decrease_take( <::RuntimeOrigin>::signed(coldkey0), hotkey0, - SubtensorModule::get_min_take() + netuid, + SubtensorModule::get_min_delegate_take() )); assert_eq!( - SubtensorModule::get_hotkey_take(&hotkey0), + SubtensorModule::get_delegate_take(&hotkey0, netuid), SubtensorModule::get_min_take() ); }); @@ -2843,14 +2932,15 @@ fn test_delegate_take_can_not_be_increased_with_decrease_take() { add_network(netuid, 0, 0); register_ok_neuron(netuid, hotkey0, coldkey0, 124124); - // Coldkey / hotkey 0 become delegates with 10% take - assert_ok!(SubtensorModule::do_become_delegate( + // Decrease delegate take to 5% + assert_ok!(SubtensorModule::do_decrease_take( <::RuntimeOrigin>::signed(coldkey0), hotkey0, + netuid, SubtensorModule::get_min_take() )); assert_eq!( - SubtensorModule::get_hotkey_take(&hotkey0), + SubtensorModule::get_delegate_take(&hotkey0, netuid), SubtensorModule::get_min_take() ); @@ -2859,12 +2949,13 @@ fn test_delegate_take_can_not_be_increased_with_decrease_take() { SubtensorModule::do_decrease_take( <::RuntimeOrigin>::signed(coldkey0), hotkey0, + netuid, u16::MAX / 8 ), Err(Error::::DelegateTakeTooLow.into()) ); assert_eq!( - SubtensorModule::get_hotkey_take(&hotkey0), + SubtensorModule::get_delegate_take(&hotkey0, netuid), SubtensorModule::get_min_take() ); }); @@ -2886,14 +2977,15 @@ fn test_delegate_take_can_be_increased() { add_network(netuid, 0, 0); register_ok_neuron(netuid, hotkey0, coldkey0, 124124); - // Coldkey / hotkey 0 become delegates with 9% take - assert_ok!(SubtensorModule::do_become_delegate( + // Decrease delegate take to 5% + assert_ok!(SubtensorModule::do_decrease_take( <::RuntimeOrigin>::signed(coldkey0), hotkey0, + netuid, SubtensorModule::get_min_take() )); assert_eq!( - SubtensorModule::get_hotkey_take(&hotkey0), + SubtensorModule::get_delegate_take(&hotkey0, netuid), SubtensorModule::get_min_take() ); @@ -2903,9 +2995,13 @@ fn test_delegate_take_can_be_increased() { assert_ok!(SubtensorModule::do_increase_take( <::RuntimeOrigin>::signed(coldkey0), hotkey0, + netuid, u16::MAX / 8 )); - assert_eq!(SubtensorModule::get_hotkey_take(&hotkey0), u16::MAX / 8); + assert_eq!( + SubtensorModule::get_delegate_take(&hotkey0, netuid), + u16::MAX / 8 + ); }); } @@ -2925,14 +3021,15 @@ fn test_delegate_take_can_not_be_decreased_with_increase_take() { add_network(netuid, 0, 0); register_ok_neuron(netuid, hotkey0, coldkey0, 124124); - // Coldkey / hotkey 0 become delegates with 9% take - assert_ok!(SubtensorModule::do_become_delegate( + // Decrease delegate take to 10% + assert_ok!(SubtensorModule::do_decrease_take( <::RuntimeOrigin>::signed(coldkey0), hotkey0, + netuid, SubtensorModule::get_min_take() )); assert_eq!( - SubtensorModule::get_hotkey_take(&hotkey0), + SubtensorModule::get_delegate_take(&hotkey0, netuid), SubtensorModule::get_min_take() ); @@ -2941,12 +3038,13 @@ fn test_delegate_take_can_not_be_decreased_with_increase_take() { SubtensorModule::do_increase_take( <::RuntimeOrigin>::signed(coldkey0), hotkey0, + netuid, u16::MAX / 20 ), Err(Error::::DelegateTakeTooLow.into()) ); assert_eq!( - SubtensorModule::get_hotkey_take(&hotkey0), + SubtensorModule::get_delegate_take(&hotkey0, netuid), SubtensorModule::get_min_take() ); }); @@ -2968,14 +3066,15 @@ fn test_delegate_take_can_be_increased_to_limit() { add_network(netuid, 0, 0); register_ok_neuron(netuid, hotkey0, coldkey0, 124124); - // Coldkey / hotkey 0 become delegates with 9% take - assert_ok!(SubtensorModule::do_become_delegate( + // Decrease delegate take to 10% + assert_ok!(SubtensorModule::do_decrease_take( <::RuntimeOrigin>::signed(coldkey0), hotkey0, + netuid, SubtensorModule::get_min_take() )); assert_eq!( - SubtensorModule::get_hotkey_take(&hotkey0), + SubtensorModule::get_delegate_take(&hotkey0, netuid), SubtensorModule::get_min_take() ); @@ -2985,10 +3084,11 @@ fn test_delegate_take_can_be_increased_to_limit() { assert_ok!(SubtensorModule::do_increase_take( <::RuntimeOrigin>::signed(coldkey0), hotkey0, + netuid, InitialDefaultTake::get() )); assert_eq!( - SubtensorModule::get_hotkey_take(&hotkey0), + SubtensorModule::get_delegate_take(&hotkey0, netuid), InitialDefaultTake::get() ); }); @@ -2996,7 +3096,7 @@ fn test_delegate_take_can_be_increased_to_limit() { // Verify delegate take can not be set above InitialDefaultTake #[test] -fn test_delegate_take_can_not_be_set_beyond_limit() { +fn test_delegate_take_can_not_be_increased_beyond_limit() { new_test_ext(1).execute_with(|| { // Make account let hotkey0 = U256::from(1); @@ -3009,49 +3109,161 @@ fn test_delegate_take_can_not_be_set_beyond_limit() { let netuid = 1; add_network(netuid, 0, 0); register_ok_neuron(netuid, hotkey0, coldkey0, 124124); - let before = SubtensorModule::get_hotkey_take(&hotkey0); + let before = SubtensorModule::get_delegate_take(&hotkey0, netuid); - // Coldkey / hotkey 0 attempt to become delegates with take above maximum - // (Disable this check if InitialDefaultTake is u16::MAX) if InitialDefaultTake::get() != u16::MAX { assert_eq!( - SubtensorModule::do_become_delegate( + SubtensorModule::do_increase_take( <::RuntimeOrigin>::signed(coldkey0), hotkey0, + netuid, InitialDefaultTake::get() + 1 ), Err(Error::::DelegateTakeTooHigh.into()) ); } - assert_eq!(SubtensorModule::get_hotkey_take(&hotkey0), before); + assert_eq!(SubtensorModule::get_delegate_take(&hotkey0, netuid), before); }); } -// Verify delegate take can not be increased above InitialDefaultTake (18%) +// Verify delegate take affects emission distribution #[test] -fn test_delegate_take_can_not_be_increased_beyond_limit() { +fn test_delegate_take_affects_distribution() { new_test_ext(1).execute_with(|| { - // Make account + let netuid = 1; + // Make two accounts. let hotkey0 = U256::from(1); + let hotkey1 = U256::from(2); + let coldkey0 = U256::from(3); + let coldkey1 = U256::from(4); + SubtensorModule::set_max_registrations_per_block(netuid, 4); + SubtensorModule::set_max_allowed_uids(netuid, 10); // Allow at least 10 to be registered at once, so no unstaking occurs - // Add balance + // Add balances. SubtensorModule::add_balance_to_coldkey_account(&coldkey0, 100000); + SubtensorModule::add_balance_to_coldkey_account(&coldkey1, 100000); - // Register the neuron to a new network + // Register the 2 neurons to a new network. let netuid = 1; add_network(netuid, 0, 0); register_ok_neuron(netuid, hotkey0, coldkey0, 124124); + register_ok_neuron(netuid, hotkey1, coldkey1, 987907); - // Coldkey / hotkey 0 become delegates with 9% take - assert_ok!(SubtensorModule::do_become_delegate( + // Stake 100 from coldkey/hotkey 0 + assert_ok!(SubtensorModule::add_subnet_stake( <::RuntimeOrigin>::signed(coldkey0), hotkey0, - SubtensorModule::get_min_take() + netuid, + 100 )); assert_eq!( - SubtensorModule::get_hotkey_take(&hotkey0), - SubtensorModule::get_min_take() + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0, netuid), + 100 + ); + + // Hotkey 1 adds 100 delegated stake to coldkey/hotkey 0 + assert_eq!( + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0, netuid), + 0 + ); + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(coldkey1), + hotkey0, + netuid, + 100 + )); + assert_eq!( + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0, netuid), + 100 + ); + assert_eq!( + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey0), + 200 + ); + assert_eq!(SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey1), 0); + + // Lets emit inflation through this new key with distributed ownership. + // We will emit 0 server emission (which should go in-full to the owner of the hotkey). + // We will emit 400 validator emission, which should be distributed in-part to the nominators. + // + // Total initial stake is 200 + // Delegate's initial stake is 100, which is 50% of total stake + // => Delegate will receive 50% of emission (200) + 50% take (100) of nominator reward (200) + SubtensorModule::emit_inflation_through_hotkey_account(&hotkey0, netuid, 0, 400); + assert_eq!( + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0, netuid), + 336 + ); // 100 + 18% * 400 + 82% * 200 = 336 + }); +} + +// Verify changing delegate take also changes emission distribution +#[test] +fn test_changing_delegate_take_changes_distribution() { + new_test_ext(1).execute_with(|| { + let netuid = 1; + // Make two accounts. + let hotkey0 = U256::from(1); + let hotkey1 = U256::from(2); + + let coldkey0 = U256::from(3); + let coldkey1 = U256::from(4); + SubtensorModule::set_max_registrations_per_block(netuid, 4); + SubtensorModule::set_max_allowed_uids(netuid, 10); // Allow at least 10 to be registered at once, so no unstaking occurs + + // Add balances. + SubtensorModule::add_balance_to_coldkey_account(&coldkey0, 100000); + SubtensorModule::add_balance_to_coldkey_account(&coldkey1, 100000); + + // Register the 2 neurons to a new network. + add_network(netuid, 0, 0); + register_ok_neuron(netuid, hotkey0, coldkey0, 124124); + register_ok_neuron(netuid, hotkey1, coldkey1, 987907); + + // Stake 100 from coldkey/hotkey 0 + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(coldkey0), + hotkey0, + netuid, + 100 + )); + assert_eq!( + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey0, &hotkey0, netuid), + 100 + ); + + // Hotkey 1 adds 100 delegated stake to coldkey/hotkey 0 + assert_eq!( + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0, netuid), + 0 + ); + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(coldkey1), + hotkey0, + netuid, + 100 + )); + assert_eq!( + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey(&coldkey1, &hotkey0, netuid), + 100 + ); + assert_eq!( + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey0), + 200 + ); + assert_eq!(SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey1), 0); + + // Coldkey / hotkey 0 decrease take to 10% + assert_ok!(SubtensorModule::do_decrease_take( + <::RuntimeOrigin>::signed(coldkey0), + hotkey0, + netuid, + u16::MAX / 10 + )); + assert_eq!( + SubtensorModule::get_delegate_take(&hotkey0, netuid), + u16::MAX / 10 ); // Coldkey / hotkey 0 tries to increase take to InitialDefaultTake+1 @@ -3061,14 +3273,15 @@ fn test_delegate_take_can_not_be_increased_beyond_limit() { SubtensorModule::do_increase_take( <::RuntimeOrigin>::signed(coldkey0), hotkey0, + netuid, InitialDefaultTake::get() + 1 ), Err(Error::::DelegateTakeTooHigh.into()) ); } assert_eq!( - SubtensorModule::get_hotkey_take(&hotkey0), - SubtensorModule::get_min_take() + SubtensorModule::get_delegate_take(&hotkey0, netuid), + u16::MAX / 10 ); }); } @@ -3089,14 +3302,15 @@ fn test_rate_limits_enforced_on_increase_take() { add_network(netuid, 0, 0); register_ok_neuron(netuid, hotkey0, coldkey0, 124124); - // Coldkey / hotkey 0 become delegates with 9% take - assert_ok!(SubtensorModule::do_become_delegate( + // Decrease delegate take to get_min_take + assert_ok!(SubtensorModule::do_decrease_take( <::RuntimeOrigin>::signed(coldkey0), hotkey0, + netuid, SubtensorModule::get_min_take() )); assert_eq!( - SubtensorModule::get_hotkey_take(&hotkey0), + SubtensorModule::get_delegate_take(&hotkey0, netuid), SubtensorModule::get_min_take() ); @@ -3105,12 +3319,13 @@ fn test_rate_limits_enforced_on_increase_take() { SubtensorModule::do_increase_take( <::RuntimeOrigin>::signed(coldkey0), hotkey0, + netuid, u16::MAX / 8 ), Err(Error::::DelegateTxRateLimitExceeded.into()) ); assert_eq!( - SubtensorModule::get_hotkey_take(&hotkey0), + SubtensorModule::get_delegate_take(&hotkey0, netuid), SubtensorModule::get_min_take() ); @@ -3120,8 +3335,209 @@ fn test_rate_limits_enforced_on_increase_take() { assert_ok!(SubtensorModule::do_increase_take( <::RuntimeOrigin>::signed(coldkey0), hotkey0, - u16::MAX / 8 + netuid, + u16::MAX / 10 + )); + assert_eq!( + SubtensorModule::get_delegate_take(&hotkey0, netuid), + u16::MAX / 10 + ); + }); +} + +#[test] +fn set_delegate_takes_updates_delegates_correctly() { + new_test_ext(1).execute_with(|| { + let hotkey = U256::from(1); + let coldkey = U256::from(2); + let takes = vec![(1u16, 10u16), (2u16, 15u16)]; // Ensure these values are within the InitialDefaultTake limit + + // Create subnets and register as delegates + let tempo: u16 = 13; + for (netuid, _) in &takes { + add_network(*netuid, tempo, 0); + register_ok_neuron(*netuid, hotkey, coldkey, 0); + } + + // Action: Call set_delegate_takes + assert_ok!(SubtensorModule::set_delegate_takes( + RuntimeOrigin::signed(coldkey), + hotkey, + takes.clone() + )); + + for (netuid, take) in takes { + let actual_take = SubtensorModule::get_delegate_take(&hotkey, netuid); + log::info!( + "Checking delegate take for netuid {}: Expected take: {}, Actual take: {}", + netuid, + take, + actual_take + ); + assert_eq!( + actual_take, take, + "The delegate take for netuid {} should be updated to {}", + netuid, take + ); + } + }); +} + +#[test] +fn set_delegate_takes_handles_empty_vector() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let hotkey = U256::from(1); + let takes: Vec<(u16, u16)> = vec![]; + + // Create subnet and register as delegate + let tempo: u16 = 13; + add_network(1, tempo, 0); + register_ok_neuron(1, hotkey, coldkey, 0); + + assert_ok!(SubtensorModule::set_delegate_takes( + RuntimeOrigin::signed(coldkey), + hotkey, + takes )); - assert_eq!(SubtensorModule::get_hotkey_take(&hotkey0), u16::MAX / 8); + + assert_eq!( + SubtensorModule::get_delegate_take(&hotkey, 1), + InitialDefaultTake::get(), + "Delegate take should be the default take value for netuid 1 after empty update" + ); + }); +} + +#[test] +fn set_delegate_takes_rejects_invalid_netuid() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let hotkey = U256::from(1); + let takes = vec![(999u16, 10u16)]; // Invalid netuid + + // Create subnet and register as delegate for a valid network first + let tempo: u16 = 13; + add_network(1, tempo, 0); // Adding a valid network + register_ok_neuron(1, hotkey, coldkey, 0); // Registering neuron on the valid network + + // Now test with an invalid network ID + assert_err!( + SubtensorModule::set_delegate_takes(RuntimeOrigin::signed(coldkey), hotkey, takes), + Error::::SubNetworkDoesNotExist + ); + }); +} + +#[test] +fn set_delegate_takes_rejects_excessive_take() { + new_test_ext(1).execute_with(|| { + let coldkey = U256::from(1); + let hotkey = U256::from(1); + let takes = vec![(1u16, 32_767 * 2)]; // Excessive take value + + // Create subnet and register as delegate + let tempo: u16 = 13; + add_network(1, tempo, 0); + register_ok_neuron(1, hotkey, coldkey, 0); + + // Now test with an excessive take value + assert_err!( + SubtensorModule::set_delegate_takes(RuntimeOrigin::signed(coldkey), hotkey, takes), + Error::::DelegateTakeTooHigh + ); + }); +} + +#[test] +fn set_delegate_takes_enforces_rate_limit() { + new_test_ext(1).execute_with(|| { + let hotkey = U256::from(1); + let coldkey = U256::from(2); + let takes_initial = vec![(1u16, 10u16), (2u16, 15u16)]; + let takes_second = vec![(1u16, 11u16), (2u16, 16u16)]; // Slightly increased takes + + // Create subnets and register as delegates + let tempo: u16 = 13; + for (netuid, _) in &takes_initial { + add_network(*netuid, tempo, 0); + register_ok_neuron(*netuid, hotkey, coldkey, 0); + } + + // First call to set_delegate_takes should succeed + assert_ok!(SubtensorModule::set_delegate_takes( + RuntimeOrigin::signed(coldkey), + hotkey, + takes_initial + )); + + // Second call to set_delegate_takes should fail due to rate limit + // Now test with an excessive take value + assert_err!( + SubtensorModule::set_delegate_takes( + RuntimeOrigin::signed(coldkey), + hotkey, + takes_second + ), + Error::::DelegateTxRateLimitExceeded + ); + }); +} + +#[test] +fn test_log_subnet_emission_values_dynamic_registration() { + new_test_ext(1).execute_with(|| { + let num_networks = 10; + + // Create dynamic subnets through user registration + for i in 1..=num_networks { + let netuid = i; + let tempo = 13; + let block_number = 0; + let cold_id = i * 100; // Generate a unique cold ID for each network + let hot_id = cold_id + 1; // Generate a unique hot ID for each network + + // Add the network + add_network(netuid, tempo, 0); + + // Create work for the user + let hotkey_account_id = U256::from(hot_id); + let coldkey_account_id = U256::from(cold_id); + SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, 10000); + + let (nonce, work): (u64, Vec) = SubtensorModule::create_work_for_block_number( + netuid, + block_number, + i as u64, + &hotkey_account_id, + ); + + // Register the user in the network by signing + assert_ok!(SubtensorModule::register( + <::RuntimeOrigin>::signed(hotkey_account_id), + netuid, + block_number, + nonce, + work, + hotkey_account_id, + coldkey_account_id + )); + } + run_to_block(1000); + // step_block(1000); + // Log the emission values for each subnet using subnet_info + for i in 1..=num_networks { + let netuid = i; + let subnet_emission_value = SubtensorModule::get_emission_value(netuid); + log::info!( + "tao per alpha price = {:?}", + SubtensorModule::get_tao_per_alpha_price(netuid) + ); + log::info!( + "Subnet {}: Emission Value = {:?}", + netuid, + subnet_emission_value + ); + } }); } diff --git a/pallets/subtensor/tests/total_issuance.rs b/pallets/subtensor/tests/total_issuance.rs new file mode 100644 index 000000000..d446e656a --- /dev/null +++ b/pallets/subtensor/tests/total_issuance.rs @@ -0,0 +1,136 @@ +use frame_support::{assert_ok, traits::Currency}; +use frame_system::Config; +mod mock; +use mock::*; +use sp_core::U256; + +// Test plan: +// For DTAO subnets we need to increase total issuance of TAO when it is injected into the Pool. +// For STAO subnets total issuance for TAO is only increased when the pending TAO is distributed after running the epoch. +// For total subnet tao stake +// For DTAO subnets this is incremented when the TAO is injected into the pool/. +// For STAO subnets this is only incremented when the pending TAO is distributed after running the epoch. + +// TODO: Unignore when we move away from using withdraw for staking +#[test] +#[ignore] +fn test_add_subnet_stake_total_issuance_no_change() { + // When we add stake, the total issuance of the balances pallet should not change + // this is because the stake should be part of the coldkey account balance (reserved/locked) + new_test_ext(1).execute_with(|| { + let hotkey_account_id = U256::from(561337); + let coldkey_account_id = U256::from(61337); + let netuid: u16 = 1; + let tempo: u16 = 13; + let start_nonce: u64 = 0; + + //add network + add_network(netuid, tempo, 0); + + // Register neuron + register_ok_neuron(netuid, hotkey_account_id, coldkey_account_id, start_nonce); + + // Give it some $$$ in his coldkey balance + let initial_balance = 10000; + SubtensorModule::add_balance_to_coldkey_account(&coldkey_account_id, initial_balance); + + // Check we have zero staked before transfer + let initial_stake = SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey_account_id); + assert_eq!(initial_stake, 0); + + // Check total balance is equal to initial balance + let initial_total_balance = Balances::total_balance(&coldkey_account_id); + assert_eq!(initial_total_balance, initial_balance); + + // Check total issuance is equal to initial balance + let initial_total_issuance = Balances::total_issuance(); + assert_eq!(initial_total_issuance, initial_balance); + + // Stake to hotkey account, and check if the result is ok + assert_ok!(SubtensorModule::add_subnet_stake( + <::RuntimeOrigin>::signed(coldkey_account_id), + hotkey_account_id, + netuid, + 10000 + )); + + // Check if stake has increased + let new_stake = SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey_account_id); + assert_eq!(new_stake, 10000); + + // Check if free balance has decreased + let new_free_balance = SubtensorModule::get_coldkey_balance(&coldkey_account_id); + assert_eq!(new_free_balance, ExistentialDeposit::get()); + + // Check if total issuance has remained the same. (no fee, includes reserved/locked balance) + let total_issuance = Balances::total_issuance(); + assert_eq!(total_issuance, initial_total_issuance); + }); +} + +// TODO: Unignore when we move away from using withdraw for staking +#[test] +#[ignore] + +fn test_remove_subnet_stake_total_issuance_no_change() { + // When we remove stake, the total issuance of the balances pallet should not change + // this is because the stake should be part of the coldkey account balance (reserved/locked) + // then the removed stake just becomes free balance + new_test_ext(1).execute_with(|| { + let hotkey_account_id = U256::from(581337); + let coldkey_account_id = U256::from(81337); + let netuid: u16 = 1; + let tempo: u16 = 13; + let start_nonce: u64 = 0; + let amount = 10000; + + //add network + add_network(netuid, tempo, 0); + + // Register neuron + register_ok_neuron(netuid, hotkey_account_id, coldkey_account_id, start_nonce); + + // Some basic assertions + assert_eq!( + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey_account_id), + 0 + ); + assert_eq!(SubtensorModule::get_coldkey_balance(&coldkey_account_id), 0); + let initial_total_balance = Balances::total_balance(&coldkey_account_id); + assert_eq!(initial_total_balance, 0); + let inital_total_issuance = Balances::total_issuance(); + assert_eq!(inital_total_issuance, 0); + + // Give the neuron some stake to remove + SubtensorModule::increase_subnet_token_on_hotkey_account( + &hotkey_account_id, + netuid, + amount, + ); + + let total_issuance_after_stake = Balances::total_issuance(); + + // Do the magic + assert_ok!(SubtensorModule::remove_subnet_stake( + <::RuntimeOrigin>::signed(coldkey_account_id), + hotkey_account_id, + netuid, + amount + )); + + assert_eq!( + SubtensorModule::get_coldkey_balance(&coldkey_account_id), + amount + ); + assert_eq!( + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey_account_id), + 0 + ); + + // Check if total issuance is equal to the added stake, even after remove stake (no fee, includes reserved/locked balance) + // Should also be equal to the total issuance after adding stake + let total_issuance = Balances::total_issuance(); + assert_eq!(total_issuance, total_issuance_after_stake); + assert_eq!(total_issuance, amount); + }); +} diff --git a/pallets/subtensor/tests/uids.rs b/pallets/subtensor/tests/uids.rs index b8a969943..ce8d66cfe 100644 --- a/pallets/subtensor/tests/uids.rs +++ b/pallets/subtensor/tests/uids.rs @@ -5,6 +5,9 @@ use sp_core::U256; mod mock; +// To run just the tests in this file, use the following command: +// cargo test -p pallet-subtensor --test uids + /******************************************** tests for uids.rs file *********************************************/ @@ -228,48 +231,54 @@ fn test_replace_neuron_multiple_subnets_unstake_all() { assert_ok!(neuron_uid); // Stake on neuron with multiple coldkeys. - SubtensorModule::increase_stake_on_coldkey_hotkey_account( + SubtensorModule::increase_subnet_token_on_coldkey_hotkey_account( &coldkey_account_id, &hotkey_account_id, + netuid, stake_amount, ); - SubtensorModule::increase_stake_on_coldkey_hotkey_account( + SubtensorModule::increase_subnet_token_on_coldkey_hotkey_account( &coldkey_account1_id, &hotkey_account_id, + netuid, stake_amount + 1, ); - SubtensorModule::increase_stake_on_coldkey_hotkey_account( + SubtensorModule::increase_subnet_token_on_coldkey_hotkey_account( &coldkey_account2_id, &hotkey_account_id, + netuid, stake_amount + 2, ); // Check stake on neuron assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey( + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey( &coldkey_account_id, - &hotkey_account_id + &hotkey_account_id, + netuid, ), stake_amount ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey( + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey( &coldkey_account1_id, - &hotkey_account_id + &hotkey_account_id, + netuid, ), stake_amount + 1 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey( + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey( &coldkey_account2_id, - &hotkey_account_id + &hotkey_account_id, + netuid, ), stake_amount + 2 ); - // Check total stake on neuron + // Check total GDT stake on neuron assert_eq!( - SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey_account_id), (stake_amount * 3) + (1 + 2) ); @@ -288,30 +297,33 @@ fn test_replace_neuron_multiple_subnets_unstake_all() { // Check the stake is still on the coldkey accounts. assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey( + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey( &coldkey_account_id, - &hotkey_account_id + &hotkey_account_id, + netuid, ), stake_amount ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey( + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey( &coldkey_account1_id, - &hotkey_account_id + &hotkey_account_id, + netuid, ), stake_amount + 1 ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey( + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey( &coldkey_account2_id, - &hotkey_account_id + &hotkey_account_id, + netuid, ), stake_amount + 2 ); // Check total stake on neuron assert_eq!( - SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey_account_id), (stake_amount * 3) + (1 + 2) ); @@ -330,18 +342,20 @@ fn test_replace_neuron_multiple_subnets_unstake_all() { // Check the stake is now on the free balance of the coldkey accounts. assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey( + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey( &coldkey_account_id, - &hotkey_account_id + &hotkey_account_id, + netuid, ), 0 ); assert_eq!(Balances::free_balance(coldkey_account_id), stake_amount); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey( + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey( &coldkey_account1_id, - &hotkey_account_id + &hotkey_account_id, + netuid, ), 0 ); @@ -351,9 +365,10 @@ fn test_replace_neuron_multiple_subnets_unstake_all() { ); assert_eq!( - SubtensorModule::get_stake_for_coldkey_and_hotkey( + SubtensorModule::get_subnet_stake_for_coldkey_and_hotkey( &coldkey_account2_id, - &hotkey_account_id + &hotkey_account_id, + netuid, ), 0 ); @@ -364,7 +379,7 @@ fn test_replace_neuron_multiple_subnets_unstake_all() { // Check total stake on neuron assert_eq!( - SubtensorModule::get_total_stake_for_hotkey(&hotkey_account_id), + SubtensorModule::get_hotkey_global_dynamic_tao(&hotkey_account_id), 0 ); }); diff --git a/pallets/subtensor/tests/weights.rs b/pallets/subtensor/tests/weights.rs index bb7f11908..7d0f2fa32 100644 --- a/pallets/subtensor/tests/weights.rs +++ b/pallets/subtensor/tests/weights.rs @@ -12,6 +12,9 @@ use sp_runtime::{ }; use substrate_fixed::types::I32F32; +// To run just the tests in this file, use the following command: +// cargo test -p pallet-subtensor --test weights + /*************************** pub fn set_weights() tests *****************************/ @@ -169,9 +172,17 @@ fn test_set_weights_min_stake_failed() { // Check the signed extension function. assert_eq!(SubtensorModule::get_weights_min_stake(), 20_000_000_000_000); assert!(!SubtensorModule::check_weights_min_stake(&hotkey)); - SubtensorModule::increase_stake_on_hotkey_account(&hotkey, 19_000_000_000_000); + SubtensorModule::increase_subnet_token_on_hotkey_account( + &hotkey, + netuid, + 19_000_000_000_000, + ); assert!(!SubtensorModule::check_weights_min_stake(&hotkey)); - SubtensorModule::increase_stake_on_hotkey_account(&hotkey, 20_000_000_000_000); + SubtensorModule::increase_subnet_token_on_hotkey_account( + &hotkey, + netuid, + 20_000_000_000_000, + ); assert!(SubtensorModule::check_weights_min_stake(&hotkey)); // Check that it fails at the pallet level. @@ -188,7 +199,11 @@ fn test_set_weights_min_stake_failed() { Err(Error::::NotEnoughStakeToSetWeights.into()) ); // Now passes - SubtensorModule::increase_stake_on_hotkey_account(&hotkey, 100_000_000_000_000); + SubtensorModule::increase_subnet_token_on_hotkey_account( + &hotkey, + netuid, + 100_000_000_000_000, + ); assert_ok!(commit_reveal_set_weights( hotkey, netuid, diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 36635b4e5..518a2f143 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -94,6 +94,7 @@ substrate-wasm-builder = { workspace = true, optional = true } [features] default = ["std"] pow-faucet = ["pallet-subtensor/pow-faucet"] +subnet-staking = ["pallet-subtensor/subnet-staking"] fast-blocks = [] std = [ "frame-try-runtime?/std", diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index fc2732094..a20435c54 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -33,7 +33,7 @@ use sp_runtime::{ AccountIdLookup, BlakeTwo256, Block as BlockT, IdentifyAccount, NumberFor, One, Verify, }, transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, MultiSignature, + ApplyExtrinsicResult, DispatchResult, MultiSignature, }; use sp_std::cmp::Ordering; use sp_std::prelude::*; @@ -65,6 +65,8 @@ use pallet_transaction_payment::{CurrencyAdapter, Multiplier}; pub use sp_runtime::BuildStorage; pub use sp_runtime::{Perbill, Permill}; +use pallet_subtensor::{types::TensorBytes, EpochConfiguration}; + // Subtensor module pub use pallet_subtensor; @@ -135,7 +137,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // `spec_version`, and `authoring_version` are the same between Wasm and native. // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use // the compatible custom types. - spec_version: 185, + spec_version: 227, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, @@ -151,10 +153,17 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { #[cfg(not(feature = "fast-blocks"))] pub const MILLISECS_PER_BLOCK: u64 = 12000; +#[cfg(not(feature = "fast-blocks"))] +// pub const SUBNET_CREATOR_LOCK: u64 = 7 * 7200 * 3; // 3 months +pub const SUBNET_CREATOR_LOCK: u64 = 0; // Disable for DTAO demo + /// Fast blocks for development #[cfg(feature = "fast-blocks")] pub const MILLISECS_PER_BLOCK: u64 = 250; +#[cfg(feature = "fast-blocks")] +pub const SUBNET_CREATOR_LOCK: u64 = 240; // 1 minute + // NOTE: Currently it is not possible to change the slot duration after the chain has started. // Attempting to do so will brick block production. pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK; @@ -299,7 +308,6 @@ impl pallet_balances::Config for Runtime { type ExistentialDeposit = ConstU64; type AccountStore = System; type WeightInfo = pallet_balances::weights::SubstrateWeight; - type RuntimeHoldReason = RuntimeHoldReason; type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = RuntimeFreezeReason; @@ -735,7 +743,6 @@ impl pallet_registry::Config for Runtime { type Currency = Balances; type CanRegister = AllowIdentityReg; type WeightInfo = pallet_registry::weights::SubstrateWeight; - type MaxAdditionalFields = MaxAdditionalFields; type InitialDeposit = InitialDeposit; type FieldDeposit = FieldDeposit; @@ -774,6 +781,13 @@ impl pallet_commitments::Config for Runtime { type RateLimit = CommitmentRateLimit; } +pub struct SimpleEpoch; +impl EpochConfiguration for SimpleEpoch { + fn simple_epoch() -> bool { + true + } +} + // Configure the pallet subtensor. parameter_types! { pub const SubtensorInitialRho: u16 = 10; @@ -786,7 +800,9 @@ parameter_types! { pub const SubtensorInitialValidatorPruneLen: u64 = 1; pub const SubtensorInitialScalingLawPower: u16 = 50; // 0.5 pub const SubtensorInitialMaxAllowedValidators: u16 = 128; - pub const SubtensorInitialTempo: u16 = 99; + pub const SubtensorInitialTempo: u16 = 360; + pub const SubtensorMinTempo: u16 = 360; + pub const SubtensorMaxTempo: u16 = 360; pub const SubtensorInitialDifficulty: u64 = 10_000_000; pub const SubtensorInitialAdjustmentInterval: u16 = 100; pub const SubtensorInitialAdjustmentAlpha: u64 = 0; // no weight to previous value. @@ -797,7 +813,7 @@ parameter_types! { pub const SubtensorInitialPruningScore : u16 = u16::MAX; pub const SubtensorInitialBondsMovingAverage: u64 = 900_000; pub const SubtensorInitialDefaultTake: u16 = 11_796; // 18% honest number. - pub const SubtensorInitialMinTake: u16 = 5_898; // 9% + pub const SubtensorInitialMinTake: u16 = 0; // 0% pub const SubtensorInitialWeightsVersionKey: u64 = 0; pub const SubtensorInitialMinDifficulty: u64 = 10_000_000; pub const SubtensorInitialMaxDifficulty: u64 = u64::MAX / 4; @@ -816,7 +832,8 @@ parameter_types! { pub const SubtensorInitialSubnetLimit: u16 = 12; pub const SubtensorInitialNetworkLockReductionInterval: u64 = 14 * 7200; pub const SubtensorInitialNetworkRateLimit: u64 = 7200; - pub const SubtensorInitialTargetStakesPerInterval: u16 = 1; + pub const SubtensorInitialTargetStakesPerInterval: u16 = u16::MAX; + pub const SubtensorInitialSubnetOwnerLockPeriod: u64 = SUBNET_CREATOR_LOCK; } impl pallet_subtensor::Config for Runtime { @@ -826,6 +843,8 @@ impl pallet_subtensor::Config for Runtime { type CouncilOrigin = EnsureMajoritySenate; type SenateMembers = ManageSenateMembers; type TriumvirateInterface = TriumvirateVotes; + type EpochConfig = SimpleEpoch; + // type EpochConfig = (); type InitialRho = SubtensorInitialRho; type InitialKappa = SubtensorInitialKappa; @@ -838,6 +857,8 @@ impl pallet_subtensor::Config for Runtime { type InitialValidatorPruneLen = SubtensorInitialValidatorPruneLen; type InitialScalingLawPower = SubtensorInitialScalingLawPower; type InitialTempo = SubtensorInitialTempo; + type MinTempo = SubtensorMinTempo; + type MaxTempo = SubtensorMaxTempo; type InitialDifficulty = SubtensorInitialDifficulty; type InitialAdjustmentInterval = SubtensorInitialAdjustmentInterval; type InitialAdjustmentAlpha = SubtensorInitialAdjustmentAlpha; @@ -868,6 +889,7 @@ impl pallet_subtensor::Config for Runtime { type InitialSubnetLimit = SubtensorInitialSubnetLimit; type InitialNetworkRateLimit = SubtensorInitialNetworkRateLimit; type InitialTargetStakesPerInterval = SubtensorInitialTargetStakesPerInterval; + type InitialSubnetOwnerLockPeriod = SubtensorInitialSubnetOwnerLockPeriod; } use sp_runtime::BoundedVec; @@ -964,12 +986,18 @@ impl SubtensorModule::coldkey_owns_hotkey(coldkey, hotkey) } - fn increase_stake_on_coldkey_hotkey_account( + fn increase_subnet_token_on_coldkey_hotkey_account( coldkey: &AccountId, hotkey: &AccountId, - increment: u64, + netuid: u16, + increment_alpha: u64, ) { - SubtensorModule::increase_stake_on_coldkey_hotkey_account(coldkey, hotkey, increment); + SubtensorModule::increase_subnet_token_on_coldkey_hotkey_account( + coldkey, + hotkey, + netuid, + increment_alpha, + ); } fn add_balance_to_coldkey_account(coldkey: &AccountId, amount: Balance) { @@ -1131,6 +1159,14 @@ impl SubtensorModule::get_nominator_min_required_stake() } + fn set_global_stake_weight(global_stake_weight: u16) { + SubtensorModule::set_global_stake_weight(global_stake_weight); + } + + fn set_subnet_staking(subnet_staking: bool) { + SubtensorModule::set_subnet_staking(subnet_staking); + } + fn set_target_stakes_per_interval(target_stakes_per_interval: u64) { SubtensorModule::set_target_stakes_per_interval(target_stakes_per_interval) } @@ -1142,6 +1178,22 @@ impl fn set_commit_reveal_weights_enabled(netuid: u16, enabled: bool) { SubtensorModule::set_commit_reveal_weights_enabled(netuid, enabled); } + + fn do_start_stao_dtao_transition(netuid: u16) -> DispatchResult { + SubtensorModule::do_start_stao_dtao_transition(netuid) + } + + fn do_start_stao_dtao_transition_for_all() -> DispatchResult { + SubtensorModule::do_start_stao_dtao_transition_for_all() + } + + fn do_continue_stao_dtao_transition() -> Weight { + SubtensorModule::do_continue_stao_dtao_transition() + } + + fn get_pending_emission(netuid: u16) -> u64 { + SubtensorModule::get_pending_emission(netuid) + } } impl pallet_admin_utils::Config for Runtime { @@ -1442,10 +1494,10 @@ impl_runtime_apis! { use frame_system_benchmarking::Pallet as SystemBench; use baseline::Pallet as BaselineBench; - #[allow(non_local_definitions)] + #[allow(dead_code)] impl frame_system_benchmarking::Config for Runtime {} - #[allow(non_local_definitions)] + #[allow(dead_code)] impl baseline::Config for Runtime {} use frame_support::traits::WhitelistedStorageKeys; @@ -1482,11 +1534,41 @@ impl_runtime_apis! { } impl subtensor_custom_rpc_runtime_api::DelegateInfoRuntimeApi for Runtime { + + fn get_substake_for_coldkey( coldkey_bytes: Vec ) -> Vec { + let result = SubtensorModule::get_substake_for_coldkey( coldkey_bytes ); + result.encode() + } + fn get_substake_for_hotkey( hotkey_bytes: Vec ) -> Vec { + let result = SubtensorModule::get_substake_for_hotkey( hotkey_bytes ); + result.encode() + } + fn get_substake_for_netuid( netuid: u16 ) -> Vec { + let result = SubtensorModule::get_substake_for_netuid( netuid ); + result.encode() + } + fn get_total_stake_for_coldkey( coldkey_bytes: Vec ) -> u64 { + SubtensorModule::get_total_stake_for_coldkey( coldkey_bytes ) + } + fn get_total_stake_for_hotkey( hotkey_bytes: Vec ) -> u64 { + SubtensorModule::get_total_stake_for_hotkey( hotkey_bytes ) + } + fn get_delegates() -> Vec { let result = SubtensorModule::get_delegates(); result.encode() } + fn get_delegates_by_netuid_light(netuid: u16) -> Vec { + let result = SubtensorModule::get_delegates_by_netuid_light(netuid); + result.encode() + } + + fn get_all_delegates_total_stake() -> Vec { + let result = SubtensorModule::get_all_delegates_total_stake(); + result.encode() + } + fn get_delegate(delegate_account_vec: Vec) -> Vec { let _result = SubtensorModule::get_delegate(delegate_account_vec); if _result.is_some() { @@ -1560,18 +1642,63 @@ impl_runtime_apis! { vec![] } } + + fn get_subnet_info_v2(netuid: u16) -> Vec { + let _result = SubtensorModule::get_subnet_info_v2(netuid); + if _result.is_some() { + let result = _result.expect("Could not get SubnetInfo"); + result.encode() + } else { + vec![] + } + } + + fn get_subnets_info_v2() -> Vec { + let result = SubtensorModule::get_subnets_info_v2(); + result.encode() + } } impl subtensor_custom_rpc_runtime_api::StakeInfoRuntimeApi for Runtime { - fn get_stake_info_for_coldkey( coldkey_account_vec: Vec ) -> Vec { + fn get_stake_info_for_coldkey( coldkey_account_vec: TensorBytes ) -> Vec { let result = SubtensorModule::get_stake_info_for_coldkey( coldkey_account_vec ); result.encode() } - fn get_stake_info_for_coldkeys( coldkey_account_vecs: Vec> ) -> Vec { + fn get_stake_info_for_coldkeys( coldkey_account_vecs: Vec ) -> Vec { let result = SubtensorModule::get_stake_info_for_coldkeys( coldkey_account_vecs ); result.encode() } + + fn get_subnet_stake_info_for_coldkeys( coldkey_account_vecs: Vec ,netuid: u16 ) -> Vec { + let result = SubtensorModule::get_subnet_stake_info_for_coldkeys( coldkey_account_vecs, netuid ); + result.encode() + } + + fn get_all_stake_info_for_coldkey( coldkey_account_vec: TensorBytes ) -> Vec { + let result = SubtensorModule::get_all_stake_info_for_coldkey( coldkey_account_vec ); + result.encode() + } + + fn get_subnet_stake_info_for_coldkey( coldkey_account_vec: TensorBytes, netuid: u16 ) -> Vec { + let result = SubtensorModule::get_subnet_stake_info_for_coldkey( coldkey_account_vec, netuid ); + result.encode() + } + + fn get_total_subnet_stake( netuid: u16 ) -> Vec { + let result = SubtensorModule::get_total_subnet_stake( netuid ); + result.encode() + } + + fn get_all_subnet_stake_info_for_coldkey( coldkey_account_vec: TensorBytes ) -> Vec { + let result = SubtensorModule::get_all_subnet_stake_info_for_coldkey( coldkey_account_vec ); + result.encode() + } + + fn get_total_stake_for_each_subnet() -> Vec { + let result = SubtensorModule::get_total_stake_for_each_subnet(); + result.encode() + } } impl subtensor_custom_rpc_runtime_api::SubnetRegistrationRuntimeApi for Runtime { @@ -1579,10 +1706,26 @@ impl_runtime_apis! { SubtensorModule::get_network_lock_cost() } } -} -// #[cfg(test)] -// mod tests { + impl subtensor_custom_rpc_runtime_api::DynamicPoolInfoRuntimeApi for Runtime { + fn get_dynamic_pool_info(netuid: u16) -> Vec { + let result = SubtensorModule::get_dynamic_pool_info(netuid); + result.encode() + } + fn get_all_dynamic_pool_infos() -> Vec { + let result = SubtensorModule::get_all_dynamic_pool_infos(); + result.encode() + } + fn get_dynamic_pool_info_v2(netuid: u16) -> Vec { + let result = SubtensorModule::get_dynamic_pool_info_v2(netuid); + result.encode() + } + fn get_all_dynamic_pool_infos_v2() -> Vec { + let result = SubtensorModule::get_all_dynamic_pool_infos_v2(); + result.encode() + } + } +} #[test] fn check_whitelist() { @@ -1606,4 +1749,3 @@ fn check_whitelist() { // System Events assert!(whitelist.contains("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7")); } -// } diff --git a/scripts/build-spec-from-finney.sh b/scripts/build-spec-from-finney.sh new file mode 100755 index 000000000..a2524777c --- /dev/null +++ b/scripts/build-spec-from-finney.sh @@ -0,0 +1 @@ +.baedeker/up.sh .baedeker/forkless-data.jsonnet --tla-str=forked_spec=subtensor --tla-str=fork_source=wss://entrypoint-finney.opentensor.ai \ No newline at end of file diff --git a/scripts/localnet-baedeker.sh b/scripts/localnet-baedeker.sh new file mode 100755 index 000000000..834b619bc --- /dev/null +++ b/scripts/localnet-baedeker.sh @@ -0,0 +1,65 @@ +#!/bin/bash + +: "${BUILD_BINARY:=1}" +# : "${FEATURES:=pow-faucet}" + +FULL_PATH=".baedeker/.bdk-env/specs/subtensor.json" + +if [[ $BUILD_BINARY == "1" ]]; then + echo "*** Building substrate binary..." + # cargo build --release --features "$FEATURES" + cargo build --release + echo "*** Binary compiled" +fi + +echo "*** Purging previous state..." +./target/release/node-subtensor purge-chain -y --base-path /tmp/charlie --chain="$FULL_PATH" >/dev/null 2>&1 +./target/release/node-subtensor purge-chain -y --base-path /tmp/bob --chain="$FULL_PATH" >/dev/null 2>&1 +./target/release/node-subtensor purge-chain -y --base-path /tmp/alice --chain="$FULL_PATH" >/dev/null 2>&1 +echo "*** Previous chainstate purged" + +echo "*** Starting localnet nodes..." +alice_start=( + ./target/release/node-subtensor + --base-path /tmp/alice + --chain="$FULL_PATH" + --keystore-path=./.baedeker/.bdk-env/secret/keystore-subtensor-node-alice + --node-key-file=./.baedeker/.bdk-env/secret/node/subtensor-node-alice + --port 30334 + --rpc-port 9946 + --validator + --rpc-cors=all + --rpc-external + --unsafe-rpc-external + --rpc-methods=unsafe + --allow-private-ipv4 + --discover-local +) + +bob_start=( + ./target/release/node-subtensor + --base-path /tmp/bob + --chain="$FULL_PATH" + --keystore-path=./.baedeker/.bdk-env/secret/keystore-subtensor-node-bob + --node-key-file=./.baedeker/.bdk-env/secret/node/subtensor-node-bob + --port 30335 + --rpc-port 9935 + --validator + --allow-private-ipv4 + --discover-local +) + +charlie_start=( + ./target/release/node-subtensor + --base-path /tmp/charlie + --chain="$FULL_PATH" + --keystore-path=./.baedeker/.bdk-env/secret/keystore-subtensor-node-charlie + --node-key-file=./.baedeker/.bdk-env/secret/node/subtensor-node-charlie + --port 30336 + --rpc-port 9936 + --validator + --allow-private-ipv4 + --discover-local +) + +(trap 'kill 0' SIGINT; ("${alice_start[@]}" 2>&1) & ("${bob_start[@]}" 2>&1) & ("${charlie_start[@]}" 2>&1)) diff --git a/scripts/localnet.sh b/scripts/localnet.sh index ab564871b..40490509c 100755 --- a/scripts/localnet.sh +++ b/scripts/localnet.sh @@ -38,6 +38,7 @@ echo "*** Purging previous state..." echo "*** Previous chainstate purged" echo "*** Starting localnet nodes..." +export RUST_LOG=subtensor=trace alice_start=( "$BASE_DIR/target/release/node-subtensor" --base-path /tmp/alice @@ -47,6 +48,9 @@ alice_start=( --rpc-port 9946 --validator --rpc-cors=all + --rpc-external + --unsafe-rpc-external + --rpc-methods=unsafe --allow-private-ipv4 --discover-local ) diff --git a/scripts/specs/local.json b/scripts/specs/local.json deleted file mode 100644 index ea97f78db..000000000 --- a/scripts/specs/local.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "name": "Bittensor", - "id": "bittensor", - "chainType": "Development", - "bootNodes": [], - "telemetryEndpoints": null, - "protocolId": null, - "properties": { - "ss58Format": 13116, - "tokenDecimals": 9, - "tokenSymbol": "TAO" - }, - "codeSubstitutes": {}, - "genesis": { - "raw": { - "top": { - "0x1809d78346727a0ef58c0fa03bafa3234e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0x26aa394eea5630e07c48ae0c9558cef74e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0x26aa394eea5630e07c48ae0c9558cef75684a022a34dd8bfa2baaf44f172b710": "0x01", - "0x26aa394eea5630e07c48ae0c9558cef78a42f33323cb5ced3b44dd825fda9fcc": "0x4545454545454545454545454545454545454545454545454545454545454545", - "0x26aa394eea5630e07c48ae0c9558cef7a44704b568d21667356a5a050c118746b4def25cfda6ef3a00000000": "0x4545454545454545454545454545454545454545454545454545454545454545", - "0x26aa394eea5630e07c48ae0c9558cef7a7fd6c28836b9a28522dc924110cf439": "0x01", - "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da923a05cabf6d3bde7ca3ef0d11596b5611cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c": "0x0000000000000000010000000000000000943577000000000000000000000000000000000000000000000000000000000000000000000080", - "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da94f9aea1afa791265fae359272badc1cf8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48": "0x000000000000000001000000000000000010a5d4e80000000000000000000000000000000000000000000000000000000000000000000080", - "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9b0edae20838083f2cde1c4080db8cf8090b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22": "0x000000000000000001000000000000000010a5d4e80000000000000000000000000000000000000000000000000000000000000000000080", - "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d": "0x00000000000000000100000000000000000064a7b3b6e00d0000000000000000000000000000000000000000000000000000000000000080", - "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9e5e802737cce3a54b0bc9e3d3e6be26e306721211d5404bd9da88e0204360a1a9ab8b87c66c1bc2fcdd37f3c2222cc20": "0x0000000000000000010000000000000000943577000000000000000000000000000000000000000000000000000000000000000000000080", - "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9edeaa42c2163f68084a988529a0e2ec5e659a7a1628cdd93febc04a4e0646ea20e9f5f0ce097d9a05290d4a9e054df4e": "0x0000000000000000010000000000000000943577000000000000000000000000000000000000000000000000000000000000000000000080", - "0x26aa394eea5630e07c48ae0c9558cef7f9cce9c888469bb1a0dceaa129672ef8": "0xe502386e6f64652d73756274656e736f72", - "0x3a3488932ba83145d9efdd3fcf226dc44e7b9012096b41c4eb3aaf947f6ea429": "0x0400", - "0x3a3488932ba83145d9efdd3fcf226dc4ba7fb8745735dc3be2a2c61a72c39e78": "0x0c8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a4890b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d", - "0x3a636f6465": "0x52bc537646db8e0528b52ffd0058bc88053e26875c16521070589474f090afa963724b5f53bf3986a96e9c501d422803497a408757b1ff0ab6df6775e02f35c8cc209a41e4f95287499a795d2d895eea95eb900b127b11ed177df10ffc4f5a23843442c8267bcb2d037318cf145d15f2db45e1b7c334ea451df98c665147fea2a3ace519a341b68e1fd12d6254c18c6e21c413526aee8428359f3b215ec7abebc115cb38b83c626f0f267ceddbe8baae4ba38f3af2236a8a3ad2d4f259d783cf1ab7dd7531d753906f1583e6cfcffaad6ad05c87def3abde2ec8a8b97e43f4ac17fd56db88d3a8932dae1765d7461db7c86de7e301a36bd589f6d121b029ad6e715d760e702201a95145451df99da823bf7543e2affa0d818306dea6b23b91809476ed1faae5475d0fbe4fd4e8a698c24ec8a80be2d25e33dd62763ee0328ca40f024d8228fd6dabe589609eef0720ccf3ed150b30cfa8e583e01e9892f7619e6d8d208a9607827960cb6fccc1e5b1bd87dd0dfd1575fc8179e2e5374756a0c5d27b43515c49cebed8b688b72d1154e9abb705858d5e972a50ca9ad5cd890c93d87ed86f69834078db2d60d552d615844004410145aa7411e3b7dde5f6dc05b16aa0ad4245bdfff870bd16942abd2d2858f4576af91d7a5b4ea4a1e59779e6b54d1a61ec8258f532ea93cd9f34ae9ae16d705cb1c5aec7c5f13ebc41ce064715d7a9ec7ec08c794e3e60cfcf9a35fc45616f8e6cc1f603046208298e2a205c1fab83c7b5ecad341f8358359fe3e535cf679e930f7e7c9c8797ccf35d078af319f3708fc9b50ffbf00a4258655b20bcad044506b182356394bcfc56e2e1c5f3858a5a2e6c599751f019d896715ce1c9f8b32df36ccb892bbd19f3c4ef7ee9d6db6aa28d25a3e5e75692cc33bf5fa2f7db2e0fd2b76dc59d44777570f5db2ec43dbfd58f7b3b3c47bfa2e660933e2645bd7d74f95d1eda49ab8354bfedf1dd35baaba3ab1ff7b80da910b665cb9635f4e81cfd563dbf9d0fd8a3fbf00634aa4d60cf07e19ee74e883cd76fd5fc6d483fd8f0ac9ee77e6cdfd501ef137d78a342704b67e7e8a9fb815dab1f6ced23fac11e7d9bf4833ddf3d7643e4e77d785b0885b7ad26d268f9f96d37e6b6fbd17dab9fec2d7293ac492755d805913dbf6ddb91eab76ad239da246bee1bfd606fdfe5c1d58f7b108fded5b17dbb4fdce846e3b72355a1d8b0eb31dfd16f3e7e3b21f273c36085a0b7d232cff6bd649ed10fb8a5b9baabe3dbaa10dcd2dbaf6f07647babbb39349f38a2db1a859f743ba390b53aae63f4e3c3c92b0d5e5fd81e7b9828fd5fec4ccc7c5e079f899a931e80782644006f3a0fdfd8c3444d55bd3cda9c091bbe7d9fc51e267698a079cdf7a6d8c3c44c55cdbc547a8dcb4bf43357cd54954bce6bae9a39f7d29988559565f7aaca3b16af8a55955511c0abb2e3b8cbbbefbdd8c3c4a8aa4667fe565355f5d80dcfe18cbde62a7e4d555dd7bdaa1addbbaae6db9990b7a9aa9898bf5455bc5655dae97615fd5655315eb5fd7418cf3b5755d7f55155c5aac2f9e85ebc771577afaa2e98abaeeb1c87abbce35055313197a92a9963d87154550c8ecb6032c7e12aec3854150e2de2b84acba92240c15415cc65647e829191a9bf61343a0e9cd1681b6954a666c6257a186ba399986d3257895e1c67352e25ce28e6456f84c96c1737533393d192cb35d2b4b879988c0be7cd685c8d0bc6198f4af49289974c4dcc72d0c1dbb844b7efe082c328871c606ab6a8e9e85cc5d7d1d16666ea515e7614a7830e578dae830e14c34aafd7e146d7b950a8abe85139a0b2928cf77a1d6a5caec377b86ae63be8e85cb55d07079def709576e590c3465f8fba648ee21c72c84187abb0eb505539e4e012bf030e38e05cc51d477bbd0e8ee3dc30b3c375aeaab90e0a0580e35055a8df80c375ae1afd86abbc9a731818ae797d0e3838bf01078e9f8e73c371ae72394ef61c9ee3aad273c09d9bef7055e93bc09cdfb0c3735c35f31baecaae83bab9a9bfd1f9cd55f437f0aaed37c7e174fa0d38aa0aa7aa707ec34f387eba8afb095e751d87a3aef28e8200c8e12aec395415007278ad2a001c078ea3ae8aaf5769cf51553ae8f09caa3a55d5e93030bfa92a1b9b9faaeae630303f5d25f35355d99c6e7315577d56073ee73bdcc0bd1ca7aa6caacae638e7b8d7ab46af55f572c3eb555b5db23af02fdfe1aa514d6275e077a82a1daa08a0ce761caa6a347a4c55c57cc3e1db555a2562abaad1f69baa1a9dd3ce5d45eb10ab037f73954c05b23af0a8aaca41e600a8aa5a55f538d0e754d50d7fadaaddc2133390b1e50561400194145d821351987106375ac0c412524cd0fbd4d46c75e06955bd7ea6eeeac0db5037eaec71e0d4fca6aa4ea6db54d52a083be082952b34c8a28c20a46a562e0841144e40042898e14a0c523557b954d3eac0d75495a96ed4e1a17ea8deab4ad55b1d789a9a459dfdcc55b11eb13af0335525534500534cb83ca6aa4a87a922d8493111ff52552ea497aa6a75c514354cb9e20d3174e10ba9b852d0b2832a4ee082378860861413f1a5abbcba6375e04b5545aa1b750250bf1dbd5761756775e0bb6a8a3a7b155723ab03cf55d55645804a31313faaaa1f7ce085177020862668b1414aab22788a091bc020030fbe88421367e0428a093e76555651ab038f55d5ac1b7574d46fa7f7aaab7e75e065f5a2ce7ebf8a453aac630b13696c8b016f5b4c90d1db28e6f950cde7e7e0df700f4cf13d329a1fc33c2ca40585d5b1edc31cf3ecf99bc370064fa25cc03bf3a098e7931ef3c4e730cfa823a7e21264743cc73c71d45f8e8e878fdf41c2313233f3e1e54dcc13296cfe4d8c125e1e5e5622d8b12ea3b67eb05908db328fbcfecdefb78bf227cd7a93cc035b328ffc7e835d0fc91be4aef9ebf2b1eb21f9175d4645d8dcf1b79b35dbae87dc0e480f781f9e54f645b72585bd8a105a296dcef78e97ccc3df2ff3c0ef99728c8ade61d7632bc7a88c51f13eacc3fb623a1e3edec43cf2f15b0cf3c8df30cf7549b7b7bbeec33eccb4890dcd6495357cd6b09e84f0e1f9b012c1beaaa4b0b70b02cff5e3c3c70a74f8c5b617f0b6b5c413ed31cfb6944843ef63b86753db0a4194de73cc037bbf395b81de7bc30ac21fb6b5c1dbc3af76b329c146efb7dbb6b778183f08e3613c105cf821f98f6bfe2629ec48b95bcc65ccf3c1fe2e8f00783f9651fb58b38d394963472a9bd3d242583779216d9193943bd2d8ddf21882ac164a403799dcf2188258ba09d7f0fced864816ec8278ac86e7b60b02590d1f212f61dbce98e7b3c17185c787ffe225a3f65ba4393c7efc7ebb217ca0583346ed571002b16dcee72da3beacf95fd6fbe59e651dfe7e5b1dbc78d8dbeee06d0b9ff0b6a5c419bd2dd619fd959a4f80de164b4a73d723080f7e5b2c28cd5fe689e74be6c1cecf98679bbf71d703ab0b5d84b4ac306a3bde4648ebcaead8de2017e93646616fb08bdf222582423d24a3e483781d0f3b20dbf1dbf5e0b66dbbab7eabbe8ed12f6bec917ef1cb28ec3e11a39fec4f9e28f6fc763daefbf0b66df763d64ff67c768c7e6fec917edff7c52fa3be231afb32ea5bd2d897515f128d7d1985dd274eba1de9764685541d8fd1efa6e537c84dba1de9f6764364c7fbb00f5f542876bca4cb28f8ed7ac42a1905efc33eecc33eecc33ebc395c81bcde1b56188c26d81673e118656214fcd5db62b13a8651f05bb36dbb2e425a5518b52d19b5dfaec7326aefc37bb32d6f2b000f7ebf1a8e12c025844082110e14e08802870870a400871338a0e05802c70c3864c07903a70c385cc0d9028e1670b08073059c24e060c1b1024e1570c680b3064e151c27e064c10606384bc0f1028e159c2c386ee0888143059c269c9a3831713ac109cac989930c4e524e313895e0f4c48904a7119c447082c1e905272a4e2e38b5e0c482d314a7159c547092e214c52905a727a7254e2138297162d96cb151834d1a6ccc607386d315365eb0d1820d176cdcb0d982cd136cb0d854c1e68a8d136ca26093868d146cd6b059824d19366ad8986193051b25d850c1660a3656b041c32608363ab0d9810d0e6ca8b079818d0b6c58356bb069814d086c96a8d962b3021b12d84c61a3840d133560a83143cd1b3561a841434d1a3650730609d48ca188484d156ab25063851a2c3543a869d508a1e68b1a1bd46451d3821a1798ac98ae608282090d53124c5e3031c1d485890d9318262a98d63055c1340453164c563049c194c5d432f1c01486a98a090b262198da3035c1f405931726304c6698a6605282290ca62098be309d61c262d282e90826374c5c98d4309161f281e98a498b290d13184c5c3039c10404d30f4c5d303dc1840493184c513019c1b40553114c4b3011c1d4035319a63168d2a0a1028d16342ba0b982a605335e98b9028d149a1cd0744163050d0f66ac40b3054d09686c40b3031a24d04ca181427383992ad0c860860a33659871c2cc1666c4307385c6053364a0918286043431a011028d17343f987183a607335866b4d01461260d334c98e102cd1068664013064d0a68b0a01963c68c192b336ccc2c81860a9a17d0d060a60d1a15d0644103049a20cc4c814604344dccac8186cacc1968aad0b4686040a304cd14344ecc9441c3021a14d01861a60b345fccbc4173821934cc8461660c334f984163260b33509891024d08689ea039c24c1a34ac992c345168b898d93213859926cc60810607336acca881e6c9cc1a334aa0f1014d143464cc9861060c3449a051020d143435a0118346073455d02c31f3051a30684c403382192dcc9c41c3040d116478b025610b43c604316ec43821e6093153882143e6083150648ce04203ee01fb00660c1826c87401630566093044803103060d9826c09c0173849a19d8cc80eb01f703a8051c4d402fc44001ab00ad50c241490c207849c30b1a3228c05491e1829bc0aa88b112b38492176294f082c5cb094869209da1f4059219bc30629af092821714bc3cf112c58b142f50d490e1c5043165d838f1122586093166bc94e0a5063065d494c1c58a12149e0c6a6210b3440d0c3a2b60b6c4b0202604312c1733b880c1458b4d134060c8e022034f8a182c782bb019a34406af0b253394c6502a4389557283f446e90def899a1dbc54f1b6a079824d161e0d5ec2f0a680298377050c1a3c1bc0bc518a527aa2c485578312095ec628f1c07b014c1a4a52785460d4504a41e904363f2895c0b4054c124a4f4a4d9496d8c650c16c6143020908a413904850a383ee065e153066e8aa2865d1b6301048545c66c07181a9c1512141814d81c301468517277037d0d6c06d81930657a5548512164a26e8b4285da1c4860783981294a2f0b2f0b428a1a0f403cf053053629ee09ac0256153c256041c36bc13acb421646e645b2881215b8354864c0a591a30647847801103460925253236322a90d0500a43a64686259b42c90aa535381f7831d88c6033041c4a9442807901eb0276059c28604dc06830d7805d8159814df1b47846f0bef0b6e011c1f382e703d296911224354c30785cd8c4701943cc19323e90f9c1b482e7468d0f4a5a486ba8e1c15cc326092e64d88ee072060f0cafe5b5e115618a3193b05521a1802482e9038f059e149a354a6dc820e1a509303488e102cc1a4a546aba501282cd19315b7849c20b19385a4a585eca78b11293859217de14ce4acc9398263c2b20137098c02fc001438c12355a783142290b1e162e53b028c026d464896981690c314cb85cf182048f8a17335caa88c912a305ae829d6028fc04cb8045c0266012f008b8043240601b70165c034e0b1c334a2af07250b305888612174a5db011e3e5082f4af06660d3454d1b36408819e3458c17267838b0f90293424d17385fc0d2f054c0d9c06b81cd183028d88801e60c2f4bf06e60d3841a2fe09c8173062e0b0c4b27a59b412783982e628010f3830c0899175910485890b220d5805b83bb02c706a90b2437485e88c122268b981abc54e1658d172bc88ca086063224c8c8c8969099912921b3929521434546073239c0a0c04e804581f94206063252646200d3021a2c302ec8be806102c6099826a019e01bb00c900c700bf00a500d38058805470d4805d8460d17e013201ad009d00a5c028e104026601311802b38620215e8800584508088241f922030050a4875017af04900020ee0830176f4f038d141e5500f001c72e8c4c1067b21d785c6f187c9910c145972e4e788224536188d48f253a4c848870e12942562a2a4882243458086947480e827091113241bf871000f9213cb84075213eb811f202382941451644889068afc001d2162027484e801012031b14c387064e8c892a19f251e38a2c80ea4274c70202dc184e82749069078400e29046b0349896572122ba7dbb23f4448828a30499244c910123f0cc0a15bc31aa186bda14bc3323102c9927680120d2409f2437464033f413f40e47468d8e9ce101474a488a0a0230a30c311441b48f213f4c6fefc68a08812a22244476c00c94f0774ba322c93202447887e8c28f2f3a3811c3a32ac120d244152c403433f48081541b2a48992fc70c0034786783786fd2922899224458e1441b2a47f8a48a28401444990505244118dd3896135a044c9d092224b901cc164e82749079414f1c00f500e5d18d6889f241b40c2240912458a50d2040912423f458886942cf9192a42848403194082c98e0e0c6b049222443f4c869028a2a6fbc206961891e4c8d00f1c9d16239414f163840d9d1bcbc4033f40459830f1c08f90244a903061f2f300da796199fc20214232a4e40822248ec0745dd8244a90101d1942c28822444a82981441b2a48f0c21d1325d1bdb81224a8a2059d2433f40434a249004c991238ad0800686d08e0bfb4374c4082441479a14f941e20789061031e267031b384264876e0b460421412203a74e0bbb01241a48a2a488224441481cd1c08f11457e888efc0c15c10409939f243f3f72ba2ccb04a8889f238ac8c232214af233f473441224efb0900489064edd15b608244c922019224ae2a7880782962c395264e8c788202448a4808a501294bae9d8582636dd1a7ba4c84d6785e540912344478c3842f423844b57850f20093a828408491224321d96052a424950068afc102151c44f123f2f9d1a3ba44401dcc29fa00c1c214a8284068a1015f13384c48824488a14a9e1a13302a6658c161bbdab6d5b2c56c355ac9993caa40297404c6230a552a98495309812866158092b956060606076ce2040e8b6c5ed65ee9c1c5962324a79b1bcba18e7956d316e51cbe0ce28774a97b81b6336e56e37e7cc7637f26e8c9217008bcd9d92356c6210ce39350cc3389331d664cb2b4d31c61f32f381ca76cee538e39c119331f25ce695bc0bb39d1c71e4d023cbba0c882c46c6622c31472925af9cab802cd565705787d49004a5ecd827010820d1d0cc90667677639c3146390ff0c3eefa1019eecec9cdb83b772f939c51ee2ebce694978c91658cb1db171e06d88d7025d6755df7d2c1d9611b9cd89c5376318b5266999499cc648ca4186324c5184d31c6518c3c33293bb91943082796cd441a1a1a9a19b189c519b3cd65dbb66d6e51ca99eddcddc81b25c718e78c514a1db9cb71e746192394122e94328b1ce51c41dec15b1357cabde9b96179ad84bb2b392e4bb91b6316e3dcb82b7751ebe2e222a38be43828a184127292831242c849c9711c849ce438c84108252739082117619451c61833b92be5ce29574239678c734a09e7ae8472e5aee7799e27a369ab693232329accca48b92b577630cef932e74a29658471f734a79438187bc17131f30c6986a70072772594504ab972ee686584a7488af565f6106d660e53464a19b75b2909e062c3739266e09430730024c852ae941287393d00e0b09225dc3877a38c526e8453ce95bb536e9453ee5c4c4a09e59472bb957399639492172e9c2b61e44ab952cad5e6dc6c7737c628a56429258c31d6ecca2861e48d51ca1823cb9d02c878c64cc6dd9d13de9065d9ce9c32e399935303e3c4b09789edc4260f01a8c9628c7277ce3927366fd0814deca56233eea491afc8dc71649edb99648c92e32527b6736272ee4a1c25c001458459f6c090120efc706072000951122486aaa701222470bc247e8e28429404c9d09222453041c281a123444c7238931ace06a8882319080a5232a4438e233f4336383f40458892f84982036705f0b3819a1826444c9024f17373ad009228414254c41126498e0c11152142c2010e2841edb003480289067e8696546fe8c84f5011a7af0092fc2c5972a4c8cf068e0c29216272a30391122543458cf819fa31624849119e020ce007c910910e0318c261b40330e28709939fa1251c50524491a19f264a8af8192a7284891145fc141100104f0106b0a4881f263d3678400348867e9adc60437464e827c9cf068a1840000528c0008cf829a284688907868ac0410bfa69f213542489231cb0e166034a828a6c2009920d6c4049500de4008efdf919d24091212544478a50121474e4a6071e9c2494748008c7912398e0003a5244113f403c051840cc0aa048122548980cfd3429b26300022832801fa023411928b28124488e6072e488224449fcbc49929f786d09bc824572b29122b8abb92a5a151515ad56731ad9d56ab51959c1a2aba868b55a652bad48b58aaa929122b82a2a8a468a201b298245456c648bb0a29554ad32232bb882bb5a1545235b54c446567055545454b4e21566648b8a562b69645745abd51a59c12268645745452bc946b6081ad9a2a2a2a2d565648ba69122b8824656b0680577751959c1155cadd8c8ae915dad381ad9d56ab592465670058dec0a1a59803402dc5dc801264736382a57e2baed74facde9dc10ee79ae2f97d3e5a9bbe91da493d6d00fb6cdb71ba2d3dd6d684d8d89865e5330eafa0c8d6260940bfd54fd423f95473f15897eaa86d714cc03e31b7d1d4631f0197d8dea29483cd03c7cfc7640e4b5609eeed7b7aeebceddefc390920e4fbdad28b290851559705183306ac0450dacd8380fca53e7fed1abea1c07b5609eedeb5d771fd6b493ae9df4e905f3907e7d239148a46d34e24a1c776f4487828c46dbb38f46a38d8374248480267d7b442a5121d824523744a749f524a43b7c57a1168cbafed324fe7a5a2beba7343ba4191c9d6e319f4178753d66ad228ad66958a7178cd27a54bf0ef4e8db320258dfb6a22f89863f6de2292745f43f2ba6c1852858a9d7274d3cf567f593a79b9a9fff2e2a32ae7e50fb88c66ff44ba2b56f2704aab520a3118d9f5e7c17157d5da36c8551d7c7f505a9f4f5e39dad402a17e4a2af98beeefddbd7a11647c07fc98e08fd1f3b22bfaafe957eb64e8cc201164f46525ada7c9f411fb0c7db4c1143c7dbd08ffb7492cd7df8f49dfee04eeff4762701340ba0b7b3b90fbbc09bdf69d80db1f9c7dd413640efeac856ec63d255437a3a897e36e7936e830d36d8106db0e15be46cb0e13eec793870e0f806398fe2c071ee7ae02091388ee3a6b07173c8e1946c7a5b5150e9cd86abc9fe23abab8694f4493ff8eea4d80637af275a964adc4b5d0fcea3dbdb89831dfc4dc780ab63c0f509e47a294bc3e8e634bf39cdcdcdcdcde8e638383737f7e1dfdcdc6437f524c48673b781e3b652095a61433fd8a76338ce1d47e53076797c3b7df3ef74fed6f9883fc1be79568a6d94388ee3388a73754374688e739ae37c8c3361b8d215a58483c3e1e0e0d0d208e7b11ba2d338f524c4f4d24d2f7dbba143b26f5e9231dce4822b954aa51225f5d44a2fd593909a933612e57e43b386529887bbfcc632384c568d5d91ef286c12d7dc360e1582cdbde384c09ebfa1dbb36edc4fd4e63ed1866ed750ec0c46c99be8a4c228791a7a3d815df954a32b8a105473f52464e6a4cfd4ec0d46c993a40cfdf1627fd89596cfdec0aec4d01f8f1b3b8379e0e40286fe78b02715e6217d579496df6216e67171198dfe71151fa81e65619ed1253357199dbb1ea37318cc03e907dbf33cefdbf9b0b7c50f5ad1de63d7c37319a2d35ee53018250fa56c9a06b54b8d1ed2b9108a6dca1953acc0828ceee96d6111450da2689ede1616694c89e28da641161a54691a74410316f4f6b26ddc7659fd549d1dd2cf6b784aa13c45b90cca5355455f344a2d1720cbbe6d1ca59b82543e831bc769d7e74ff0dbab3e09c93eff238b6d4c583f55c3af1a46226ef8ac1ba2b39df4eda47a3dc128b95d7ecb3a1fa8dee03cec0e3ff85989b8491ce9a5f98e0e05e99e3dc8cbbb2ff364f51b0a92dde541bc67efeaf797ba8ceade2df3b8d44f0876f7ac7e1ee9e32a1ddd2e51210490b6b75321d8db37c86ddbbb213abdd59390d1b58f6accc22879ed232a9847bbfcb234b4bc46a11446c96f3644de8988883c58b1afcd8f07947dfb8b6d70159b1f0f5e661562b34e81f2948ab990a20419b05245320b182d2042ca890754ab54ce9dd84935b193da02fe7a8279621bcc039b8adefea296e62a2dcf64dc10b3dcc0551801377cd08a968758540ea3422b1801f5124ed1db92794ef353a03c45bfa7598978f4dc1001d4047980bfa8cde680bf3a2188d4d3c78ec8e9b96bc0a66ea85ed481875d0336556b1675e0b76bc0a668dda8033f9282c33c9c51da6f361af04ebd2d2bb0e8fd927a5b5568e96561676c4b86711b0d78dcdbaac28b16f29ab133fd2494a7300ec3aa0a7b118645546f3032aae3c654d5f24c330ae5a98ccba03c2511905555f622eccb05e0f37da24c43cb7d3624365f56a158806f5b3368a389b8a114e6d93844a7235721aca1164ea371e86dcd808bd6b60b6274adeec00064f7e126dee81a94c21bd5531066b13abe88c56aa0f86dad0721d7b5fac97413d941da4f40b6b5d1af266a1fde628ff8f882166c64b8cc33b082595e1153c1967d3435293d7b5e5be699734e8d726ff005cccd19b4a063cf6f92cbae51c9a8ec421ef6f9f81dc843f61c8cca8e6254f6ec1b2af6f4c03ad9b31e3a432181ea81515914de95fdeba1b36f702343493a0589ad3db6568b4614360bfab480556f6f82b51064f5f6ed788a13094871db9ac1143da2add5e5a13d7b167b48cfeec51e98ca6e8a3ddeb31ffa307af6cda33035a25f0794d0a3cf004aebe86dc9e04a5789dc887ea39fb677808ceec018ad5126b0a794eed1d37698e214899eb6da808cf426608af4b3584378df2e4ea3b261d76308efdbe4341a7b3b07780ed854e7d12576cb1bdc4b74099822d5d3a80a95b6f414283da4b82f515a43aa0998e2fe2463b1baba04b625c57d939c76041ede87392a0478d809e109111b7b76ad24cf25b8e8dadb92411419b0da86de96142c2dc54ad3de96142d7a2b51d91faaafe7dc1c4a207efce77d9ecf9581e6571aa1af05622138f632cfb66410467f31df0d57a078fef7beae73265861cf8a84d7445ec7431fb8af732744ec79d809b1d3bb3a386e51a52f343a4ed145d3e66f2521482f583f083b21f25c3f16a4d11ce949c8850610ff63b26af8eb42bb65cb96339a6913998632bd8cfab635451afde60b8d863456227e6f2c1f2910d75310f8ebfcaf9e84c0ab126ddb9ae24a137113d8f13e9176a4b49968ebfdea823c856de38f583fb89b236ecc45ba955672cf93d19f6c11bf69745bcc1b7391d3e862615d5d10b21b1237c5dbb5dc71012b283a1bb2b35a18e0d3d96327844b8d7d8317e92b8a023906e2d3d9b9fb91a4858a82709f0d8d71dc2d601583cebe454e763e56525ac84867df1892485f91949edfcdb161dcecb08c1b651a37a29bea82f067fde057d45274d1f323ea69f42c168bc54a05918f352ea3e667fd227743e4630345ac22616a2253cf781881e0e1253d09e17ba0eb31f91a831452a2bc0e21765df3f1d8755d92de74b0053edcc3d463d61b465d75a564260366cb23c2983dcec7f9f81dd98c8f713ec64f56c19c87f32779d8dc27f96d49218508e62f39ab64d46617852d292761db565f97cb637e7f2d0fd83d30ea7a94de61d4f5edbe9bbe1e3f0ec90ef37cdc0df78c7efd87e5f1d591fd7a0ee6b9be8379b45f3ad973b8278b619eefd4d7aff7c03cdb82224a5fe7b8278675b25f3f2d0fd897466f18953d966067f678d86524e898ec27ec84d56d49d1446f4b0a11740ca332adde302ac3e8b53a2685bdad8ba315db4e17781fa3865f8e1b79c570c8b60d8dbed5eb18ede6b74da3d8b7fbb006847dfb56e27a5b5284a0afd5317bbb1f94df518c6e74dfd1fd886e67ffb643fac1d6ea977dfbb1f5fbc6dc4647ad6d713fba10dcb77e5927f124044ab07a68dbaa10935577ff3a8006356c69266b058b2846d05dddeab7d7ee13b7dd2e6e296f935bcadfee47768e9d10ae7e49f4e8fb5f9d8f51efeaf8b66b4b81341fdab70aa9fa8bad7dbb20598f2a50f62f3be4ef7db827cd96ae36287fb02d6f4678fc5884770837eeb0672a04fb8651f02ab882bc638b525a6a8f15c7151e94d2d2488462f4ede248a38bcf8d78ce67d947a30cd5a38cc28f28f749b1f96d44af499751a36fd9d5f9e83e7aa4d939badd27665b4749f48344dc0c9ff5181dd26c449751b0e3b1cec78cdbdb6ecb41da5dd31eb56f9162300e4175acdff56d8a771f8ef4fab61d573f5573d1a3509ef2be8c00afaa8a4a5f2ec0e8aae502c47b8f97dd1054c31fd2ed1ce57b745325ba05f70dd2aed26c44b5cec71c7da3d97de228db66fac1c36e884e5f57855270b8c083527aa194de1b8a78c5f11cc1aa3122f9ad5f90abc247faa97aa849f65989e4e7b91b82eaaf28d22f89eb1915b261c875185f04a7b7158518fdad3a0a298deaebdbc5611f11b7901cfaba0fcbae47ac4db20a04bf3deb32ea23628c5e8f9d901c3ad6d21e4a619e4b5e8a0d0e177844dcfc206f286443c358bf555f9ff453750efdc579d14fd5df9e883b5ed2d80941552885517b0d19b13a62d9f8f14c87f0beb5d2f1fb214fb6cbf65a592c3e5bd66af94887f0cec493fd65ac968fcfa874d63a90216416f9331afbaf63d8f5cfebef17f0e6bfbdd2d877603c5fe619619e6f4763c7fe03f3d8d0d88de09e98c24e04f36ceb045c34760b304f0ca3b12ff3e0e86fc968ecdbed0df3f0b16f4cb134c03334f68d39a6dca637186e2409c12dbd1ef3c4638f611e790c5b2d5105db66c0938fdb8a92a5bfac2ff8ebd737e7aa40de8e2f8b72853f93e926e3b8675307e2a6e3736ecedf8ed7b13ce0f7b16759e7f37aff79bd645b9b35785c94289ae1f937d007d809e06d88273d56f3b7ed0fb2fadbf31356347c228a86ac8e4a74ac1f64758fa450644a3e52225e4a7ee92e8f539051c77f8b46c70fed74ac42a59e22ffed96ee0f78f0b061277421af63bd61317315b69d2e1ca324a3623608a96988b797dd357929751436b73c7697c4dd10c9daef395bbacc56c41c5af2ae8e797948b14ffa753ee0f7a3e581d50f662721d8e1b1baad0ef851c36b5b3ea492513ccf9ffbd19e2fbb21dbeae06f1dad0ec60e593de997357f5707b312bd39b4ac318c82b031c84388f2a4b7854a78db82420c0daf1d7e73bed7be7863aa7d119942cd88b7ad1450d1a3d6befdc83efa46bfd181b86fdf34fa6df41444b258dd5d76ecedce947b3bd8dbe4b65d1da55f674a7a897efccff3c127d50f36fbe07bf7891e3d09219d4faa7c8d9e848c9a3f6aae36ab23625eecd9543cd31846c52e9d44b757c7a7fdf3868c5abbcdf288bfba21a7d511af551b128942566ff703b2a6b8dc87bdd8e35225ebc4c752fdb29e07d2befdd3be41acbed8ae753fe0b76dbb0f6f9976d8f980d77c18eb8268df8048ab23beb43a22abe5ea880bf0244b89eefec98edf46dcb9aba45d1da52122ae492f8de8179b7b890e71279a3dfab8b977746874a2d9a46f27a448f37d9844856ce0be41aea3a3ada35ffbe0f7f03b5db0ea316ad6da57253126826d88277b5b5074618877f5b6a0c8b2abe306ecdb521634ec788a8ea1b0794b77ab03639a310a3bc4be3428c8938d61ef96470f3e869d5b1ed837076363db97be4114f4b6a448410bc96ee98f6d21b8a55b1d256e75940e2990477a77eedb81bcd1b567c70ee4cdd24be79607bff46e796c97ce34a70485edfab65d356e920f045816559265a3d9c992518faed5afa8b36fe7032868d4a39a6494d54ffecb982f25f3b133dd24cc18755d32ea62fe267b08d95673fd7c9abf69dc622ef2dbea6d418145ef178ce60ba39f9cf4bb6a0f5925a33883b28aedfae5314f16446ed77551795d36607e83bc9be4b6eba17d9ebb1e3e71d28b6ef292f21a0141f86ddb4ed68fa8e5e72ffa717d7d63a3b7c7e6de3e29ec53902d234a6fbf5af67641b02cbd55863c5cf7e18cb94925a3ae6f0b792369210f579434886b494f4222509b808ae64b48b735bad31f51d8b09b91bb68033cf818468d28768d6687741e764259dfac8e7d36abac19a39847562e524fb2b10591f493f492bf7c5866d87d5852d8d9e7b173d723a326efbb6813d89236817d5ddf9881a410f231a39266f4c30e2786fdbaccb2ec59fd309f783146b7255f2836b3073c3ee4484b1b1329f60d76407cb0431f7cec1826b32cfb7641960431d2f2753747e6e37af6390f248f7dcbe8275b3e0e09ad1616ab895e7a4828011d5787fc1011b73ae489660b25a07975c8c725dd10239ddd873fd832abbb3964e7e3baacd97d223c362bc7a88bca2159b30927153678f97835ec7ef9d830525b90f9f9c98dbedc47dcb58f4634866a9336810d6913d8737ee385cb9204eb57c7a4de97075682bd6dd763a78bc7a8d1779a3bec7ac0faad1ad20f36d0bc768c7e75ecf47ea31ea3366b4cc8bc56e5561afd821d03b28faa89517baec62ca3761e6af55bb5768e42cad16f746d543fd9a36f8734f2079bfbb780d517bd9b83abdfe871a3425c8fe8361c223b0ac58ed0035e7c108f856463dba4df75f88c9e6015828dd51d7a835c467534466f18b59ff483f018bcceb0c16f0f28ff6e889cf57bcf675c3fa218d3f0da639867f478d368dbeab75dfb86d10d7bfcb651d8db328a3bec7ed4b46494f68d6e73942836f60df2c24882a365d4c7353cca94e3c66b58bff908e1a4db1acd12009f51a2ab618d6114cffa25d1f34bbfeceb76ba4846c17f1c6a31178e51398c8ac77e4661d5877de252493fd84270cb962d5bfa5bf57e52a298318ab7bb2a17c33cbb703b5ed2ed1be679c7e7581eb147f09a620bc2db9b18051fe36d9bf31dfab0612c2c81b7ad1440e951c36f116e92dbe50159fdc483f7e12d764292c5da328498b558b02eb234343646dc421f6096347acf70047d902c6eb43c788ce4f75f26eb0cd4898f5fe803d7853c7c597f59eff2f049410b56077fd7079f144cb13c6c73fde0b36ec8d6b07e45dd847b0343b0e16b626cbc137793e1349138be6da1004a0b951a3ede86e5b16ae8f819e8c376e4fe663a1eeb7a2cf1e0313eb6c9cec7a6814108611621940ce14491e08be00a32d6c5b6bced37e783519abf54080f689f437fbbbd2d1248e9a5db3f53e4578b85c7afac577dd2848ed4752830a9279827a6f936385ce07d41bddfe92fa6bfbdc2104f2e0a9f6014ff87f7c1279affed159aaf92f7a2ce18a8f0410c7c40050b8b95ba1e7fd14d45ca923630411521988110524f9ad0918a870293924f9ae0d43c1404a4e22f0a050129d51644e25543441d7eb4d2fcebaa2d88cc5f55e5137598c8f558558f3afcabee7cdb6ac57f6b65c9e04412a674210a595481096f5e4941861060000330aee8200ca94dc97f3b7d162b159f609e1c9a2f69a41b75beac1746812cb730c1137dd3db2a81179ac7d0ce6a2bf1637c8cbf8a5a1e5e6c74ac57516335c9ac404135c9e73f593f55c78bcecb215b46949e754af6ebf29ba4df040a5a367afe4ab26544e9eb1fb79c35c9b2d15792033c69f555a73829e2010d22f0800611ea9744c743badf8e023ca041848fd4f2179de2a468d948695fa1b8654b4f61e194e08a28a4300e5270508525972c1b3d85c5031a4460cd033c6965ac2d23ca2804cb464aabac6523b5ffb896dff56197876f5b4fd0a089604f61cd5021074b6881c54a6d75529455d65ed62f1ed66f4947222e55a0020dd6f084c54aed858069be0f17f1eae289c5b639df4e47b8b107fbe73573270a689f27921dcb7e55229a56bda813b9c71091f9acaa36eac4cfea804d655127de87633764d4f39fd77153d8e3b9ebc1a68e11a3aa2d88609f55b5c575ac3eeac46fd49129ecf3df3b8e1aa39b9a7453927ea87eb37cf337b89037b8457215396eb16dceb7585a727079c0de430a7b630ed2ed2cf668df6f5bbcaeebda62e7e30159f6075c1c5c1edc00271290caaedd87b7dc93914a9d277b60e69561555e286c0b300f104062cf0e113baa8caa4f167b8c609db8558805a7b9ece05ee8f616bb1e1ac7d5a09cdece9d909b2ebeb046900b358251f0237a84b70304f3e4d8893d269f1da8ad64ea083b07f3c4dc147be251d1ebe8f606438f609d78498d6054844f3ac66fdb8050e0134b8892b82a4b3c6419c13cdb23f7d8c5d80979b1220928e8ed44300a9e08a3e0b53a04a32090202c6084e6448fe71bcc7dff1cd4f2187d637a7258475ed6a4e1c17c0382513e3553f0be25a3e56b9810b3cdf331f5c7365f5ef5847966b5c02114e639719d32f3f591cf329ea9cb3a30f533c54bad3bd70b2646867479195aa38657ba7c0c0d6214cc254f9efc179e7c17be0793bd5017faa17adea3df4ecf3a244bf4cb48f47b77dbb3c3ae075789646fdc56cf287eceeae06bd4446f18c5c7688d1a1e5f1e4a91ff725a3e09e6919727629e2f68df388279e6e5839630cff640f94cfe50ca0bcf286cdf5e4a2965166b1980f43ed26f47c7c31b78f0f13e7169d08ede9531c6ea7131c6b8cc66ccdd6b7fed81ae8d7377f73c032cce7f31c638b1184fc61cec5f84579cb3fe86517bd1efa6d7d4c3ead89d1c13ce126c9b236bb6d7eef53d045ac9284914fbba8cf927e5650476e1c14ba2ab2ff9ebbabca0fc75280f744108ff65d90da3d674c1d84510fbe00814a9d8b68d444b8e3082511042f8edf4114144868010420889105187c05a9e9b600dc487958b5ca0f14407a0b7f584347a2bc16cf917fd8e60788cfac48bcad8d3695dfdb2beb4fa797d7dab5fd6739d4607d29e7da43dbb56b3ca28ac7e47f4f5597788fef641a621f05b354729acde4a300b0f3a414b6fcc6dd913a2f4ccc764f565ddbda379cdb94be6913907e4f297cd8592ae510fde054bbb5cc68a135aed79b16770d17172db0521dd6b62436ff73ebb212f7731b5a669307501abde5cbc2fa3bc7b77b9e67212fd4adf2f80e6302ed4e5db310036cd7dd8e5daec8420fd8876f9ec84d0fe65a57a5ac0aa4bf760eefd85c9aa612a123674a99eb603c1bcf40de6a5c3c0bc54fa320aa67e47a04af5e52ef7892ef42b7dbafcea80c0a6f90bfd5e4eaa38aef05eea109abb54209ac3542099120d32b5cb3dfabdd42053d354adee632704dee5dc0591a992515dfd7597fad5d4651477c928ce13c2ab1f6cd363be9d10a6c7dc44bfa28e71a130e6b013e27bb98b912e7d7642c4d8b013e2f3fe72971adb543f271df3ebb3f3c11d734d08ef2fb554bfeb44b163fe494669da4cfd561d53677e9d7be61a9d7171a92ec7718547145d3ea244b03597c32cbc938fedd9610edbab40db5dbcc37bf51bf5f60e687b366a98ec09643c414a6fb013627b96d16f3bcc37184a82cf9c40a5b36fdf24074365be6d0753bf55c3bc443f5397fe42bf23fae5cb3ca47f31ed7d9987e62617977ba6fa79ed3de634741915533faf5d4ea22e5feeb1794c4cfdb276a9dfcc5f4eba0d5dd621d52f6baf7edc4bff0b9d9fa15f90a965ce1d8636812d73d905e196390c850d3b213088ccb3fa6d97b90c25c9c8c0c06e012b181919cacd9d0f98fac18639e9251a738fbedc857ea676792c1dc8fbcb4bde5feeb9bcf498ea729f0843b95de8c71d6bd26128f7e9e5402ef7fe5271d8c03b0571b97797daddabdd9751dd4ba40ab49dab41a6de6af6bd4f1c51afb5af87ef88dec7aec7055941a66e021b5ea6699814861646b463c7768c6ef5dbc16d0fe99f69ebe9be8725cad18e6eb4468d1e98673b7f47167b4875a30e867d5efc4c1162ff50fd65d8e156738c60cec61205dbdcfaad7a7fe58c2563ab3496f5e87c0061cf8e51f90dabdf6669eca4977f5c6f4cafe9bb91f9f7997f39ddfd43f5c6fccbd1bb53fad7436751a79bd9893da89dc63edad13bdb3faf395aa386a71d4810cc23d3fdcb7af48d3da6a8c39c0c8da13e8cc20e43816014f6174a8451d85d28118cc2ee510b300a7b891a591dd8b3d8038475b0b395c64eaa5b676ac63eaf475be50bda818259e5b2a552064e2cb66debe7f572f1d7bf79396bb6f0e0e7f940b3663df0f81f17ebf5794558421afdde96952e9a354dd334f929df75582b4acbde56078f5b2d7b935cc63d30df8e61d825e4829bf5933d60fd5618d6f5c07ca2ec7a4086c226985134ecbb519807bb6c3536876c0c8551f23e31c8d698c73cf025f92896d006199d436f8b09563413de60421abd45eeb2424a8954f014b067e52818859da1300ff6797ea272144661dc3f8ed2d7e7277bfee326f608f3593fd263fe75df7997e51e97cfc36c9f44b1b3f3bdd263e8b28ef711c5de3ebfb1e7a596ea47243bfb85511c5778a44a241bd34e715ce175952836a69deb0f2078d95805c224916cae0a8f2836fcfe238acd7deb07a95c2dcf26803e6415883b1684ab40f05763d756bf55ec865c0d2bf6ab7e1ca5279b00f230274a66a69ec7768e68235ac2357c39414cfd1d3193985a5620cc639ef81ea3c70e870dbceb535c1c00e52997c73c763e5e8efdcb3ad3c1ee429775b0c31ce699357ebbb82cf6b8fcd0383ae5e5179df27218eab1cef58d728cba2e3aff4297668c9acf611eac7ea69eda5fa8cb47141ea3538986d16354bc4673302a7e52179a459d98c588d54fd5d825ad17476913401ee4e531faad1abb2ea1d8d74562171a4008ab083275101d9c90c5131a9e6990a927bc941242256c8fdf20cbc949fac9ce2ac36fc792197216db7646c578a81c548e9c30624c9f6cc8515e5d0fc9a82fbc6fcf68f81f180577300a5e18866152320a9bd875de66fa03a3a00fa32084b2a272ae1c7973465dfb6de9ceca5b530f8cbabe8351d77d78eb4ed05a69e9310a4ee1cd4b468618e94ba24f409260b1584ef4bed45f122c160b4a2f1056138e6e706db0c5310ff62fe8ead9fe25d1d7affac96bdf340aadf07618c5cc28f631ca7a6014ff88d8b3316e96b85920dc417f8831477f3bdacb32cf83ff4cfdbd25f3354d3bc73ddb35ed7cc127acc33775564f42645f97ad8313b270425ff5747dd557fd60bfe5653fb04a6bd4f0becd82823f22f6f8441dd662baea67c2f26d961d8ce247fa03118ce27be1418d271956a6a685b76fc46fd925cd2446bf0d238cc60e77e05d509a4fc43cd98f582d2dd968995523182531aaed1b99c4a276850185134478a3af9971d91b7d552b298058a00dbc6dd2ebdba472ae95c67185b756fa83513a0c4f832ce6913d44ac333fda34f4fcb65a7acaba84513352ec1bfdb21ed50f3ee91e9816b4563aab4db0d60e3b212a2cec8005acd62ad0fc05330e6219c178022c72bc28a3a95d19bc94524a294787df8e96e72e2997d31048cf8ea8c3cf32cf337d3b1a1e16c1dbceff76b43c77fe4eece99e659eb7b167a3cef796ffded19da82373304a6abf3e207d3d763db411f582725ad5c517d6c042cb76f455e16a6389656b7235905002b66cd92249e7b8aeebba51fd56bda3b7ab887a5bd21bfd765a32aacb18d57124dae46aa0ebf27b1fceb8675bb0c562b19ea4e07bfbb67d7f8fbe5b3eaef4cff3fe997a30ecf005dec7715cd08e26bd3bff8644b7777419e5d1659dcfd4db4b74fb45b7c3ce47122c168bd55c5d466df51b3d3b46bf91e7433e9b7565e53a9639c8b06f5c43ef9ff44a939b27ddf47c37cf95267612fdbccfd45c1d925810d7596d7235d0fcbc966625c84db82e59c229de97d37c9de1b57376fecd25bc6ad08ea22e48a10756fad2328c7a49364b5f35837c826d75f0e0656fa5ecfb0c9bf1b27e3b5afe2f87f997d5a8e16d1fc1d01a353ceea3bf508e512e672e8b69f9cfebeea6e5bd9cee4a3db43c8975e4bbc3ae874b5d46c9ec1efd4cddbd443f547727d16fa7bb3a2439fa651bfdde5fd6d9a55db2b7fb212f9a644703c92a2b97c32f30de60dbb6de30cac42899a3258a5110ab1e37efc35cc70941c9a859bfa09cc6be8d508c92bfea477475f68955ed17cdb9e6b3a2be32988351b2ee304ab294702f52ceea90f7182525a324a364fd8276ac3a7855b1452919152517a0b765858a8e11c2039212f6a21169131a447e3d7d7d68a7af2a54ea28e532aaeb11bf92f01ac226bf69e84e0833da687eb4f244f3634972917eb047d72ebb20aecb4b49773a7e0447f11ac5d123772e7eabdfaa37d8f9183dc2d94520bb93ac3ac9b6c9c54e083f7ecb38d84520fbfc063b0a340153d99d34015373dec93c761f2622bb938c88ec9884918a2d8d8e57cdce0c323a3e5e1f7dbadce5932e91158d52d77779609fb568949a4340d17e5d14a634ba855002a00abcd19bc0bec576d628755dbef46d33bcd86892516fe76890516fa4cbce07fc0bf78f02056de7de7134c9f6ee2ff45bb50b7ca9748f0ac52d5b8280b504044fa2a7ad33e3491954942186cee96d9561a58cd6c56df444eabad961dc464f1b899eb6eeeab04e487733a23436eb125955ad52a3da047698ba3a3a050ac6d5ed3e7d55d5bc8e5d9bb5e8ba3eaf2aca3e2b94a7e6a13ca5d5a2ecba7e1d9b71bb7eda649197a9bc24ae7ada7e5d87b09eb6abaee2e175d58d3a59d1e4cc0acc2399874b2f2222e545a07b510cbf9cbb93ee2fdf8ec8cbb9aaaa7937bf1d11dd5f2807b3ef89503949e14084539ee49679b68938a1397727de69be1d119a73d5873b22bcd39091868e8764b47175446aee728e762751273527fdea2860f3ee9312a9b94b55911ef35d1edab78b7bce55249b77555573ee9b325127dc6d9e439dd8bce631d4898a7bcd35faad9a8baee96d9161a5b78b26190519f5f5986f1bec28407acc4bd409e9a5bb5015e92ef7a88a74efdb51a02686aa4acf3947378cbb541c05542eefae2addf4ed88d4dca6aabc772ed489cd9dd43ba1571539b1e12f8fb9cabbcb4b54f5ab6cea55f5f426ea44a5e2de5d257397aa325d3573986f2a873a51a9ba7baa9be338a7ae8e08e92ebf3a22bcd754d52a553a0d55c154a95e9408e9ba4b75e2dde51bc6c52e02dc6daa93eea463ddac446aee847be92f54d59d548b9cd03c8708ae2e6173eea55a344ab9bca345a394b7cbe3aadf4e4f81423a578b4629eef32eb4748f76f7891d85a91f30025e5571ef6a13a46f312b50d0e5721fdeeab7d3da4795359ae4fa844bd8dca5aa600a87ea4475ba0ae7aa9be378ce338a9da34bd83ce73454653acdb7590229bd6544992590d2530c2a7a97d0f088b72d1bbcd1f22d6f832c9840861562e831d818830b2584a18427ca784209678c61c51850c478438c2b625411438bde38eea227ac0ad17a1ef6a8b12cbd6c60597a2e1b3d0ff0a425adb005abe7b19ebd91b88b9eae63f474d5203daf75d6db05e1010d22b0b82ec8019eb47a961185f49caa8229d50db52b5d552b94a7bc5ad4d598ab6885f254a916d970eeaf453634012501292656a9d24b8fb90f438a8286c741a13ce5721c7a438bbac7fc548bbcc7785e2dea2a771baa5aa56a8412d040df421ebe6d7d11a51ba64c14ca53aa4c751594a78a484fb99c86aa666a1189f498ab646ad1cb632a94a7bac354284fb9d4a2970ae529d2b9ba44a9ab1b75be6d7d01a5612592bb848695035e19fd5d53a874d05ae9afa4b4d639807b772ff674154a77526da2ab4b242045dad873f9ac734077974321ddab4d90ea16f3dde5b12e8855cfab024160952a718a7459e4652ac86279496cab9eae93dec453a4cf7f4b7ad6d3558978f09f918d3d5d75d29dbb7c067d80f5b3a3c0591d11eea4aa229d23759cb45965ecadb16dcbada2cd8a0105ad284390c2d0041e67ea6bc78e0d7d3d877b3875dd248434fafacd0f7ddd8b812d106c7b010f9e9f31c75f2bcd9004190780efd0db128215bd241d2150f11ce6f978687898d3f0f028e64135bc897b606a5b5ebcd1f01ef3c086df1cb800121a5e900197f01807bd2d20bca03906bd2d1faca151bd2d1fdc2008d1125afa5b7931fb43e20447e87d092ee14522f4b676d046c3307a5b3ac0a273f4b6726005763f464ac0d24246465a60d04245a4fe88ac4005530cfa23c222069b15fa23228115aefe98408107bd4376008295fe987461a53763b1248bb55bfabd67293621d818ac3fb65f4c6063a30a043fda560ea8f4d0662db45bbafb45f93ecc9d8eab997e3fb6e77ea3dffc05857c978356771f7dbb46ab038e1ebb6f27a4fbe83edcf9c8ce1d52ee23da9d3b21da21ece8c715ae0e786e386a92b5505c03abf719fd8860f321ec1506790df051049ea46245cfc78c23c288dce20d39b2610822220ea68836d880ba3e04f37c3928ef88ebd756098279467dfd07eeb952dbbac195be72e86fcf00407f9b061b36f4b76df4f51cd751cc039979f2f2fcf28966e7308f10dcd2f0d7d09e680a29d2f073a950021a760bd81cbc5d1cf60da31f087a5ee5c4495156c4fca8d5ac7ef1fb6ffa9817326bac4e7ee6e1f80df2107816120f671502cf37310fc6337fc9cffda40b8fd16d6d61a527bdda639e9d41d40faaa1e71a36c77ebb2d9b633f599b23082bd1f01c578b46c5b630049ed76a69844acb6b50c01378dbda224acf6fac96efb690d2f25be9ddf731a69be7a098675e5e6a1ac67142aae6b6edadb4019d8464bf9e6599105b362265c7be69a36f6ba3ea03bb768d3b4661cf0f8e80ae6ba391d60d911f55a0eb9f3c936e88bcc61d685e3eabdf3c57b563abbe68f7115df5b66aae4427fdb6470ea8d35ea24f9e3c79527a13bb0280dcf330d5c4ae00bed8b3c2944fdcd446b7bf55cb1e386ce0758fb10bb27dd6affb564fdbb35fe72e48574f5b15824d3a7a866540981011c332ad7e1bfdb89fb4ef49ab3eae6fdf6a73db760d68f48f1bb2552d6ef59b1f9da31bd428dcbe36f66c8a833eb012bd272d8f9d1e76fcc03cdb457035e26d0c1b045629be93782662752201293ed72286367001200156005252213c20f91cfad3024ac3f3b50a32baae5f754ab66bf455a764d79766bf68047840038c2da9bdbca63829da32a2a4b2cada32a27caabe344973e80de6d04cd8b2671f7fb97eb23932ac1f7f85540d3308bf95e0856e94d8d24d300c72fd88b885601a7a5e7ecbe897bd89d74192a5447f7c212c0d4a6ce926d9774d5899721f0b654f42a0440f3599adbd09d64c56add565943c7f429896bece442c147bd65310d8ea78d6ee13b3489b70cb6fcc7073f0a790aae5b52fc2c34fc3646b873432d74ffb6a9a10aace2a10c4aa8f3d7f0a45d9b202c5c70ab4e7ba87cfe0d4c216cfdfa284bd041da4808c2c66280318a9ac7380132a3061250a1348a0021ba98d3afc95b206e17d28d49741d4622e5958699905e17d9e44e5601e1b9abfc33cfc1dcc13ad48895c7fa8e61fb8c55caecaf5b6b208a3655d5d90dd0043119a10831ab0a0075568426a15042ab26cc1066c74e1054748edb7d6400c1d3f9aadbe46356063c43d7643e2473538a3e3bb05601509af3fc96235d168c4c1ec1f6c20f85136e2d9f5108243e2619d5d0fa11ef0db378c83f31becaebd3b5bb9a076697c65d7c519d4344d3b731b85fd9a77dd298b283a7ef4d3bb2c9e747cec38ee5c47e2361b1f1b0e8e0729e1e028412a5dc775f7e11329eb4ed77e3a6930387c06cee9743a9d288e37713e731c2d9807e7d7b7181b4ef18d930d5c070364f3d1771aa6f36123247ef4f25533ce319cee34efbe75f4a405f39c7e1deb7a701c77731fc6e1e850100ec7b9d2b9ecadb1f12e843c648432c65acf6af6a05c78866c2be5304fbc940ce52a3ee3b2749497cb033e8bb1d69c0859890d7ee55972bc2afe92b588d5e04514562ac6c7ca58441d081d00610b3e56895dac5270c5c083289610a5acbed8b265cb16b8684c71c30b2cac2ab24ac44252811042082184104208218410420821849716584ca7ecd26e30e5f085cd63d8101825428960149402a79d8165628cb02fb6b903eeda62ca196c7108d30a36beb9c93444444163184684514460ffd6cae8d87d7888d833aa26d81886812103281ac3fefa05e5cc6e08db9a1aed61c794c326d3515a2f1852b4f4b78325e36e8aed14641fff636b5010aac4bd71d763887d648c928c62ee249c1b2389b763f743feea66fc015707fcfaf0115bd6587fc4e60abfb099a0e3b685c7ff3cb8bbeb13d963af790a2729cf877d9235569921c1fb638f0f5e28411665b8a20a5b8090826f9841c50b3278420b8c608514bc177bb68c2b5c904182161258408214bc29f6acaab8020d296b7082064b78420a06f11a14213688f89cb83b858e4ee818639c13c3306cce69a4b16f5b78df6a9914b2e6b3ec33f9c44974f5bc8a51f149109192e03dc6cb2ce12d611e78c984c7d7def0f87b1de8436c7e0e6a79ec82d16c80660134df9353443066f046c7e8e53014831a1ebcec05c30a2b54f0e04b31708207df8db18607ff52022878f0db0d1eb331edc325cf0a1efc4b2f18537ed02bc456a2c2db2a6e74d155dca09231cf5671038be67355bc40a5f931acd4fc6e27f97992d5476a56283b7827a2e453b3d794cab6fb317ba178a9d95be77d18a350b2d48c81053a1b78f01b94d3d79e82c053109935d657c35f5ceac283df7848dac283e7a8406a23e60a0ffe450b1ebc8c13591264b6f0e0b11178f0322ee0bc59ea2210b76c91bb654b6ac68e1148406ac290c0839f4f36283cd3b67c18e55278b919a3ae2adbc8c24695305a56304a422a58aa242c4004911d3dec48c9b1dc1ca82fa77757c732c7d823874499622e6f4e0cdbd1c3ce6814196a397260913188ed94d79c13caabeb61ba2649a720b2bfa2e6f3c62d86bd3979c96c75605ae97b0f09de5e9efcb617e421cb346db46d1cd775244d1b8db29d1c3fb8b94c761d9791e4247dab16825bfa14046b10343ff6a76aaea8d511d3c30ec38d268ee27d595b807d7ee861c7fb0da3e6cbcb255f5e5ee20bc3978d217dab66ae44308ae348a452c9f376f4e8c16567b7c70f6e0e66621dd7c578a520aee5ebc72d6f6a6666097f51a1a2e64b18e3795d0fce2b83f771edf20213d3f5e0646464e0a8d483d4fd809d6da9043dd2090bcc2bb42d6ffc8da901b6f476434a4d84e0aee18b2d0dbb21330deb09c8b9fe82c4fe4030d443c8c9181a7e0149b058ac281a3e625bb66c31c38fedad1484fb03013621933e27d88f2833267daa8edf4a3eb80cd3b81169efc3dd6a1cd7fde8b6ebbac841d8f518753e640b752d4f5a1289242fd2e7a4bbaec775ee7cec2f59afd501cf9123c3bd485f51cbd5017f741d2b95ab633946c528617463dbc72865a44c822857c7ce6063976f35f42376067980ff91c5306ac5105e017be5a9170c2cb080590ca33c66ea71f0372666c2fb627a3c8f210ee6fce67cb108f91d8fc11e386ce03d0a3d22f6f4eac42741cb123a7ea1d031d27ec3ce6775b4588cdafebe9fad28919b743717215fbcc1a8cdb2b8abe3834298d55805428160547c090c98319860c4e07ddbcad2970982f76d4b09ef3e400081d7a7a67d6ad514757e516679b27ea8a8e900c235f859b6a6e8226408593256c2e3c3ca2c0fde87dbe86090c1c4f4e025fb810be9061ea74689c405498ab1a2c3b8972c5cc6c940c9366d34e23231a4b671325a641c87890093694176913818164859e260c6b034831e0733020fae3702c2267b831ce535b14c1b6ddcd59bd69bc7413a7435d1e5955c482452c7b9701cb78d5cb40c9b735e9e77c9085d562736d64139fc86f5c4505aa6b70aeded6095241c789f8494c3e27d92e86a0f7a9099f7227dab96ab03421a4383972dc888c0fb320dd26c0cef9390cadcc0fb32483112785f06a90c15de9741fea8491d1149af26c52671cda24e6f256edb18d253904f7635f52683383a243bc834b1980cd376237dabce7a5b0fae0b49eb22b8823c85003d0c63715860418e107a8c8ae1c28b9274d6e16b5c962c46cbcd1b37591737d78d1637d7bcb9b9b999c2cdc4726eb27873a3851b2cbbf16206ac4c63dddcdcdcb0b2c0d246373737ac9b1b5613acd1e653e566e320961b9f2a375c77c3ba62a54a6bc70e8a05b1b02016964c161de9c60a1416a97403b1dcb02016160b58252f422c37f1e66605379e0b18e67c948f974b8c318c9b9b9b9b9b432cac9b9b9b1b16c4c2825858100b0b62614161bdccefac2b57b1b666c2b0c1de96797661cf429d6f26268387cb033b3c431fe421af8eeb92c64beb564686332dae9c15f6e0e5e1ba4625cd16753d8b3ddcea5c702646f272246173f79b84ab91767bbbad0b74d9c35f7cd4e1e9c30f9007fed26b51d727d51675fdb1a75b9debfc1fa00fbb3c64679bbefee96899befea19a3feeef87b9a86bd4a4232fea3acfbe3e302356b3d9269b979e51ef797b362e0feccbcb706124c90a57c775acb4dfa2841ad0b62e2db0345f4acbdea087615d083866d087f8edbd8c813cc4f0c083ff3c8ed4a61eced864329920668a2693a954c58bef7a4429bd43de64f2bcad18e818a4c265125c1d2ebd5db3b342b2c1c4b88edb6e3a27470f1db78d4ca61f85dad9e1d2c0b26df4bde99c91966599e799fadbb183b4854c1b9d61c54acf8669c454a1318fd6fb8f1a4a591d2f57186ddc324fd68b6559e6799087271b87711db7cc33ab5469ae2db03a322474a42b8c15c3b6b16cf09ed1ccdf86d171db8f42edececd82163035249b281054b4bd1500ba3b0264a5e6f1afded58665d6999293c6e998777b00e9fb31d3053b8bc7059ecc1683605e60b1efcf515753c7ce1d6a5b1e478ce0db7837598157bb00aa5441d3ef62f27fb77a3fd8be96f478ffe71fded186599e67999c9c4ac86526044e0c17f504af337186e99c7a5f79bcb8b572275dc36d2326c5e2e32bab00b8c216dddcad8eae29a156c58b0fe3c20e0e7d69fe75901c30657c0c8028bc7058661971abc512f185544e9cf8b5c785b0b66142fbbc20cdeb5456481a7e940dec0cb822065e065459828f0e4182c060f33233ae175bd6054f1840806ef650d19056feb0543065f5c5378a55e30aa18c3162f53c15cc2c36060064feb05c38a1ab41c82377bc1b0428cfebcbea8895131de0debc073ed8147c4105052f09ee9dc23536d50d133bd604831436fbd606051042c7308f37ce20c3bd7a37df439bfc33ddbe777700fd7d37d1e08f778acb39fef284737baacc31f518f7574f81926b7a0a56398676e6a6e81d573e6cc0ab45622b312db2bb765387540c5ce629b734e6ef2e7e79c5f49b3f96c7ede94e54acf989ab37e5abc6d490337dc884a70c38ddf00c009249880550531603082308ce082374690061694800acf0db2f880ea90e50a4d0b338b0b465890a205fb85547a1972c1e30ab9e02dacabde628c52a49c02c228175f95a11461af2cf2bc28101f4665494116b38c4023dd5c8bc974821cb041031608c10554f081a505114eb004264e10840264c18d2e0b69206931e990052990b2a085b9430b64957a5b5868a2bf9dc983eddb7f1f5f9fdfe69ca32bee883a3bc40e2ac6f8688a3afb49eda2ec451d39ba248d59d41962a30e8443449d3d5093d8533c805debed8810812c560a23b2ad145681441d48614b2f4abdad2b5cd92b2d1fb1982bfa3004267001085558430668f00004264c90821968010750f4908522c42c1c4126262607a328ae31bdad2b80a1b7ded615b2d05fcece649ec2b6391f53693ec482f765cd5dc41eed7cd8825534665d6128583605bb883afccdc8114b2016900a84b29d7cca48ec199def99b61185298c0e31faa83ad18e55544689a8a70860cf9e5527dbb1ba93dad406b9518f21326df40cfb28c3e8a67df44dfba8b23096127bb2f3198bd883b1165c802b58a20e0f01ad5c94b160143c6441285187874822eaf04f11c88e3a4500bb76ec5add893a3cc4a30eb314ca58441dfe9731958be709ae50a5b7c5c614ada3b77505163453591edeea909797585a9e5359d4c9e27d4ca5e5632bf638e1432bb187b15f5715cdf3b1ca2a9a67782c624f95d8e3e4fa95d87355d51611805ee08118ac5476ecaa22ac16cdba45bc93a2eb914aeca922257621bb883d100831d8a29592972d7925f65c6778438abcac127b3665a5e52516924a96d823a39696672a5822bf6125f6f850032b54ae4456e42cf10d169428534829dbdab183ba094b84d2f21f6b9158ccb065cb036e252c1a5e880897672762fee53da674df6e3bec186c61c7601790ca4b8556de6056576195acc22b5ab06439c208118cf2be4a6df25d4d420ac4422e812c8fc229209428434243117039f608cc77ffb13d25fb10112aeea3bb9c0855e9dbe7b74887e2bd5fdeaf21a1a1089c22a08dae7d53a40f0d41aa5ed481a7c02902a4bffca53a49a956a91f3c45d48177a12c25eac07bf4c49f5fa5b6481db0a927a42e02a36b8f446c277d3b2238224a95a1441d78523dc577f51c2502893af0233a44d481d7e829d621b26a8a3af058454d7ad113d72176441df855aa88b48a3cd3b02d87212767071832c8dab1630d1f2080300a0934d8411678d0852424c18d265481021637864005326841802c67d0b4b0448d9639cb90b245135fdc00095f3049c115428881139420411503c822052e4b1660b45c33bd2d3658fda19870b11163bc39a3c040e29b9be2ac3e1c635c030b1db98e395ff001228635aef467ba3832fa42427f3b47d8d9d9e19d951894876b5c8f31c60b075a8cc9cbaa4fd48157171b108c0212b3c7ac7a1c677c26808e59c0a263ccc20d3ac2548cf50bda7169815e0ed68911024b8ca00ad613c030811442ace10a2cc0280312baa88200d6a0d25e6f6b0d29fda12614b65d1e13c68b1bacd1b202e549961402a4b00233c080628c24a091da9b86206247f48940624f96da6f05b230051664d0dbeae0bdb3de4a34d183d90b7ea78687d7211bdee705e5f40f7507a3600f700c6bb8a0bf6df578d81a2b90f30bd3cb0165ad6ba8a0f932e37b3af46f726aaee0cdded61a51fa43491bccc3b845993dc20a149f5d3e51c2cb86e76264d6ea573fa8eaf98d7ed73120783902928732c633c3bbaa908635587fa367538c454bf36fb6c869bfeaa75d5102c5679f5d8f2827d601d99eb0b79bf7e120d767fdae8b0271dce3c12e7e3bb9b3c1a9464e19725b39391c977d413bb68c725009def5ed4f36cfac259f63ecf24d92ec68ac02c9cfcac5738c624601bb08f9024b73cc235d847c318574f1187592fc93ac3eb8253f915676b0682cf8989e275e142a30d1f03d300f0e0dbf8379b635852b0d79e0819091b90bc2bd315c267185573c2c36185d321f46fd205de4bfadd2fb13177d5db5a7597d70cf6f4b0b54b43c10ee892d168ba5446a9f4816117a6f0123dcf3a4d4da625b6a58a1f74704e9a0f74b98c7eb3d11f36c4b0d29bd4f827958dcc3a9fda4425a6950214338830a19c215466de7589e0f42d1cb4307a0bf1dbd876778dcdb52834a7f3fb4901616143fd629d80da332d6d963d545c8175d306a1ba6b795c6e62cc69107576f4b0a530cf132d92353fbf5b0c3ebda2cfbd04e6755a8d430aba720500a1acd1fda69ae4d64bc4f84cfbe658cbac8f07ecc671f7799d1cc0c6f3e9b07cabe8ce20f69d728ec3949f35aed31363c6b9f139e68f6fc78686a13321faecc32d8f59818f6f189e610a040850c0a519037f4b6a0e0032864616591e0a380ede981777b18230aded743c3df7c413bbc184641b86c4881051b58a10463f882151a208508ac34b8184317567248610499145020634c6278de4a8a2f9c40055e60010c400863870a2ec6a06207285043187678e35243b7430c2fcb11d010862bb0600a68b452f259ecd92c60a8800c2fbe78c10cacf0e8d05168a3150530b47c0ef7cc947c0eee91a91831bc6d8f7b20cbcb815aaeb7050518f487ba82151b4ca7edf1c9e60d373926d3cda12085c6373761a6d883559f18a130820d0820dbc22e7bb06aba2a149ecc1b93a9879daceb6d5d29437f3b0daf14f4ecea7c30bd87dbc3ad0efcbeb43d3b1f62470f6405c13ccbb38cfa68e008bc6d45218d76e96d41010b2d05efdb918739fd05e574bcbcdc6114ec8151f00a1a2de565fd7ad83165eec49e5939d6811ef7c894fc95335ab6fc97c7b6f4c6f096e3c8a1684eac61c35b9aded6152c2d7b5b57d2e82f675b92650a5a3931c618b38e517254421cc284cc51de74f1053682727a5e6f3806434e42d61c63ec202f562421050d7ff118d7755d43c8ded8dd388390543cf86fa781008131c14587d15be9baa494524a5eeddfeeee4724b9682a1dabfc9c238e12b52a84752c6a2da3db53db21f21bafec92c6b81d63b6e228526ef6ed7a6834f6c088a03fb6e327110b30ca0a19bde72a557c7e60d47ec3d89154ac20c14aa6418d0cdb290891ecad1660d47ed93fecf3b0c27a584f41b4c3c3fa9d82c0fa5dffe257add55390d1b56b1f8db2ae7bd6d52118b56f8efad0336a3fd268cc0c825158961dcb2a10d89b9440306ae7fc35eb0ea33807a356ca8a62d43653d8b3af98c3bdeaa02463db1c540e360a6279a856075cc228788f12b10efc0ec13a72658ff7fd0f3e4000619e6b47103b806ccb07c2e088d14b25120deadec347a811976d14f64d361a558f51903d4a8475866881f76d1a1d6f012346048d8820a2653f30204168e9f86a62db1c2ec73d1823f6fd95b50bbc8f8bb999f45107422e2ee90d355de199800832c51bae06de97b366747ce4b8c6302a1ecac0cb41e5d8e98179b8fef88e1f980708e639c12f10e6e15b8927d836e783541a23238dde13e19e205807ebf1e1d61e48104330cfb5711de9fb1e3013866144441dec9b05310a3b825198181a7b0d13b46d9ed7ea8f6d29d00ae6c1827966854f18a585f73d2262ff328e3d5ecdb0ecdf1b12e1da89b4460d0fbba4356a78546c8b591ec30e59b0533a844618458d6014bf448f60149fd471d847342806d82115cc831d3b9c82793e22ac9f388cc23ca32a61141886a5b49ad5ef0da92cc38ebf5afa0b423576cdb97d5d3362973cf68bca6397bcb0eb9279926879c55f978c58c7c835ca8ceb19a5c1b9826d972f29fc765b85b0661927ac5f120d25f6154761d44a08bb1e844d0079d8cf43fa04e4012e849f944d007980df4ea2f79032e528bb54fea23093170a76772f040f3ebb318dc1f506712d46ec19fd4335694fbad2f11d97a5e337ba516744dfe858bf20545f9f8d1d3ecbb0d6a45c75961561537427af58d16744e9d805912a803ccc5f8f745e5446017988875d8f59651446c5a802c843fc4521bc94535621ec19c72878e6f956679e473a2fa36c5ba4720a7939c5b7ea29e5b7bbaa10d6928bf0f18c823b19cf336c1f6c68046fcf43f05b4f4156f6b7754876d08e960f5af5aa57bdf1d59229ef457318b52c96c6c25acd15357be328afc9a83d84752fc857e421c7f00857a9bfeb825cc826711739b95da3a9615c4c8cf7228d893586bb8159ccccfa9b94fbe39a5bce59639847cae69847462352d653907879593fd9b1c22078f0abf6611ffee80a5246acbf18638ca8d938ac8e4b466ef928650e1e791923a33632f717310be46c1194d3f2136e1967e45d5c2d8f753de44e8ecd4839ab63bfc4f30191bcb00fc3304ccec85b1631ce3967dc8539f0362607700b53ceca92f3aee591f2711915fbdbcbba9147cac871cb161ff8df72ef196808f66ed9d2bbcb83ffedee6e027a5711c6267c56c7b29452ca4b5ed7e55900e2c0830fcae9ebbab86ccf524a29a504b2e306413b72a07ad86154ce0f3b18b5cf5839200d3c28a38c11b53a565eb40c83071b464b19a5fcc10ec9666cab83c75df6b63b7497bdfd5b1e4b56077c09a732a8c449152a84a11e25215308d1d08c260114f31440404020168b87a3e15816a60f14000fa2b250549f09e42447629442c618440c01230220200032431203502727d42fcd0647cb1f40377b9ac08467cd04c4e47fb470a92d8d9781af1b3d6a68d49801e61f04d2ca48e49e88ba5ec19ac50e2e539989ff909ed53b2693a3faad05fe7f7b0c701808346a45824c9be00bd35960aaab5f1fed15a3cc53daad4350f201fe32f36da19e3338b469ba1cc19b00153547b9c81e2ab5f810426cf8ab4d7f695c337df0611f7186ba4599ed369b44ac1f3edfa19e106e7095d1e8bcf01df3f50dec6fa13fb7e3d55e235030ae80d4d8a0b14c8fb92c5b42c03b5cd355551209c7ca58dd645f0e4ed7a5b7001ff7d6aadd93eaec6391ea407aa8ed1be24a59235dacf23950c95664855594315c89a586302281fa31b4265e1da9623d87b2ca60ce473aaab4d2d99cb5eb54575d42b87765956a2b565b47a83957eb6a8a8d971a3851d62392e3630d2d59fcdc2461ac0a0b76d2ff3eb7875bf8b14eef77ed53173ab3d280859f910b13d64b3d94fe7b886629bba3d4c0f1ed0cf5ce8fe4903d82905e4b8df4f5c2ca5fa786fc355d6939a0cd148063ffe9402d20e64ad0c5b67e328c0a80397f43c5d488e08fb4db1d900ab48524b4909e0ab7d2a0f6cb17229fdd11bcc8b712fa95b74cfc14d5a127b57f43bf911b95d4c7178f8c24a7df96eaade87604c7286a70fdfd6f77ba362feefda095621a7f9ff487dc1f043a8ec68c248ec45aca7e8fd6928cf376159bb7d8a5ef39fab8599170f0f9954c844b1b5c365642ae4d1b01be616878702dee130c8df758b8c13713afee16d0c14c81773c08dd5b2a895373ba86119d597c5add10472089ed3c8d2d425d96bb2aab993adb76cd612756d27a32185665748f06549f255f2d4df5cade0d84d82ce3ce05629a720053ec3f913954fc94cfea030e71248acf1b42678c1d24d9eb5e78e29b89ec919889f5a887315656bcc7209898012bb7502359c89c337229fab47857c1639d4bea106c61986d3800d2183d055883fc1bca67712c5f178b66c29d83ec2b2c80c984be54e68515ecccd28fd65c3ec43a37ee04c724292b4c6ffb01eac662da254fa3e448399c2bc2d9da936d6dd987d5b65ca32c362023e8124a1ca5e27043cef9dc3bd31a57e2909c39c09835d6d21e77e7fffe04af5dcdd95936d1632d9cf3a3ab9df69292e47ad48ec6ee84d491df9f75d125231b5d16ad74aeecab3ccf46d351d223fa5abcf136dd581080c5a85ff24f4e19188da0b67c2c367b258bee333abc3c63f1f40c086f9d4662d0b07162795d9320df931b6a559cf7144957260038063e59d49d9f7f7ddd520bc8e1464d1e422be92b9b1f7f07c20646d9f783d1a940c1f1dfcccf37d735bb7defabd6ba5c1b3d8a969dde91bd922c9657a3292e8c0a476627dcaeb42c3cdbfe6b26022434dae891a4eb7e66b9548ccc5d0a281a098d734d55ef63735d67eeea76f761c5d0d4c97ec362bc59538428cd6ce168e89dc3829801c1c28dc029f6b1668f6b3264882b1fb06632e4c2f7392eaf9b0c3d2e6d694a10e25d041fc9d04ce7acdb54fbb1b0927fc14bb38e68814c22184402d30db5171e901acab05115e06105222bf81c8ca4f3aa5dfea99f2d7676fb3d44176200a1b9bc5f8b82c9a1c8a211e912b22ee9ae03f2ee686c9dc32496331d94ae15f119097b8ce73a61940fae1aa0165534cd3ca67a5e3718510af4f9b52a21c23b6d29e6114322ad98379bc3239f2c34247cb88821eb2694f03fb54548774cc6e3e0ba0ecfef80b37f8dba0cb7e693e96521c160ddff4f9b2a8750fc23c5f571ba1a98a69bcc7e2c7218fe4f70669a493b2c5b377737973f6d88d7f695cc0b88dd7e5476e80a63de34c7354a2e7e77ea8a79a9f96a0d9168c3f2f2981fd3ba3228032132a3c02d024ee757863333464ee5e84d9a50ce19c8250c3606c1c01aee6bbc17d22dae228fe7a02d3dd6e6ffcbd58b55812642de07998a3b8fcd0d7db6cc739bf9477906620acebd94458a0175cd7cb15858aa72d4cc94cc4646db89a9607b11f78866d29e585dc7f9b1d21f366f190fcf707c271a04936c9bc7ee5c892bd4b805fd015997e704363b87facf269a68332721b48611330b4e49912a97087840cc6aa2db764e912bb80e7dec0ab3b1b4819b065e5f06a9077a7bd4aa48a285554c223610f0fe68970607ea83a58529612bf250bb85e6936cb50e570c082ff54330bb7c6a522883fbb0d922d303a9a21c674409a48310db1a06a866f805362b31f18fc83ac8401d1b34fd064e47d0a0c8dbf5ef05947d5379144b012f9a0b41dec08be34f7d1fbedca450ceb484eb4f24e71963fc3917ef0bba869f1e62ae216c3cdab1788da62971b95f1a328a8f69a480d07ae230f6a1983839c26d43146d7c33b4bb04e516119eebdf33a6aa2ef1b1332c2e20182039628f66a0479b90620c737f0d8c3e6b0f5ae202f373796561c63243469ac03c1c9506d6e819a0ffa1bf61ca91fe60c7ab1e3a97ae171fc1fb5df6a8eea99b8acb4567bab22b75829053bc87c16d8b7237db35a04391d28488e984e007d5929bbfaeff0cab958e773fb66f118925d5e08c3e8449635e37a9ceb0d28ada42f0744078ac2d499fecdfc4b126e86f9b77b33c8774a3a0694ae0c1b49421d1395d43cbb519ab1a023f2ca22690a0d8b0ad9b5b32692e29b3b56c5fec087553888f5628b85ac2dce5e530897548f81a6c64da3a1d66acf0636f224505b23adc295a362922c09ebb043840f358b2ccf8ec0772ebe220818a6a97a4c1e2a2e00e9941044ec285d8bd59d096243a591d38bb9327d1da17aa95012c5410f9f4ca4482117d11b9752ee6fcc9f0069707f9176fcbd2e2796475ab07fb82879b7176122d0970892e2d89f7fc046eb07e78d2be97d964ddec36e98f91b7a0ba11d0484c31971e29593435af97f3d03722e263088457299f57d02ac631641b941352ad45f9550810e9c421a48dab6d1c32240e666511c866de1bd65c85b54c9148246c03bbb5530bb14ac43a18693ca4032639a3f1d74308a1b0ec4535fce649ff532b5f83b454d1b22ab8ebcfa20be0759ef21849800ac90ec88c8fcf5abc43a47c50916e03525f809e282aec8c6f66f64759ada4d8f177f609da9b42acf7ddcbe65170787c9e5f171f11f48505911b6cbdff4543ca9bd0f62e0eb5288a7f51dd549472cc7185f9218c1b304cfc2242a99d0bdf494afdc91bb60d4046d92a47f951c8e67772dc4d2a38bdbefa9648eb9fa8bd26f23d71a9dad6173376ea60c894b2b3e185a7fa16ce722cb9694b240045dcdea54e025dc4155fd002073f38562e58b01cf1ec757c7baf7129c1b663ebe5ed26b7b5dccc09a7cd87e1929558e47bcbeee0d40b748dec1fbe9006f5b3c4fae5d7befc94267586628a4d4992f98de1c21626c90bbc6202f71925f6a81a1ad36149b1667abfc81c6c508d9c82d9e071af08c3eebebe28b283b9f51cc0a6a37c40f2eaa11e78460dab78f598aa08074a83643862bed2acc109959ed9926712be8d01a1d352628798c458335d55c00d160a2a258a398ab24acf31a769da2e716ab89d10d1054d5dc9c46007b70c9dea01e5ae3bc349080cd9dfd5164885cba5c5915ddb0195547fca2229ccf2561b707382a5d622dc6cda22eb830819fb5bcb153d002bef77f07ed3faa49242b75ab4809dc2ae780a4abc792ec86bf8d98144e3dc0001cbeab56f462c8f2cb5591cd6cc715f82f6110ffeab88d1fa12688b2407b300a5d0fc898176b91dad696e32e4aca01e7f36ac834b326190500c2eac63afe9bca72df420df844050717fecfc38edc6209b3f832a7558954d6a38b276aa6ad51f52b53bda1db16b4e19e983a45b8086689bdc2282886e49732c365a7a05dba5e1728b0c6719c3f177a016ea4d0fbba227e4c99fb2a26ee10aeabbdcf3fe608cff44abc865e097159931865bc40904db521a64989b0474a395b9bbe32a1f53caf170f4005a274eb945c64d1c7a1c35b2dbc29e04fda0fa147438a66de51043ce43298cc82c36de9df62d68aaca45a48fae50ddb606909705cff425b25234873c5798f516c9e0a298b83088b0ea58dae35777bce2dd4cd6759241b95cfcf5f3e069a4e9673e13b625b2f2eebf93f70df969d458241a2be95f8ca27b414fb9c099a941b1fd73bbe5becab6ae9cfc4bd36e6d0e73b02347bf22113f3795f98b6946dbd2697243b6d4a7afd999221715d1f7d2b5673a5cf1aa4f55aae8e3af8ba3686fa17bb288e9f6412d9fe1660de53f2c0653acd2c0f39a4d164b2e26cea96c88344a76d0b520a3d2fb986f140a107306beb8dfaf4be2bc906e90c2d862aedacb3ed3a2f47cf28645456059a15d6abef455d213cbccf78d731731a46ed7c54f8f886e471e6c197961c94b549fa9698532dcf9f2b2a5a2105b2322fbed68aacac17355bd6f6023d8d6d48660d68dc0168754988f74091a35cb11390c0006c4de5670cfe97fb262a1cd33ad160dd8b64a9c0980d05806d93940884cbcf73164e85b79ea4ba5e657d3b4ac487ecab443613cbdf521a10d8f1170cedd1865a0711282f6ddcadbb9a1994e08d5e0174c2d9263624cadbe1c6fe0a24e1e31a7f11bf97f1b9b086953098fc1281cda3e07076789449c4e444767da30034d02cb9159f63d53a4298eb3790af939972fda462d85b5f7b4b2cd3631e9b35c29c69b360f4c2dda5390af96988c0eca8ad9e5227f94521c0fae36e03cd1b40eed726a994ec5f69ee22b6cfde253471dd65a4fdaa19ca167fb668be222eaa05131d1d49f58276d4be53a843e8182f5c949a19f79ca50503a7d648c28fa73abd191b953078ec2bde99feb413cff2f5d7b02c9a70c2e3dda54d803ea1ab53c13cf3f0d80a34ea139d48d23e730b9d14bad22702a09eebf8ce645bf09087cfadb476e82f2b55e50287b366af8723c5c364c7f9f1354f62735e64fdc42a4b79b727df712980b5d6bd87b0dfc61c1805b6053acd3a0885a99b70519b3cbddeab9bf9c06dc210e1d492f93ac9cb2198a24567f3fc1302e85e8fd7c04a2634af3c72ac925f42fa2410fc709c27a8ab8a1f771f9ebb8c4519492f411ae1f68f0f5dfc327f7bb7f4fbf6f0dc27039eb8bfd7e1873792060928c4c4d34edcfdfb004af79b8afc5224e5d81b83e0ecc0552f15ef6d95797782c72b13d26bd91af1bb922f18965562234fd68af700c1170a629f4a0e24fb44b382368d24541a9d0271ff8c5dbfd0bb7dffff81867774bae791eb00006fc518f338d6e0e382d87636dac4a793684a1c7b91cf280017a29244585950f6a871065d1b76867236440044ac92e45a23316a62ea1983867ed6606ffae86395c5304aa46f9fe38c748313cb2f35b8d13b243b848a433efde73012cfef3b64e3720bbdfcda56abb86ef2c5b272f0912bc8b604cd243d02a1e6d1eed3e67076825f3a4613f2241e5a4ce1cd20622196862b05be4b7b4990ec6dd5dcef0411d282a9a9664828aff4d9f5177204d5e5a0e105c36144b48f290a69c10c3c11b454fae9dfa5c349ab5a31b40a306a4b08c0786a2aea24ae306c8ca1ec8e66f263b2246567d58b47933d0369e85a46c866bb6e56b435a656c12296dd90d830febe2691264b408e996ac3f959de8834eeee8c2289057e89b1347125a9b1fdd3a981bb40e21a396452ac4d8fa64472689658924e9bba8751d5beb82e1e299b2525857d077b828a56b5d6602222034ccb8fd4c9fcdfe5a290112279aea9ef34cdcfbdf7a10f62efe4ad0b6ffe6fc6da1f6d7eee5d33c6843513fab04b7289e3182147ac1cbb453d399fb570b885959cd0cbccf927e560a9afd16e1c0fdd156273f61b4f94e89eb872b3a6f53f9abc9106a14f8e0e2e5351b0479e0df0856f88a2adee48b61719ca78b944f65c4f2d2b6f4a2b5c68c4c6af73e31ee336a41f9cbccbd2880985852a99033434188e4946bdd83a9124d91902ebd4be37b2dbd2244213c3d9384ffacd58ffb077954a724220c7c0b01ba76602d5906f65cf321a062207ea38dde12e51a44dc7f214408fe185c0071e297fa63d6589ec61f3ab393ae779c5c72a9fe8a232a31c2dabc99855338a55e26b1122257f5dabe17b3f008e5857b0c81d2a4b5b776667e52783935d6d094b15c51bbcff0afa7dce06c95632fe1144f4709f069e4fe754e065a8ceef344bc5c297362c991fe6c82f1798c59e1611cb6a12fbf523f12597ade6dcc89d54762db942dcd392c848cfe2b1a887338f7f2104c9d1a6759b1bb29eb5c1bd70d7aa40dd0d654fe6548a4d5c98943c34a29d881af7cb9da073f2e14acbfdb3df4622b314acb66f976d1cea2e1e73945ee25e56d9a258dca76ce5f1f75d150a28d1820169291f8608127ee40a4862b7a7a31bafe224bee8062fa542fd60406c81339e658aff820981e7c1197906c86d0d2590511b2b219efcc4d2633f4941cb51a996fbf1d381828a150268708b791cab8e7b777ffef738116180686df184630c040b9a8e9ee6461c85e54e8442c46fe14194c50978685549322431a1539d6ca36c504a05b40321df1973aaf6757671bd9960535c40d270f9387f9884047167298d62d8fc030bb5bf0da1c98436943a0790526e5116144006023f88660ad65f24377cb323ba0b4c96c7c4fc4a23226087856eaf0201842b067c1c57e4573bc53db9b5eb4a72c4c07c1b7dd6f5ec421ad5b567a757936b899f772636e237da08bc8a611ed7c4ef9ce39f21fae96fd6fd39023b21b7c2bea1220046a74eebdd4fa8876062975bbfe7fa6da7df6e3b066a30bb1a0e63d35c077536afcd231a6523663e682dd25460a8793918718f368252438c36c70cdbcb219e4195b854d992342dfc88405a29752fd6cc54871bca18e63633eb6eb43494b8124ff819e27149ea056a8efc438ec5628ee3dbd7f726ed165dcf4c8396a3a8becc1e2208d1ac1fe63d319e2e3c832b2300c87b0d57ce3bdd3210b0a3069054a33f8f10a8c74521c77312d23695dbab505ca63b0f8e01285939b74035cc6c8cd3c81acba2d0e9a4a93340d8c656734fd4d780cea9ecc9b9bab6aad7f501e0330ac8709d1969d730e3471deeb9513f9ef6dd5d9650b1d341a55224138c94d4e1c74f9ede9949fceba92304f8b9c5b8fb35109a233a5bf48ec502f69935155a277259e12c4aeef9386eb9fc54ec9869fbd41a93e1c032d05cd2440122e16d1d4408ea431657260cb17d0bbdefc7644bd1d189909dad9ba4bd028c95fe2660df84925f6abaf04c8c65eace568893aa7289f311d8410cbef42c5c6040eb90ec6e52f9a7befbb54a75df6dc9ac82c5e67c3e6e59d8aa23cf37c91bc8c65d89cde5b7c01945c36b323010639ebb9335823fc26246215ebada39965d1ee4a4808414746fc654acfa2e7ee15f3a3bbfe31f2e45e321eb6ed550ee3b911afb534494dddecb3078ffa1ca22f60329b143fd79e935a5ba21eca945cec5027ffaf1a04dce0c7808ab8172dc027690cb23d34f38c100e33c76c0e687a8a1925686e97b158621b0732f14d28504998fc70b5d8ff96948fc564d26532cb7a9a605605acab1fb0979edfb7dbd7999536bfa3232d46d75ad9cb88d178c3ba590b8eed53b16b4680c24b40456efcf18fbfec1814ecb437a470d48c5fe8b97185094ae5a6c5b4f340204b60660c93fdb1b8a09f807f03d66df5b319a5d3fa9a1ae02f48c059c2cb3ff3249477508a9e0d3c7d0538baa722420f2b1dee4a5c831f4d6323481bcbc8024c1fc23a8bca3556fb107a2d08b908fe5855df292533d31b17b4e12511227dd4f6727d801c75f60162667034a05070232bfe054ee8964651c73798a60bf2468b2e405fb78f3f534daaadfd7400874a6a0ba86cc60e81dea850868e7ab883270588e6cff921b4fd90b62db1397e85ad4757ba7c71ae29a65881717c7dd3680a684129623a9569474f35a7f80a53933433c7a98dd74a796c15880db5be5d0f60a17bed8fa8e325d29048196cee606304b8d724ff91751ae75e3e614f786104847b4518cca746703ec1c652dd80d72c878ec449ffb6bc91be44115a6e918cf998b1811ec4517512b39c2eb83d02e4f5693a69b5b529ce18f7c24aec574729d5f88b7ed3fa27624d5aa9c358601b3ddb37368b726f46ac1cda6cdf26b261c68a68935221c7f368985aa511ae55104dbdbfddd9fbc24133afff2d2d8b8ce0c797e30a52b824b55bfbda19cc5c868a0c6cedbe551afc78a05a8744acd972403d008ca187de28f71b0e6f8a0a88e90b4791eb08f933b1d42a3cbb1885d571d26641f20e27b101fe2035f4e06fb1a866a1c1d7be44cfad411f980093aa7db028411c3160ce55533199142df524d6410ff22237db2be8d1923dd4466e86d2ca609be8c0ab41cf523b859aa91edc62b15e512edaac1b34558b84e7d1fa46a8d2e90516fe93114930d54827412b82177fca2a9563ca38bf86b409fd61742c1294d9299bc51483637d98c3cbe79dccac5fedf04a752d1b2ae29bcbf48ffae54f61748baa815832a87f9441017494b2958a363ecc359242ae212436d572b081120f0b6b55929b034df59518a7e71f31954890df5fca77d8496b250be03b1762f15aa85beaae0c683469c9dd00897d4f7baab79d75f238dc3c5e20e8050ae9697596efcc5dcd76e8ab88fc7326bbd29b950f814e3a97ae4233e1fffca1c3ec26406f4c226d8e6213e0f85172cca241b92fbe368035c0a596abc901eece993b46e1ed94b2e19c16a3c62d97b59d253d8d11caa01e8a153e3381264e8c162185d4cb0ea3bf690295ed5410c12b48e9d104bd042d8e699d43fbc0a1de640695228d7301970c82dd1b63d2f6d509f623c43ac7b72c21300600dfeb7712fdf0bcd1e4af854cf95263fd65e7171f1603bcc444ec54999d5192ea55b25380f4b91af831bdf33e819033cb91fb9abd665e924ca93b326f0631cab60477d478a1453337f5f47e1b64a8f7a9b4a0c081cfb388698564944210e0e54c0572328b7148b0f024010e7fab9b4305d0196f21ccf5b8cba8c664918cb2f0b3ef4ae6d5b6696328a58cbd3b77503b8d61bb9385183be5814c0e38e39de149a6633fe055f19a27fb07e1f4f0ae2a88d5e9413542f35888de80803916d8207f072bcc02b8211c330637e530f2acfb8ad8722c17af1a64f1c804cef65080ee77aa06bff5d836f0ed14208b50ec2e33ecfe082fa8e1687cec7b722c023676d8ce126da5a15860757d0a02e419417f685e9762050949aaaa9507fd87f4a34d366e1d70436407124a8fbfe07f9b6367580ac6228718e45b4f03860925047f1114a9c889cd399eb7ad9ff790428e6c531cb598d161f2c37fc712dde444c138be73d51439092db611d85727b83d8c6b5129f45c238aadfe20a1a7f51eca7fc371c1eeed54c2acd0a0734969f06d5e764bfdb2f69bbbf7402b31d77bbcb4d26248c32d7f0191e9d9ce95386abab613bd8061c8cbc809a5619c170c83fe8c91931eb7cea191d0c87a60e1c8c449402cc769cd96f8350534fa8c54bdce4505c80d727524027a4b95a1f2804c1327ae49ecc879b261891264d0c349001a67e6ead747cf8b377d0b3e68cc41db2986848675af18ae6efbdd64f61ec914c8d0ee5f7ddc904ccdc6d0a185de1a4de537d0c65a50f39a9ed1fba52086ae12307fa73c1ecc5867e18b01d5191c2f4cfeb99eac5078d7be1b13647fcdcdfe2ef83952c69b97a174e55340cc9653ed9f0b93c98f35935928ad50a78e9c667a01f652d7c1a9d6e6f5bd194d831a824f0d57e43c81bbb05eaf3b69e06902c1ec82024a77d9d5168b9ca0dec0cd30033b1c1e23d188edc3c994653c5a8c5c5ebced048d3d2d4b0a1923a70361ab387166175e0633b805172cc5d4dbe5df252bc7ac6465daa847b024fc0f1d9a817cc89914e6219ffa40b0b2bbae9ab7c8a8a6c556391c10d6792e643abb97e23e496dd1e8e4640912a4d54e4e5a747a742903cd2e816682cae7c62a987045fc92cdb6e705eeca1fd72c62a29ab337ed2cf1ca632c2500d0ef6ffaec5b5b7594071ce4540ea6efc8e9f3d59e041eebc35ee7b8f51fe284cd94a7b7070961ec0c1d98ed44e783de09d7ed288b4e55e18b29fa7246a9f804bdc589d551b4d251aceaf149e4202b886c0b61886ad7f00ab8cad1f401fb40ed36f0ed75f1f5131941a57a839fa1f4c9007a13fbc54d75f341d085d703b812aae741f49ab79949083d1e10243c5dda2f6b88600ab0f33b0dd2e63661f4b75ab9056321d7ff56184d9dec725fd8ebbb82ab95950652a7a89ac5943f44dd5f9616cc4482d10feb05309fd4444f01a427e7c7312c0136a693996c5d4103733409326586fa6f14c0074f433255706569ebbbd14b21444b8a05d618c969bd61c65dd40b080fde4171439dacb3994b87ed06a27a2cea2b29d9dcc0342863328553b0e6a49616535e87213fa1339d9d3c1f39b8773d8d0209b34032db745ee83bd14d9b9d0026208a188d905f6740698dd9b5da1f4d47ed565d9c9f83fbae79fed0f68407b4267256bdf46639af4bdef3d31b2c62c21c1deeb47c44c2010e0994a1c52dec62a667d56684bc52f9a449c063302716ed81336439f3e4901bf0d60300a9aeb7663bb9797a374ac27b51d0b5914aad956f2454ced0494baf28a141c53c2cae730a31855ecee4520f37b99b44fa77fa288e951062e2a6d75acc35c0f4d041374dc860ff5cfa8c91950694692cf69c3879b349d5afc282dc1083699329c378f6d1a6b1097e5c8eb0ffe328011f7e0a078885c0e131c7ffa60e298e9badf6b61b70e23ce99f6cd96715c46e46ab3b11b2a73cc0ad452f9bfb94c3a09a65e0704e69c2ade4a64d86b246b3ddad6431b91c0ef9abe1260817c2a45bf6716e60630258243ff7512cb93387a6cb6a6b5505b492aaeaa748b2a396ed5048dcfe0c2ef085032de90ca2fb145ab01535491196a79118710b1dec70c161fdc278d7eaec197e3dcf11cc9d3c3bd76c63dd43f84822884a6aad69229ebc2b4aa19dcb6f476696761f502c6f16b6e9f08650ab321ce93558aa310f50e45e7204062931249a0b310600c1473ead15cd2abc1a81c573520b6d74d25593d41473dc421a9538751fb04c230369d7e664296f787ec4046c8ea4fdb1f3aaea4adc4addce93fad7d8b0ef2a68dcb9c931d2d8dfcd91a957b6725fcfc67c1f31153c22ef357f9ac85975400b8971671672779928a4d6c1604c5ff7c5726d29561894684d5da4216911ad61c4d455d4c6e594c3bdea463e7c8e6d4fe51585c1f1b81e643d7359f32d200ad81e1152f57461b15acdde160085f706040856dfb1f671185c7878f268339ff4484446b87805a671cedd805d9a5cf435354b0a00db89098aec6e77c1e12b3b04419d3f675759f77adb846ce88d856f5d9f1b8aef662b61c07f9ca1df1a640df0ac87fe289f0ec85428924bab85b218eca12c040efe2930801a9025e8fc247e52983241ed553654fa5cc527c98d59932a0e05e7f2a69fcdfd76b4a9b710b2239be95cf9b015750333ba4a9df127ca6c3848e847aae74fd3b9fe87372c13adb13b9445b7425a8b97c814fe9164a7567690d2cb4587d508c7b712cb42d640199d5b679752fb01a2da1d173afe601d80314d44541144e4d4e81eb4e885e0ff6e8b2fc7732a03b4a0ec452226b709f69a7fbec484ad1c28a3d9f7140b00e8c4e1a05367503cdd9f628502a0d16d65a5d24f24e817fb4d38c674aae38a42d1bd626c2086a1fffcc86932de6a98c9ad30b5579d9e798b5e1c2d30c4b393a60d64ee7cb84db9309f3cad345dc81ff96adf65583125665b28222b873520cecd2d36772cdb034a46da2460f6f08223bd3c1a39f44bec5b79400e25196dff8f59cfa32f8b108a6740eb777a0f09e5961e5aa94f9eb18ad8b482d09d75eca37ca1d34f924e4686f92d15b3c04aad0f429fc91cc3b312b5e10fab4058066cd87cc818d596da2fba5b9e0764dc30f95b90e0b5d4a312da6ebc089f2af8456357ef24926260672729f3a08673219e4320ef1d4add0e722a488ad036ad8a47e68302ea1259e1cb5efe086e8ab9c366903976504ed973f7dce0c7ed3a2a25f2e8604910f63cf3a9851d294686c426085ec3702d7a6c9185d2ee5e54dabd1794bef5cea5ae5ea8d4bb7a0d97e2985edac17892222031c5bc19298de2841a1754e399ce0ed289fb65a8e6c3912160e7365bdb33ee05d8659c58acfc9352116486482228a60516f2a82255043c6ec10fc7cd59f74d33072930eb27c321086cec4ed4b14db77dedafebd7ec6d170f4b6c8630e26202e2a52a6d71e615d9c90cc625562afee613a80b23478f505dd072be91916eedc9398a7c00be0a28c4e35e6a7368472964e2b3b92f2ab2f6f9f51dbdc9241ac424dcef497b535f9237a470a47336e24ee0a8108376544dce44872dcd18b49603e6e14a2b6a437f79126a0bde7a6eee736153a872a1bca0a15037b99c2ae73cd59a42bb084e4949f614b9f2f6245c0cbe3252233d11b587c9f310dbb881ba5aad6151e3f1dfb2cd90403e58e3863aa1b83ccf6847dd5d2cc583e8a274a99667d81f6acf05076660361ec913a296913ee249ad10053e109c0bde17884bf3f7a98bd4445510c19b83507ee145811f93b8b5192873cdb602825d46eb93cf1b2840165f2be6e0f635a1d7a0884826a3016a877e7869448de46001810adf6f9e5e71f0ad0edc3b3af336c5ab03ab00589818d993cf577051cdab3ee249ce83ead4e416c68416c73a2f3c780fcec2adc16bc81a50a36314d0bb1e761eb472269c94393b08a4261606728281817a0b162c7035390d92b313cf735cedbdac4f0c67916f4dee1d05c3f62d64dc61c25e2ee3eabac657e6262dd518f069230743884875458d57e17144fff4c4912bfc30e9a43fa6e0457c3e5a5c8682dd910526ed3d4b62a67e2d4086d53950e8d44dc6100e80d26bc6bb8f7518f548a77baa207adc0e06c0e9a69559d21ac61d765cd4bdf225adc354c23d8e15622c98cd600972afe84ca6fc747eeed45d13e37a1c3814f817c15c781bf419267dbeadf134c93119a624ac674723ff13e44ece6abfadd8fdec8c7264f61dc1279f99b89e8ee7d8017c4d34bfa821648560e8de562f1a3baaa98c61c1877a1490dddc4f96fc8bd882ae1e65989f223ef5281539545b38cfd8296e2a08e005a70304114d8b61697860891ef677c410a5c1b9ac9b7d9d8a3cdb9018d34f37d9d44039580c0666c1b949b65ed8222906c2e7041312506d1f9cffef2213bf597323cb51f35a5bdf9fa032acb156f3fbaea2038e20bb9354582a02af4e01e006a631b21cbdd47517fff83b3341a7db88162247c31aa59119e4e63573b27617abae11d4a51066aab777af72b243ac4f69f5f707644dcc55c1d8e5fa6d87870cab6098df8f9352018a20596762185a30e66548d0a1635998bf61c625e31c40689b29b32e9918ed8a955f955a8b4daf75b5cf81f1da3dab81cd182de0f4610dbdcdf286b218174abd8db030739f4896b9a4e83477cc1f647d72dcfaf01c48780cd8cc616a6e6528d6f88309a78d4c3969bd3fa55d5ec31391cd6e628382aedc73981b990049c405443077224411d99c9adaf9b8c5c0eda302f55d18fbb7b50b98803df0c08c6c82c6b7fbdd0aca183dfd9010206c35b3d2268f214261c99d599c598d15639ad489762544765ea1b1562dcd24aad5e8fcb0a7dd75c44d9bc8424d9efb8cca288c322fcc815e00ab8c5516c6baf73d060ee1cdf935ada50556efba63560a9c17bf7f7e00968b737d0108240b326c5956da08540bed8d864f6e4d68de0422d13d5faa5ea139ec817efa799e442f4766eea513cdec7a9407169c95388299a15945a357c78327b2bda5e92e1b188e093610416c5ae9aaa15f78f85f40d0e01d0467adae888be0ed353a55946515d4e9ae9b363889df44d0dc6c89fc86dfa438d13b7d0e06d216ad473091cc966c9f4b292e8528d2a6359d7c84cf1ef071f74b305fabd637be2d638c5fcc49797b1519423d56b4e435bb1c58e107e2677a0be828c852c4d9a40cee68460ab7d8612ffd45b189119c386700b04190e102723bfaa6c5d74bec860f21cdb41b6fda4ee2394971142b984e97e1d1f9d83b4533daad53697960ad675ee29d366d8f76cc1ef6978186e5fec8ee25d42a49ed8b9b4b690eb7bcaa7cb5d2105ab8f9d9dde8911e506b69a7924c707d05885bcf9a82209a703a99d9ad90e3ae5f58633b650264698378de21e7ac0d294d65abe4b1a48e1cef6cbd39fc56cc66bf16b00743368404513ec171b68471d623f4bc684f1eea105a5ffd7e773b0630969b929a96fd1d99c6fb4d4de45166da0c9ac0a83aca81f3e0b9aeb09808a0248b19caccd78a08a53d652c7ae1902c7a6f43754e11afc7444591eca4d6a60c406a3af0f8c7dc0beadaa2794f7a01233d3162d4b056b73295d33259708887a53f4118743534d5dd49a43bfcee3a1a563bc1ced2453e18fc3d86a17d1d0b1c953a35454ba838f68efdc81d157821b7843afa095d822c748540f6ca247d7bf7e0627cccbf2e2e6579a0100a44c4d1933518030829d88a53f50b49e121be519e547e404689238718fbfc1202c0de8bdc38322239a88aa793d505d6cc6358819e73444d1be0cb5895529669f1c99e0433ad0ca919737384881b84a131da06c7935a2098780b355e8275a9001ac98bfd6a1928005881fdbaac91f6ebe2bcc2524d2271f658542f207a7925b20aa36c69804134858932a78788743e6b28c5f800ec1e983ebcbaeefd7e6c19c75f943cb47391c2c91b5c248f56158483785ead4e574f2720162c14988820f8dec1b7c6f9a92f81566b05a2f0d7aecc320a9755fda72806bdc3e359521b2362370001dad7ce02b72a02fec9c6024401bc21838aeccfa76389650df27b7b03f5563de13d7281cffad4ecc8845cb77cfd8e54ab92cf0a31d1fe8f6facef22e460e3f011c86637aa22443685573bd6c784ae1bd9259b7a405deb18e0fdbbcb8cfdf37b3655213ce8c6a1da6958e0ba0959291c7a69c1f75544aad2ea8525a9de574b4703bb3f6e64ad63dd7fb4a13e0d849c0651815588e93f08778efde69f0c48ac7e3f18ddf8290a0349813a176fcd8f65d66402f088c64625b0eb9843042c3286ed4ce7aa28e94d2b7360f7b75fe7aa3953b964e5d51e95046d5eea69622ca0b554020b20c874a9bfc53b91698e95f372ad92a64e4b3ac778da41654fe808ea32755bc0b0d30da97db82ef041631038ece81b1e29e1809b5fec717a0b3a03c4876eb1631edc170b7da2aa4fb0e0b69f30ebae57c88396c6f44d17ff6d068336fb35ef5caeb502218a4fbb5eaea8927f321df42b55f37260b5f6aeaa17a10d8401121ab80d3fc320b3db8a3d4d454709acf6e175e471535d688e024042b179adf727b4f88195d2c38245817a8a97490f826986dcf7343b68136312e80b728272edb5a7981b78ed0dc8afe9163a415debf0e651598a41dda60bca1077d00a638a32ef6599654f26e12a7b27547ac55bb8f758641c860dec07a041f3d098bdeb5d0ba6a76fce8bc1a3c78c43c5fc476a008ee8452f2596e00b944eefd5635b4d44975febe3e3f0a6708d45e60eeab81df34aaa6d2bb0cb4406040470fa63a23431fbae76dcae9bdf6126d877237d4454302de517d317636fd796cd0a53494be9bb0dfab4358cbcb83de897ac113d81a14347cf31ce8aaaba231b01555fc9921fa8a65273c6a9d546a9b59debc145b920f36edd9e3aee857307a170000bb09dd67399678bad989cec0458a4ac884b6f786b1e2c00c939972a8ce24ca915742a98e98449a791b2d5333dcff29cb91e56092b57473e64b6e590a0c428b30b5b9eb4dc411b7d0f8456338b3d15706128b491d9fafdde86c76ac2f0031f3342ee3fa6fec5788e81e674c35781422e60b05c2aaa329255ca65bb43fc9e555d70537885bf4eacac34c3f88e52a0fec320f1eaf8f29e81eb0254a2f402dbc40f1a78551cc90c93b7706b50b7a84125700637ef8eae83f052b786e7d8dce671505309cf905ee4a16c5a7ad2f71ef429b22128993792d93f25bbf2467092a8f10300d28ec340343d42682229e8fb676d90c1dd11cfdd39ab5262e23b08e403c61393a87caac441c9e49167ebff2dc760617782f0cd46894d17ab9c4999a3c04dfaf20b6d6af5b1912678e66c2eb95701937bec209176a41de96062b41d3feda9088234d4351ec33619110ac15f1b5f671e3181b11fe156e780f6cfbfe7e968759c004080291a022c49b90238be99c46a10c96b3b11abee548cbcc2cff12abefe0f618d0e923490105e3fd8d75b3dd5ae3e45994f6a9df0f20e80b5cd498b886773c1b5cdb2c4aea21e4948ceca7ac1abf6865bdda489223219e3e3005badf33f79d6b44a5d437735f074b3a265ad1634f262d5f8be4b6403e36a526db6c30a50fcd9df6c92825119944be31ac4674d002c19eda81edf8254096ac447f8481faac3164c421f9872b3ae625bd004a827fe22ec1058b4c6f9abc49ac9cfda62af15ae52e84061ceb12a45f85aa230fae77b09416f618a37b06b674564df4d1fce8dcacfcf259c2208f2cd586157340ef480a99844c6ff2483c12c3745532cdc94df55f2fcd39bb05c00a03dc93c80e551988a23022b7760d6ab8471785933da42e2b93e704a313aff5e48be34a828453185729a9a0dd0fd39e4e841b63ee50b6529d4cad0cee23ddb214cc96424e35237245841bf081e241307469d02b7e8940505812e3309b401173b81fc70304ea9e0b2e2343be76fd5ed393a9651acc751691b645baae28aebb5e774ad3a8d07be4fbe03d65ed06f31b9b946823ba01c29c30fd92de27df53febec3dd47cc2875bf0ae54b635ac7c87f45fcacec1ba2e974fc778bf96d2315d4fb833d458475983412b7cd16a350e6d67ecbdee8318c6ae17c3463bc0ff4899fea45d297af9012043092b885da2ace3d7fff49fb41284cbb02ceca32b146d70cf443746a271746d17b63de212f8df30c9f63a0615f42995cf0db8606ea359b0171993eb633fb2a001eedb015377ca56c244f4e9093a09d3346118bc0de22d1b962d2885b4cc05851bd2b229f41cc16994f7a6907382f219604b88457dd390af6a69bf2c214b545e10ce0d81824a9f863976e5c7c680b3913bfc11e2961d5d355ee97a4891e3668560dc378da07dc319107ef4981a1ba50527f4b82921e6296e9c94bae5e1eb95748205978bb7e2ef94ac47baeb162d0bdc1d008f6ddd338a843f7c9a69c69832fd5b5a470c9d08b03ec1dbcbb2421f991fee24161bea3eb7614586630ac62675c7d2cdc893e2c48ab011734c750ee238c22af9c49129a27f16b49509eb097b29c442da975839b93170c5abae5250de9ccc9cc6809bc8be03c61ae37c67efaecb86909101f5d0671a54325110586d3468b5db8c4266f506ded910952fe160b8298a78ab4d288d585c4c40f989a0acd38b46d63f52ed37af50970e365f0e495164e51105ce45cbfebad264e54c12b0ecc05776d87fa9c93dd8f4a253bdb58c253a0a096a01aace68d090ae012c04590f5d55c9a0a7e8e01a621e44e428c911649b6ffc07d4611e1893dc88a7b7da9f6369f3acf244428e837c024a40c72233c2075def651a879234d00ae26331a59196376f2f3b301052ad0afbd483ad41d50a5f34eb6ca875106116a0e866b0b83d3c516c36a88890b613393655577b7368b5f0a71428ca97b7b312c019d4056c0c057898f15b5834beeb77aac03930c0255d2cc9f4c3402d6c8b0e81b89fde3a5e00540b79c7ed3abe74d83f906fbfccbc81bcb3762771832e0ed351345ad27ca99430b4e8ad20fb096c8e8c0683d3b89454da1ffc1db15fe1a3be94c19bd7e95cfb85ecdeabef8705c0824ea245a6ea9756630ca2a7aa98bc4a118d8eb258d9bc56a7577d2e5cb5ee7c0fef0c2366e7996bac04d8d5b1ac51ba21160d261a97d4239476c896593b98ee5c0ace6f80ed279205287f0b4275b2dde81804334ae93d0c2d1f97986d7d0b421e91b8897ad011e238ecb73c5c046a6e427529e8b6218a36e644a020f91fd8d742a7847ea897995a10b08d9b84dfe7293c6b03207e1aceeacccfa8522e7f6fd658a5828c827941bbfa3120e5510a0f22bda7891624aa96139f81e59d87c38df03df5cfc1c41a3e03f02561937a73caa1c1c6e69a6e339b0c9a2eb40bbb9815233893e91052975090ea60675dbd5bba34e1151d286a4853d6896d2245d648b7b626b4d197333711c042978a85a19ba2855ca560f23fb2e88f2cfb97a90c7b7e71fb8f8c311cb60b7de91ac9602fa2af92a8fa690ebc560bad140d19a00627e9669f65dad16b8a9951eec78d095d46981990e422b3f5722832a9167f2e2c2fcb820501cdcdf24e4359960a376492ace8b9bbe28a57f4d2589eb6fa446d9609a626a8de8393abd49d90813974e01cb0283ef218ed9c3ffad8ea6389b245a999e6a1862cca81a52fcc505f253bee42fcca55d74fd4ca854b40872ca310b3abe8e8cc268a67b7fa0e75b92071a9408045563ade66dfcc5567c7142f0c57469f46535152cf5899a3793bd7d66f5e5cbf504c3041f3b6c948ec36cfaf4fc6b83c90fd8e7b36a5385d64b096c4140116b0e457b03c65c81b8493376936cbb4f33cf9257aba73f2ca5aac110166c18640afb220dace84c1b86be63eaa7a8800df532ad46b9dc730f26a1281bd0d4bcd4c0d3e4ccb50eabb027a78e0e39c11b88f6e90a5be5ade80a21968573a6acf5648889938b69221cceef3f7d1afde517c1c688f6b1b5661bd6c816cad8413b639d10991dd1f0a7302f0f6fb77c0a27d931291a92d1e78317a264cdb29a03d9c80b2e65c0d011fc79646a967c43c7ad2a30b5f1ce01428f7a2945597121bd6d29f17af570120e9700d728c21d7bfa8e9051d5ac1191027e237d9bbab04ec14326c1d4cbfa1b858a3016f0cf8180b93450ff719a8ca329c2fbec352f5db8c6182a504725ae8202ec6c40c72ae9eead3056e896e6e902c2c0e96cdc7417557ec1c7cc17a39e2b933abdf7224d69d96073e89fff4435a1979c09497ed209b358d5e8ff407cfe66f0daf275184895a9cd2b0cd65fdd01502fd2fcf443fd4c017636834133918c80b07fe16cd3c21966bcac4329c701afc8351665c68a3e53e11c82fe18d8110742c452f4d9177cc59c70f5b1c2ce5269f2594811b1fe158d7cc02709806782d214217da25ec76a46c5ea610277a4a8fc162f3f6400c4982dc68f3497c57cf2dc88d3d2c3f8e27d150c1a06c426d17d94ede5e5605d9da8beb502bbbb379293853e3417435c5fa3fdddd3ac16d038e3e3192606818ae4e0c0461ece8c51102146793caf512630b6f3463bd8941c5d08f1897a027addaca39e503b613ccbcb6bae7e64b09dfbc553a4fb11855b920a59c4200492e028092cb13311d8041dfed14f42e1ba3cc6a9ed3eb156d93bd7fdf1b3ebca42feb902c69108f26c5fc46667241c07bd105655f02c86b83d264d4438d703472bc483895f890f70ed7bfa068d003bbd44ea674ad16d0f5335779767bfe9f9e0c234b75e315b2c91f3d4adf668af7fc06f10d4307e814d1ac67352bd02b6e76248afe6ff01ca777dcb0ecf2d3327c08c4fc18bf90f8dfc09a0cd09606d5719caa4e60f2e3ac307c607bb94f4a71d62fea3254471fc7a08677dfe410b119c9cd3d355769377cdfb90e6e4937b16a8115efab508ac756fd63803c10157841754674327a071d1b4f3c252566c085548545945a835bd968dd2ce371507a6b3a7bf16e843d9b376cc46cd707d1cc70f54d5605e0ffc631300e3183f8274e185e9a3b53c36025661978bce499a5401ec181ac5031e3736bc5b217d26ea3451ee00a0fe9e831464783797a318d9966374c3bbe4aa60750aad26cfb7339db9cc2f90d3e4280bce148f0ea0ee106e20dc71e03bf0c876616b95d0c0baf480f62d68b56c58f97fcc540c39e6339cadb60e0692882406d7dbd866def23018e10191f2905dc856734c4e3c846131b8a582a882d65a9e660957ab3efd832ecdb8e0fae3a178aabe49da06c6991147df4ba7da43b73a39fa8d2a6b2d2e02e84f0790c2b9dc2a5b273ef27534050a79dde8080114c21bb28ff66ac885f8bccd651583c064434f48b1c02c954520bf8fcd109a741654ae8745ba025efe4dacd49d266aae6d31f6f6d1e41410ee68b9ef7b0310d0c6dd747e2001178182cb3578b2125a8926875e425182ca95aa8adef22e6161bda276224af2a4b566ca9315625045e3bce96dd27ef964a29e6c818a43936ef91bad24c9ef01640bb945eed285191452bea04d4c63ddd6bb1b41aaf6ebfb57a492ca3d2d0ec2f3068131c3e6143438a6b51883042abc50b6f433c76d132f0e78086e4a211421e416ab451c87012fc0b4fbc0b44846b236f962974d359ffcd97850fe0e93f436cddea14bfa91860ce32ca131bb096e7dc5c7f69e9d1d42b16c26b491d985fd6b641c12fe4b2a1078c75a2d9d86614f6ea7526610f35dead43dda8a0eaba35b06642c02064c0ec7e0033b298ac0a9296ef6e6cb288bb3d7c44f64c8213633514129e3b688b587a0ebf150cb1bdc4ae16d5924bc9809cb527261273217369023d4342551af1830026887800a0f099b68b24ce6cdcc9791dffd6ce74198df4e34db7e9f74fd82ab4a615122e1e6de8e7e67dd10fe1df402f709cd101471a70bfe865a5f6fd7ade2c8404f91deee99b42217e37d7f2ae3f08e67514483cf06c4eb1f198e2af9550582311af8696338d786898884c6427e74d2ca53e41fd331291cc562101ee660091db4c22f28cff2775f4f5f95bc6eaed81883c042dcbd5589c70c7bdafe3a85bbe855636a8b5fe912a69318d669bdb7ac070401251d8d2da8035f263996ce4197a78c59bc4e4da9cc27d476cb4586f30709c07adb74368a7d7389318d2d456c4628127fab300a3a81a21e10a289ee3f3e023db264616335d12b3a21189a3088b04c10c41f16da8b7467226bb980adbfa171c6221a6a36e89731486c7c84405d9af66a172ae3f16764984bf97912991954300366a89e259b6dc5d463662a53dbb77d126a332a5ed2d1b1611c09f5da7e7d41ea3662bb38e685acf8966d01732991d7f9597b00355de90a25898be9338e3330a2f29d8a019ff1e6094d22f10668df25c357114664cc0c4e414686211ea4cc40148967f222fd1d03c1525d419cd6fa3e03606ad3f5a4ac7ea89e749a06765c954c9d6d210318bbde195549ff96f4d6702031cc24b51a509845604f75209dc30040d73e0d2489b84f5e3d68663d4c774ee074fcd4b15c56cf7ce5c5f39faf84146a0b2ed0fb2ca4cfc930f9c1394afd601544f51741ccfba9cc25f4237a46333bbc8d14fb6d0d85d02351157df03d2b03a11003c12a078085461f1842f507043e4bdff954ba387115be0d7fca4a37d37dd637475af7e8c50921c9c21586eb30a70a0a98782e819226f0da72a714c443f90e9da10ba85cd29e870d3d17f009150219566538436c0644fc1d5d5bd7d84525f30f31503f0517ac853e69a834fd7d7f1dc1f9e010d9386473f02dc549a8bd975c1c66b69f771c94477e4d4f46010f14717b0c16685a37aeacd68407885b3c4abaa6208b939b7953da5bd0535c6ddfe7ca1dc2032bcf7591b7180f7e270dba39651a137671a31ce489707763f24692baef7dd6b9283bb4f56dc7137eed1b7c099774470faf24b70e8886c6a9d99f23057f4ad7b95af2be7bc71b5fac89c5ba6d481d0afb7a57a6c6f83e0751bb215e1f62ed217fa36e5531398c40c3711bc5f5035f7e2d6f0020a577afe73720bee1df5e0ea54f4adec59e40c34ae1b00097f64c4300dfdc4fd7129eaa6e14b55680b20a4acb59ff259fb56a353be752f2de34c0413b1f2de36c809eaec242d8df3890e2e5ec5494ce344e0a8be84dc6a991a2ca2babc26ec79da7c3e0b5bc1a56a2cb02e769c53e58eabcd2a472bf0500cbc2fd15e4cac290b21657484d178f9fb890f9e2d13cf11d76da5ff080c972ed07ecb27e6d56311d5efd60a1d8db90f7ae202de805fc080faec6ff0098bdb009666a1e1c0948b2af517de7368e627322c55ee4dc4758a40196e7a967e27eb62af1c95cadd5902f34ea502099bb48bf374e3df4418b319a3134c1dd86849a99e5fea13c02497e27ea425170bd84ce901e76fc9453d13cf74a2ca19207e6f843f519c504381e99a8fdceaa0cfec71a3a0e4aa45ae14e5d973e06021dea0d1146311850f36e7fe2c14c37d3e950e795ea82466e45d32df33f81bc6b7882c926bc71ee25c83358c4e040bd2aac398abe612a2decfd21197f957adc0048f70f7bb056eee38116702091dc7e3a0121dbd065ae6cb12123a8215f701623a682c2bf7c65b38493c601bafc677c9b0da06488070529ced262e435eb9f21b94434f2b9a7f59b676b373963eded3b873fcd056ca165e7417c049efdd236890e60b27978a6ee3af0eeb8ef06e4ad3d21e8749098c9ef3ea0a08d6c51c9a44dfcaa26b72b1985559f5070f92812e6f5e44193ce07202a4f702584e08cdc3c8107d0fa3fc120886267a6a8a96d52fa160ca0430fb3a09bb4879d0002590fa66bad4f8629244eb79450ab18ae39610e170553c84edcae0742515bf0000fe0aa9c1804752168f11d578f0fd99f3592518c705740fa2014265faf2692d3807d3dda53d2a8ef6265421d6e3711fb04a2dead0b950c221e576e651bbe93e40fb76ef87345685f9773fe5504d3b61738fea7d455c3a7dc20b4a80cd6cb74126711966b9abdd82881bee9cddb7b13efd2e1d28b2d66b85fd74bfa8658856bc0db077127b6f301b77c6f90d7cc14133edb9ca6d69291b76db6521ba0016f26a4fa37436d979b144ddcc670cd5efbb3c1b9e782cdf0832979f0258431983088e8cbeabf482b59877cfcddbed140d49bee852216a8147e69f82347931575d5f030897f09faaa2135c40597f888cd9d28bb61b10002372ab7e297504a5183f77e52376df7677104959e692732ab64959cb216d9d54b65889918386ccfebab0a96db33a2efbec9c25bb16e3d25b5ab40109bd33b409c585d4718dde8fa6ec275e5e69d4c65637842c96e704c026a6709bf9e7bd8ba898e584190dbeb69593a57f2e73e45dbabd4db6f5672705713f37cd8f593a29ff084ba2f466cd4266d41a6544490fa85dd9bb43e956ba02332515f28ea82916c0ff536dcaf65143ecffea61919e5d9d8f5bbd3afd59b41c95c4675778b0cd81b0145374d177bbc57cc364dae7a6d64123513fa3260b1b78b83f303225f5bb6179a456a2fc49a10e376d5dbeaebb71fc93fcc0c32f07f7ec37aa450c4ca823a89b7bca20d38924e7181d6ae2e17137b5297919c8bde7e9bef241cb35dafc3fc06a2ba5f2dea9367ee0c05b703a8f25a1cd067705f865f60aa8a426f7284dd5a1c96b659d2021f3919a5c8d8bf009871a8060d986b72633d289f6afb1f43111594b76f5e766e03d9fa0968f5b98121405ec054023b6ccbb3b2f18c5091aea7a9e7e38ae4746f861f14481f428bd14dbca926afe23ba37740e0e7b3b023979f4158aede5ddad4b889e5cbc786b21b2e0a9a2e950fc9b680a7b613b9e2259ea8fb8494baff99f50be1bc9590707e1be7ee07dcb39c933550b6535e5fe7d8ab25c40a909c17c3b994be33988a3f11f7e3895537685e7e25e4a64f069500350f81dfe52ae4391a7ab3e2493402e107635dfe95d2eeef4301c0c34ade886d8d6fe38fce39e2a9ac26ab78d3b8e7503c129d1208b1bc2a189a2258c07ad7045211e42acaa80c3bf2d9f8ddcc84cb17c4bff0776f43cbb2c22188fdbf3e482a489d04eaa7efb4eedf788db3a6a138363c7c82a9a2c32a1701d5ceb211890bcaf3a9887e9ac09b2e53533606f6e5346323aa835fe040af4a9dcb0a1f1e6ea3354024ca9a3cc10200a954ebfb53f180010a9553f22b135c76b3f4ba6ce6fb5ebb76dc1e42427fbbcf4abd750475a5591e28eb2969524db3ec2856ac5b3cea025b777c4ab02ebeb88c178e70c92ab4ef9b35bddeb9fa7062960112ab226e1de436b72973f2626a85fb8783a0cb5f12754434879214a9a45a88472254b7ff139ba7e392e7d10d8c05a900e36bd6777c654c888ab7ade6dca954448d1da094af544535c40caa49f113da363c0dc363f3412071e5f48778f3a084c537f42ae7df04b1790e8f8bfcfc7a522db40633962354a2583c8c59be70a3c095a144434f84712c8d77101550ae32f822958c27287e3657a380ddbb50dca12a74a7b90203c382402cab059409bb8afe60d0a2c3644b8763da3ee07ab5389a62a2ff78f017c608078d905eb01b651cc533f488b2586038c1a24a6e88752df2f2758f6781ec7751c5df5ad4524fa64ecc65269c9258a894711d0e69231ccf99e8977ccfb58b1e635ab1ec0bece7a2b5313d07b3e55374ad65cbd4dd9329c737e2093c10645083c91f738d8f0bb0b67899676096e2b3fb7286cf88f68c17fda4f207d827dbc2fd19e1f6898ab849a44db0014ce016bc3238f246694e9df9944595c70a9748ed3439e05b9809b3b676de03a8c048268398333a479f382749debcea7354a6cd61e1d41430fda455143df6cdd95017989c4a0e1ee0c36a35f069342978bc68fce8dd52827dd8905f69d494e65338154757cc8bbeb9596a2d5b37a4a4480408ac05443700025bee24891cc4657a778c0e1b4d545282b72a6d4f3fc64101e9baa118d629a8ca29ecb96075e24e9d581311f28c54f0863b7bee15612eacf4b0e6c2bd63e80f8b16f46c9d61a0d87132b4af9a38dedbc2ab08f8597c766add771d02195bea36467bfdc71fa5011fdeb9526b9475efb4f922841cf12773d02a1f4256342e8b97397676be5a44eace30e578c8ee0b92f7da790ec50a4b7cadc7f648b3b7207daa2605473d241c42fc982d03e47f9840846e25d3d94a81bc9fd222eb1863f2a341bc4324e9e45348410b66a60877dcf7e92ca2de415fb67b9fd59da8cacd449c8538acff802dd528c984de400d88558913f8cb30543d7f7e311e4cd395608db9eddee18e30a32e87469bbb74431daa5a531ccc6bce51a7a8600e8d3cb56880c1b4da4361b4546bc90e9e020599c9cb73da2e7d7e5ef3ea602830816f1990d8fdbd2c5eca0821c91c0f337e80c8fa4bc41ed6d14215b3d43b383baad5c84373695e0e4be3840876d83ecdee9f203ac8261f94db0b6631486105378ac594360ccaa48304fcc99614c2be7a7c1b6b1cdd48ff8ef3679ada56f9b83a2a1b5afd421e087390b34928d7408ac418cd6b22fbcc02461b96aba27bd1170b4abcf335c37b694ece6d12796aa49a8e390988b8b34dc9c9444fcc11fbab0ab8ada8df4fc44899c65aace426bbc3eee23bf1996be183c40577751def4e2f4a35bdc64dd3a9d4d22776ad90ccf6905913ac2b929b9ee2c6d09cf2a30163d49c448de4a075fb222cba98caccc7c9c2e822a5b53980085032aac8dd8dec9a715e5e7daf580fdcd0f6e192ba3c91b72d0f5a949e8ed58b9daa1781c17589e499ce92dc25ab4b30d35f55bfb527a4e55cd3c96827e077f2b112fe44a68391324485fc929a45987468c91141e28cd6010e45b1987b9888fcdc8dc9db340ef95b28ac085a2f2caa71702132526c0e28dce183e0d63499b33f4862249e90d41c2eb1f540802a85753f80b74bfd069186ba20c7ad38ae9faa658f41a91f9fd87bd21036b1523d1c810e24811ce689b4a5170dacdac7053dad80a3842e144d812255bb66b9dca875d77c8764de1b501c18d4d1c706600f7e12cc52512d25c42c7ee2ad7c2b4e9484ebe7324643bbb460d89bcc52bc87950de1639e33664608c88d07e69b751bd0c5d6a693138a228e5741758315258f66cf77cc49ea81dbbd05ef859e21acc8d5c55f569b571e4632fa13d68afcbed107167111e102989b3c8e5972336911c9df2b45506e1cb6da10d8c3c46c3799e6ebb8f55af039dfe29a82098abea90d6ffbd906ca74425ee10d00d58c5412c4f31debd1a82d0d915f5716d461660e191b51dd5d89a50ec6a374065173945b03daa992361a4c70c20d288f5b6661e61eb15ef7afd8e7fd6f1d6ff156952147f10c4ebe2ac1294e5236db9652437b4d7a934530869acce167a281a27cb9231f91f8efbefc7d2bc0a3d02cec64f95c823c508be8df982c5c5c6272c14e24947f98483b1ccdc2831bb130a8891169277a4144746da67cd2cd8755cde582786c869750528a93df31484a0a94515941e5402e1805c07cb4300e6c628e0cf42d1a3d0ce9f03bc98ed07e1f4ad9b00be25bc089838292f527f54da7af4c00fc4628681096ca659f77e10ff807aea54affc9e3a0e118e9b9dbf257fb2b2cac69836a0561b1a756826b308b0406b8b562c10696c118f72359ba789620c808c5b01b2fb79209dc14a31aa0d689f78d5c22f094b341d6c0b77443a94c53743824c9b6b06b9e2ce72326009b2d58b3c33c1530e7c294899c5d5baee55511656db9893c104538e8ef6482ef5b2823c6c172581f44656ec3a738181a28c404f20889a483e8ff1426fd77532bd28f160e9ad886fb421e700bb23a4f38089cca40c146fa1794b812639d0ea521e01f3234acfadf1eea2dc4d48b8a80aaa63290981975648f77f075d3cfbd30ebd2f7e7627aac82a0e2398560691424b3ae88536840c0db12a7933df53152b606bc71bf405b000a8e3ed782bc962ab9d98ab4b6a47ef79d9805ae1070b2e95f480ddb3dc7bc0a2f4f0c05b8602bb3db7a67a60debfc2864c73cccc91a0154dae7fd90f0fdc457d6ba31f3d11e32d43a1a922dfa5a16286e848e5437b4ad9caadb13ddf940c6322f9db80fde56862c9493c52de25fcdac2beae7dd47a75373751d61b18e8835b80936f65c72a7a82a49c1468d1bd9977f1c9c3f745702974a9b29f2059405b14f2960d70162d2e2f60200f7aa8e51dd1c9901c598b2f93dd3f3f9d17b32a583ac433c4f91bdf4656939850a93557e7093fe8d6791550e5b3492aeafb0b8b0f50c7983ccce5696ad61336656732359c8f8f0eb7ecf06823ee59776196a30bfe9d9d39e825f2336002c4b43650c94d4ab753ca220ec738c578d3b87eaad07eb72deed5258083d76975c62cbfe1663b1397ff2a88749b3fcb132abd9c7cd3398173cec7b0223eb74fcd3d151f1b31150b860869204bfdfa02db4a9758a16dee86e6b62a5b3723ca396ea723960660b90a7eb6020a42870275b75dbf96b9289867f738bc98a2ab8441f24e8676cab8dff2fdbcde06d9e2330b2c6904c67afc41dc7d1be43b5fa91f6fa900382630a3cfb33e3fd18924d73368a8fb2ccc59860b64c78c2f21572b053ac6335bc41cafb1f814d096ee7ddc7775856e4c78b749058f55d5f8c31ec3dcf0f0750db4196f64cf9fde13189deb16e823f7cc3ad369fba794bc861857a045dffab48660c679acda842cd0c45f2dde90be672e27ea095e1f11afb1b501d80acee83674c2c3013de345c8d6eece35dab2bd82e5774161c508beb34d2e3a4364ff889c6720b4c4aa221f1710b262b9ec1e036350e1d81d6ce5ad2e3a3f3025c670a86c060b665cb6e42b5541546b3494516580b8b2e36fe63899e5015540768ed4ff65a5c68fc4dc1d11e343cf56e71236c39eb0cee6d8dae6a01044385690ed9d4f27f6ca84c7b8cc6b7e74c6a41aa61f6bcad8a8b56bcbf03a561120883905013d045ba5023471ee04f4d79ed52c8d13adc0bed44602c64454e292cc4b187e5545d833b62f2667e3bc411c95184e07acee4fbb5b51222316b4919461267f70e8cc01def95aa2202d5d2d15c7590ed68d4a92904da82631c64113595f3bbe65de5c4edc79ffbd7cdf251c5d8570559030cb4d1836ade8edd887afb9dfa879388b4c2f03abfd50785861ed8f18f44b007062e91a02bfe10b0c5b4b4d6bdbb5a4f44204e23c6aaa7cb2a126a497cf0213bf5fee6e48de067ea28fdb6c888352c88afc8ea39e821b3c8e261c3722e39aa827505eea03819798002d6304909e6a507a61bd9490cc67f2f078c89c2a3b1658bc73dd19825f44d09fd6a147ea86961c73d9abdfca72222ed8a253e58458bdf051c84b5b1083ccf31cd62733a97b4ddb2cb3a53fca6cfaf4435a76d63b78541d0b52349f5a819be2d211e6b0c331622d5dad8448dfcc7f4f390f09365f647020b8be4b543de68377db5d0e4757b83e42c0c18a284c1396a9e9e0dc1bc471194b84fb25d0247b2b6a8d5a2924722612880bce38162b389b28a9039ca89b8e4f08439d64df67f9650914bd3a7b499c30bc079c655c5f1e492677ff27d08d6635dc3bd2692b0f496e8c755d6f56527b74175c271207c936f50808d71e6c33f8c54f103cdfbd83ad6c747202b24688a68c344305458b38a62bd11fe18ebe3326ffb879c3e582d7991eb286d71fc2041f8461faf473837b49c54aefbcf424628c2c62485c01f96cba31d7f08e37d4d03c930cc2f72ca566bc2e4cd386b13f505bc6c86b1dce95a3cdc5e730e51b1ad859e7bd011f280a0a116cfdcaf0156ecbf3d4b1600f00cab44b6d9c0a6b8576721a31a5df2ba6eeb8c0b6a1103342d6ce2eccee0041b668f381714917d600838d44d8eb9beb87cf9d81c8859e46af73f4a0b25d8147e3510b66b9f15261c0004c2f29d253005b4971f373de91fdcdbdb45907fea5734343109f25cf8c6992d8d80f65249b863718406c361a3f6251556076f24b05e7f54c7ed945e347ca2284ecf0238d735f216adb5e1051d444aade58d547363b61c5aecadf6db37c50737f7783e771a7b1ef570bdd71dc2893d8b7567087ea9ee996f8904c807ecfa1bb058b3504f4f6678763534534cf069712ddff2402bb1947f6dc53127a12d69d1953216d1711ae2491a930c708087d18eea9331ea4aee6a4e319b97c5ff71ac5e53a2e20d9cc5229172fd6b7bb218b5d6c95cb348422988aa549adb8382ae4b874824fb705ec2ae76e3736f6e6252a217454e7002c1409ea62ae4b8a02b18654c460678f44896bfb823a9b494720d26124ae9f667c692a916898d5a09ef423cc515f10e36e36962fb8583504d3c067793b16dee1ace4f60372c3026ab9b991b3d82aae5ec12a107cfbd8316ecf1d90da74abe59f573dd6fdb68fcb420246cb52633481f17c1480bafba9a2e1e8189cce76173fc87edfa90123870d99685ee9954ae965571ddf475d8bc7a777c885b698303bac69e38d5a07b24cb47961c59d02ffb25cee985b9b96e515cc9e8321720b1202cacccae2a0d7fa39d7013fc53d30de9a8c78375304c3a7e044a3cae2293d5cf6556c1c27ba5b56e31a6e814512f101f2824bd3d2e1593f95b5ac7f62577e38564ebd08b946c68bbadd62b8a9d926c53bd5517c46726c4a8bb92b32adfc2296dcbcb3c9623f2db46ca3115bea45c815595eee119fdd68b2c9634e35d49e91147bc562e63a992ab7130b37ebdba4d84e3b1acb688e8d6a11ee4296958fafc5ec56970d8f738aa1f78c5264472cf43f5a2f04073dd7a73484d657ea955dce02352e0db0315754e17633c2085391d95d420519b8ae13af9e0170e542fd2c6bdfd13f15318fab9c7a005a5121b81840c21c08b4a26f4e4e791c9c32f135dceaaefd51e2dd5b0ff5c55bead3ba9f17bb0cd0417442c2920255d8e90e535e89a1d1cce9ec15204330fbb0c09fbf08bef7c6a653f83eb345c126c4eea4bd4474cc5208d3f8e6adb236b5ce3b1e841b06c99a0cac43374b47695942212a0062c45486c7b82672530570c6fd6885d09900cb5c4f3b74d4bd88d4c4c75727bdd0d922a30c33679ecc72c33cd921abeb2cc6998bf6ee92a24c7809f985c1e7c1789b6385ee560cdb342aa7943ea65629be129bdd4c7ff0f541f365b9b924116de408d9d833541177726816fd67c3c152d8a037ac882d4322224f6a698f9e2f1ca3aa02a76d6a08452d752a0b49b9f50216934451d1a4c428b7ffe35374c8a8f3a871ae78544889af34a96c790b54386f0a7901e3e11ede824242df7bdf433339d39a599938330332cab6587337e06cb50dd0d840526986a0ee6d291d98580b4ebb28a52782a4d436b1ee908ffec162325e573f70fd3aa9d218efc135b39f41a1bf2393492d4e0e196e977bafcdd20f86b3b01341a1376ae112ed9b37c3534bb2124490cd615f7e31e3fe4cec4046f3c39176a288dd59775c4ba3d16546a7b44b00fbc36ee5e08c5df62dda2785129ff79b66fe9cf4f6779a6002c33ca7991bebc7780fdf117886e4ae2bc7de6bcae3e33c3aebde68ad77eb84f1986facc6f4e03f815dce5bc5a8b050d9e1a68b90c07e63f5ecac76d3ab82388aec3b9ce09a67b19aa6095385adc75226e826ac1c55b2ea6875432ea7c53c5e6cdffc9834594959499c2e389087289565d23ecfb0e157991acde3d03d9a37da48e1d18b11b5efddd655ec5a506b00876d13d4b46ce9a5234e84b662345fbb45a24438c32a6a35d8e126403b34d44d0f5ccc902f2f613c18d19d3fcfeb1cf0b5f70401e125efd77d96e6611abe6d6a2c5423565a34eb27520ef2d3eb2806b20c6f9d1c53fc29ba77c05a4d1d623346751ddaa1b193b66b4dad5a642223251265e9dbfb724829ab08de996dec44ce36a549f42f23c16cc05cc5fa883901ddeabec87bbfbb6197078ccd2c7cdee669ea6c0a65fe7cfad87063560c307181eb64533d0d0f1230269252d853c898918d9495c45957eb002e36dd95c25b4ea9ac0a23a103895fec5d63f14cacce989431b494fc813cf2d6b1528562ba61b7eef451c5d29f840c83bac1ab63092e6af46e53318ce4dbaba4b45f7f7f34fe116f32b4952ca3cc9956eb3518a314f90b8760b76e27ad9aeb215b4e006644016e81bea44aa652776198d4116b6f1b2d1ad504f2f9c44acb19d6e488a11ca3df0d353583eeb669f65b3085f73f2906f08229768259424cc4d39b3bc70684298ca65fcf9c480c7982816d2e53448a7d4e28a6cf51fc444f4e924aa1b89f31a89be2ed3909130fc6c5133638559ab7060c4428d1c79cd6eddc0f06aef04ac86180073553e4cb703301f02dec84795790c30043ec431dc84cb029cd3afa96631fd606bb2f1052d295d1236cc067d8bdfc73851334b1e193bb004b9fc446cec7307ea07982b657c2cc4d3e935a7b020040f18aaaffe049ae17565cd1776170015e2ca766815e435973067e5477ba857ae2a178fc5b95b3bae2fa499058c79f0280d491d5c65c8175d84bc882a7852f76352e5cdcf3eca7a49e06286f65f0a99c60633236bb1032298efbb473c88cc40ac5326516c756562cee112b7fb9d5d46661e3d9f2cdd904a6f0fe2dd7f4f5a0be93fa65cedf259814a834ad50b4beffeef8f5a7d2084d0da925eba7625ca3f45a99a86fbc085ea4c45829207e76484db67c9b23b5acc7b41c2d1333a003aa5ab682db84b779a0dc2a21685522af367928b271b735b3a0a45851fb4777e79b7d2544b308aa1b6110e23928ae0c9df0b0e1ea589db1e6f2b6a9eb07328423c6e916a407f09faa60ae5b4604c397f7a34e478c656b2f15d3ca8f16f568f35f796a0da1f93cb1d048eba4dea8850a610d762f62bef7628b637af9f11133afe0f50604a502eac1469a552092aca30e27531d57a22f9ca755a71a3fa5373c1ab1781cb6023183430dbe127dd2720ea5d1661133880b632ec81d2614a2aaaaaaaaaab26a76eb5cbd8891317f7de07c2c5e86b99e8f6c106e89dd5b4a29a594018b09bb093309412a600a1b632a429585a5449296ae8030b6a64049fb0dd8f71b1e5b8c559e74841999d27e033c4107540f305c25d420d37e03e6fb4dd4196153921d66968049fb4df00734b05ea0f122324496f69b2fdf6f9a567cbfb929cb95e572b9dcf7dcee7df5c2bc8cfb972316fff25c0f077578b16468c654d3500828690b1a66406a58390ac322edb9e3f7dc2f025c668cc6307162a629ed39201412242864568cf992f69c97ef391d418e5ab688a9e12199f69c0ca61bc9a1a42a3996d29eebf23d37e37b2e07058582a228fa1d2d16c3f411d547541f51b487832a142844b0b21435e5f8ca1fb888d6d0085231937694cb7794ab05928a8e10483990d28e02cfa490812a81c5222aede8d777540697314cc086b8c8f09276b4228f3ee3192ca92d31d28e6ef98e4a7d473baaa56cb4948d8d4df26dc874d0e62b1826b411da086d8c7fb94d0f072d40cd30cb6b18c2c797202b50a4302dc1828492761b2ddf6d42682903e6469023b2a6b4dbf440d224454719310949da6db27cb789faa0243a6c8cc9c2324249da6d2a1831c91032826aacc8d26e63fc6e6363a34fe0f4091c0e871b7b1c99c6699cc619ff725c0f07d5b118c9b329e3091f41d2cb7d044931868a080598761c96ef3812a8e05ad3450c93d798b4e37630719d18d321068856da7157bee3a0ba28799242e475949476dc90a3241f6088e9d13093769c95ef38216e88cb666ed9cced764bfe2df99593615e467d23f65bf12fbff5705005927471ed503a31054a7ac548991a464d39c94afbcdebfbedf747b88658b884c62869bf299141e3eacc1713664b69bf55f97e235342893146561126adb4df5280250c932416627480a5fd46e5fbed76b3725a39cff31cfb7b1a4fe3d94fe35f7ef670100a3dd230811a32a5a4489a83858e2b5543452dbea4fdf44df97efe40205545c71a2a4722aeb49fc0bf2076d524a3cb1527beb49fc5ef67d4df33529ec4c038fb5022ed67f0c945142167c41c3d88693fa57c3fcf13890dc9d95fdb57b71d6dda6db6b1b7916d5d1fcbbbadabdbbcfe725b0f07a15066bcc292a32c8c476a533484a38b1197de9ab4dba27cb735c084161e3e5670218195761bce8a48a5c711294d63d26e83f2ddd6a1c69895932089e3095fda6d342881048cca8b490b55da6d5ddf6d42dbb04351da6d5235a95aad561bfb5ab016acd58c7f79ad878376acb06cf1f05183094b0aa5cb16a2912f4d8e10497bcdf7e47bedb781202da0b09048583dd25ef341f2232baab1344244da6b4ebed7be6408410ab3660851da6b24e00266094192223624edb526df6bc2daf06fafe513b47c8246a3d1c69e06a40169401a8d684b8d981b6990c0d8a2036199124aa0a01021493b8df89d56b3101d61ecf05023a994765a2592700252048a0b092769a7717da74589780a6e7d2995750192765a7007474098192b7185448db4d3987ca7d168656699699ae6d89b649f7bd8a7f8d7f8979b3d1cd44185b1cb89a61553904ea41f00f3f5e58288d90a2e6937977c377f36f812e2820c19a11958da4d200edf4fcd2f8d9558dacdadefa619d73179c622c908156937c3c4444931030796a390b49b4abe9bddec2694124a5996c92f71b1c4c5121f4b7c2cf1b12c7b38a8c30a1a514c80f8918388043cb265896ac68f3522d25e26f95efe7a30a3298c992f204661d25e1ac1d802462152e29b4a7b89e47bd9f5c4c9d250d81a2867692f833090d10b5223481aa3a2b497c3ef6569f3bdc4203606b13732f91bfb7c6140e263a091e8fb1efefdbeb77070073f58b57f7f79f40062359645a44bda37f041d038419423e8e24590b4ef23df77d45fbe7b38080bb18fe558e8b3a2ad68ad937fb5511b35522335d2f897eb1e0e32614894af2ec4a91c6bd20c68843c6d99150d0d49bbf619f9ae7f465474955991f952f322ed3a0527b12e36ae6cd19a92765de4bb8e4a7aba61e662895794b4ebe00858d040f96531e3d124ed5aebbbd65ddf1ef9f6c83927ffe65b551536ccc41fe63bccc6bf3cf770503ddb3a41c4d453f1824754901a6544569e928ed29eb3bee7df0cae48414101f1dd487b069280468ba7a662902342d29eb1bee72823920d27a220c3324e69cf41266055925daea68850a53d577dcfc23cfccb7bde8282a1608cbcb8888bf8888ff888f18cef78f89777bcd50bf6aaa2ee0f03ffc7847f7f2f93cf82b816c4ed1799fc4bf6d7f7f5be302011782df05e1a97f7bb150c066fd58db2c20bbc4c7f3b3c3da152b3069906c8517aa98062642449511a2292f6ebfbcbbfdfdf02ea012cefb6ec17f096f76ebffe761bf637ed76ec2d991051a8286414fee575c7773bdc7db75b1c0812ab3e6a05d80768b44cc8b7b6878352b8bdbd1c08d501b77a00cb6f0b6e108a7d2cbf97ffa036a0fee529f0c0c82fe7000ee2f8d8733aebfadaa21524bd47a4b030e132a506559534027ff90e0775a0c8161a1b22a24640a597731ce4032652663c6071d185440a81cf45d922e283714b8987f472211cd4e1090a0a205b67ac82c6f472142ed003fe720a5ca0fd97eb78a07d33bde53b8883f256f02dcf950555e11ee6ce866739b6e903edbb8783f256deda5ed09eb7b6f02ddfc2adb587468a044578cd75deca5db827b4ebe25b8e9b819e55d0ae836ff949057744bb06bee5ba1868cfc9b75cfb7090166aed7bcb736668d7faf896ebe3050abb409a5bae9143344b0178cdb3500f6f8ca8d6639cc71863de8383506df363aea12201ae2080362b508552e3330f0bbda985f69c85f61c85f6dc23423b1e423b3ebee53843501c2168c7c0b73c841368bfc6b73c8425b45fe45b8e8302edb7ea2dc75942fb1dbee5651ab4dbe25b5e26d16e8f6fb93904edd6f7969b42d06e816fb94905c51942717a68e76f7bbf35585be345d2b09be88ef7fc3cdf6d9e8e5ab4c72a3109b37580b53ba63dc025c247be243123218d3a2186a106124cd020bcb6f23d751876085fb25c328d889b7753f38eee4adeb9c97b0f8df79f1aef425fe3e9423f264fef29793aaf9987f6ab15f52a32db48248f3f6637adf0789a00fa8cb712f7677bf7de7b6db8115ab89b28badb71def3f3ddbc3ed7844bc2d57031d89822ee0d5b65add0dfefc76443cf9c156afad0aa6448d505eaf7c6638ecd7be302f5cb74992e50d4fdc1419cef76f7de2b84ed0df21eb6aaa15724145a8fb7046a6faeb7f69faf7c779344f7775383bdf16c60cfaebd2d6ce793253ab2a58780a187af5b5aba8469e55202eb5db05c6729bd6023ad1cad0d98407dcb9373b501f56d449c336c8cd09e755b70c24210a2dd945216d19e755c760fdd1702487009d35abff2adac27c6d40625ad1cb50eb8386150cec55a8b7d6ec6dcda9c73b6d6561c64ab8fe53433f722e01bc466e7ab085f735f69b56ab840f7628c3131682d43d11c8aa27cc9f8288aa228e7684d51940b797894a720e304d2e772b95c8e77e0c6cbf1aba5303a0edc78e7066e3c34aa42ceb944ce7928f3e49c73ce3997f30839e79c73cec91eb2869cc2ea73ce3967aea127f39f0bb4c333372145f273ce9cc96bd0c03570e36930737272727278066ebc1c20891f61048e811b6f043397cbe572fc0229943c0fcf17a884e7e116b8f178501445511445519457e0c643c1fc0ecf3b9c0237de8e2984a24bde41903154b4b89071420c1525a5208c31218817f637811bef94c08d97732a7228250932434bcfd6a1a7c6c8af45952c42255b09dbb5d97a35d6a3cd6697804c6fc3b1d96c366bcbd96cbce2e2db5010bdadf6361f5e4990bcb86165cb172094cdc04223cb151763521b89b7ddb7d9780f0ebaa92db57121126fe329cc781bb75143de86a22a97cb71de8d97e328603c8aa228ca39dc78e8799ee7799ee779f20d37de89fbcf67a113669f7936334733df65141e3ef3f4c6cb7fe3d9a29ef37c81f8738ec28dc7cd2b132c3e43860c193264c89021438624b0b7fdbc8d47e0c6b3257d7dcec5aea933315230d1d125cd69c0147d30f3e2cbf128cd16e93387c08d971f70e36510fad1d1c1f03a1a5e8704067c374127023a9cc48bd7d1e126892bafc3d11d89d7e1bcc493d7e13d285e87fffcb4bc0e17d2e12824b1781d7ec28da7332ce1fb095f8b610389e26b088a0f62d25e853b601fd470950832744c7b1d1efdad5e43b55a0dc3f0bd8ed13e2431a13466051252ed670d91a01650491727353ba2766bb95aafd71baae59aad86abf1da6df06bbcd6acaf36fc5aaf9653fbc0e26bb50628e9d1f5bb5156bc91d69c7a9429ba4a93e5858cb466f4b59ab1c67f2ed0c96bdc04a1222a5fe32930f91ab751247e5fe315cce7e47007dc783911b8cacaca3e159f79cedcf455f9ccd1159ff94e4495cf9cbff8cc7b8cb47ce63f4f9fb9d0082e9f390a519f8fc27ce61c400a7ee60db8f17251c3883031d0284181b44122ed3d9fe31106f661e8834c9a343911df853ec76bd1e7722fc28c94892871e4534a49f05a61e2858d2d5f66a439dfe77c489fe30cb8f17210f87a8122f05d87e16d1ade4682096f3be16d5c6fe3d9c64da5b77194a8c9dbf8eef736ce4134791bef41f1b6ab10c5b771a122156fe342379e4d0305567850c14505910b3469ef7994571cf40264141a2d45b22288b4ff3c5af45de8515e713c7af3a8096321ae28e9623a2b93a2954b4c4b50ca27e4879814b5211ebdfa207c9407dd78e8f9a7ee4f0c7f6af893843ff955efc79f27377d7f72f4e43b0f5c7f72dee2cfab21b03f39d08d77fe2ce0c6ab89f13d060cdc841b0f03ce8d0b7a4d809c39b302c9c9cd51a907158b0f21cc8a3716c4cd4ded06dfdc9c373c288cec6f6e6e6e6e6e6e903737dc840b54fe0d1732f3376180020833e46b5c01375e6d270c93f4e7799e274fc08d77722c1b12aa0960208a8025093b0a1b7ee60800f3509520f97a04413245aa4a6aab65618a26924e50c9b295da88dec67f6e3c1b3fc08d773356e42f18e02f7003dc78174e780bc11c2c448420d264c402af38c80436c6a4825b452b230bf683050b3d0b350b16c642bc85db5b508115d507a3165056c0a4163afc082a41fa01e4ea8893d4821d7a0b3d38e8c782050b5c08c85b18531ac0d77809375ecd4422a642839890cf9c841b2fef0a70e359187b1144e004b8f14430c570f9dd8e9b3b8eeef86ec77b763b6ec26e27864702bec67d6ebc5ae6d9cc1ccd3d375e1ec08db713223e0078060017c08d0700f3ccea2bf07c81745f618b940d23f008b622adc0511c5402296493192e2348abb402df5d20ebe12b70122a70132e10ed2b4c69f224c3099f7d32e715be02af4716c89e3ef31dd9d967cecb889f798f59d367fe236486f5f94ce9330fc08d97871abec66beff91aaffde76bbc76a1af55ad4f8271ace22584d155daeb500449b61c21a550e34146da2bf16bbd1a5fa3e66b35d38cf18a058c11328ad29ad8123466825c4152a2495a3bfb1ae764435fe31a6ebc9a71841bafc29a1d1f02cf17a8011f02e7b9f14238bf9f90832446267a2aba1431e9be6c99e2c44a19325360e8cc74489daed4e96c3a5ee68b16099f4df8cc5fbc2e84d7e9743ace7190edf5e874ba354faf43e3e3b3166152459a1169c63ef39e1f35559ff9ce8d9785d0f0c82ce00293021e512555a5b622205a84114b620a7a496d656fe3fcc6b371b131355f4b6246eb8c8faff10c375e8debdc783a64191d8fc3330ecfb9f170fa095ff2da6bafc32fc9be167b255ada12a7e45b44655abc52641996485a3829c26508448e22e59ab23ccb325796f6c6971e3c8819c204aa2999761b548111b0a2154d4b5bcea4dd56a92979b7c36eb7be1c4abb257e597a219bbeb4f9f28c5896a7e391323f88a465c5b294e5248c1031adafb44cf325e71a843f2517426e7dc953d0f1555846c697bc2ef91b9e6f38861befc6acb572249ff9851b2f57a196cff19ce3166ebc9c49e5cf939b38a8c21a0f413557b6989ad2b303902835b8c8289959194bcfe49f5c841bef44ee7894e70b64e151bebbf150b3a6fb1ac7f0355ea1be76e16b358e627d0df9fb1a07c08d57e3635ebced6ddcc4411d60a4194b4162e8f3c24a6dc821dfd516105c5623521b9ab7f10a3c841baf34be507a1b9e6db8eec6b3c1c155b233a7e21017e28a329c0a18417a8cf8a10209ee0c0e57c30971199771bcd7b102583153752655c6c9151c8db0164d4c47379ad26e7b66be5bdfef713fbd5eaf872b7118c77fbeebbe6471e471e6e3b6ac9182820a0489262a29ce8293940d1442a8aa34a5b8b1c7e170368ec3b940f1b817438f7341e3cbb274e1e44b8e73e395bbacfb8ce133af5c3e9f399afcdce2c7677e73e3655eabd56a359ebbf16a2c9cde36c2db387ae3d96c6e3cdc8ae2df78be71dc8d773be169546a727021f322a45292f62a348012a7135b4a84bd204a7b15fb5e89c5a7f5ea558d4fa359daf73af6b4154352b0cc9e08b1a4bd260370a30bcb8d23135daca4ddf6cad02ccd2e3d8d57dc2df06934eba4e469e5d32a92201e8e1e9cb4521ca5348ee2201e29ac2821545e5098a434324fe31cd368342e04f6b4ab15c3a7f1e49f3c9f62a4bedc5f1e804ac9f74362920296963f2469b4c6969ca032252d915ff2f3c62b9dbccdc66d379ecd24a3f5f97792465f26944c505993668ee2a00e43b0acb4964a5c899222cd6332bf5201f5350d5fe3b41baf76e3d16cd48d879976f451ef949c0242af35e6d91a797bece6d16152e81682b385e0e0e0e0e07cc7d9429c8de3f597e3f4705009468881d2e54b56931d4c6894a81cd162a5044c3b8e98ef38bf619a1c6329caa4acbea41de78c070f24468a2a9892d28e13e63b0ed21a291c411659c686a41da74271058c18495e2089483b4ed8771c1ca3b4e36c1737dbc5cdcd4df2efcd66bae937615ec11be2df9be25f7ed3c301fa93246934cdcdde921ed59852731389685ff5109e1f8ce769fc8a65a567d45a6b9d416bad754e6badb58e58bdd65adb2073e2bdf7de7a46d6580a53eb8954069f45eae85c8bfc8ab524cc2209a0a6e6636f34014e6a8449489870e2949655aaa6c03cb4b0b1a555630910da0d2213a3e0eb0354962d2e642c468021a346f20b16910c1a57886cb0ae286980e14be2d584f894650436b8ce98a414612a8afa92c3d2b1952bcbd28af14b8e0197537befbd15f07befbda386d9dcfb52c91b8c8e556bad9750b1345a1a1f671a2abba40287a2aaaba5589665599e25edcbb22ccb92c7bc3db65e4df9fa12d53bbab22ccbb22c4b1d5a310eda2065cb05d512a624607a7366468c06892543a2a0c88041c9a829b359d1929b2547cb25545f720c3ad07ca94bcb5287a23ac9e40075d4dcd449463ca6431118114715d4892e60d27d82324684f0a0b2926422dd4f26d79a6637f890349a79de1e3255b49617de7befad35568d7c45262a7766532f9035b3ad6a8ed8a77ebed25a9fe87eadb5d6bac5f5a94ee60d746a67c5d3115ad7a77eef41e1665e3537678cc8573b4a64e841738d47b7f31a1245489f0b32145752cd4d1c9442e1f2c295f4e50c52aa9d5e63b548bea6bdc672e1e1b5d6fb6604adbaace39909d7f9b837b59b5b7d2abf5af7cb75dd391c7a66b1e18f79c963c3fcf10532bc0c70c9d3cdaa79faaef2f4cbbb1c63de2fc7381dd4ed06ec3cca35deefbdf7da5ac2e5e997e7db13428e6c964725ced50ec185a95bdc7befc5f970efbdd766db9b0e9bedf838b823ecbc0d9f76a71aa9576fd3d7eeaa715a6fcba7dd39b5a03dbfad5fde56d65dcb8ccb3cdd067f79722da166795b792100b584ca79be62bd8d66de9aad1927c20cb4e79aad86530f01dee76db596b85c4b28917e8f837bc102f906fa67d0f338443a639b6b2b8aabb584ca11f01daecdbd282a465e4c8c276c150855fccbf14dc7064afbbd26098cd8d72a813d0209982c5f6bcffe6ac3517ee596eb1b24fd955b5e3d50c57614c37419a1034b4b6ab3a9e54dc7066ab9cdc4a679cd6d66d3b4b534b50daeffe02fef3141ed572158efebedb10136ebd9b31468afc81368af5f26d05e8b4a28d0bb54c5fc7a0505e2bb690109e56286bdd0def3f549cd77f3eacc5ac245bdecaf574f63dfcd37ad036eefd77ccff85644ed677e7bd031c46a85289ce8a9d39d5b879e3b4e01144e1d069caf574f59be6b20d6b019eb362f5c26a83943833d11b199ad6ae898e931b711dd1edcbb3d9827c7c26e0fbe471c2ab45b2226ba41760af7acacbe5ba2d6e36e895b8fbb250689412e62b18b8899b66ebef75a6b5388410becd4e720b1894824a2403eeee23840d06eabba6e906d717d8817c87227277be3c6775b0534057c6c9ba097dbaadb837b825ae1edc13cf358abdb83792d047a91f777abc5a7055ae00c6cd56b9e354fbfafad0dc2f06d10b4de96b7ebb30decbd41185a277406b60a67ecbcd7daaac7f9e2eb04b57848747b9263f76804ed167889ee05c21c0d42cd9ddbbb3df71efddd47b4a375e72e402478b9e6a9c9402d50f36ed6cb7950f2f4dd6ef3a09a27c9ff974de49c42af618fad4f1744675093e75bcdad4efee57683412dc74bb69c824dfee5e811f47264c53edd123ff30007b7c7d6dbd3eb158ddee3e07ebe7707e760a097a34b1768bb010ecc5b9e99f5def2dc4441bb696fc5f73b5c3b01dbb05afbb4f496638003d556de31bce517f0e51cc0f8be2d61ecf57a1e8288aed1061199c82b19c1fc96a31004cabd9dc1f49683e0ee5c40e8d5b57381214520abe2ad59b1bd35e334d35b9c2cd4562641f9731c13a80daa4fe5358de9e1ab15f195f7dddb5a42f580f6faf5959b3d542786ee2ab45a8eb9e53f3848062498b010bb42e645040563c0a2bcccb8b1650bbf9c7fe7ff28dc1f1c54a904498e8852e209184c6d0cacb1e25418283243a905b03126c07c68114524b54455498a3e1d5d5552cb7564d09b29688906fd29a2dd267dbd1747c141b4f68bb18554a22cc9a745c22ac70e2c265361e0951abb69afc84c5844261ef5961ccc67f40a2d17936125e80d1109d444a17f68f9e29e39c1e87400a84142d7ac5d20288132f09d0e430f0e18b83b3f18763adea3a57bcb31c041874143f9f52aeacc7712b00ea419659ac3e267f3e7f34e68670e8d6f0a09716415be697c73f799dba837994cd3bead1200157af37b6ffe26bee5964b75803ed603585e35182f5f39092e9005d62861b89a94294a2ef1a8c7324b76a861a2f5e20a904d710218c79e871250482ad2ca7f701009a0c020cba448793224adbc87efc86c72ec02e5bea2f89ac443c5182be314a319692dd3fad0e5050c2d3fd2caed576d4096c1e65ec50b5403a1b7277050871a2f5c28a9b91a527326addc0a7150e9236a89d25959104b5aedd2576e83382800655e8a9ab6aac09cd2ca6d140e5ac091151f4ca448aa004bab05566e7f955bdf05b24a5f3be4a082e5c98b6b4588b3b4721ee0a00e3e889e66803d390693d2ca53a83c0695afa0727bb46117e872ddd7da7b1ef71f135e3cf92ee44bfb098fab160eef95d82586f4bd1ea5bd7a3dae1559c7d6847daf24d25ec91e5b22dfe36e7fbda6efd6b6d8f16e9da244e0dd06a7c6207db7554969b7561678b75ac30bbc5b62d798d8776bbd1e7f1df1d8632ee3bb4d8e48bb257b7c7ffdfa74f0521295ef17f8b7c563deafd38d7accef9489e1f75b5522edd7ea31ef576b7889289a7cbfc51369bf5e8fefd73d5ea40a12df6f5245da2fd9634c8473601469c72d1e63a7a8e087efb8eac7ea31d6c269c743e2d216eff57a4b69c75e8ff1d74d3b3e62a4120fac94764cf638133dc65a706ef198639ecdfb21c598eb764c413f278afc4eceefececf0ddcecece0e4fc18db72374212727a77e7d4ecdb1393c39391ccce7e4e4e4e4e4e4e4e47021e0e728113d8fee79b2ca54c148e6889194f2701407e5a89c9485106226e5ccc4f37014dc783cdc8494dfd9d9d9e1bb1d7e821b6fc704375e0e9acbe572b99acb55c8e572b9dc4e2e975b4af1b95c2e97cbe5f05c2ec7859e3ec753a0fa1c2fc18db743821b2f6704375e2eaa769ee779cfdc79cf133dcff33c79cef33ccff3bc67ce79cf93e7e4e4e470a52ddbc9355ca01d7edaf43cb910953f790a5f7f721b35f6674e4e4e4e4e0e17c18d97c3c3c3c3c3773c3c043cc76b522e97cbe594a47c8e83e0c6cb2919f99d1d5e08134d8ac8ae134fe90e99deb0884cd98d1f52d21d9bf43bfc0337de8e076ebc13b5286a51f486f28af21abaddde5459a7c36d6e62f101a2c6dd65a54d9342ac344c3593839421469a65708a89c44f1d4b22b622c44525b5b67beb29bf5a2ccbf2282513c22899be086f5e54c0dce666f552c4c82f039ab434b3e8ccda746199aa76926d47b03695a4a53d90499bd7365a6b9dfc8a15f57bad93387aaff3de7befac13c13c35d289348dc6e46fefbd37ae87a2d5f85a6bad6b16981baf79d53d2736312b59e30d484c17e7d0bd6287b1d65a9f1d5d9fbac4e1ac45940a3698f458b056c43ed5dcb5d3b4f69200a23a5c59966589966559963aa83ed241fa420a431a3ba2b12e46d67164a29b9b5b7ebf77b82c4ff8b22ccb728ad7f5a95f7ac39430adcb32f96559d66a54461a97258b2f4b5c83370dcf2dc05acaa5cabed856b1d4bb2ccb928a10fb94c12c125b6b13b572d4ed743a0c794cc308e288e208230e9ace868589b6e598d32cc5107c18fa91b54474c1e584195e928ed054a1185204c38664d48ed2c36d6e5a1136299188e0ba18c91efd5b5f2e5bd7a776995ee8d78e039730de4384755ae94b912e5f0d20c4f0fa54222f443188710c6b74620b9a1d582c828811c017191744cc1489e1c26a25a9dc7838fc84b96aefbdf7beb22afede40729941e948c20bdfdeb4cdcd4adc41054d6d06d2b7c378efbdb518af4f3d72d082dc7befadcb46ad5596a12ccbb22c735e5c4c00cdc69aa0484b23346b8068753585009296595f62261b8d7634816934b0a62355d45c9d39998939121a7d15873c4061ad28b18e450c689eb2f7de7b93e95d9feafb01c9307132513d3f250e9f16391ac4a41dc65bc5f0fa54224f45d1e754e326cb1fab2a0106d0b7e380d4a3e1d6f8ae4ffd715803a4edccb2488c311cbcf7d65ae3183b6badf50fa7eb536f9853e8ffb0da7113ca6bafb22ccb526b2d2dad2438689b9b5c59471a422caa76d2ee476bad9dae4f9dda61a9bca7e4898544c90ea62c455abeba924061014547083320aeb0d098c945a07a3bb896297d28722471a564e5c78daf1c5e452957455648e30b93f368b36fb8f7de7befbd7718322c19a6b7fbd1334201c3498ca117bea6a2d8941e2bb21021d3636391097256319c123e5baf5c410206d9438d9495215e46e38734421f3786d0541cf70b230deb18c4eb538b690ce3ce6c639d0c1d1d323d5f11bc45541cc2bdf7de196e29824978a73b8c7b0a12784760396a5d49e2aa1159a29e30dd8aaefc84ec28752979297d31fddef828b8b939b637378f606121007e34450c3c4ba4648fb385fe61b6ef13d187f7de7b6ba413237190e0508b47d6ed96bfbdf746eebdf73eb7d408ab315683cc06918d231b4bfb87669e10e28a083245b6381d530d2544d6170e2f31689208d1f142d7cab22c4bad7518e9b86c5d44d2fc8eda99a5c6345c8578d1847cd18484ed866c1bc75204665d761c35a9284ea59baccad18809952866acd5958de46902075ff077f3fb66efbd7f5fb1805abff7ef8186247e39bebe8650e91e31a568cc189029e45590ae1653327cd111499a6d0c06695a6b7d54619f6a6a2df9bdb1050e20920338d1d3387299f200468510028efa8ae564c9d4a6940f9a10038e61532f3f2f43134f394b291f3421062c2f44da8bcdcd32d42cf5a55d29afeb535feacb4477e0d08dd1b0081eb6ae4fede279f00a5201c7b80103e203b9755996655215f6a96689436ca9d492312e7be56611000e4a555689d08680ba82fcaab1e6681b4da521730388102740b68cb7ad30a7132c30aab0f0600cd1d561c514b032e08e345d467e18e196006f3861618a375dc32480a1cdefe8fad425deaf85d30a74731881ac62288d64ad86c7eccd4d936f7ea2babdf7de7b73555d9f2a1c128bc692eb787d6a2944d339d3344d31c8332da46841b164f525060ca6145886eca83a5233729665a9437597f209997461c39adede7befbdc18ad7a71acd14ec88ee72893dec10480270f0f0ab43d6108553447419fae830c5058615939a2b338a3e6ebe5c29e1297b46ec83c92be39300337eda6766e9613189b59ad65a13bf5e5541bed644da8f9bd65a17c298ae315e63be745213d2ce6b1ace43c7eb5391bca1a40c239ccde6a6161f65eae6e603846461801a6189ec04d189a3bd659861adb5d65a8b855d9f3ac6418cccc66b8d691b400cf7de7b9b5f2955151e11b4a6d5d00a2d67c25c5c19daf0a40856922fbea20caa1ab47c84c43ed544f736755a6bad75caa2a37bcb1a626e19136843f258dbdc6c42044804b4d65a6b9d948269b4a4171a93108a803922c58d6b55d45599b344bf8a8c61a0716e6e5629c214b5cdcd273c9a94a121806370ca066ecace22fa19cd8cec9c562295b4358414a6cb121c2f92b0a02449a9d243849a12cbccc72dcbb22c757046c9ca010cd346ca1bd0082d58953612141146038ced2b7f51b40dbf208de67332e1c30595950da81f5e52768011fb00a46cca85989b95f443f5930862ce12d1a593398445f1660c7718eb63d8f5a9c731f34886eef6de7beb3edccd4d218e1c626ed50006606fd5572c29c85b5596655966c879efbdbf7ed7a702bf98d0afa81ddf7b6b7d41fabd7349150245b04a60c839671bc2b6b959a31499cafa1d767fabcaf481e41c8c7e1589c3ddaae563ac2cb5ba42e4cab22c4b5c9665596628b1f7de7b6f26a2eb538f784c4b750a1532c32f6a8aa884d8e0c915915295271e5f78346dd91469aa52c2e5f0e5001bcc8cf77904d17bad10990a93e8d5569ad75aeb94ca21cd344badb5d6b5bdf7de5a9f44b7d4e8dbe1bd09f07befbdcbc8ae4f25e2607694cdbd37181ec2c6134e30b1f16bd692236cf41de121a58935a439a254c48a882ba4ac1d6367598e4c0181b24387a632cbb23c3755599617be2ccbb24421d4ba4cc2279a9175cc197288cb8b27a32812c486983525b160e2a5c3b6c14c54e54531d92a00fc06c0de7b577dcd3a22fcbdab3698e3ed662bd692f19801a31bca7ed9a99884752c7a2c7c2c7e38646ce9f2deb8df7bef1dc4877daab9f7de1cc3c905ef6d9a1c4c24f7de7befcdcdba9515010d1c7ebdaad3e5885995881f39c8a4bb0888d4142945ce9809d24cf47e599665590e69a1d3214e5ad7dcc1471a2d5d44a6806650a46598d81326452b1c5723725c99dd60fdf62e7d2eccb68ea5da15f29e5828ce2dd513c4418c11412a314a10013bf0205343e5414a0b88190e2a2dd92a31923263436a78434bba6b9229620c1869cc8a78a45bcac60e633d757daa95c973a185fa8a3035c139c9b2710c1d1dacd75a6b9de5457cad7592d818ce2a83e634d25aeb1cc6eb538f2612fd1cc91d2fb5d63ac65e6b9d0ebd81acc873de7bef3d64ecfad4216426d1f5a13d91a3ddde9baacbef5de21fcdd476db204b038851ddedc91283d21addd9405e1407552d1bc9dad65af39cf30d26ec537fa3bc2c4b1868c949f8c936865aeff82e52d14c0d87ca80208285d4e3c444118f31578648378a48d1b81065c3616898ab5d8a5cddc84083169795a824c95bea333989103475030000288318000806512087b230cec2640f14800f579c54583c2c91c7e3112908a3208681100641100000000280e10080c131e6157702b763f8cd8dbafe5844d47a92be5b2d96530fc7460ed773251e7e719337509d14cc473ee97d5642d2c9a49e79142851a0f1908952bb842752d41c4f89404a1c4a3b50fcd0912e03c00fcfa81383892a717e5e5d84489dc099294ff6c7391029e1e2cb719439d4a8b90882968ab71b0470a7468eb6d2a88d893572a5923f2c11c23bdc63297ec17e28a14b2f6af4b1c92ddcab4e9500e1ee6a13b7b36ecf2b49949e6ca3a95f46f7ff716ec5bb75c0d5cb69175d47e0eb5868067cc3b9f9dc3cd06be175cf4e61a7eed4eef84c97ea81ce71112d5ed479f112d1bf7a284a4d24fa9f9e80b2b9acf7d9b936ad0ef88e5905430cea0139f47ef366f4f240353d819e9706f5f9fc2ac4d291f251d69786b58123dd4842197172a16cffa2e5d10b596360395992340ca03cc12683b17f06a8cc3e8de1e98a3dce0fc9f994e20b76dc40b86194831411359e6538f9c07a5788003c79c98e496a591036e93a1e4a1307ab580a9402d2e22cb568b868a8bc0c1fe9fae5fa875bdf65f13df4b2a1f384c6937022fec8b552b8c96adf1c0c5c0290930454713c068a87f3c2b42eb6453aeb054ec9b096645e03ef82614a46b5a4eaa6df18b266c15212303b6e45f3a46039d8d1466abea4fc62f6af11e02dacbd60786fbaeae720b7e845f16800effda009259a316dd9908d5e9655ae78cea8234463ae336d80764b97e6bb625de8cdfb52d9bbaacc4554320c784c39374d995849337ff64068926a7b4e20c9000f714a7a46922914fd8fb11bdee6139e9bb5012bc9f5c9aef5aa53d55cffe1d86715bc544eca37657b9d6a51a5665fc200d6912e0a41a56d5c222788a8254712d67a8d291a094297100306e7fa9144ba725debc704b7e76046410e4b95901b64a696a3fbf410de27c7a14c09cda36a8aeb1097af40800a390d1076f8e1d62d7b821a2c0b2f72b00fb9aa90bb539b726b1bf67254ac1e19027b2c7da798364e9a555e4a02ec70f1240f61f85dc7abf9182d2b612d0bba33b9ab586ca4a942f15f5811828d5da9ec2a0b945c0f1b6ba5b2aab03a50ed9d1475eb9b41b3d1fbe3359bfcf3b5bade5b5c0a74021822d61570efbc777cfbb94b9fdc35141757af750954567827742f01b06e04e2a52d3a1274246bfd35be0f31d9c3eb08ff67dc3e6aa01ebce1f9f944ece2a3500642eb873db5ff8d99e3271ffafcc9a3118089600f0d045fda17c255700cb7b759e8ddad6814970ccbb5c653bc48814d8ebbb11c7d0a7b44ab584069636a0c284f6ea49c0a94d643b8341a6dc74cf676041758437d011039a925878aa360e227cb5c2ca72c835b24a7a2710ae1683af97e9a1034775ac5268546eeca861366f1ffb0957f6736dc2c669053f5d799f13a4c5146b24e09f5db8f18c46262082564311a84fa478fe948d2c820e0566160c09f60952965f2d132e08546ab3d54b7ea942b3785a0fc224f6965cb9024521e3792ed29207544c1e50dbe00a6048af649f8753682ef05a47c048d2078033cc9ab3da78e914c47641aad8509427bec29055f9135fd2d54258a4c93b49b495199ceb23e0a4682a69712707a07a5255734df63422a00d7e5a9985e4ba8172e7c26d7f45c90cb74fb5f406a9ca82b9a62b5de306bc62154eb10d651e9faa0825f0893c3f93f54c2d2481e2cf809bac52b2858ae9356d38e3b9005a5319d03579c98e5cd123848e3f0f4e410cf3a68d80f9692f58006454fd2071097035897acaae6176edac498d44abe0903023ce6353a4f39e8fbe02f3c79f209ddb5ee511869821f0e23730b6b82c963943e9b07263daf14a219729526fe32c1bdc2f4f1cf533ee304b9e2915fa6b9aec8b8304b1a859c3279885e4f2bbb3a4926822ccfc6791021bd9df10d7c48c4777bc3dc901cc7cf4d3a5e5ca0b842b8d2a2c1a42b39826873c2694497f2f2106fa5e8820fb1de09ecca219c616b68ef3d710b4713d6b373da53621d6a2d869d3d516c024eb45b7184688b6c37384c7596c833587b97ed488062820db598511df12ac45864f56ef8b1f0f9a3ab40933220ec5148fc641676a3463b31f5b4d0f1c18068c1acd659d84b0232dbf78e2f12b05dcf415aaffd3020a412577ca21f68068978290d913da54125a62f00028346a13f53d67a3c8fc93459e024907993d1424a04624f6f7f5a8149190f96918b1c855ec09dfd04d0235c60b8b6071af815d02f0ed9062d93307a2d9b69ed01e12d1ae01424f635d91b993e62522ad9566d892afc986c0a7499a7534128f18b676bc12d9f4e4b2617f9f6d25abecb2f0ade437f062806a4128e641b68634a381ea2f37463e76d081dfd884b06e4b855c18f7f7f514d7baab93c4144d23d58a24acf3a0c4d82c59f911f571fdc0c9de4b98e12a4bf976416a2dfd30a9d2b2894f8f5180c6a6a6ab793f5f62b380214eb538113464f16de4c4c72088f2dd6af9766e084f57c38ca20b8e0508c43322a5e67e0ce38f27c8091ba931495d57287c9c200f5ed24a8491da040e806666b72224652a73b092988bc72f8d6e192f2aa2ec6cb6713c9c40033deb937f004a7018c4e7b3c59b63b4eb21f0acc813fc1867b701c01ec14d67b226d810b051f4adc6f2d6e9618ed567de685aecb13511098fe7f5ab42780cc5939d7c0037486e05952061518d3f710d34fe81192d18d4d88f874d893cd0446a3304826e1a564b21f31bc0c505f80ce9ae2a260098c332ee63878af436dd7db12c30b527474c20915703d1a3203b23d750554ee26cbfba3fb33442bb1c1f4ffe4aab0abe9f80b20cf07e5f15861113f48a20f70dc1ca4b4e588472db853c5a4467ee0b51ac4e6c9f6e0858b6f79c0f7cbf0bed09dbc4a2fc8644b2e297868636ab00454e3eff64b75d87df04d1e470f299bfdd3a138203cf01b95867821a0566821db93aef437e554714b684ccf7039b9f21c5cfdb7c92960850c88be6ef069128494d656a8fccd6cd6324f63cb4ea5c74088a937c485b4defc2af1f859c7301a9fd7bd21789ee9078aba063b75d9b5cdb3bb37136850f089837852b7e2d6e7e75aec04d454534431973aec84faab1c4a46930a340ca6484de4808270241a6ed74ebb3e58e64fca5c8c2207d23ebe46eca844bccd087c1e6d71cbc39e45870c5eb4d552f2d0fbb9bdbb1668ed18598067fe9ab1b1fe891f0f18dfb5d2106370a414f7e646f07ca7346e4a780b9d2a5c089ecda95b228e49ef39e6572abe94e87b0c2d0052194b83dfbd34ab0a3a5f3c8ee99a89192724ce265e1714b26715c37bbdd89c1b9b318c1e005b69aa9e3a337c4776a836c2849d081af76d279a8c8afadd85d97d0408a071f90c21092f89e83dd8fff0883c46f634202dddb21822709eba3b1f187bd1681c23bc11b6f492ee4b373c9127442224f1cc1d9aab782adc146bc41c1cf25c994c14bca38dc751e2beccbb1ff6904cbaf46d8c6c42e432e6e1ffb96f397db49a98101963c80a928f3d342652c4f9a7a93188a623698f807f072642b78fd43240e8d7563d715777341fc017e4ca01b317da380be273d0fd02b6119629919f8fffa466afacdc3ba43fa7b774bfca95ae9a6106bd454951685cd0a98207d23e44f97e1dc10e800992646f6f161c4aa9a7501185860d09a9141ba45e33caa539343e1393ac1c8b0baadb8d6e058e307a119c39264dadfce7b78b724b13efc07b39745a4a94ccd45cd42441639f34156c4104a98f23116e723572e0d79c4470ea7c551476ba326e5174fe312b746bbb4187a861600a9ef0400432843c7c42041e74e89e978be9254681d70aca0bb1560ac09b50e906f125fafe9e89b9b6435b582d28159112d4769e9f783b8baab13b46ed0ac61ff76217e0c7d8d287c5d5154f0c149f8959249ae7fa64d9e2b63994dfac28871b60e0beba511c056d732986b58150dc8137c40ef1828bbbe4e26145c86d27fa8f2e51a741ce4e4baf572a9db645a8010247dd33f3802d957b7581ae1e1eea4ea5c257229134ae7cbc294b11642e68eedf59f1dcafa58b81bcee25c8dda2e9133437b69976df30fade0a9943f10cb1997dd396278d35edf797b4efa464fe96d76fb3d468ed5cb60591dda0a26b7f64394d2ebbee03c8b9b9820bd76e4116760b5ae1cf814e6cc79f1830251d28c81c04860193a7dd2130b6a518b4d482ebf9797a39fe8b75ac3e10389c7ea165b409ac7746c849a002d67e52e493f977b566dde5fd5d260cad5a08c89d205e056040a1b20579fb2e25aab2d18432c0fb77d4b3c361e41d45f818ab58865f694876301efe450ae73daf22c5ab5961e2c8bc3c9608b75a4ab182459ce2ddbce7458d005206869b1e0ecd4fc7c297d66061d6be0b6d9617b3a4ab8b58d5982ec59621268a4a4bb79c1daa8d7d9b75a22ffb4146258746f7928286e0943429c27d91219cdac0f6bc7e130a7e04220e60915e2a5ffa14d81da348bbb3463095f27be6ecfb2fc5c2b3a3244309bd96f184c27024de3fad80dc620a3c30a923306f8871d044e441cfbcfc33cb3d0acbb9b1c70f3565ba0ce582020ef5f61ad0429c056c228e278b096bc9882863e9073822c55cb78d6d16a5c6d03e4ca3cb862115950da50489bc8aa0639da04f175e08c7e2a92a06277a14d9661f9faa4fb834b229b6a41055ec2769c411949e2fb434a2dadc9679733db26cf5ac9055fa249af0585381b08372bb1e89bb1d23f4080787545c85433f51839932a6c207f09946ee719fab58b86891017fbf020aa7d34ec17249c4e93842fe17fdc023d98f754c53237b9cc2354287d869b945e35d82c65459461bf27c7a52ba1c8f037c2a6556805714b3846c4415456e21c3424fa55afad40b5ceb575d132fcea75390b3225faf790d7f84bebe25196e3d382400b25d3e72bbe963b3d92ef297325dd70fff29db9290cb03edf590c4896ab4ec879a7aab845d794363f199b990591437866c44ff45d1d75c57cb66748af5d5fc052a2dfb75ca537edf8e163b76e728514e029df02c8cdcd22bd9cb1f2678e11bdc1921ff452dc794b743102e5252b525e2a0584a04b631c51f5cb69a2d258fcaec072783ce2eced86017958f13df5a3eb4a5878d9a4999797db1ab046ab2b44335210880869f740913d5ace23f0f9ce97e2960ae1d6d1245ca5ff428e6d7be522bffd4499741e8d939c6c03e94446f6914fcd82c2b3fa80e0959655ffe2c90d6f0440605f21c7d2a9c892581ac0afe46ec99a1a9c25fc8af7eb62f151356f54c3c99c103e0db27b7f19855bb0f7560981a9be2450d2171e6791caabc7322f992ebe96fb7950f946c57d94c82515e38d4c36f172021867005c1e88524f3ecc8238013e52f39b155042cd20218c515bb42c2588cb72d9b8d6fc5510dd9700033fece8498c7e083de2332c6a44a1350e0d57215da81a785ae51d0d3215ddeb7bcea8214db5874e6798cba548a4fc8a1cdd392ba0dd1d9fc203a1a28e76afa8e9487dda4391d9cb2be4ed862af816c626af3113426537591abbf0140bb7edeeb6489d37ef49a5b9f45709af196cc0d85cf02beb3538a795392c14e781d74293d781eff96ac9b14531d819b04469819b6096fd745924b41edef9da6b1e9a9d5a12cfb22e1558275c2b881e286542c312f5a1c38800f3559f56b6ec2ac6a1a285581518ae5c1a20b61c2c7cd9f904aa4fd5d136ed89314ccb137062f172e9ca38aaa9de2342890ca9be24c579519530f96ef262dae1179c76253906b34272e0f84cac8027aa08134e006613e2dd744b10a1fb7215982a5e7b58f7e81b82f657d6a162e812667dbd969da90282a5ca8b298d9615c22521cd393c64a007d7432515df9a23c17378668fd57d98a511f2786fec0808cd1ad8f9ddf3e58e67036097ffbae456889a34bc75b0c28e0cde90c9e03e5279b2de0f9adb157221d3ae9dcf51696852b6938debc25a81018a615baa00b3cb9448799b074c64a8c998db493da110feb4b15e4882b9355ec864f47e4e0f05085d2c00a1d11ff898959a18b49f593a0a6494249a293bdcf0c2f9f9643097b6556287da5826c2c5225cd46609264bc4b2d0f28eff994896a89d968a286b2452241b4ddcae1819cdee2e4fcd2eb97fc056f2570c2e2a758fad57361bb7483c11502d3a02de54f08ceb0815801ebfe9be21490067584a31dba3172f06a54085915fbda405e494a8eba7495e7a63cc7352dec0f896700657c0c74fce7d794d36b2a652296dc9cc729eb38f6274350b205390660cde061109a478e76e4612eb8aeb96cdfa31af16ab4b6bfc3b08ff0dce8e653494495b16c7aaa1b0dacef3ba37aee566b6d54000c550b15421b6db6eb03b2e479bee34727a4950aec11caaf4064dd06e565ca462d57ba104cdea84becd798c1c5278374b2e189bd3cc370cc2a76c424ed025af43fcc7c9240be8101d27d1f8e77f6e7e001c916ac16006eaec7bb9cdc73a4e3e155078d212983719f4a376618c5b0927e3a16ea94f03cc3e1fe9dbc908f8d83d93899110bae3633e50c412088496145420e71192c6a4342a26bb1d2a8561ed954a7565a95a58fe256f6bb855badae540b3ca1d723a9a48a48b4a0317ce390aa3007046d1f536063a0697fb32e757b554b8aa6a8c87aee9cf21acf893bb401d202aa11975080c5c3c874ba944f06fe8ecfe9fd1472bb1622792a73749c665437a939b7c1035f3dfbbf6d4ffba75b34332e4397103cf6246b42a482c417d00d83f802b0cc8805b2120b32d814e7d20e98a088e86e39c11f503683b6c59a84d77e2ecc2673d72608cd327356411df37d6f0ae40f8626d7b7dca004d1cde7e6620ed1240ce11fa57fba99b0ecad20d4d30f0427102753ac19700813885b36565a7dbfa8144ff57abe7be347c38fb31adca30097974a4b1ece436877d50ca9c4c5c15a67083bbf2dc1a23c8f449884e5462f2ede982c20213896497efcf05f82c60106970282e6b71c844bc039b084286fa4a504b899df6186290be49477a04a8b36a5f90b95d63dc3da4f72b78a2eed6cb87dbd941738afcc5701213db79cf54b601ffb6effa8a96d7079d24d46954a5f11d1765a30e2d8f5ec17901b47d6ca02efc962c2624e0e6de1ae1bcd0c8a4e0a2f3a085559b22ca411bd281c867a0784964acc351cd23fee876cca284045df0eaf6e47edc2b76c63e8f54c08d51f652862873bd004848f2181fb5cb59a5750815c73de337565629dd28bcd45cb5a80a73857b74f494776f8bc536b89094492fd10200913c1a97f792423231052c00a10f0dfb4912dff05d57e7bb439ccea74f50c06a9430218e0c38c3371a4f4749a9c000b909f45991a895b2c07b24f28e3d6c1d2afe826d6491fd28a8569ac39f15f555b3b37e682e663aaa65514299fa7081eabebfac17526cfb45105b54246bf40cee8821d88bba82712936cce97dc34abc5b471c541d5c1a55100c5c49a0b9044fb77e3ee2716250d1851e6a235d2f4908bd6b5bb04dd11ae2066b80b67bee26f8e0c8792cf7475ab9eb4f935d0bcd48a5977f669c3d384a1b557764c89dfc1d44faae41f8f4f8a2c8fa70ba52ff758fe8b9c233785df42ae3cec9332390c511fb009bf1f27f0f4be2ccc29038ff165b5461df3771d85f7228d1022d0382bee077ad528d604debcc45d278a48eb2ec118183788edbddb90abcaf6df76e12b0fc9c5d1a2d9b1d515ef0c6224cc67ddd0bedcd8866386e8feecaff3abfb505d303283536d5d20023861270e4fddf5e37ec347af3761c49c7f7d8c04ce0994a40f0a076483167b396e7179bdacac0521737ef01ab13edf8cc950c746f4d043fdb4f9052d4b2796043dec2239d78eda641f038fc94204e086bd539e4027a5a24fe4f6825abefe996bf20cda73f3f2b15e5bf0160151568b64a8c4a24786da93a4966c9010ae0c08813c6a5c4849508038dcc0db2f0d95c8788c3fe4607b887d311c5ae69d60c360833651da27c84707d520e400823ce1926638d416df58fe482ae8074d00275a604e3b64ed10adc889715548976109ecd312517e3d2438ad39984c07540dd06fbe91310fb941877df49e88a3e35aedd0d57483153e3535c6847c3a0d398193909165c51defc4aad40bd16db92e62653a1c0ad87368303f5a86b625a86a5b403c685d0a04b16869019a3733c094999132ab0a31d65da16392f82fb987f25806259d7ed817aaf0c0ff0521ae14ed9d40a8632cc206fed3fc224dab4cf195ab71ff011108e8cb192e3670fa5613fc1b1ab55f2560b0dbb5278d8d59a615e9783030c97830c6fbfeab1937d72f7549008062b474d0ea160be3df56520ffd03b8498a3c23577867c255c1d2bea262945ae8dc100a3f10e029ea048bcd34a1d3bfc81644d0553a5980800c85a1390f6c61583027c38d368c9f1b0c3d1569f4816b0ab8b7fe6afde7822bbd98311ba559d0d91b34ee318344342053d0ea7de54a27ccf1b9c25666dc19c135dacb2f3590f0d869e5fc29eb9a42b83f305e8f193e9d32784c20c0c53caffc4ba1dbef33c21ebe92350cfb4e58c405d5e466a75f22f1cae3f0d3434e0ab7d90a04f7476241bb2058f11ad6dcb866a07891386a6a2a7a221cf95d9ae1d8f9bc90d2b5594ae70c8e056ba8a9f925329652e4ecbad337e42587a6acdc91bb0cae3613a8da3ea8ff7ec344cba57a84830057cb870ab0131c8230b0f5a4b1bf249eb17121bc5ee2d97751c14c69d45821e9df5a33f09d2089d01102306f446c2e1e9733cb13ba986b30d0ea6e336f35cf520f37ade4e46101468387744b4fe96c5ba1842348b499d9a2eddeb7b15dd32424b945b9ce5c156b4b599af7e5fce8ea401ff8d26f32047b84d0d6db5581d214c713f080f80541916b9034e764e492e1b6e9ee9eace3786767c7f2b718dad0912d04079e1b681be8f35f87d990ec0aa0b9771d40838bf13523812eee455778b99b4f84777ba709aee77fd1fe52c24ac5bb901e297487dcf5d07e16a1bf3c9361d1dce83a6dfe1cdec0b447a7e94c024f9ad926a547f1163adc36744c93603b0c2d68267fe404f3da2aa7286240a600f2be8875127045a45bc549a05810b4b6f843e92f95200d998f786d253fbeaea2b527cda8658170b219252fd0281a83cb84fe870ee1de1beaf6bb300936fb5c60e667b3c42e0f3ccb2b9de984be85abe864867b1716db6113cae3bcfbb01d7f2879a0984be61b3a8370bd6a42d4fbfd0a9e69a209d0cc234f8ce07b3405b7cb8064c0b88980344de8f8bfc3c0b09b088bfb975b3dd28aac65607bda6631d17bcb12b952772b9c884201b33551efd1c9f24d71e2fe8cf9f83c9bfb7c2e62b02b584c510e8b1e27696189a2c4af836e7398162235559912ff6039c79c40dbc32b736af8084d162cb177cea3a6f355641b8ef2d871d664c137af39c45061f16893208982461b742c46c972e8e0497abf63b31c7c6a7cf4dba5984d03a177b9072dbce4a907a680caf296e2977927261eb41eb72b84312e10398d4124a90c076aa01d11b55a7834138d5d51bf025231b1155880d16a5c39dfe687010ba0d03bf728378454b5c3cb9cc09f7a421ae766d4c5f6566ebca9ae601b8c4df22135de90cdbdbee5c77806772aeacd930dcb6051657d5e1ac8325303f7ee8c29174f5e646418239b026b26e29e00a8776752fe61f93f80edf0af102c2775381175c497f1dcb9c0ff0a328353784680c35199bf3c8466a535d092be5bccba85ff5376c4c09db042d2aeb24eac945ce84e133d0078f40ef5cef9419be2ff85383faeb4aed8ac6271a9c37a7d2fa4f9d98b4b11ac3020bb58751f90bfb02e8b937f1e5da6f8bdfdd0e70e4095e12b207e9ca0431722456d0f45b8cca8b622a66f32074594c0a9f3ec1712140f04a6457318ede1eef38ac9c8301aeb4e70c9585f0839da2fa4d62b33f7ff6f9fa5887c278a883ea5b85ae11a85e50dca419bc86489fbfd6020b94d64c34d560946eca6e0a5f120fc47b226330230173bdebffeadc8c1553d8b4eb6448959aa84a30e2db804ca68366a957a96aff5cd39dfe9d1261e7f3bf31b6ed42b26e0cc68b1d90132f8664452b418539ebf61361e0707f225c7a515873eca0cbd3ec27291bb7c3c7d656db02bfbbbe4047f3d2ad500bcfef6cd2a552574788a944302fab42b9a61c064bcea66cc1eafd91406e3f7d3141594d20994014fba5a4a7e42584c28865db863fbf190051c519ab026b758a342c407fb489fabd5826acf4662addbbf0be107d07decdbb659f8c863ea117e90379cce559b534306ae782d37e455905d282da214304eecc03afee870294aed699a320f678260d669351d8c15349e232dce2c2545e641421a74615759d853693c5902b3bea348b2c20a5e8997e50e65aef2fe2a1bb6fc5ede0d3ff21bb8cc1580329ae5b52afc3ba961608e1743a1c177ab136117f37505b354468347b8e5df721138bfca9915e8e1134a42bb39ea6762d26b560b7e8db02724e7f6cc5a5ed22aaf28e40379a02b203006245dcb80781296cc43e66656297667d09448c04f2ca9f8ee68ded02364a204e930981e7b2b2a2c613c620cf282a5ddf57aeb0df5f24f1707299d7a628dd570bec95d2e1d78fbc3a0fee86e287e542d36de03d7990d658e9895bdef952ddca86e6ea4a0e1d52442a42e2d4ae94bbbae682ca06c768dba5e1d9cabe5e863085b7dcedb4140e4ae659b950139b466688a12e6c2c249993d1fcbbaccc3113cb2224ed87bd18fdc5d63a23ec82738ad0a1fa15f100ed1fe7155281b65c71848d3ccfd1713bfd259c8ae50073d2990b17b9f36f744cf67c60e2a4c6a92791eeeab0b3726c017f9af8854e9b09a0670e8058427a07d69fee21880c85225b7f8b2547753643b942a3ab08e2c01059bb920438e4f206db48e0b475575831d64890ccbfd55f1e61b39bc19e72541c9cfd33949d04ab1c94c7b7eb0215c170bdd7acd227b0d65b67142564061ed6802c76cbdc144c77d180bdab5fefa3120bbc095a41143a532439502bf2da9186a38bcb30335f9cd2ba78fb2dd75f042e1b832c7185cae36d05e883c0bf57ba077b472426c7960ebdb5340472a234d0a7bf583c6f10bdc0d57c02d4e0e2bc0e8e94306bc00d0f3b6fcd51acc73dabbc92ffa245d3e50a2ac31c8d9b8a72a35ad169a48a5ca9ee50bd6b2d915cb9c1160ebc9837b4c63f3397a6deb18cc6ba6ef3497cd6be1fe64aed3f7b4e3bec16388b9b5aef3193e506b5513f7eec208b036ae3f9b259cfb86f51ef6b55ec7f58d454e501044bc4d76a95da716d826c7ec21017d2df1f16a30c5b1ffbee8d561ff62e20f00a3cb978dae3db79755f834bec970d33f035304c286f833ed14f08089fdbfc929fcbfa5305b5d0403a977138b05aaeda7f1a6c4e95a49525d756a31056945fab67403ba1548d37d0b5159d6f5537b2b951d098b45cff1831dd3b790beda3cb8fda253f9f15030e5ee09862b392b356a7aa03316d2c1a051e45e4ab71e728b9d3b6643fa888203fe58a9249756616212c0ac1f3734df659cd06e550f42fa5cb39ff397b4b8c5ca0e27d002b1abe4c64c331b6ca6abf55ba899351d8286e75fad177cb9f42bc2180185f0cd1d37d6ffa249a46304e2f04264ab6b8fa339d80edb81021eab30274bf826664194cacf692709ae31edb63ec5edf63b420d270a9625ae2e41eb8f48e68d9811fbb46d275af94b4ad11a73c176da1a8b58df14b7b6fa601766250517bf955ff3c40c0366a36cfafc264084d77a0ad7bb5bb22dc659efdb3f420774c2047d938d91c37c706ae44aeca1e5222da3be7028ffd761c218a31f7f6c4c691a958ab5e3e1013e28dce73901daa1b469f3585b29b4a8c6da121cb766f79638dbccc5af62e5de3e9841fae8d69c769ae93379def750faded555f81d080330d1cffcaea683c5ad542c54be49391e37a916877735b6d0934aa5b588739b251895890f5b9a1ff62bd25bd8a4b7cd96b9ae98f9fae37bddd07a182a6fdf289d2065347a7f9675409f8a2c6ece39936e17641016aa228ebf421c49d439f344034b2dcda2a75f01694f71f9309684005c017b28fb78e9eb166e0020042c57a31690dc8b9d9813adc70576393b9d512ba289d05cdb81de048eab04cf359840192a02a4eefd42e7620ac669b6db8171c87f99a4f0a89717e90c733320db91e1a4ca9189d4b4b9956c19def14b3402bc282417e6f9efa013fb5aa579775bda73cf449065f0e34adef96c1550fcabe499ace5b64754d92f693d56e4505c1d3d022eba5680a374a15d93a952b8b559d1e44d3d63904ce5e50314c97d5c6cdf4c811c7e807ab3319d8bc41717430ea7b613073a20da232f48cc1ea0f5cf99a5276e43ea2926c0d9ca4e68a5baf57cd32a706783964a60a604f9a20d6398373239660bdeb5018a6c1efc9670ee12aae8fc4d57c8ae98c16719b2e01f76a96465a78d47f26306e455e9efeb4673356ae9609dcafff15a20c90bb198278738c2ff15663bd68df52cdeabcc36fee1cad30d5851f01d0b32930aec7c27a144e40b0eecd27033a4bf791c2917abd87ce39a3a27aed55fa6cea95276e4eaa448e160ae113a8ba28d1623231e4f0125d298349f2549aaf24d3bbf19b4d69520ef3e5057c4f8bcbeea11a5ad54f4c726e59da9ab543842a9c268f2ab40520eb306db400efb99b0ee646a81dc2dd122162f792747b81d8f93c7caa91510bf29bb15d552b321fa8fb81d507be16ba63e82f01fb70d4a472f7be32b5b6af8bcaf2b84925cf41e14d847733cb0811d2cc6ad9a78ead63acc69d4e4ca934d5a17b6b37b9dd75a404e4e46d28b4423d0f49833250be13da11331092fbbbfd6c6cc4318f4cb056e10e1aa5aba8149648677458f6fab06b5e7badf3f7fd434f6aee0aa6b0936cc555edd4b02eefb6fd29842c5576a4f5c9690bea525fdf565d4c4c269c114a418bd6dc957c0436cf4c0b7756f8135852ce9133a142dff407eced01d67e52f83967fed9f009c59146c82fe0be0103961164c7ba6f612429360f899f50d538bbf1ee2c4b168ce9bc4883ec6d8ad9e0eb04d55ee2a930aefd7f87478e61b1320ea4fceabc71354e5aa83ced74e5805266b0035f58684493e63e47055c1754b1c0282fd249a03064a7e5729a78bba452a28921a6522d71115f049bb1bb76151d6688664901ca6633337880def8d1075541cc1ea97d4fadfa52b69127d2045fd495c2e961f5d10fb826b1d812a84e6d370c6f5db9eaabda7a9a9287c5c9fc56d2ee6f6a1f88925b05e4a99c2097bd5ba8c458c95e46167f1cd9037bd773556f0cb13fc690350fc42a47f6802135ba2bbe9b4b369841136b1655df9b6342fdf6bd88a541bdbf8d21afa400073e3da732d7dccabf41d31f5108d464e2227df3d5937a919dfa15d1d564d12e4e7af9521a3f5f390ec645e164e61043f63d645f1887915bb74f510bbc7b28b16640fc446cef1487fbbaccc337f093a4665db83dcb6d56bd3bf727197f0b25d1006ccee766a680b06d47ddcce3d217ad4464c43e19ec781b49d928799c9b6fd55c801cd68732b14cb18120f3a6e4e650c16c967bcb2a268d9295069eb7816cb76990e012fdd4dba59a1e841ae717f0b52992d073184a209ab29b3c7f005ecf20ed7e61f70b93e8d6a7dedd9aee9a30f4c617d2b54763def414d2007bd5dda5bd0df55cc2a3bf1c7722662b5bb56ce17f73bdeee52d256962bfc5c64bf19e59dd500e58fe9760d5075d6b08ac9131b68987d78af699431c946dde35072be27e2d3b932c83696ff37fb6b55827ad324f167533fabb268c3afed76b15a8e085a5770a3213d68dff07598c02da64b9fef5db7a31470eb06f17c5cfbd43bec2323c15318569d9b11a1b433446ef943dd031a06207ba13c6ee0a2352585161e246fa31db33f60ee8a9f613eb710f80ef0c3732ccf6175cc8bc47f72c201b15d931f6dbf8bc566d9c83daabb72a45e91cb9e6ef0bb3347ed107f606edd05de32791df7a1693ef16fc5f957978dc61a517a8d5802992b4b93e48a0db267b42a25c328832993fdda38de1440d76a11c04336e4109940908de68f3a4ef5b4e3f4d141d4d1ebc6ab9bb809ef42c93493207711e856377b5b9fb2de64f9656c014acd7ee4a5458f1e1e6121135eb735221ddb7cf718c861ca551109a852410ff41b039592df20b9d725a9b49e3d03d4f957915721678989a5657b4a66bfbd65138162d305dae6ce3114774f5db7a1642cef9ff00f6180bc3fdd91370cfeb415c50fd418ae2f4ea88d4c99e890b48f4eabd7230716f2b7a374afdec962026edc151a28ca5feed6bf9f604551b34d226df57a8a8c44120e57b0e4b7022f4635041e151499ad7bc5aaadbd7fdca3853e28ee4a3fd145a2e2bae4694f022ed5baa76e07945ff87be387e6831a7db1e4ae7d2414d22668feafaa5fe1d4d00cd9bd3b9f392834084c110e77fcf66298fe2d58f80a0a751050bf340280f30bca2aae93d717a4bc9f1e449720bc031e891ef21d597f7a3aed64c65aacdf987672621141c95ad7d1b86503cd5b2cb60349bb0340b4c7d62e9a2f14bbad3bcb16706f5c31d2f66aaa72f03e3a165c8fd257338c15ea06d022d4961698ce19f29f19d8478769e2bfc7f5c7bd28f6a2fbd0e5a7d9ffd6a7260292e378404e51f71182e32feb6c9066e85026550ba5a905eac84f0f660010619816285271d1169b306c93b5bd86595c49b67a8cf9f5054f3341c3eccfb28ead05acb8e28cc336fa9910cd74a507da14fe1966b7a00fe3d5ed548a107fd7af3b8a434f855eb51490e4ae52f826df2adb7c0c0e37aec6a7df41c3599768493192b56e6dd4edffa4946ddbe7082d2890850caefc714e63f55204e82e27a7176ff976f73e7a407f6d226853d43ba37087bba117621318023eaf6a04d5ac291ccf6fc3df2cf7100ad1748fb86e403c34f949d5c382ad87be63c1684bc3305afc404765893f5068a99bbc455d4240c55f4d83980ddd10e5a887bb52cd50aff1fa9ecf7b00d09d6ad6ec765568f4e7f6f0e00298c5ca56ee483bf6f79640542121a17b7eea721f9024fa768f9eb384e98c93c2b776b033d04464e5b04ee08120eebb9e5537ca89a8f39004aecbeac17e4312d52813bfa4b4f0969b1a0fd07034c6f77ce87135a65a5ec3a29bfb11177da5400224464f350b5f099ba10fd9ffa746251790d88b34280a1d3722045c3b12e4d16148b764a0b86e5043675d33cbfdd8a08f15f07ad7a367412f690c14ee34b8db6ea8067ef881d0ab60792b835519a3b4eeb458d29d9c1c0c045ad897cda5c416865f7c83d311b32ae8741ce6b6a5b021d298665b2c829d2d88eebb202222b78a592ab17dbc5b6029024f15d46fd5ce6b1dedea1ffd0f824b0c062ce17dad3f23ca78e8c9f6806a54e41ad13bd7b140a6351d697597300961322fd6c556e4cb83cba6a1c4b67391f13416f2c0f5805a3cd32da95254c06ead1a5d38162a1b32e4fa169a90a9f55dad03ec19188340b1002b0390db795588f93f57050d12372d1bbf89383c44504d222fb3476a7cb30b6327d0893d01c75a87bf04817320e2c3e14e164a77ea05f4fcb89ad4d37df319ffa57eb23e01a7343a4de476a96d2677238aefb600dba8a713477678abc4838bf2835f2ae541f6f2ca82af66078b666124bf0a30c84a44f301589bb7a6e9a05c3361b2d83345b3e2c2d6d57c4a9d43a1eb1d058c7e15c668f780c49e5af9237b561885f2e56d9a948752986c551106da68610b961112c06c356a95d4ccc6703a657022aadd6003d08c11124163425c486ce5ba7555ef87b12301bf6d88ff59b9bd351504893eea755114278880e22776e4c242f815930bd9c42453a447c18430ba9a38e5e909864463b326929f28c38984e914f29f553e0f502bb05e38d23e892bc02598f99476840b0c6c43808e619f3b215a07c5f19d8ec5082970201e0b230b7308811146a024a08195e92e91188e92c58cee96a9aa3cc82d53d36aa54358e53ab6e0f15a233da55b7d375735139e9ae8ef6c6a0d35476df2b8199c5149a11fa48341dcc6f773ee33fa9c27407ba2cf57ed9a6b011533ab4d891088191f466c895a3b7b374aa4468f7fc55a9fecfb0ebe5e442df1ddc8b998a7662076d20e68298cdac3bb8d991312d30ea5885732f52b0bca8abe89346befec240688dabf59e86239bf9c11eb5a321165bf670861382aef72abfba207b31add1b89b0d2e17860142118701014ba436a577c539dbdb49420717630af3bed0c408afc8d796cc3f80a5d66c6bc09a7e094178bfafde56b6fc78b0a536737214f1a9ba5fe9231393750faadff98f5e4c79dd6442871a90994020eccf51fecde08285d676114f05f83eed6c3114b8aee2131d98a12c790232a3cd88dd9bfd25b59aeb01e2a7918d78b7de643d81ecf759648317a97c9ae8865a4f69319b680f68b1384c16ad243f08a503fe7ac3f02ecdfa7668f4e7a8547f673d3c1c41fdf47697f0402b8b126d5693a1e26e7f3b58bf28534701982bd946c55792a4a2f6f389ac056d9360077344acfb5c289015179cc0a0432e40bb913a3892eac7a74d87dce87218c91ee910384cc01caa9515b5d308c59361d131f6a17642f56c15b5c455dd1ad3f526711bafc0bd411585190357b73f25b7ea5464cb49a8857a24d658e7560088e1f0500474fcf1d07417416212627ca8658d69959b34e0c6eafab86b13ceda51bd97bef2da5dc524a19ef05ab05760555be5ecc04df1756ce210e01b8a0e162c905538895b4d65a8720931430296d5c43beb9a5ee563c3047968a02d48fd65a6b3dc6e9d6aa1455559668628c951fadb5d639b808afc1c606ce060c2e581766bd81b801d6f5ea440715d61d299994d70b175ebdf1de1bf3f14b063b7e453bbe8a52b8f9dcd0d2baacc195b3ce39e74ca4ebd62a11af90081b5e04a75304c6f72889f291c7bdf7de5d5166b850c5061d8d28384a6a1cb9cad1a426062a514d6214ed41506badc550dd5aadca125131561e2a6ffcf56343a77339e79c330fba9e73b83548f291b193d12403aa2a7c1024c3e6d62a0e069a030df09ad15d144dd3ae208777dd52a2b9c055bb115ffeca39e7245a398fb8c48952d60cd52fbb50ac31a66e9c6726bfa6db902a437ee89bbcc1b0f2bd75b80107c90db1032cec9043c693a71c6a58907b2129063467aec0d00333a6049386e70a026edcb48c9b155ce56d776bb5a9e806f584974cb07a72b6505f51b7a85c9492ee7b2c7861eb0fb1962ce12ca29859e01aa2a36853662676d885fac3189650714003cb268d5839e79c7352d7ad55afa224364440a02e763a186badf50ca95bab544533aa7a9821ed2da7b4afe4605f585fbd2f2d59ce19e39f6ecae0674588c04f533907046badb5ce399716b8c00ad9fcd87cf170cbb987ef9eb06541467bf87ae194abd65aeba83bc5c37cf7de3b0b1b2db8ccb74c81f8045c74786f2e3f9c4f97b461e0702e535c471c33ea0fab54a930a48236e16bc4ae3040a1f112a2fb99dd65d2d402b8ad01763afea5b51eaf8662a6679bc026433e84566bad5fe0e15a0d7786c2bc10d3109622eede1b8c0d7def7287a9e3e51c06a3b2446d4575e9700929d0c5e44c0e31bcaa36a70c37a634d1d24363630ad50a3c1d8cb5d6fac7756bf577e2f7a565f0d8d2b5c63978205ae6cb16a9a02564a2069dbe53d54b09b4c2554fcca0aba81add0578ac90430193ae3035d0ccc38d2e3e5e086285460aa846486d2cabd5fa80b6a03486387814b57430ce39679dd3ad55a9221d550f5d68d928fdb897299f18df87598428c206fb838dad208ea243af1b18e22aa523eb0c555f3e38e9c278efacbe3ff4ad613b85bcc4b4e4b424b544b554b59415a591e89c73ce166474cb977bd56e461597aa1b420d4eb8c8016046d345cf4c8926d46889545065cdf12a6801bec19183239765604063a735ce92c29a14725c09692203cd3b60e17a01873128e04285e6283de7265c5538bdd8962316349d3e94ac3661480e5de79c7316d214963987cbdf0f086abc85c6add525262729b06fa1fab926642da81fa5df8e8ea7a35379bd5651f1f178206dc838bbe9cb0d06be9e297005ac6ac2b7c40b56941f593940d89011f5638d8f8b93cda2b25141c80bf58751a2c4fcec2ecc1a47c4d97b6f274e9cfadebb32bfcb06c46b7a3e6658a29514a6044b5266089172c2972e3180b961c071c46163bc42ce39e79c9bb4c8ea393729e1049e1badb5d639e71b12327cf64806901584acd0e4c4aa09981a9ecef4e0b2e29165611082a487d56ca9e952e3c5949b69adbfe461d75a6badb5dec1b8b54a6389c9498a2a9bd855e51ca5c79d7306cbf09043c66ac1705a60ce39afd9dd5a6d82ea6ba6f48be14c0a901b5a5812e5094d4e120a68bcb0c3862027407192b9c0b17031cc9ae0b46880031691d9606525cbc8e59c73e639e79c478c275a60d526a01a5036f7a380940e5f44744bbe8841778c1e60c81063052b63aeae7e58ca0c8d7e64aa7e6118532d8a82ecd2987081b5f7dedb0216421e96cc7eda7891f265cc95953264724b9cb098628292274d78d88a3979b10203f0e6eebdf70e89909514453249b83316b1d65a9fa1716b75e9c419a69d17eccbc7477ff5eac48bd4d72ef7de25c677ef8dc327f66679227634c9d0a899dccb6805a087ce7534507befbd614bb20955eba7aa3141c4cdfb12c512eb9d28ce0003b5d65a6f9005132eb0cc310ed0836b840f7bf9f17b2d8dbbc4bf78e0f87089a1804c94701911446b0574adb5d63372a289194aa2186ead3536a3b5d6609c44305222182a114cd5093059df8383795c34698ab6d4f47beffda5876b35d4b1d248a955b586478b24c5ca244c16ad0a7ee1ec4c757af8e0ffc44a6dab07b63be1b8ff6c9db15ae4e8987f7d106c896a7d6e38e8008be3149f1f3ff8fc2fe835f669587eca3b7ffeb506fd3c082be24fcb183c6b89d9d75a2fe8b3a7fd8515d16666b53e37277f0b2be215ab85988e6567ec4c43d8599e29efe94f27cf544787ecc171279938eee4108e3b4984e34efae0b8934138ee6413c79d2cc27127a338eee48ee34e22e1b813e154849f3014a100fd7ec86bbff77e0a5be26fdd9e17df7befd5ba02de950a7abdc2f1c688e8f50a07a64c885eaf724c5837bd5e9550060c0ebd128634e97959e16287d88f1007ed8c5c63af572c7e39a0e420f3db3ba680e35e61175fadd8726d897a43eef5aa459b0edab3e34f513db0dd86e099f2af25708a5ab38ff1d9896e09dcefed4417d6ebd56d4b4feb2ffcfe838376debe077050c5daf1a0a6071f5794aea0f606e4471823524aacb650fb297050f5fa2dbd686125648717d4cec0c20c0e27284203122cd4fe8e696f21ae067a20adadb5d6b7f59ae1edb90ca8a52902af4f9868f4fb29689f30e13aceedb162c87a417a6f3d9f3c46f9f5ebd3b63fff112afe114afe110afb2354f647e8cd1fa1fae431d2b670fc23b4fc2334f64728ff23f408ad7f63d632bceac84cfee331b30766be0e3cfd0e7ed0f0faa487afa73f0d104d22333cad3c0a6c1384333cadbd0da4f0e2f779d2ea754d7e7b2cd50dda3f5b85758370f80643976edff6acdc20dca864f5c44c960b847d59ddbeddba4020ba7dcb7581aa150c4eddbeedb25e3708a3f6417c498061b381bb40a9d5599d2da1bbfd115c207ba5dbb7366c89fb36053db5b95814b73a1c64a96acd7e18deffd0ebd50d3efa3d537ebb3db55baa6edfc2b84056d6ed57d80798e8d60becc9810b3b02af56f2e51317a6565824203e2e6c1703095b1c047efefabc7aa05333b87f7f701ee21aaee9addfef765bb14b16be24e19823e9074f2467d0a0bb8d5e61a490f50c10196ea51a344078f7ca95136c88a5bc93dcb24921eb86e90614d2f066d7c98f31371c54a958ade0e1941507612a41b414b9dd1b0e6d76f30163bd02ff7414f08529adb5ce399736d4d99eb6d9669dce87f7de1bf31caa919c288aa2288a4bb756999ca4a8aab2ac68adb714aba3d16a95111a56a7b55ec1a96b5d44bc5037679a4c6eae57272990ba39cd04ccd657c6c1ba0ae3a6b5d65a5741f1ea5a83a1d65aebcd057628341ca8d0703adc0ed704da13766077a2820b539514bae0ca7ce90013305d4ed831850a9519aa9a72d513ac3a75153979f12128c0e5ce5939b1b11a92542eed9430756b95575402566e45cf2fe202e1e808e12ac75106ae0085a95a9bdf4ccc9322e74cc7af005a00f83195c380cc121926324eb29dd64d0c5f0cae18bf1e49d800279076250d47c20481e90f6be01969bae14a028310998ff7fbac3fb46ac213f10cc6d6add5ae22185ebb2559a8d35a6b3d2284e282fa417d652551556178c26d44881853b81766ed81e801eef5ea84ea0bf7305eb2c3a81c6a1fdee1fea49a4093db20e9073a2982024f99a5324c659cb28c1a39e79c731aa95bab5427d254e51c15b60ac891260a929c12571689146698e25af3e5051bac68c0632aa7b5d65a6b344db756a14ea0990269fac34ac6051572a85ffcdebdf786badd5a85ca859ce3ecbdc717204e540c1c9e5120a97c5609f3ba785e3c364c70600537966e30dd70e22166bc2668894f7ace39e72f5cabe158ea1229676adf7412f1412e8aa2288aa2f824756b95aa2acb4a962d8d3e75697d33e50026da34812e9ab2ac05ae31f7cc5b2c8837a38a922d563428c1409a232e4409594384c9caf01483a7eaf0b3b901f0d0547134cd94e43ef0c8d91c0c8b950d0bb4d6fa85d30ba9175460a8b5ee81a46b9d828d13a6ec18f284e3090a2a389ea410c64c159b2a1d68bdf3d65aeb5defd6aa968feb87eebe6eb9831de3de7b6f9c2d7a8accf195658c40e156c20414ddcf926e69b7d494896c81f60626adb5d6e393924bc8f7de7b4b9fc0d2256ef925056fbfdce2ba4125de7ef9bb405e17c87ef975814474fb259b0b54ada4e8ba7dd80d9623c5df96f8f565bc5da034e412bd443617c862e9f647dc05b2358021170e1a7bfcfe175b22ec126ed912f70c7dd6c7be7d22ac00f369147fbc6e3f2c7bdd7e024c1ce6f17a091347deb2b2740f4cdcfd7535750498b8116a8c531f9542101ca7bafd0e4c9b45c32dd6c77eac064f43aa2ddd7e68e502591abafd908a57758376a8fdb07781bedb0fb5aa07b5d61a665da0fb16d7a07a468d1416a468b081051af4be4e0dcac13165a765491b1d2fd07b61bba06babf410a257ab2fbe4e560bf0fac4c756e7bd3ef1e175777dff571cf9e5e3f0c3301fa1e3e1ab7832927d7e15b2cfbf9f8481a70dfc0b7b7d3f9f36fe37c73e3f0ad9f3e709417f7e23fd59e7e739f6fa51c4cefdfa54f1fc51c84e9e39ecfcd1fc54117bfde90f366d586badb5d69a070291e681f84c816bb1c72f3b55c41e3f599ab623d4f664247bd9593e68da9e640f62d8e347117bd9f384003e7e23f031885f867942809dfbc15385953d8ad8e9019cd69f9255baa97832823df82aca1f5f76aa803df8a9254d1bf93ce29b003d4247d3f614fbf1e4116de0f388e7077842281f7c14b08f3d4f08e3836f343e78da9ec4b7dd1f5f3c8dc08f9d36fb68f9e31b8dfbc737826d9bda1d90f2244fcbc3b5bdef5b5edf6f6120dc27af12aeedcfa6ede1da7ef26213677f3e5cdb0f9ab8dea7d6073ede3f42c7c57384daa67320fcdaefadef1f2184877fdf92e1a9020f042a7adf56792809ec93e0e2ee5bf4eef01d5ff070b919ca13827dfd46f6f51be5479ae1310de70941bf7d14facc9140f7db47813443f7e70854d49ef98c3d120954bf3d71b9192a7b2412a87d1b2e3743f5239140f5692b3f3fec71b9196a1f89046ab33d19e9b7a76d7cfdb62723fbfab4896fdf36f2787d59cc0401569a4499341fd7c09f509b6f7f7ffef4c333690845f5ef336908cd9f4f15b6a70970f16b45f5a9223fdf2f7e7efde299cf14b806fe8820bca247688e049a1f6986e6738c81d70f4dbbc335f0add9d4c1d757bcc56e6182db0dd740b407f489045bd1fce908207c9f3912a87d7d22cd50fb15cd27d20c6d81dbb4419f527bb3bc5e016002f2c8de8c0385150b17bb3040560083a14455d11124861d4d207075848718252f4945726d5c28198204070aac7af59a823223cd958c21301cf9489324868b315874703a428285cc1118a250e90052650219a72535b4209503bac315aaad1e16198480313a924687132d2854c4741265d6f470d8b16555e6848e17389284d181c4a3a6e932f3654c929d926f03548494c0a2e9480d23dd02bd2b6a586831d2c5c9034960a6b8e89a71e38b04baf0c0720106060e3e42c0a207173463bed2789558ae74482dc9f242a3024d8894d9a1842c43bc1091bc066160f58293264882dc5812549d6c915206ca0d3b2532d0fab5d60f6bfdda49f2ccaf4414233c349b1515614be82ea2d644541f16517d560488abef82e0dd3f0c027753e0e864e00259ad6e7f0317a85a65d1e8b58bb4e07dd01c3184f38e2fb8a7085e0dd7dcf39ef73cef29b39d361b31e686eff47ad562c8962c86dbb48195e42886f52a69c7dbba66f0d68a6bbf7febb52578f0db7ecdd1fa581ffb312bfc8f985c68ca71022f59d070314f8015a58a9391362ff693bd5eadb84186675a801efe5f70ff824bd672065bc0f8f7dce64d178ef369f5a5c818dc39792acf1fa126d7f9143888c768e7797ee7e4f9f015ddf9233404889c9b1c1e82ebe48090f19815d770fe83f966cf165e795de7038818081d580e880ff54b163b7ceccbd7cfc339d3cff9b4835ed39f5ed39e5e9f7f5105f11fce34fcf03867ca713e873fff1156c4419c69d8eb8733e5bde29c3f22aca87ebdca29e120d4fa38cfbfd610e3105654b9696452e0f6d81f61f0f427bc39d3b087b433e53dbb0b54cbaa12eb0205005684c91984cc20049c9965afb4628a50f67b965a39f873c81c324488105f6145219ee8eaf0c0437cceef3c4fe9cb62e5f6d89ead06fb80fc6a7d2e79675f6d09dae313bc3db327b10993e2f867b3d9135d21f3da0dee9395044bf003fcb4b35a9f5b4add1e3b3379685f7b2a42d9efe73c69a6f8f93982ed1f84f84bc215996e8f6500f941b53ee5ef1475dc1477b2535c8ae9429825d6edb19f639655b7272da5ba7dfb376678ecd3320cb737a90b744f1dec1684056beafe303ef5cf8747f0e044a7f6d148d9ed47f0e04943a8d00b3d2ef74943e8d0233d2afb74df3a4df6d81cc1d23e94f1bfa69069b3d96c97db3a8d3602ee341acd1c793273a492f1709e27bab29d1dbef303d8d9f99d1fa96e8f7d9a39f26e8f7d1989836aad195c1c1c9cef813180f6382fea4ade05c2f9f044779cba4034aa0bc4795cf6640d5624c39de6804a93d1ce5177cd91c60176524e5a7476e0f747ddede9b19f8e4e7d14627dec73e0234343081621b6c43dc7333cf696f3c8388f6c67e789eedd7902c08a7876c6ddedb17f801d9e9d7364ba3df6751bfcbcc6252d563cf6e9b8d4ed6bf0d31a95b8285d20126cd75da09cb73fd2b840b4b7b2139b2927c278f6b49f9d29d8671fe2b9997ee74f9a1ce85cd0317e7ca6e4d3fe9e297fda13e199593b0fc19fe8ceccda754ca237b712aed9d741c3875ee82bae9167ba952a0c04dcd00bc9fe9a290960c74f93fd35d3cafb799bedc968c836f4b521da93e608b80d9b9ef3e42d6966d8c95b0ed52e645634e765e608b8e7e83c3ed3b3631e1586bea2427fcf9404b0dfa77d07b007dcb35a1ffc3943e6deeda674ef3a99fef4fb032bbafcac21ce54a793e41b005644e29f9df86567ca3b7e7ea63afde2bfaf01ace8923433ec3a662ac22972dd1e2b765d331da183dfaf9df6f7af997ae09ab4e7005644c3270960cff99c5364c1fad8d719a09755f2b64ade961b1b7cabdbbfc981c77e7853f67559b47090f81b5f8ba765afec5da0f1ed9756b4743808a78047fa419fc8c77d7cd2075674692709b8e3b05718798e5b788c674bc4de3e8963ca9ebc155644e318df4b3e086cbf7ff3f84cef83782efb0afb40f60177d9ffc08a4034a076d9cbfebce7d6b022f2ea4625648e62380811267b52f4ba3df6a7f3e9e97e4b17c86ab940b22b7b2bfb9bbf4f6e58d13d65b78431008469fb8d69fb07d3761cb376b22c2d6c01b9e3e73ff4292e9ad1fe9a29ef77e88d84de36f4e499e2bfe1347304137499ec89ee9029f24c710ad7ec2c8415ddc8de147bb7c7be6885440e0e386b75172815b37459461f8f7d2a667512bb2e1e0f078d4d78ec33e84dd53085839e7836d4968af9809ad27b32332406120c2c9c98544912a48a95960ca84da1aba18549872f568088008c8d193d2f4994d8a005f0798080dcd594d3b5b356644164c19618b7f0d8196e9930c5b2875a10c38ac8162718bb702cf42c6c16157a1bfe0ebec240103ac32f7603fb4477b6ebdd1ac0233c0d7fdd47fc0dbdd00b9d36a11f1afa23744fdd1efb43e6e66db2e4e1201e23a21ffaa1d336f44427cf3d42b1b696b97d65cffe07163c2d7b200c9de24ed4e1f4c06d173a71488ff64fc59faedb1fb3f070cbfeba8a2723a2177a15fdc46d2e5cb3436f3ffce1201544e7fec235fb426f7f44903087a6fbabdb1fc1c42b4a74bbe538da1f87f483127d8ea3e8a761aedb1f1184e3366dd08af6134774e61e257aa4476d4f46fd891e3d911e253a6d6113aed9efa18e6be82b4af469d8d4edb7f080d05794e8447a9e70cafad8af5968f4b005abeb53dd7ee9c3f64b2e6cbfece1f08783844ea44785de7ef8858386cedca34267882f092b7b65d9fbb2879ffc0a2b229fb4a1d2c32deb53f64818ee02a5e28f24cbde0d92955a596e500202904ca8644b9a6b52142a06d10080000000431800101c0802391024611c2525fa1400093aa48ca87c483c1e8f04a3503010088241814018080003c100001010168350501c253b581bee1e636c581914d99d5f70e98edb6d32d866489c57fec81986cb3fa23682c5e1f43bb69e298d0e81be5dfb00a3843e3a845a4b7f157bb3f2a2522daf436431c92bf1f1679d970abe9c0152160dbabd1dde86b8b9cb017deb91f0531217c9717a247ba3d746a79dbc15eac3a57ecfdda9174ec9b57b2436cb682d41348a4b122d443d9c124213c828e9d2a228f4616f0d297fb4ce30aa13f7baaa97ba991d5f49387b1fe086be7b5ae947dbb6e2c9116b29f2629e97d18264e10ba0f5eff95fac5fcc103b372e70527452d0fd169a18b8c06395db8b5ee4f630c9176644293dd8fde505776f14e61a5d95b8a79d84c80f8717259ee4030c37e15632d1d679cca3ce59344add0c8401b369179703b48a618b41f79734d1a32de6b0dd1b20f9d7f64967d2fb57174e1caa016092414a53ea392eb87c817c32797f88df60f9f2a0c134a02de68cd9561bb15b0a4c2d2fa620b5acbe6f62eac70c610030b5936c978f8804414b20e1c9767818cc1f2ce8c47f81e8333a07358183c2afbce9ca06a53e2b230209192bf1d21078b13d7915eeae1a44120df85098cd430614b328a0089ca154d49bbb2b5bb75f8589205ca3b8d8bae374b1dbdf69d03f0a6256a7eb0fe733434220a36dc4b7d3d2432173edb71ef61542f6db4a109455a5ef4a34fd003b9c76758cc18456f0ca3fee0a054495e34c7168119cef567783578e091f15e87f171b0343354451c3f97810af0c36700468c3bedf8de190b98456c223e3e33ee469b502419d1450addcdd846bf9e2c9758f084470dc5f843e1fc099911df50b615c7c9602aba53dec3d1a8e5207b358cab701fe48297f8631e1ff67d1780f9525eea5bc95e8f2957a7bc2ce771738e77eee7079127c7196cb1e34e771145b0dd86837039276b4ca41385798d8bfe37eb33adc4b7935e8f2faf35f92791e6440047d86efdf19c6d6b7d063dcb32c5a07d4092f7d92669c08bce62d1bb6110f41b4527fbcee7e4ec113f3dd7d8e2d2c28c75caeecc5a08fdbaa23a8c07f961bb8d1ac69f740b2f68920b3c2b199bf32c9d7a8bb282c4b353018ac83bcea6e16360f681120adda71d6e4606f8a3a240e274fd78e8b3a5db91e3636882a81ba62b7f92a92048347a890c30d0ae1427aaf32152992cf65f039960f445c5c1d7b1e3d7c2d8c965eb3359bd2ac85741c956943e498dcf8ffadcd0083fe27e7b7f2841d80523b578b8ad5fb29cbf881ab906239d79914156f83d2fa4908eec5f88d11b3d84ac49bd4737b77f2e909adebd6ff4d404965ab63977db29c69b9f510d5016d8ad24889fe1bb9a88a977adc23783888db6731e0b9f00ceb13713805ec834407d74aab930a103d8e968acde10054fb23e86c79d4bb50585111e9b3e024e1db779bbb2f6d757a7f0d4e2fc693fb2011384eb1d3fd6fb3df0259a427faaef829677a894247353b769f3540868d4ae86a8604a40706a3da1208b83b11fc8734114dbf7871d2b9ae27c54d081f5773a11d93cf88a4881dab2c2af43813cfd88fc59df91af7995166482bf2946d69b113261aea50fb12b6ccac189c2ed3673616a5849ffb9925a4e8dc638baad898da5f85cde83069c81c32471995eb1c36ca28896c8cd1536d3d096342a475c88119217408b1ccfc376aaebf8abb6185fbbd7a4d193ade99c3d22628040a7c89391848ec01956b4de0df050083c6252da9a415311b72c0fcfdd377c5bc36917c7d2bfd4893254d8c6eac37021a29ef43c6773b079a67581975a527d9bbb793444cd5a3f59a923f68f0f44a69345af6cb8b3bcec844bbe6f2fc15d204820d204c0dd5273f0ceaa9c9680fc0e370074f8b689cf1fef6eed28221a8c762a8858d9292a58d1bbd3510367113dfea966900e735d581ab963cbec47c07b0bb676edd2cb3d856f81f35fd24311d830c61ece33f011e1e7365968801ace1ca7b072cbdbe7f5890a3887d56ac18d818bb8f10d8417805894089b36b499cd40bf8802bac62505e5c740315bc6113b0eda086818f1631de60ab3a6d0ca91d1ce10a211fef7782ab1a8230e19a29572e1711d5be67b36d1938ee1571ad9c0c7ba1c2bd94d1a94bf8879cd94517cd444f778a513861aa78121950d48c5008dbf6fb8761de7fc283ddf6d9d8fcf256db0895d88519b4003d68b1538efe9da325129b8517dccec35428571850a768a03b1c5acac1d4744ac010ba5c7428c9b7ae8db7422f45c1290aecd09ce8cdc1b7ffef54ce01a85fe725e22dac125168c29dac92070403d1f200bea0a7df061aa04fc03a003839bb0eb929a54c7fc8f1822d511e7e3dde3b4afd1890b14fe944d30ecc9e0f37db78c8382f88b6d94d9811999b03f80e8a2f25f5936d4267d68042edbf56e3eada5294f02bbb7f11f1c9a4464cc691fb39617692c9b9fc160cb6ddcf6bf4ac919c2df3344bf72d50c76926d9b85cca37f61632707fe68d92127a6397bbb4ce3ceee03dbf646c3b24ba10cf2e0717c9dd5fc42f9ce18e5b19e78b9c198ec644a1c7a23d33d0a4116711fb148de3555a441ce2f4a85da2b64b9aee74622473d36f73ad8f9ee4952693f94899045622754582a0310b12e80ae11dfb81184ea27813f76163652995c6eb4e83a388719aabbe7e60e545e934a43f023d0ee2348b468e6c0ff68f896750641a9b031d10648ae253732fc866f6146983bffcdb2d2e5c795bc0990bd72b08124ec1e6ae4428837e968e10fd3bc0dc18dd83a6ea42fd8a4a047d1ac9a0390b18e84ad8e9f19ad15f0bd7ec20a3a40a68ba2d41b2af264ea1bed2ab78d0500575b9bbf1e7c3dbe0881ab5c8b2f799e4174ac3f1b4280977a1d22a61dd0a5dfbd68a461dc8765e8ed920413ed7627310a7d2d46cc01609c0e0a45635d8f5e691469feb48f9f529ea0c514fe91bfc4e98be65322c046a69082fadb8d5b70d58fb1239d6ccc52262b2fa6af2c5faaa5c25ae5aac5dd71896561873d220f994c5f383e846a7a1f2cf0661247d85f84d4817997b31b892baebcc89f9f7b3ea8f44d233cc87c1a204e2ad6aa5654437d3c5328e739bd7dc8a1b8a063850790d9f3321bccbe98e2b7a95cf979cacb26708d5f96171ed4f9079ae072c1fc7b4700a017dded8a9eb02e182f2f11895eac72d6767d66e81b7080177f51d877caee7688b905732c34a55571d2def0b58f2335e056e5643992dbc936b9899563ba76fbe95695d14dee07d666ce19509630f2f4851261d99697db948de74bc59f933c3762aceb08e7e5e805612f6f45b02c76e31eb96e3939da0f67c57a4e250add8a87ac5dd11994f73776f6151f0ce5944d7a273edaa06990a79260ccefa898b8823967e53354a088a8211d558a866e28115ae84c3568d10f017c36b9e0d00695063248b8f311ae65e6aeb4b04b0876e1c55494fb6af558b50738c7cbc84563a77f772313c86c039e05881aee3c40b28ae748db396cf62d48cb818cb7a87a768234a4f14f93d0520f1ae2e49e4825d14b6c7659e65ec5bc2b58a748fe1c215d238a773476d32fd3c69b043f97086560b312a74b38e24e152eb0626da630b667b3f987e082f01520dc6a7354358c6be5f6087965e2917557e592f9c10bf529686a1a52c5c0e634336a918d9771f807caceb6863be276226854addd91e151f15cc70f296546db29bf5261166c11cfdbd166d8b08bc04210c355e74ee30a2a34e3502671880229c0aa5fe8ea9e93d19348a307c10be0a03c8bce0fcb003f6d141e8fed17d37cfbf6b1fc1794461053d48322d0de3706d339c4c59f934bc5c8910bd439e9a40c9d393006c59982eb86b9ff7da7525f5d36b83461022908974adbfc4b9d1309bbc5f51327521a44f7dc97278f20001303732d2d614707c837145479ea6b43ff5c500f59557c7a298852fa6ac2f123a6462e6e437bd8f1bdee22976a012d7d26b57228745a533d81f9c0a02a4e6765d5efb8fd20dc60090e17f127911eb6732177be74f13f4026cfbe8fc92532790b49562e90033ad61f21d4600fb180312df5fd5d029f844ba8771b089fe9ad7c54a3a67da1d467f01ba557329a7766479523244811f7ee2f4771fb85e91bfdee657da00c11f3708dda413034dee3fcf6a324ebda25d887c92a5cce79ef498cbea7a80d2d0e7c472ae717090b8eabfecca17dfd4492900b03c61cb69f6e6b85f70d606dd4a52199cacebe1389f7b3f5da6652d50813e4251fb1dff674f5c29e382943f53e99e17a154f3eaab0ee97a74aae408255654d6c209c1a4e6e993d05e63f34cdd0afd390510537f4bf63573a5d7113df71f94eef05e063d1544d3286326e839ac86f542ca7e973446c48e0b67352d5274456b18f96845de981c56e3a7265a226fd2e560616043277275397fca7943965ca348eef2ca50a315696de943c35606c959d215e5a144ab084bc1b55afa0f72bbe1d5d7663acb79453987d23a6ac3abd208cb625dae81952d7383347f2933930ba88241202d5be57c56d4d8e5a04a02f29f41419a887f0cd0c65e218726571ed1f427b6ebe2b1eb64c03bb0a39dafecfba79c7f12f7409b0c03ff718c2c392ece45f748f69943a249db59eacec1201e62d217527e43e52772db9fe5dc02696c805960ac89749c28d95029d4feaf29119357e8498e9c14b28020be422eebf9bed4561e6fc569fe45181fc018b9dbf46f47e90d76061d9b33fb66272b5ca79b4701c94efe556ab2f15f8422a6536a8aec02631ef3e2a189399ecadd193c527409213cecd32e62faea60e251d56d54ef6ac3e50e1337b94709e98e22135da3cd846ceea5bb011538b5571f63c2ee44c2d4d0161bbbbaf97651f85b5047e504b92607a54687314b84cf491e1ce0f26fe5020b32b24f56c5ecc2cb62bc264932576bae50f64843718182a3bf953265a81698e25ca006fae089e2edbc0fc6b6406d41168817ab9090daa9ae0a41fc8965624a38ab352134402121a0fdb7e6145c9cfe4582e6637f5216099221d6b19988ef1519435d0c22bfbf2903c9ea93ef457a94939edf655a420e021c0cbfdfb33718350d8c6813b634bd214598c6f1a7bfc691f1e0c75065c52822903a4626c76f4cced2f290386ae487345b3524ad796f3e51ac413550544dc93594884932dbf89449448996de9fe726ca9824f374fd699247dd88ad4b37a8cc5c20212f5c224753c2287289b1b0adbe258655f730e1aa47bec0ef866428f06de699e2a099c196c83bb2e53b248c92085ccc3c637f1784454c4dea80a1b273434047ddb78b53811c420c75193791d8ffb4074e45f679e8dc4120f378c8ac6b132113524416fd95f46ce33b108b61ee137a58f4773ac8a7303ccce4b7ca74f04f6cc63330f6f8b054e21844ff62cf7cf13342f898d629fce8de18465883e8f2dbd3f6cf4b129c3bb89106caa2d27a4627fd7e3c10d11bad09abe828c6201273a2a27d08852d792928fe7bd9d41bac0fa3cf9401900dbe648568ad5831fe37d20d21562eda2a04c519535b84b223951937fadc449fedd5dc2f300d5f688372ef3e1fc0de0d492b4ffeaf46f3f5c09a748c28a0b85105214a8a34e20e171d2929c896851f57d29a9fda70bf10ccbadedeeaba49e51668a166876502fffc5b38f240726a6e5eae53d1f6158d74804af021114b415aac1ededda9e58679851b95294ea0e2052a4848995e0934e9ca797a595be32e875c48e1518ba745ab52a1e0c535e6c66341753f5e92ac0266834d35e325c5f05c3f993a2dccda688995c5400ba2fb019a915a31e836d24c5dc0910d723f3c405c45949e6179b99889d2a30b793be0ae2071817eb9bb788bba9f6065e94386c2388455d0a1a37f48a53c3f35ba472c81976d29d7b4f51cb1dc7b28f1d96ad84a02c4bd68e3dc282321a51719a131f010ab0350acdfa1fa2c4d1fa7905483e2f24bd13666bf77c34a28f3f56574468251318e84511e1f904d24594141150d010a85f57f738816a93e8c844d35a10162ba94481528140c5f19d4098806d9a88ca22386ac5ac70e3cbc2c95c333c97666c980b693e6181d50b0aa51bbce7942b7b6054350c071fe04234abd91d4590df084067318265ebc3e35f879f611bd0d1661149ff45248fa27a1459fa2fd4708a9fd9d86792bd9c5b79a45e5bee0cba83c4873674e452617d909b6d46dce69e82bd9d80249210a2d8466729aeba3d3bc18d67102280f2c01b95e6453f8c2e90284cb2e1e4d7be1e61849e344cbbad9bf143b1b3152fd97378be14c6969a7c28ae8cfca4e3b3324b5739dd1889ce4db6b9e8ef3cfc654ec272a21a5bfe69edc974f1f4d0f69a52af7d3d6c6c2fdbb235006951ea650c3cfb93bed60732ac75db94403ccd1b3393a7e803c4025567d62d373162dfe2336c4ef606306826e40d4433c040501d0c1d9a5333301b23bd107d677ce49086e951b75152179e494c9fe21d12b2bc08dce4516a1a24d4c3c3cfb0abb33d852b31af985e7c75caa7ea95c5417abe91f301d306569b5c6c4078cf58786956aee29298613cb0fbfe1b886d90a2f13204a09f418b42f479b486583c15acaf32c2ad2e693d4cf8bd20a5e7208cd8b39696627c1887ce679709d92526458b07e521f333a406517fc0928739303362af68aa285f514796ac983a78c3385b02f87e0bbec9f15ffb90e27f553827c47e55c355125d4beb02825c64b9e5a48c37a36e33e1cae0752f46c2964a14fa808806843cff20dc38eafa99cda809f3bc533b9d37d0370141cc9e96ef283087434b0123cc64d849c174f3a213bf8173c45f843fb243ceb6b34edf9ccbafacaa7b80e78526b351db7b75a97432a749d70c950833b7fd0911525fde4e40c6e1be321c01ef35cf352f622d5d9909aac0d233bce39fbf5d3e0962f463f30573f8700fc55316812987194dccf00d8101d97e456a2341748ee2f6bbc95d4425ac89c2e71db2425e3971fef5f3016d1cba7ef78fed4410222e7931424e6e0be0e825c7560facbc1f9e95bec41824670dac4a5484f169246ba60430a45401ee9450d163bf15674689dbe25c65a21047994548e3619c9a7b7861298b3957da57315bc53da8fc2eebd7effb166f562d2a62f8fac01104116287007d236de453ac4cf105a903804d6682b0b33a93ba6f445061850ca087bb9e3f9c2aee0004a4d8dfdd27761ae2b3f75f76c4348ff83d2f944b8d2066a54fbc19e9087dec235143ad73eb880bc507ab6edf8085e4a8fd0646028b2010a2050cb2a12b15e8ca18a55a40aaf43d80413917527d2ad4ce7341bc327d2760aa354f2d643a7ff4bcf2cdc2859b7824cb6065a2e0a4ee92c7b63a9800774b9a42a3abcb8c8645d30edb53b415864b51ad11934628767bcc09306d79050cdfd5b16d7b3135fcfc57fb414e549a8e399dd6161cb68ba620b0dbfcb366c1aa41c5ca797fea7c74cf384c608db12aedff6c4231ad0af841f17044ed9d56780bc94e980f6875dcd76082b1db1baa921c69f715f90dc05f9ae5db60745556e1b604ece011b4a16bf4f3f6283dc5b8cfbe7e468a66e95ea011f3038f050653b8000df6b5d41dcceca801da188fa0ff3547685b29889679f65e1c85a73a0a759ce3bb5cd0d7f49c927ad3c25d1815efbf8070180cc62f5b956de29f235e4cb5106e5f9d7f9610d9bd60be4e0cd642bc6c46a13c436a3530ad25cc0c3befb7e0d5b3ec62afa99983e3caf0ceff850bb6551438604a6b8be0316bdd30cc5ea1e38fbc680a192d2bdc03cc6a7ba5e31afb94ce7c23f983d956fc3b1fe15e7a536e0e7a0b8f6d25bf800e220974d52b1c49113a8b2b28170098b3effd5c3b480bc058ca99b19c28c405c72db591fc310c0a7c58edee5d2d3333d57b63b07b6a22208e86c610c23e47412d95323e620acc0c5408f9f0587a11d12159a692595f3d43b0a662b5b1711644473268404e9a9d9985704528e1795b7eb4a988d4709adaf15a752f7ac8491fca2fd288885536843b12037759fa6f6117acee6434c5f51c8f3691af2360a98c3f7cd3388364923d9f38726c7ad6b167eee682162a17b67dc9a0edef85db28f1c6fb72a32481837218aeff07279c438fe3b8ca058c6b7803a84f3e9301c4a0e78446d2dd489c2c5e7ef52959e430aa5274d90ed659bd1a8d64abfe26bfa46a151a1454605541772a0342349c1b7a5683fa0d309b8dc0d860dd9b88c6c707e0c732885a9f3096c12fa14e5f112104100c515d336051d7e99cdd64485bebb51d88138eb88ae861dbdc49c208b4e44088bc6620f2502478ea385ec0568a690c65ac80f527a4c50a35933680b9743db46278063056266a02e3c807b009fc6da21f93140f5b2fa061703cc1596ee9b34cc0eecae1ebf0afd9ec846a29431a692fb3a3adcc5594e898aef68d32941ba4f983bca8910d8c40691953c549b8abef41482b348c035f9b1011797a84055b2c849b5d928b5abea79133e1a0640ade9d6f2bffaa2b85012630a29bb20c4ca13223ccbedb4e0476f4d8f07e5a131bc2c270b299cfee3155c4f2a6a3f93a6303c24cf51ae23d961ee016a0bbd6a91b3f3f00a539858d31717822074d47d2f3978b8acbdfcaa965a351b19d8eebc462beb405708ad958c4b98794d81f2c9f415d80fbc8ed06aeb0fc2d6b5b041d8eb2763a7c1be32da4312bc62f9553270d655b834bca3f18e1fd476a5f960f96729a45e22715ec81e0dea9e8a7d915d8d96f5246be6286f770388f39790460ce8ae2f06587dc265cd374bc32998089ee54632f50493a9a811cd9568b82f582fa9a5a068945ec73b644c3650457f2c851b220c456f3b7733e9e5c6e6dc69df13a740512f2313aa436c42f171901e04afd2e04123455cbaf13eb65a4f2a3d61dcc8793a005ccef388219a5e3c768a7b850356f108567842088daf672d9b56389e1ce014b5ce745d08f0ede096c55b9e7d1310d664f47b8bf3d28a2fe6b9e5b21d698ca97595618a0509d0ee0b386232a18f6a010ecca53bc68b66a1344433daaf061e57b109792236d9bf893ea93d740198c9cc85f87f50c56bb057e486c8d0edda5878014e0cf6ad312ec0c0fbd1b2c64ec749d60cb7d7fd0d6cf315c46573aac3f1244ef53bd36960d4f626412bc26cf29a24285e311b8c4c4aaf61a6411bc3c6577703f106142d74dd226f52a0c627b0d91227cbe1f16176421d5a06b8268bc4e8de7a23089c893aea7322f5e0f459d583d3fb1aafc2e79409029386489b0478bcb9ca689bfdf75f9331dc5ccabc8c562206f5242915911bf2412ef2827361530719fa4abe54d6fa2461a1181fe377a46674bea74fa6079069f37fcbd665937c0a3edf6e9aac8771aae59fc25b0863f98b14417ee20e82a514cc7690a6c250ac6a667c96b49039f972c4431e50cd80de703835301dbc1c74142718bf4c01e94ba1ce236314893a3427ff1205a3a0f7fd013f2c1df8e116a1aea15217733301d3e8cbc1b128c7b1a6a6deecfc54f0a7efb12fb798f2cfb7d3f4364eabba0f81120a25d834657c45f43fb4b6276e6d6f22aa8b862ab1175c78fc0e7c16b7e3946c28b6f861a720b5ab6ef5cd50e6ef53665614f38a54cf39d56352545822b036e33133331a4feb4c84aba1b31caa264246610bfb6945aa2e75e2e68a7a5a76125c341cadf8c89431045089ca3f81ce71d21bb4533418741917952f9ade3b3d42f4523dfc558c2154fa19e96b138a09984098993b966f9fa2fb287ba4e82e549f2928b9a45e65974aaf3170bda392bb204c420cc6133c2566c5fd5206fe2c89232307948b48daf2c727056eb1fae5dfed52927450cc409811d053e7845545a7db75b968433826d68499e8229b62b8090fbdcaad8051f60bdff2e2b31b947b9b4de90560d64343c4f0e9415111e3721b8b659114896e1693a7238d8462a422dffe8da2de33b247523d53e841cdc78a18c4e378c04f35f51cc6811f76a160fb5e89563bca7329dd885435aabcaca00654e48326c79e0f979235423be02c240b464804f16c5879786768f4291f746d790d899e4a7f601c1fa48c0664e9cc30c0638f23d5f428f77719d415d8e480ad5f5b3a72779ce2af372d091bb18a416294f27a80e04a925fc6e35e15535adee4f8c7ca6e090395cf9ac1639b781afd5720599e29a99533414b205eb1e4daf9cece8a1ac5832069e304c01f554d76b54f2ee4e847bbec51090bb3a25b627d0fde12826502b3f011cfa08eb8aa8a79ce65474b32208151b359171d6fd116a920435c4173278bde1b56e336f08c0200032eb7a1374a5a7241d4bda99c501e378014804216c4e132d9341e064daaeeac63b9fbe08a0c0e56ce4ecbf8846ac6a6bb2090a8bd87228a6b2f8c49cec6c0cac9a2ce559ce655c541b179a2575e9e7de18151383dcca5479b350c77b67b8d049575a673e3bcaf29fcd914d80dcdf564b21486a06d512481b982626d3a5d838d9657417051aa848e7d24f445d6db7740688e2eb67899f4e8e1e5a12731b8726e8b87d3af23c05231ab4591d85c7d6ea8eea117a9f81fa860c3b930df4e1466aebeb967422e5f5c559a4db4b4fed24a04065ee85f6a8c9f48b7c6e81297174a2a9c54e3f9081fefce5b3e411262dfe55f4ec14566a19bdd29594735f54f043ca001d2c3f3580aead21a268b43356e82c99f1d9fbd7ecc7b94f9c00c107f48433dd298fd0e33e858c765be42306020ed50e04cc9176c57ba475f30ecf3e39177e45f611d113b440104a5cf395d9452b4a3acdcdf6ee1b354dcc85415160586bdd978b5d533062df998ddc8c2356b87769ab04bd8d7a75de4cec368911449289248dcb5faa8d0440ac665649021cc04fdc64c8d0520834c99918783ccc28270a3b28b29bac26d53e037ce85fc3ee53b918e2d2bd3bfb06a274acca55010faceb9671d33ad0bafda7da2b0f121e42124f218a633ad9678653c648818822573bc6e3a2990fca41f24198f5d514692cabeca9ecf9d8664032fda4771a58a7efd7041bb634b6f18d8d44ddb8de25a1fccee791d21369e4b52e3889f8d15dc7a6c0347feb002ecb744ee8906dfef77a91466e5182a8cb42e4035b4de044a142c0b081508aee3db1974b08dc3781b31cc6d5b215eca31705b8f22d4f51f69299195395de68567e148c0b152439e69239a0b312a9f4f6d4c62879ad919b6ac200413c40b2cfc7eb266363e5ecca346241f89efb828430b21559644c58f1649722f58c6785b2d4897c4f9d33e4f22ef866f3c7c56d384300c204df76735515a0f0e3b83ffc2542d3c3781a250a26ce579d2ea560b1da309d0bf609c60bfeef3a41143650203198a114655cb690b1482c8939f897a8010c1a7eeb4bc52f6172d6591abdb1c034ae5292dc739170f1ac3fbe8f7089fbef40d744edcb43cdab725a50fa85fa57a07302ccd77d0c41ea9ae602d376bff0e8525ca909d7e66e931ae797147c3e3e7a68551ff5d34146b314a7850e0fb904514c0f4c2b0ad70261a4f096dad7928e7a852b0a21e3f85cfb814bbc9c7cd918dc341e8108d0b56787bf8dc09c4e727755e74bb716db371018c432c789274d1e3a96adc69a14cd2a13740b0ed0db66c2384df46a6151146e0b1c623d433dc96381571390d920855ea8e1476d3fe6ab9ca67d8f6133e2bc479042fd23236c429fac68ca38ffa5ebbe0cb5e5985bbe9d2251c4da7a1ec93666bcd929819dc173344d509471203a683b0ae99064127d848cf5ebdffb9c5d1ada907901608d33939ff93ee35183a3ec9fdae2883b2924368714de99f64f4eab07a9fdac7f88566a3265ea79e6cb87be44d6075134ae0050e6cb8a5a9ef8daa075a7906ec846052b6ba315ed5ba2d3b309d5e9e9c4ea22acee663cfb2501f71ef1a66522b0c4b30c1ea52596c71e0a2090d8e6ba59eeccd8f7c7f130d66b940e9e6e2cd8854346c1ea31b4355b66b9e7287ea9b6572618c23ffed0a26c195e3c3a4b670ef6799be442de89f6b103c7bab5ef840be2e39e8de12402280f630b4e8c3bd1b26993b0807e78e50f900997a3e940ffdc47082698a9e6a0ee2358607964e4a0d6eb77f07a9ac306c11a2b447d955b0394fadd8d5d9174991c6a964df980f5fbc7a46bb43a93a761908baa3b5ad6fd6394ef2c158282a4d3b559a9cab0387d49c4a3ba60cbff8d495d663eba70f344a0ba9454a1c14023e8b1c9fc03be2f0cc00821dc5e9e2dc07a21dfcd6a2e8d033fd3034c3ea08dd865254fc6c39a5690820a170eaa64468f15077f57d94ba5b6da43da13f400c27b68387f9714f525f968f769b48065ddce82675ebd65e5885e8a454f35b6a6d786324ac710119409034171e4648f7b71450f575124bb3b4ee542aa5aeea48adad1ce0a2cce5cc3bc48a402bb71367e96c4b51ce4608d5c96ec4a4b91de0d4e688b244515e89e8d66a5a96d39589a4a556f809aad6fd72abfaac3d00eecb3e014c3c80d2c76c85844d66634ed39be5047c657c2282273185930f679316b7f1254b49833beb750114fd038ab003bd5920181aa7036d6f925dbc53591638e7aac7703093e1a5afacb75b9f6b004c61aa54cc9abcaff4fc48f48c1e5753a2e90fc785edbf6af3eb558a509d101958655fa41d664c11c4f692b96403fad88484b4bd6537b9f796322519a90b5c0bc40b2b19f1f301ee37cd103f2322e0fe18f19b02f7c3885f0d37618b134f2401f7a7c4af0adc568a8480c517449e3d709d84ee45e887c135bcd5dd737f6972789a276ad4a0b9027bde7bbb3c90bd917b1799745e395983a67f90d7c7fefabe5a7dc9a4c9d50df0cac76fd69892c025d95ee47ef287bf8414994166ce37d4491010640cd5caf0b91911f31f9080ca174e087a8225e6eeeeb0a7753d3993de50191aa77fbe001a87d69f4f43e3703f3f49e3743fbf062536344ee9e7dfd038dfcf5740e3dc9fbfa471c09fcf80c6097f521846fdfc4f0beef747899f16d886fb43f19302f783e287050603f75ff12b03f77f6249fc9680fbadf87d81fb3df123c2fd9df89181fb4de27784fbabf84581fba9f821e12cf8417720cc9a68888a21a2a02a66403f7e0b0a8ac244500ba4bc404806546a60038c1a020aa2df4946433f349e5923f5d169c8343414e4b71185c2d8b7f8916ff19b6ff1231fbfd57c6ab55a6d56abd56a7ee437bff1f8ad96698d7695f35aaa86aae19a4f8dc2dc0b3f02918f61732718f90dca8fdf7c80424f1551215b0e6dcb1c2705e6385b77cd49ff8e0a4cbf6b7f8ef7970553a120eea429694d48b502dce592ce28d7414352a238ac879a8823a22dfadc0e1aa79ffbae354ef7dcf7138de33df76da571ec73df581aa7f4dc3751e37ccf7d4bd138f7b9ef2c8d033ef73dc50c529ffba66206099ffbe6493d37de580136faa1b023b445df0205f910857d1285e1405b46462b1b51a6b5150df3e4a37f23a31f5c360f51a68f6a022ee98c27d331080bf6bf008a04d8c4c23f3327b2f0e8b72d9e4d356c1a514e60ff30bc924add405074c2bd46f8be27944a5cec97e47d57a0449438635f18b35d2593ce337f5db091997f066edc81521e27e9b7056e0e87a3231c8ee611f7f5e092523932bb388289b4580b9b318b3385511edaa28fedea9f0695af4367b4455159e086f9ee2bcce837daa2afeac6d2da541d4bcc8de58a527192de288cfa305bf487384222d3a74924654a676e4201a655e89093f4515150a9993c86e8de093ae9dd1e68bfbbbbbb45efaded0cdab102606e8eebb10473db07fde53fe70a4f18a62d265cf63c1b60cfbb5fc9fe0c09509f7c6c7a0ba5cd2568643a599f7e0e20c5b3c641f96f2c3f7f0f9adec95fe125a6b7261124c2a6115c426198b6bcb33f293e8de52ac38078cbbf7b1d19fc9f5e21429cf4b675dbba6d8d1bd516a6fab68d650e9328f7df3829a407b8bf0492dd49ff1e85b4cd57f8941a4b8b1a4b8c475b78c305f83b4888c2a6358d25c63d962bd759425bfea611e022fe32bdff117f9d24fefaecb7ec7f83b5189bfa4ddfa1cc84041d24c10b1f8801041354106b1fc6e8c112355081172e62c4babb8108f93e1cbf07f1fcfee2ecf5c95cceb6dd4a265ca6dd351acabf1634cde79ac38f4cdf769c51925c7572fd1d3c90bdafd6ebc41d3a7ba58f03abd89df0fbcd4da62589fa72f53434a1c649293e893921c7713f29ec9f0b61e8fe96befb4c43d947e3a47dcf6112e5d27b188309cad018b9f49703bfd2483a6947d249b722e9a47be30f277f804b1b7f1b2037b472b57ee52612e7e4ba275424042114c170ae75a4f5cb19845c6bbbb4d0e24e1f3804cafd368b25b2b68a937d458c2e59e6fdff9bc637107a6835cf40c1338aa22a7966d07685cb2c93795e41c20efe7a9daa4e4eef5b87f9ce9ded0ae00c6f4fea3b94957a9c2cfdccff4a33f28462c708eb91c016be8bb79464cae14bfcd72496924a5daec0fe26d0e83b82099bbe6ffe12e7d897ab4cc94cbffc4c3f266671d2161d89884f5bfe43c40e61b87f4abd4a34fd15f16bccc1269bfe15c610d30220b4209bbe43964eced33063395f4369768788433e4724df26d34ffd90cfc91179207224fb0ff99ccfa1a67711e718e96c7a93692cf994684ec67829cd6c59503fc3981930252d25231f9a93cd1292f255f9866cdcb06103070e1c3f43190e222b45b69b162e474ef697f47571b277664eb6f8a2388ee3cf50367e8ed3e4a0a1d1a143870e283f4e368fa028546a557ab4b210fdf06154e464a7f03394d56cb939d95cacc0a59e1cc65ce2e2a49776a88071df9249f63b5600cc3e4e00bfeb6708037ed7e7f85d81853f8d65e7d3bb58e3f5a90b1a15657fcf0738f5333f4e9cd39b684e6e2202c2899b12e77bbe0e3a1dcb9971f53be00c7bdcd5fcbffa994a8d3bcc68c0336ccc712742df5f6c82c85f2cbec4e9247e2262f51676fd4be461369bb91ecb8865e75923f3b7411911c8cfd0089097f91cafd1c2cfd0480bef39876271c7cb88367f12676e412c8188a5bfcdcf50c6c2c84292fafba9bf230b893f7d1fbf281f15277bc7af207e2a88b7c7c97e1bf173a57ec7afbc5c14387d7a4319f58fca2774042e4b3f44e012ac29814b904a12b8048366b804a1f4e012a47d0097e00e145cdea42b026c827118989ff1fe170c650ef339ee504a403636b5dab44d5bf8ddbe2dab26e0dbc54992ca5095799bb789349b9982a408d1680dd4402dd442a7bb7379a00045e95ad7dad6b7bee1222390e6e3af999f469a291b496636a3f5cfc8a042d9cc49fc92bc803b200fd8739974be7f02caad2abd5f98de4209e6d26b9909afe59679174f2a7c53a1ecd419cb881f17cf33a2e79be4059ca9ee3dba5b9cec9f02880b172e485deeabfec2843295bbbd56c4dbeda6c55654a58b9a95222d4243425d00051169f9014d0c28516e5b8e6a5248a1a6e6636adce6b79d9923f9cd6d7e73a459cdbb98c28c5096424dad26859af15a2932d2e2e3c70f1f3e5ec6074d08885a1102a20109d19a8f77f1c72a94fdf0215e1f3f449bddc778872e51167fcd7cffb5f9cbbfa552593cf38ebfc758d6dce3fd6bf9d4fa1cc7ad9f096533ad19de5bdadc8436999264c813f9265392c4deeb8eb7d043c6261489b6fa6323bd0df9215f525bfe792b2952cecfd6bbd8e3b3c8f331007c8e08840e459e4628eb711a99d4dc6afd6d7046b4b98768b3b78a884f3e0680bfd78abf4a7fd5ada9c46bc5ab78152b43fe2a4f8fbf2f953b14047cfa99cb2b944f7f859cbc432a91e543be7e77afeaaa542ad53d7db5ee5df47e8634a82ad0cd4f242727e756a04acb634e4e0eedce54a1192239393f696be6cb2a34f357dca1ff5e4b6466c44488cc3c1171c6547746bc35274fd78a93fdd5566db59a0aab54aa2febed8e97ca5571b37bb95945aa48aad6d34b391afd92a3b5e8dfd6cf50d6fa1c9fa1ce10f2a978839cec6f89574a157f91352bfe22fd793cfdcb0a65b405d266212a43f4f1df1aa10cab6e94207f49f1d7e9ef5f1bd46db699070f9224c99926332ff3a58f3c5463e959f538df264d5ce6a938f32ef27895383326c9cf715567f26f84321e2439b2909cdeff3423de5801be4f5ff517472853ddd3788164c4bb235e9ecb43b4f9675a4112a3e7fe70429c1007c40161aec6d5303e9d30c67f122f94f102cdf8802f8f93647fea777c797f52e3f5d9315e5a1078c88f2fbe8ea7f9f2f6e4fe3b44ec61c8e321620f34cc1891ef81c84f0787883b4f3e96f33c1f23f2331c22e250a6b393f3447e860670121bf244442e47dc610177e36c4c40c0031323f24f7ec4888c3d10f920888cdf14d8a463a41973d070a904e42f5599039871bc8db7f1fde0ab64426ffe9ad95ff5a14c85f1a8721c4fc7af267e55564f18c5112c7a11b4c9a8646466666666665e06bfbbcf76ddbfa7a7230bc9cc3b164b269e231cc0cc7bea943aa5c62002747467b3bb7379548fdfffaaacea6deef0359b71489343523dc6187fd9d1701360c68630a1f98455e2c765c8cda84b972fc95ff7fb3f2ffef7ef10b103a2adee8072cb7486f8abc650764fa7d3181af13ff969fcb2107d5c9c6c1c6fe3cbef28f7bf0014c6a7a50b2ddfcd5fa9efffb6f80bc7e3783c963de453f774875cfc363ec767a6096529c781e36f83291c236874c386081639b9aab152ad646867991c9ff9017f46454e0aa98551b3cdece019fdf225e65faa41bba2c0a69f99e1af56e5575f7e56661e8f2598f1bf50d7dcd64e9f4ad9e88d14e019b3b495fab2b39d52b3001dc34c6abe9f52e92cd1217b937c9353a79488b1b8fa19995f3d685463258245a799d349a552ada280e7953090f2bc0285955cba6929b2fd09a7b0cc951177e8ecaa53ed88122defe352434efa83e3a782d2588ea5fdc612e7bed13aba0f8dc2da8bd9f23f821d23fb3b21fbd3bc697d9b350ec57f9cfc7aaa18c3e28c95c4924967fb9e155b4b1b895de4a4bbbb8f1d9835fe54e4a15dfe5ab41869b94151911627bdf6ac5d5ec7fe61d678dfb838cc7d3ac9bfbdd43ff2e97263051ce795aba343f9b1f964ff2e7221a15a15f71efa1486732049ff5bc5eec901ae5ff64ef61d277b74f0e83c8e6a022efbe6404b984959a8b9e7b81432477f455bdc731cc7711cf7978afd5306a571cf0145e942450b0e860958c849ae815849bc89bf9398a52dee5b9c5c78971e6c619bc52e0ffebe6ca1a6f299f3daeb6f8ee3b87295b97226711cc7dd64eecb69a464b5c2d8c8e77e1e3af179e81b0a7b61a716e33e87c2668ce3fe36c7719cffd7755ed7795dc7719c8736f87fe31416ee1af74dc47d0b71df431ccbeb3cefc67135378ee3388efbd64294b98e71ef753c34e156dc2a73d673d295bcd2683d173ac1603ca58480dddfce203db273efef3fe6fe1e9bb4ff6a564a6fdf0f30751fba3b74d6c0ac65182fb87f7eff8cdd495336ac045b22267105b48e921984cbf56db8a171bca7117a86d19309b9baf86a57fd1f1d25fe2a5fd3966449919bfa42fc55b3962db9d2ce08f8d3028b529a60029b9ed44f524b4f8d5052ff06d7a99fa4969ebeffab717cecbac02624754affa5ee71414ba29250270b5cfa127f5d117069fcb4c0a67659204cbf56d1096c6a57758eab333455af3730d171185753e2001c68be91eb3729aa9cbf4a9390fa476aaddd498b1c94ce49299d732c7b96e99c5f452438cfa77496587ccf209d7b802f7d21393ec0e50da6ad8e42a61e681c9a29924478b59a1cadcf79f386b628a5377472e20d154471410bf0122c0882410c80ae0df098fb6f1aa76c6b57fd37b3456f32fdda45bf8a37da45595c0e1c57e406fa370eeb6ef47364d0a1af6489bf6664fa0e10caf471d0813ef7e00dfa23532099de689c3a52fa5fe3ccb8fe84e8ac6790ce3cb487e6836e5be3f8173969e46a1eeaa828f07cf7c66ecc01872a025cbadbfcdde8db02cf118776d5aa38599f8a100f6dd5afef4976f56ed3298d9dd4484ed6d24f520a2823608289208c20828a230a73d293842ec428d2820929bab019dde4dce4faa82ba217896ee4e4b41dd1e102131181cba64d0a63d530b294c496c4ea38bf0fe0b26d3617b251d89cd3366dd3c623e43cde22f2578791eb7796afdf54babeb7cca78f4e4351d134239fcd53b6ab7e0f308a0853980eb455df8edec8334e241e1fcbd52a77bb4d070af32190484aa26729681e1d92663c3c46454e565414d86d220eedaaaeaecff2f95ec55fa5bbbb8fc376fc36af1cc196612e4483ed7c40473042aeef41feaa79061530b60cf9abd67cb6cd5fe50423d7afe5e452545d4bae3f4bdf926bcd0187c699384d679caf9ab8f4af8cd125b790e79531aae4dbe09d012e47d7d8ae7e1b95313715e9d3c688b26347e3582ef0b7cbb2a603fcd5730a715892a3dc6f73e3af39613b9f10d24eeed751e22f99dc7f83bfe615a45bee5f82c37cfd181b878e2c18e8972fb97beffb691a877ee3ccef2fb16278fa9cc842f2bdfdef2dfd0e9380df4338c3f725fb255613a69fb1f02da6ad1b940f1ac80cf46fe697369ef81501cfbfe214964d4eff119b9ba6f33fff7eb8f42f1565375c808b38e9e26c792bbb0ad95dc8ee3f6b5c86234e4e2bd9eb73244d11dd4fbf7677a55f2b455dc1f3294c8df1ebc1ee51d48ea34de4bd7dd7e279576e378050646dac7ec97a47feaa36c95fb57c9eea3f0ed449e852b6971d2eb9f41e1f24e4d2a17814234d44611d343ba8892811524dc281c272e6120af35f3d462a3de8ab1b91d67a5050b6636933c599721c27c5c90e72b27e4559d6577ad74264bfcfbe07396cd6682e44a5be57f15a7dcf52df6d5ee4af79c5084aaeef467e73188dd5ff4a96c85f65f3e4fab5d6ef2cfe6a308e508f72d95a72ed235bff087c6e3ce2be7eaea1b520c6779cb435613d2ee1965098b360b6eadf60223991eb2f9973063552fdcf08cc556e6ca2bffad77724cf4d26b8d4967d8b59e34f7bb2f7d39abf4ad792fd9df638ec0520eaf3e34f81fc15c59f4af11797fd69107eb23fa54287b038cafeb48abfbaec4fad38ac8bf9d39eaea5670b8dcb8f7b19a23bfe2a7d8becefef377ff517d9dfbbf8abdf08b9f423244f2a422ee916f72d6690215a7322b751188c48430fdc278935e14acdc3755f3f09eabbbff74d6313ddb149b59fc4f4f539eeef27513df7e0cf8c0763be7bd4d8a4f4a84f8d6d445b8e1a9b744decd8a4c9bd4092fae027b15fdf348d526ffad37884b6a62441fde95541ddab7ec6d83f3149dcc38c4d54a695e9ef7fa3a5ad2949be07df8e4dec9f3e352aa12d7fd4d864a83e1e9b9cc626e0d8e48e4dc8fbe09bc6d59424df87631390a42dff6fe481b6fced8803eda10eea24daf22f8d7d445b7e435bfe53ec4c6474b44a6a9efee920dc4393681acd233b93b89f313b6376c6acff50585d79b8b34214c68d3b3b3b3c37b1fa3c64acfe0ecf2a561f8853928dd5dfd9796263409c9266b3550c08cfcbce133206048dc22c56ffc94dac8e73b668ee43554edcc3225853efa0edb7d00c528766101c582c788a6c7f766391edbb686a971d41bbec07e1a787ecdb2d6a3466e795a2a06c6bae62454a1335c0e2657a81c1efde9681edcfec53e479e58aa14cb39db1d7bc7285966cbfa9f8abbb61f0bbef37b5cbf6d8755186ab8c8f0b6c6a97c705ee3a21601e7c3d6696b3a88b16dc7d7d986e0b5cda745860fbb80be6de86c2c2b77f43613366ed87e277745d15eb813ee82a1be883e3140b84737c86a820e0eec71c68feb628018584083d10bf31b0a95db65bb96ca11e4dedb2d3bd3b7787b590b7ec5b5ce21cb96c21db5fb650b6cf2a95b34b974afd5dc5613bf4562baa65fb2de43016d26c36f32166bf87ec05b2828b6cbf6dfea2d9dec8765eb1e2275b2edbef2387d598fd92376ee2afd294eddbe7c1766fbdb75b58225822588aadb5fd954aa52fdd52e9963ec7bf92a971fced4f1a3b4ec085525ddc49e37f84c25835d4f7af23ab7fc6eacf98159fb62849fa68435bf41d467a8bfe4da67d734966982f7866cf767abb77718d789e3fbfddef1cdd94042e6bc60ea3f1567f0f21f77fd3397f3849daf0fc92263b71274d493df039ae9df3d1d27a8303398f758c9564feea8580b3a85ee4ea47c8d5c7c8f5fd061336a7d366909aebfbcf0c02cbf53d89b9aa22578f225777c2a600b3607a0c72fd3b025cfadb3be082671613c25408987e3f6a0b765abbb838ad71bc5d75b62b09d82f17b8eca14721a187a8b518af56e5a3c2c09d7f813bf75326dd5b9cacdcd847ef2476051014dbaefa9cf8b5abbe89085c3aad8ffa88ebef2d7d7403dcb73e72b2a6da55db45044625e1be39ecb347b2927c4d5c417862863ac2ff636daddd7362e73b6293293d7acf77a2f33889aa02d79f19898b935b6eded3b35a7ddf64ee771e27bd2707b8777a9cac3e445bb5b434d30970d9375417ecbee33dfe9a23c0dfd3bf55b0ff277ed8c48ab676b09a5dc0606716bb7f8dc037c0fe2df66857fd1992edaa9fe3d7095cbfffa2707580fdaf78e381f5a7491ff104cb2cf67d87b2266e0dfb5f1360fa4ea3301e68abbeb518af7280fded12985503d8c37d70b423c0337645fff1c02503a9d659dcee472e9d160ea0cb395e70121828e099a74d0277d819611aca38272050ae3fb9d6546e1ad23063f767a8f3fd0c6bb8234be728a684b6eaf7f08dac26eecf98890b5bed968838d056fd923885c5fdccdd2784cb999439510791896909fcd981ea7b507da7d5f79ffa5d7ddf71b2de28cc9198adfa491ca520d7ca825ceb8dc266ec082989e65d77da69fe53ffebc15e9f075ae74c1a4be742239d3b279cedba917b3bc3ee674d3ba171b2298d731a5edc39e3049e51248196a34802502eabb5d346b9169841fce709a352affaf92485c1c4fc8c9f9f436132bffa999fafc4861b14b084010e80000e650e8d63faf9159841eecf77f1eb02f7cf889f18b83f2a484265abf88196b25440c10814bdc20450ba10d462f4f115462138554104024bdf646d5944103a152c100168adc88108ec10b718fd7bb98021b84a407909c210ee169c154828e2b339f1011f310e98e9974219f5cb84122061c4112800a120e126014cc1ad22e54317b709299eee27af38418c5ca7a8360ceec125306785cd8f62f43d5b0948d0d9a122387bc50d8aa8f68a11508c44156164ee8b08e138538b4fa6efde43208292cdd1a73018dc192f49e2b0ff69f18ac332c595cc7d1113c4b89741670467ee58ad4f611c86480bee5c81973cb14401ca73fee84159d8943d9bf2ed1e4f3034dc5f9ea6ad01f56bac30e89a35fd9fe33ad366e39a354ab8722f21f78318a6c6936ea98bba2bb70be903578977dddde66606e94c3f48e374acea805a97084962e3b0c9c556e4888e122354c9f471a8dedd0fea7f29d582dd6d6c6cdad28ee3aac771966b1c17ea807670f56f9edb38a10fa813307deeab91f1fb02cf87817b2a76fe3bc3ee76a2911de8972faece33d4e77e8a33b39010e1f99c13ef0edcf6faf341d07e09dad048a9df7bae248eb35d5d37cea75fbf8a367c55e0f93d78ef1df33ec7a937ee007ab3032b6ea24bc14c45fb15e11e311138837b011bb8efd7e11ed3166dfda831613b9486050554603a6640763e1b961300d13c931d0b50169afd1d50e9cbed3b999d1b3f2b78be23d1a0f305ab90950d6c85f4343f805c39b265ff22feb4672b217bf540ee9f62cf76756e1adc4963ea6ee3b40fb3c6fb1c0abb63ef8c93c84fb9ec594d2e7b56eb6cc6f34d44e374e3d05fa15dde7719dc0c4c2b649e2d7a1ce631ef7bc6257b34532fb843dd30fd66e22defbd164dedf29c94de3d01cf7675e95bac4eb290f433f138eff18c32708f429cf4be34de38e9ad927009247b7f39d06227e02e095b27eb4c1370374ee95fa171e8d83fb4cb7bafc78e09343a327057b2c12a81bf2c30fd1cefc2ae0bee100653bb4cedf23ec7bde5f5f43c264eea5058fb305bde0f619444f6be52aa436133e679d8b359e3bd0905b88993def7c883935e9d39e97d8e77f37c3d985e96f5aced8992c5cc61530aa1e6f9f1be81dafb260250f6be857ae8ad8e2989f74b70d892bd9fe5e4923dcff3ba64ad7fd65afb395eb23e8b99d1f95326401f0374cc008e3c1f8c2b46c872ea7eba4f509e3f29e532670b2134e79cef73469e57bed892679e5e6c3ef520a472260dcd6a34221edb8fd1fcd95a50a962254b9e5a4c2d6605aa81eb46560dddafba9145c38c61da9aef243663935583d743f7decc7e2dfd8c55fb39de3f14561a593add7bac63d38e2c3204b5980d6d71414e61dd64214e2e71d38dac193b52e346968e129b0e145647d61227e7db2862053e40b3180e262ef0cf951356400106575c690217b139bd20c1c5124a10020f0d8c88cdef1ba5999d93eab68a3b694ab773de80d27c0846740c0a04f6b7b676d4b41260ef9bd62e7f2b057b578836042131b04fc1dedf21b0f75e67f196d8352bdef2bf1eca74bc872103970d4461ded844b4e535cfa3f928e133049fb16b3348259a41a40041bbfcbb252a08b6f0c24be582fb2fe7236c10fcf888b35da50772c9a4b305830221e5dee2d3549cf90405dc352ac4862224250a50bbfca1900e857ed93e3e0d2509cb0e718bd9f77ec672dcc485b5e2e7056e1aedf2f7c429bd6a9737d013f87b82dbc759df2e7f308fedf267d19fb93e1549f27619dd119508080804413e591ce65ab27f5b699fc66997624f801b048d6393c05e69d7c21838182fd87bef8fbcd6cee2df3587cd1bd26ca3ec33b2cf2b5e0c65ef0ceb987fa50d14c57928cc1bbb31b087324a6bcd5beeb86b4a58355856fd19f3de8e5358f4634764394ed67494d89cb8000ca323e06008a1242b66175b54f939010dae38a2054b9cf49acdbf8dfcbbe6df44fe3838e5bed25a29e5aa0c15a38f3efae8a3eb0c200833c860a326430c4840722494d1234694202b12ca68110010e59c1c225fbc2044088ecd859b50466f604fb400249451202c1441051b1b5719353f4c2be87ef8f88e5a6428a3240f25a2d041a3c4a5c9d1e287059eb58a8f03c78d272eb8e1c449cc468d50468570428eee188b869727143f6011c3838707cfcc2a94d19ab73c0495815405195e2c01464c66461056c018985046af1ff9912a95ca138a20ae28d12f5f50389451549f4ca18ccaccdaac856028a33388f599df2f9451bc6a1c6f22fbd3689cf9251bcaa829fb9b1a8755bf3315bf76bd3fb992d17eae8632dad4398c1b67667f8cf167c734f8dc0b7b6f3999fda72da1bc29cde5b4624301fd6b44fb6c06a999bef3cc205ca6ef44746f4770022604d0e28e76d1d7c10e1eda2d88ce7c9bc033b711786af1f986b0d32e1dca74a0e24e65a806418de35fa62ef8d3875973fba15be5974bef1b0ca6dca3cf4a809b4ae30cd560c893c0fe6dc3fd2f0bdc63b92497dd33e1729fbee0efe8119932e1c149fa980c5c7697fe5295e7a3264e676917edbc135d68d6508f01383a106dcd20d329b2348e4d87c6e9d153305df4e91299526a431a3ce633ff8101ccedc595c06577c9f4af5843e0b31d284d33ca347bcfbc753f61e07708260c1c7dc75ba5f794e0e53e4bf4f8b2d081c27c08efc2c0dd0ba071ba9f35a1655025e479450b9e4cf39c22f378cfbc72dbf197e72dfc7bff9905d038fdf4652613388b7b91c58df7c191d544f833063e28e2f6e224759276993d7b7615fd07da39d9b9a293d80c7d6632012e27920e14a6e34848d3861203cf5cce327afcb8c053babfd7041845043c63ac3aeb664e529ed1774a9fcd3c73b777fba5a0cf3cb353f117f5bc1ea02859cc1c76e3e3af1f87ed7c59d420d32e80327d17f221af6b9a0ffdfe8192294969833d3bdb3ff316a593ab33a7d1f71ffa3ea3ef3cf47734cecc9ed3b0e2e3e8402ad854eb4a01cc130a2050902b8d95c4f4e1876393709ab8e88ff9c1346f3ae1a873c4c90ebf246b7ed8a8f9e8d12279ec40294107cd29093946f17db0e1b861a38669052c1a332b99193130405c51a54e48a0f0cecec9f46428048300e27e3b514ab69427143ee0c0eb2614420cc1d52e4f2882e0926b7dea4fbe74cda2430e4b9cec6b7b87e664ffb48f939e0f70e92d4ff73881bd9ffddf3b0cf5e968023fdb7d0fbe874868bed71b67663adb45a90882e38d15e0ef3bfb8d4c3c973e86fef2e5cb973189674f3cd2aefe4ed471728e32cc5c6405160e70b297a08080e9cfec24cfff410844479ce4d2c9f8ffee6d059e3f699a08096e07821304ffcec609bf5cc1f4658f3c7f6c5109859dc620ddeade343e91bbb73f1b271c67bbca2945eede4bb50097be6b32ab0882128298071c0a463153931d5d624fbc98695ce22d743f95c0e5343262ca3edecc9aee5b7461d6741fc344a7c37ef8e17ba3f7f673688eb3fa739cec7e664f9c3914593dde38d9bd906c82c2c85e81cb6974eb3cca5ddfe4cebba13004cc56f75ed48e90bb1f2377375d376b3ad2c9eebd91c6c9ee97dce0648773bf7befd7f7dd77fd2a7df75fc36e68abebbe4c4d2cb97b23e0df509812daeade5a27391ca793e048e3e45542614f5bdd77d6944b53f7179c650ab9fb495ed1dbd5af84763fe72c42eebabf14fcc46a9dec494d5e673bf6acf1c6396b7a7685fe6d4ef6379e46208ec25aec64d32fa71185e586cd9a2e61b9ff473f4c0d1b1a87f50cdbe813846e1227fd88931e8159e37f737278a0b0ee9978997b21394e60eecb9b9b9ca3a0cefb1ce73c4a2762da72291ee464d93c4151b27f0759ebdf3c14666de7727e912360eac1e5fc22fbdfe0af1623fb173922839225d662ecaf50c63d6162892c547ce9810a6eb1faab09bb013a42055e7c80021060c4eacf6967cd59cdd5ca3ae9eddce903d7772c369992043f6a6c827a3c2ec19ffa469ab71ba0181698fe8c85e1efc1bac88fe4dcb0c401feb2bfba81d14e73ce096b9a8ec3fac6a47158a6f0a797f56fe752692c6b2e3d58bbaed6d2bda76359ff566bdf7e0d65779cf6466127daeaa0c0a99fb1194b8d4d56b4e5bf33f38e62a927698b0537b4e5ef1d987db1d43f79c5525fdee02f570420c38b2590f00414b6596cc6505fdafc7d1f0d6577ec2df7fbe80aa6576c19b4cb9f0b8d98720bcd1af7fc71a20e57bcc08722c2371025ced8f59086194bfd0c654da83ec7eb11daf24f893a5c542222fe2a69977f28da50843b7807d873ffbd01af0b609d7901f65c5abb03ecc20decd50210165650c1c69542cd0f1f3d5a248f1d3a68728ce2e3b861a3068bc6cc4a66464c10d38cda8eac2347c338d8608bee4e2bade3a42d9fe1e9e4ace5db79138bdca3925b025b9cc9f7035bac418a63fe7c4d3b6c849c58487a6421296bee728f4c3a63269d6b383927ea64c2957aa3dc3dd04ea87343dc99fde98c1ca35aa5f23d71610c2e969d43dadc7c154f25c048e0fe7624da0991aeb24c8c12984cc3464b1442661e3a6c68f28952eadf2affb2f4a7cfe46b3849fd6df638ece4cc4e68975230dbf502a594ae6084644a1d27837306e922b366beaa0bee2fc1ecfeab95b5649e36f426cf9fadc9ad56d6c272495564f403c9ee0366a1fbc7517ec6e2797648e91f4769932bc72949e2a4a52d0bb33774df64d1989935bf9a35334a6fbf8e25c5a729368669d7fc0ad2d04d4fcc8933a7b5ab9513ab95b523ea85dcd8fc7072d659c71c9b2a55e058d64ae92d530a03ce09b35f52eb4ddaaab12a29a55f7f0254d5a58eb8f4a7f4e7b76b523adf868c1a9a4ca1071e51fa2ef8994ef89452a96266c8ac28adab191af4149a4eb484b240c3943650ffd260d5a814069f4c212aa58251a550f8640ae9a594d2ee1ac624df5a6b393bd61aab50e7a444e9a4656ccc088d7c89b1f4dec0d1dddd3dad4f39cff3bc52fc22ea8b551447cb7da52e34d55abfb13476638f5dfbc81dcb15b6ddb8c4d671fe60eabaa761e765a0f3eadf3147c8794474dd5c0e9aae7b5a9f869cd7dd75f7b4ebd3aebba75d9f76dd3dedfab4eb0898ba0f5d46027492d8e340d78de241713b841067ab7500fb84fbc6a14188d3d559ae4b2337f6c8912dcff3bcee697dcaedd8d10355391c9a4e287c32e127f589c7cd84483e733f2937ae48d2c70f337cfcf04ea149cc91006f9c3e7c8432ef6b40ce9bd57bc23da95df7b43ee5fed674f5ba4d12d7ddc78e765e398ee3388ee3388ee3388ee3388ee3388ee36a9db4ba534abb39dc755d777777d3ca35689decbe1cd85db7933cc7224e763f72ffecf684288195ab9e576de9bb5cad956b57095a5b2a95beefde0b82601886a652a9f481df77bbe794d9ee9e7324674dc3e0dcde93de1a3794ad40d01302dfd0e61b1a880dc6dddd738e4a9c0441d0643a9d4eddddfd77ceeeeed004f63d813da7cf39eb147d4e3cc274132e0a954aa95430607777d7c072278d834e2b67f3b5a5ef9642d3c9844ac1cc900167e3349511c12a04198f474a280bf46c710f1322b1b9b401558864060479fea501b2c09c2233482311f3d3e2934905f3e54d8e196156372a6c9322c99325229f0543eeaeaa904892b4d6b2404f085c92d96b80b43cff242a117568eb086d9d921863421850b9868d2350f988171b378c781c8e247d4e38e141a6de93df58b2d61b6fe02862668ae37bc4fce08732fa22a893c45f37cc9b6cc949d296931436416bff8ea5ed466eec71d67272f75dfa23341ccb1538dab1fc25b9fbee3c0ac449bcb3c5a9286012e96c713f2344626f0662422436444247703583ccd08000113ee6005933480d1b0da030d38c9f3f3383d09841ba213a9155c30199d2603da024cecc1a1a10c8a2cc74cd44e0247ab3c59db2cb4820533a49ec71a0a33d780e1a9ed6012c0da8430871b65a07b03a763cd9c103fcc6e9205a14a78b2b593b7a230f90dcc9e2025e878e50d67d0bfc17f7f36d80dc08c90122cf9f76a64492c250235ead4ee3a42da2d2276290d58198863de24e947d66c583478f1f5632337a803ec06f9cea439e6f3a61f1249ac42e47022aedc1730ff07b84b2fa3fc04961a6eee76398550d7f7d3f5bb6e421979e7b1d27bd34561964aa0c338e10817bba680f312112cff5ef0f50c75ff36f0cf598534c4c8cd7c5c484336054313131a99818148ea926ae19609ab3861bdb3a01ddc50414c01b9e8ff3c4f28130608c804b8be503473e03ebd6ad5bb76edd7af58a4acab6d5ca534823d15dbbb96e9899d45d7bdd335aa86d97bab7f451237592f3e4a6b543010a121acaed556ab99dc8b378911bf9cd8fbc8b279dbea4b31d985cd21eda8f6d293d5445cc25b54289a88d1ad12df48822d12eb99f7a99f1d07e3214a01a2485ca50ad12d5a26a94bbdeea96caa522d5a419d7c3d172733f50a270419c1037c459e188727336ae88d3c2ddb8230e894bcacd79e966b93b9e1e1db9ec7c7e8082846e7cd95119c2f16557b392bbcbd2d93aa3eed61de5eeb87497d479c9fdde0e0fed0768fcd28b1294db13f2a87855bc9a47e4d93c239a2f3d2dde4dc797de91c7c5ebe225d999e5b1b41d5f5a1ffbc3e34b0b64a358294243354b447e69b3585beb4b6b64b5d82df6c822d9a4598f2f4b3b3c3ebe2cd14a3e2528404142433fbe2c55a9d57c59222a15958c4ab7d2510929852f4b5d4a49ae2fbfd94eeeaf87f6031464f3e5274548852fbfa12ab93f2b1fd167fb8cbedb0a5f7e5bbe2316befc90be2e9f97190fed07c897170a500b5fde2029b9ff52b943b77689aeedf5e52dba46b9bfbcb7dc7db95ca49b34e3b9f912eca1b9f025f8034201a304090dd5827c095a018970be046d6011a805bc814720129824e44bd04b387be1cb9027ec097d7e808284867c19521922f26558b34293cb304b680b8dc25b7894f365c82544ca5f8649a19719b934edf0d07e80625f9aa20401e04b9310952aa69a89c864331915f9d2a4c574937d693a3271c96dea624a9af19c68307c79f239fd18f9f204748a3293cb939493d069e8543b111df9f294e56443f2e5c9e8a4252697a72da7a313d2296916802ff10e4f0c5f621af6c9914b0c0503e1202c848764f81257c1b519bec444384b6e5c94fb67898d72ff2c71898f723f4612c097b80b4e1ac097a8d98e4c2e513db41fa0209d2f51528408f0256aa84a6e9495dc28a2dc285b6e94516e1abe446dc95da28e7201be4421e54675790294dc5fbb6deea721296cd66c80dcd872bf0eb3dcdf412fd0f2e3c54bee77db0a78aaa841e109b99f26b540088adc5f8fa2f0051008723f671405ad88dcdf11d5665a0ccd9272bf876483201fc0c8fdf6a6c4cf13b9bf64fbc10b0f104fd482c8fd5f9213423b5d72ff3d4201501057e47ed08808da1329727f48b4c44c8831869ac8fd26249ea3202672ffe936c4163f48e47e6c23c2c6f324f7a36a52e4fe0f982017a02617e069086505a0e10910ca682062089900349900af13ca08700314d3f90184321d22a8e4010ce00510ca0620809f219409c08740ca33ccf03284b219ac0c1f43289361081ee41862f80084b21802f048425900b00cb1939120f923a10cc9913712ca8e589e1e6423461e8650660486978532189c47882c937d9150262bf2000865458480220300001f0b6500887d0e6531fbe428679c9c3f2794e59c2712ca729e40c94452c8447e48282332e45f086543c0c82fbcf04242d90b421e279409b141c6a991713e4828c3592116e45d086541b004f14376c185bf09652edc3c2c94ddd82b320cf6af5006b3af6f2194bd7680720b626ee18184b216803c0ba10c0810320b3699855f2194b1b0c2ab10ca5600a20459051e5985b709652ad8bc2b94d9fc1084ecd2915d9f422873e514be2694a500835c53f33f42590d0f9efce37d84b21f587e98651f3ebe4728f3d1e35ba1ac0715b9d57a3294b556c8e4f30865a463f1a188cc83c7ef08653c76bc8e50b6c31a21ebd0f134a14cc7cf32cde708653452e41c38e7f83194e5e82f5ff2f862281bb1cc649045f13f94895ffec711cadebf0c21e3f09171fc8d5086c3f38db711ca6ef81717641b37b28daf11ca6cbc9a0014abf1ac5056838ccc623d8d50c6da9269fc4c28a3e140c83333bf0a6533ab9709652b1a64995496f919a14c66c6c784b21951809263befacb94631e2694c558985785329822ccc8aa4f8532954d3d2a94a56e9051a8c7a10c85ff14ca30148ac8a7d39b42d989c817d387a1cc749443981c3e18ca42581dc294590cfc1bca40ebc54abef7bf507689e0c5279768e4d2db5056f28eb27d2f94d9a3bccade77a1ccb3ee023bcb75cc250c2b8f99beed22d3327490e9137c7097352a2917a0913871bb179bf4d0bde753e6df8e74d263536471df0df7973febdbdc3c397ddaf9e58b6368c4943b71c67e4583a459954f7fb06e6dbb5b6bad5b4be783a7dc8dd6e7a784c0a54d05410290d6e53a6104a00f5cdc27803ef74604f8c310292040a06b4b814f523b5960a1c58a7b85103f1f00812082175a1cdd28cc40151801e97ae1aa78c1113352b3d40f503842101c370511240849508bd18fa942071ff08e62f461c6b846655c208801ee24715604a324a8f4ca972ca3a2660ccd8800000005e315003028141009c562b12cd003a1f20314000e7f96525640184a03a224c87114c430c618630c01ce104290223444c4193901f084e2bb66d93dfc70e4600e3b16f8fc5e626ef98ed89cd675f897f5a16fc50f3cf7acfc7f3aa34568f8ea4a751d949a5445523269831f9861d798a5855a0063a27c595c2968d89ba3dac1ad27ec940180bd7559ae34ce560cb529d5873058e51a56c2c715610d2d15b9d4aa6acb7d6cfbab5c4a0f95c2917572296bf3b3fed69058df917145181a75b2155355504f1905ee038dc2719551e926e4420b64754983dcfa07f60b4376cad0b0310384496e592dba2bee292423a5d10d15e387e7ef49cee0fc05a7b78d83e5708ab5082bcaf2958b7e84ef038129bbd7030d0704041267000e1cea11386859023c193c04f53640d6f9b8e20dd78248623f3ee64dae547cb37279552182156c8f86beda52e57a8079ffb65fdb93df05c2b795f3c032878042a1809f37d75fa50e69560d6a96fe5cf6b2e7673fe39b71bfacc32d2e3de198c6c5c63035ab6f35ff0cd3e6228ca85568b76a376a3e248d1a5a0b2cdd191ef64cecb8ff3fa2fe306ce7f158fcb3344fec1715e3ae1b9febaf945c91b6a0f3431cf60dbe5d05047444584b02f0fb899136fedf522cef077cd27cc058b53060d844880cffcf9eef10c0fcda2a3c31ac73071b166141e0053f26ad4cbaccd20050c3f02854ed7205dc213bcf814e98f47f0eabe7d840c2dbdb118188b7c42fd1eed83c23a63df88f2689a973b90a9088451ec41351e34534aa356c4cb78b431e67d8b11329145e696e2f883323c6ad3386119fb4a0473f13f871cd630762484b2bf93511ca298a7d1c0af837be5d70253020a7bd31637b471550e10e6d5af2805c1e5af8f1ad38ad7aeaa3c9ba218e2d39556dca8b549e3a2ff781d21d1b470e0820feb0e365fe9e35b61f066fc9d4560f54027984c51c4461047e41b4aec29775471f8af5bb1ab2900e137048bfab4143b91578b3e8a71ccdfde42533caca59040a0853a6744ad604dc80891cf96eb40e2bf5615c2b77c63abf6199a01960cd8a88c68aed109bf5f872c30a12bbf08dd04b0725226a8b33f3b6b1867c556ebd20d2bf8258658872063c6b468a0420be6c9604d807d44d22d377640381debf1a0a34cf59b7d9eafcd703f2b83265c9ce466089337c1ceaab96acef9f088a4c79c7decd529b547a886009298da7dc2657da0db00da0a98960eba4ae554a024f55131f93b96c6b93958ccff9f0d54df2f66aa385c9df6087459750fea1b42d11869825002c5686555442f244254131c53743a7d26b236e18447b86ed5e910405149531e11352fca6229596c762b936859a02b45c559baed8e5a4ebc25a45428c0fdbbb8b760032ccbc88276e8584e468707391021ff6b6054864832710b6709591302734e7000d2e3c4d7b002c3caccde9216daf5eaeba0f2e5a51be46273582a9f42f666ddfe245678a8321764ce2a0df9d995600a37429876436333688b166d160f9c890a9c2cad9b0cc7ecbb2d9d9c2f980dc62ab97480a820ca833ab06e239eb4ac11cb8d3f31d2680cb1b5320321b4e8c7bfca60de8304cb54b2680d90cea72a5e6108e758d8f9e021abd46bbebee66900c64211319640f5987519946ec60a7c3183a0314618f87bb4bf1ee8d9b5a862186f13bd15503a7b695ae73b7320bdc931d04fd91ce1e0bff3dc49934e23fcecb71b4ba14e1f07d2c1cc430fbed6549f818c064faaaa85d0b5d2192d56961ec18c8e5071250b1197a3479d561f5e0f76e29cfe08ac96c435e864fc9d13f1bd1746d7175d5e7f43fcc4d10d07384036092250804618a6850a29ef374bd4e91d7c06c1976daf94d5bdd126e605f9e236f055b9c3a22340d1849258e69dbb01fc26c4462046540000c680c562085614c66c2a85778dca6e1380fb94771b051e136a60c1b8498e7487b518339b44abdd829e5f04ad293b20780c7de175b1d0e1b9809ecf7ff58182e6fd926c01c4364e89512cd62dfe82f4f5b2501a6c2b9503751e1ce54c3fa1c0b30cad361b187235fb4c12bef0385f4286ff44df3ccde983937e4b6e86116d0eab737361e4c1c4b61f11208a207be738c3e708041f2203e129a6f9583a7f3ee10a0f20073c0eba84494598cd3ab291083b0606de26134200f31120318c76397fcedd2e315dc2f641955117a00d9af5ae341e9c43819583adbff62f09ce6c9fdf00dd413fd096347f522e55f121c70b66412dd02b12980d63f75a959580244737b5e39a23d0bdef905006846c7bf331e162439c12a50eacbdf820eabed448031b9b6a05617a9532b8f1b947829c497bfbc62364f108a2c3e0e6172be22679d5f9bf796709f58946a8d5fab11bc639109b90b4be6250c4af7516783deb5e15b188e3044aefd72de08fcb0cbf5085c4fbcbadd17d3adca4d72fb71a62cc65525d78824f71e9c733beeb0c1ad6111132ee01436cc202260307df277cf88611699b898f6ff129e7ab9be4d35454895f31dda0d59ea974d900a452c5ac1183041151535031bac60e64bd37eedac20579e72baebaa28b8d43fced4f9887964665f2bf10cdda8e2c242713eb875eaf5a5096efcbf8c7228a372702bf28678418b17c274f53d9bf7640f099cee34f265752b9eebda917e09b2eb786e7cc70e82c1cbb21cf8cb57802c0efaf3a208e9a3a6bbfc30bdcc2e4ea92cb1224d777139cd3a49fd91527c818d98fbc7adb30541974aa08d788f4498ee5c89ced0bea471d8a10495c772a2518b2cdd39c95d3b6c4a8538d111de7b0295ee6a70ee90cb7c0b4ea774678a80107c8135078b17a9385f4212b2f1d1d2c2fba4afce67c122c3a43b8f8c03ff3b9cb6180660e89c4a49c1b5e0400a83ed80cd06056eaa3738c36a22fa6896b260d9e67c5819ab13600612d05b8294f62f1740ea38b67944ac9508032f2b6d0ecbd11df9eb73b11d77153ebae3ae51ab06605ae03c4ec16b9942b7b06c740433da42cbf880dbfae1a81950e1c5f7096e44b71eb0ffae16ec38983ac9f3160ea143776c8fd53846067e7ce9ed48fe37c793e7ae1b4b04b93b34c0b4f1add6250aba9b05c3ccdbfa0a4b7fe69737a6092ed05da5adb20f006da185cdc07c35ecb1cd91ad4d6e1cd1e820e9e7ee999d8fb61f7dff38a4bb40798f49cc3e77a79c459614f15d071a9ba300f36391479729fac0c189dfa1ab432bedb9eb7cf571f1af9ebbaa390648c79283270cc752a2a1e76e26bfdc84709ebbb0fd6617ae500b9d95face5d9e3d9c1d66428dc1960e9ead4fa19bc677eeb473b40a02e22920710f55eccedd054ea8d470c1f68cbb00ca5eee3e0d9eab73c7f13e89f491b207503b05b974eebcfe7621c3b225a83a966889cafd2ea633457359f36f00559e91b5362574cd7325b213ca37111d68d7a9c5b3e1276ced48c3f680e55ad1235e617eba3c518f8aa742fbe9641027c96a4873a82dbd8faf0f2be267e97f182545c508b68509a61016db72d24550cf5b6941b91768af56a64e9a17ef220043b9ba0cf7abbe83616c89ed518de3d097b758e3ec0630f8474e18672ed40dc4a79da24d28f2af301a404b441a4c3080b0d2e13fb457d0d3e1be361f88fc574e4639fd32bc9182eec4641e3eb0d2c94d92ba5c14e7ebe1cd75908f6c80edaee6ff40fbbfb0d36994ac2ca7001461c9a14956249505003f5b8e2d8f20f54dc381340e1cdd608df4cee0cb9694e7b8b994cc0a88d06358fbf6637f2854462a469a6746a7bd810b3bfe5f47b19f9998a9e12827254e387126164cece7d51f1f114ec98c597030042088d6c35043c002ef1743548e159a0f662d0c0cb73e045eb1af1c2f7657c6858f9249856146012184ff8e511d87a03030ff3f904d3ddd5ae11efdee0ad4cb43d962f1d1278b8dca355f0ff2352d9d6c27934dfc4b259a5dc907ce8bfb1f92789c49c74fe1aa5de4f561e53bc38e68c2cbfe0d85c5013845ce2ac2d9671002be01033c65e538b9c788ca7147d0fc5b4acb91f582d74f1c4c6d7f8e9670eda79462c718bd59932f6cf8e56df4c3ff2a76f80ded0da27c0ff875b5c449fecaca8c5a5f02ec33514319f899caaa210528cf71898c9f3b5d0e2f74af5378111fa9c20be5c4b0d11573857e76b7c2d2f7bc56ad04b70b1e2e017cf779ad2d975a2c806af8c569b6884e9554cb7f44c95fe941583df9039e1ba55803907f47c6d5709d956216b1af930082fb59c4d8079f561b4dc14038c5566e3a3f1627f7676d90eb7ac753e26b1ab36780bb84d25bda862a1de7d0ba3d638a507a60790a0b327422118b023286f83c5de169808c93824ab64606859305b4f0e13b8386dc6128569f427c35065e9e46218521152b417e734bdd0aee15b2842a0ccdd64b7573ab0649166cb89f1789fb2deae36a65aa2dbfa4d5f05648548b65b081e7eeac862ca0fc84483e23e44f3ba31e472e7d1201c97637c8a9ae9467b17f1df7eaa4691e00409a2ae559558f9c319a6f72bd6bb0f6b2926ef84b39ce583ae61271061abb9286d541235bab6ca698a5a54859c0fbd362f32277622a9b0df124d99ce6c191b943929862ee760acb6e95091287cf359039c662d6e3174238801e60430299d412c3c9491bd56f2a63c626fb727fa7e511a62000e9d1de6dd9654afb6c298bc08913e1f67861aa1ad726b312a77a4e166320f323edfde2f6518cc9902a2a7a2d537a71f37f6ac7fba40368d413ceb36a1e8e2b6cbe3bba4acd03487aab85089e9c2d3cb9486f2a5a946b39a8b7f95c892261015edc62128ac42f69937a33193aac1096952d8c9d4460eb744602bdd0331c7ea6e19e1fb22af73c1deb417a254920085de3c1a2c0e14f6f7c916576088fc4ea25d9e7463965a6f741c3931a0852adbbe87725ddda47f4f8144e23ad89cbb03a825639b7f98d6e149e8281346a29cf01aa7253422f191b09d9683e9e78149313351a4464a374c92ee535a05d8d7c48d6b1d170998d86d0d8682a8a64a313fa57b376fdbab5d9d83871b59915d972308d3ea05b410f0052afe5473f3ea55da0ea46e2d2833ee8a0fd12bd38dd0bb04de02ddecf36fa3636822833725f71599aef0ef079e0e316089018fa57e82d31487209aa21ddce2f9f46ed9ad7da8b82d48a2c67d85200c1394e66532f87d272ca768ef65279c0712c9201493045f8d88c73620bf8530d3a0a734df1a58abe6c91eaefff8e86da4394ee900558360f44138f839e5edfcdeaebb51227cde7d76d9c20f1711a7099a0baec1fbe52c8260d5fc72f5d8d56f8a00f5d6534f8f3adaaf23050c428f3330ee584e87c74efe4545ec535eca63adef3cdd96edc34c950f99ab86932ab3a1a43db7d18afdbc9b356b99550589a30cb7a65b03465ea97b7fc1c2a6fe1a609026c3f429a188df812d2044097d28457ae13e68a4265568e260630543bc16c2254ac75dac763624049f7747e1552ab18382a91370d1e131c348d8c88062e5d15596b324f529d2532158db40cc5f429b87c540140214ce86e9f99a5eb3d6acf6b3f107f88703a7dfe8cc6bc6aa76781842240d6318a92a5a2d35388e60365316e7d708dc67a41d3dca231afe301d8a27507809f3f22c3fa9a32b11f9ee3aae4d09ba86990e6074ccd8aa7b48dc6798214c5b2f9280c3006414122a477f417efe2bb6d9cd3370e607ba2ee08e1008fc59baae55cc66556f4065bbd50d6aa14c52d69157ab3abe7af1c719352edbca99cc0cb26650f5d85cb5723315353a526a254d2314bd23f6ab323dc925ec46dc42aaf09ecb3d4fedeaeffe708f454ed653c12d38d5de73483b7931c8e7f7f349591ee17e59982e67985432d85fb170cfd35baf5f34bc5f9d1f1ef985ed49936006253715ea5dc9507d2b86466956b4b6a4fc4b4757a0e0bde3cd0ce1a914e77eb5beea632e02adc31c2b414cd765107a5169651cddaff65b604b85d4f9a9fd342c530f8a42b4aa50976ce562056dd9f8ff2bd2f81c48d192497440072d02634fad8774e432f70b21f60ac8d4e921f0d7e5440db60be9cdea96e4082812e7f83ba018a84502a7b4e54db0f6c7d458dcf7049ff857bf0f740d28b62d75a8df9d6634892874bd6bf65c582e93cb885be8c3f2752e8f70d8deeadadd68bde3b8355156e03c9059069015929a399a39636d0e898f23d013ad0a118eb0bf76ad2c0c0b0fdf639dfebf3af3a95103a59797bef451dec1906a9ec1d9b9c57782febce584b02bc1609610319ec548f17e67e23a418ec73703b2455809e68381f601530f37ab3e990c9e2541d49da9aec95cc6d3cfd225706f4239b9d0851d5d754eb7494edbe30e1e300f060f1d56945db5a7dc239e140454980cc01e8c1822bcc250cd50be013162dca797609498cc79321eb82c80633f16c1f9a78c923c5c86497c765754b775a6b16dd657c98e1afd0af6952c54823cd89aca46524733f9d8435802ceba8ba493a3fbdfa18e24cc46ce81bc1f8282c64be66def88fa0b1f986f6aaa050545b1a90ffc396c7135205f6ea593662a26706f4e03a8fc1b1a349341c4235368a813ac26c2c2818aba282cbda7a383407ab706da36a612ff136f903d47b8fe27d2799d633a5320c20bd01c49c4ad68699ebbec978eb347c3d116ac5706eb2224b719675e2aa89863748040fcee84c324048c0e07a95f1e8a805f2ddcf5e174db989820873f7de097c2128b34000e31040e65b10cf8fff6f3752e085e81b7c7311b4657c7ab752ce8c9ea931597bb569cb3c9a8265702d2d4583571775a44d03e0300938d6102ab0430c35e9a7b9f8b07df303605b1994fd305ffbb1fcdc8f00df0fb62bf32246530ba6ac669a79c19879cf16cb35405c9c32c8e871d5d0e154f23df9c3e065f3b2f08fb33ace4b16ce79092ba82ac3d449c2712a60f153006b57a23d308fd0c56c9a68d16ce882702e4c2cbfe5d1b0594ad942e4d556b9f87b6b891670ffa04b04bf205fec878fe81073696a0734dd619aef604d3b861a51bb8a226bc699a98cda6168cea134b8e6ebaebde81a5ec3758a4ca36b5febda8bac598798c6c4eb5851e7f1d0f24ff92047d2ac934e36e052dca87995dfc2bff9bc607332ead7c1b554f53a0a68a1bef269e45812b841a6d863b88a59377780a424b67c4b694d3b40031c748d578add470edd92e9efb82349a011f76346a68b2438280af11125b00713445806e84266b65ecd2da6b6bb113db161fa64a6422ecc3c07c1b6469e5aa2965eaf918c1236a9224cd018f76b43e6bce85ab536b61290c29327c7de6b35a84f9b73b0ebf11a50b8651067d710af6445bcc3dd2302bda5df2a1868f02b6df3d51bbed67979e66a19e14d263470adeb5cfb0a45ac31a7a6348acf01f23497702ed07114f72052a12e5553a949b534c5f1551373f8ab043502448a616b90dce3e0662b9dd6ac349ca66f76bedfee08606ef3905532a606dc68fb463d4cbba8707165bfddd211123a016dcbc69cc2429e5a8973b3dc5a713ebd6a7816ebbc5cef4ca0e6a16969338737050e7f979721fec93a7b43c845738c3bfd2f33e0926f7865f8350fd6299e2b8c9b72bc0394d4dcfef0016c05a282086d18bc65a44390361521a1c00c25d9d18d92402ec02812c6db9a7ed9f05add7260d5b0d1f9e99a2fcab0a1cf370b250b4a5158037babaec9480d52beaeb57b2af05cbbec67fec2f747529890670dad9cac9dbac7bd21886e1d7e47c9608db612b7f003836eb0f5596b1d7b3a6de81e5fcc69be2da5cedc8301195316094ed5838e1cc0251d089e92f2422782f979f413b71dce2e4e6517bfbd5e1876352655e997aa1ba14002d9e0119e779890278292be94985d892048cf7351cea7bf4138d95db9731590ec026b667330a1a618c2708df7060c9c2d8faec2801f31a1e6d33a2307bf1acccb9b4d31c3b18f1578172ada08a9f377d7bc770db70cd5dfba0f39a89574052c4b8113bc600a290f4a00837c1946b90a2e9870d942c0d56b3761ab20c1306d87954ecf228f4f0feb1d60e9a25a5af002f864da4e7e15281bcb2a4f2557ac9f90bfbf5a2348859c21b9a8c093d308c9ab9721d460e999db0c97c4cdaeb8add86760553d4af376b353decca037db81561bb1675dd155165a1b24729172ab8d5a3ccea313a49fb09d901249d629dafcfa779c136e47fd6b17de46485d0eb5548bae4b90b17c467fcd31b1f0ba9408848a2475ec11f98a7a01c9d314ba1e0ecf613de2ae3a269e6aa5849bb41b87d484fb482f38ac8dcd6808d6d3de7ff14c35a93c55eac9a96028cd225a23d451ada3fceba1a79c24c24f6995bc986cc8ce53ed527045066b79434419b3b91e4d81aae5bca65a7ef2c3a6320228027c4a07f6c60c15bed689a61b4922852b0f8393f7fb49cc2a39b38d10fab9f3bd0ba02087955bd27ee0dd23f3c8fe9aa79c99c620c80f560eb0742b9cf231556eaf7a749904b8919430ba394eac618ed1a8002363acd47025e7a5b517af8f4abbed12203b4dffdec78b9031b6d685019690e1379fb33c13eb9439d8892f9d57a2ce776f38463620f0f2b2cb36ecef9e5bf73312a4b857a53c2707d138048cc61d57ceb821577b23833796050c806cba23a365feb0cff3eef4138157a5955917c8671ad6d4ba3a48ae51638142dda1733b276b67739ef9ec3189cf108ec956bc24a6d331d4a61ae6b808c226010fdd69c0b59f37329209602f7c7513ff9617257a6c54829cbd68341cd0585cca4e1a2de544c2d41ffc04005202826ab476de734ddcdaad34b815215a00e1087f1d6e1c91e1ab606d65a203dac382a0c980f05738979b312dbb4ab70b82a3d715c0b5c78837a56d4e89cba9994a536c3645716c007b23b46df1ad7f275c26b5a9a20960c3b0c3a63c55fd21d96b72d675c6973183dcbc970a8f1677131b2e6ed6499e47dc799eb82a4525d4f38228c6f7bfa60c8a218e4937c318ea526946bdba77d4a60cdb64789bb60d09566fae337641dccc236fc92182a96ac1790d1d8d090b5486b4da2bc60bf6ffd3981c7e8febf572a49f8592c11893013a7a87b23d262a27a0b0d9bf0ed7ace0b7ac4e418388f7238b8034b67f4d35a95c528aee8d5154704f28820984c33f091c4373f952584d285a459cef440681b462b77d1031235aff5920546b69e5e452ab25219625ea7d9bbb3d35ec6ffc1b79a0d890e0b1105ea967c161d5b3d2f402cc2dc5e255d95bcb84cc7d11be4c97e25be9c050fe40e6bf1a3cebd8b2511d04830cadac8fc33b5025da098bdb3cca84988ce56dc8bbc50d97ccb85692c438bbb218ef97fc5c16a587abd86b24d51fc6b990add772f860ba1e2d30f3589f7e7fc06ff74f6d18dae1b89b8148189a0507a4c9e83977d621e5a3e041ff88b0b348199fe96d8411d91789a00e97ac820592f867ac182cc05bfe036f1e65d651879cb3307e3bd38c40e033e13e27b2de4c32ed41f2ee2510603f4f91d839ab2363b95f6273bf12774bc16126352b37bb363d7a48587dde793f551661b157968b63610dadec672308b35b193f07366aaecd4f17fca62ea1b6d0f98a6e2c2119ed8a892f37551263e49291157fe4c71d14dc9780af1855d6c9880088fb0fcf158c90b570159bd93f454e815ac44f48cdcabe0c73f625e5674b1912cd59fa5190b4fa17a0f0eb37e47eb6a17e67f3558afedb59356ef850308f11ffe0f519a720af712d085b710a5dfabfe0eb261aee550495790677af8a0ab79f15572528b69eca33142b37ade2903824237c9fb2e41900eb7ec8c6ce59dba46aaf2d0d80600fedc303e23b7c51e1ec43cd04da0a7036c6fde023db0eed8fb6454270c655dd852cf76afcde96358fce213e516626558099c037e6d19d16c8b9110dc723213c021fe3311c093d866d4acf798c87319adfe4b108764ddb2f47230511e60ae111bb60f7e25a613e1f6fed4562ac5f504e7f85b4f666b5f1372b49c98158d7e4c40dc92e84844efbb2034896ab6fc13b5715a716666158708a8eb97911440e3955186e425bb91ca741b94a32807bacd463b37d3d49db9652b36eb42de31212967be14c32d5edd7945a25ac8814cd08a174589e633614e27a35638ad7091aecdb56fdd89a6c1abe8db3deb9364b8673adb4820f4ef846c40ce9f8ed893a76ce2f17bd966f45568a20c54673bdd3868aa4592dbf1fea4c84a4b439ef09c24b9be061d45c8e2b341d0e1a03209fa0b83de2f642c82628eb65063fa9cab65d4e557aed71dd8d52613f36eee219656e07c34aa170a888acc683d5957914892e0acd68cee75ce278c99a24e18f17efbe5a10664b9abee13be93b0830cf5b45fd0dce97c2a4514536670178d8e96d00a4e1dc24c72fd341e533a2ea2d512432bf29a8ade5b8472bb6cfe45d23fb522deaeb5bcd568f458a75b5ba7112e3e9b774c6ae5bb652e109682d972e80eb576e1aa48a370a3f1f421ea4ff3d96966daef56828aab05700871c645bfd171641eaa34fd9d5b28c1c3e6ef07d7db80600129d9d9acc252d903d7a8c7e1be35112a17ac2e9b4466ee56b930fedd2515ee360c67ef0f49b4eb355ebff1d373ce8f6458f1ec886c98039e7b2e2d10217378cd75c3ed90c76a6b9dcc9149ce431759ee5a211795fc89df1329e5fdcd9d2f789d37a940fafb2fdf536730e471ac1548cb63e8e20e6fa072e0f4316575e0a38c09c27860977d68a7ee2db1b997207611655eac16c1d156d7310fb45fbb65d82c540971ad7e9d274e65cf2982257f1f40be1531d35094e7631fcc6d0aa68c30d07d888d512ae38a4636af4afb66c8e670fa0f60e5dcaf0c4581de7dc8b849545f3008ffddfeaa5f8163cf36fcfda5110b4951614ad75007fafac28be4cdd7786412731c6e634b801ac4a8a1b1df1af8391115ef50196e8128c4f6a24010c41f21632eaba6faa730e43e72c6eb0ad0acca5a9804e81ed4a8f388639d116c3cf89ea661231d824fe05ad48a36bdb2ff9dbcaf1186c97012836d2fe48135a008e957b3ac85db2e61fc64a2fc3e13096599a8e0d69b6cc192b8aab766a489a939c9b8059d3e7b0c83298125dfef59637d8802eeb10979cdcc52986dcefbd2b5cb5da2c1fc5bbe3753107d47f9272391a893b0dd64fa8bcc428e3525ce1306c98b5755b1ea6a448c4c99400777a69cec4522db2849a7c70a235acc94b6606ba68134e4068abf711d3f8c39113634a3bbeee7c745a1003041341df0f35453399fdd22a468ebd28ab2b6b923e396e8acd2a73627e698f89a7ae18350b2b825e3b464acd65fedbc76db42836eeac9ba02f0743b1994cbfedb841f38b9f92ba88f47cf8299b9bcc13ffa5654c1c5f31d3396b047d393414cd2ae3e27feb8ebda7ae285d092b82be1d458ae632fdfb636cb428b665d525e8d563a0dcac329ee2372d962201c048b38c67e3cb24e5ecb8993af74d421f298f8d3184fecba628fb97a5a2de8eae0bf2f178c77d136548190e4c5d646d8dfccc026394614ab843b3d6695650e7dc4853bf15ef90b357bce373539fc40ef474f4ac0c7d9e2578ef9c1b1164d9937bc7718108986719bc3b5d2f8381ca7abc708407827a382bf8e11d911a5933c1c9fa39f5c06e1c5b00b441a51b9d22660107b28d34e0a05d85570c5e12ac08056fbcc75c2c63838aba8d863769750bbe83ed4e025dcefd4d03fa2318e199a98b6d350bce2108c78ac1f2e07711babdb096fb4e1269cd82d81926f0701a42dcd920dbbb173c56770fdc321c30d31a40b48fbaef2da0e623e1cf5aea1157f494767043b4acafed24df05f3a62436e00888fd41d1d10d001c0ac67a35b259451a852f5e6d0ce9cd7f242a7c8e7c4f553aaf6ec413cf512c364a4684c6def14c275c58e64be8fc69a9003fd66d0776eb85f21fd16d5b1dc408e47fdf3830d2cfda2cb20080e05152cd58c12b7438e40466950bd6ce5e7cc8dc62ba0adbd0bd39d86cdaf46f06be013f580d333942ae19ba8d06455b965321ddf886d87af3b08a29200cfe52861ca2e4ccf7802317bf3037e241cc584fd1cf19bb3b23ab672fd9f65f5da04f4e9897b5b6f765475e6a89ef3d2d938120ca658578d324dd4cb611ee3802392193d23bb3f0334402431603381fe19299018abb185841df899683aa7fae55ccf3e03a3b39877bf073b08dc2155e8f8d9247627aca16beec9fbf8fbbc58ab4642f634cedc5ac1622f0d92584cd420ff35b88bb2ddef7db9bb48b6e62e9aca6430ed46135727b083f366a2843a71809aeaadd40bf28ced0bc4457d95ac278c5516b4b73c7db8ff486f8529678ee527a899ee9d203b52cca8484c7a316470547ca60295277b16593d95a5c51038dd7eeb2c270d62d1b6d13a047fcd2a47390f8347911b384455c743c9e332a94998fb2ccdfd12c08bce710ff0c9135be39a7143932fd7be6bdb340798a00c6e1137f1b7ecedb1268e1a7d8408d0784e1e626e2169ea0263b3292b443c518a1403529fe5b125eebd1b3a346fb2a914d0c202ef752a67b23d4a774ff26793692c1a3e1b55dd2d525b672536a050632854ede02aeb1a872c5fe4cd90889c1d37d130d73346f7b32fb43cfd821d6bb7d5f33c38c71599f5ee9a051ee8a7504c42d4829350edf49164a65dcd86b368f314ca4e5d355b0fc1f533c469a0de8bb90ef3b103f77e3e299adbc15c434e2de9ed9b2cd38169f6ab5c68c1af659295b2f547c2073f4edfade67b767523f0478b447f0ee7d3c78ef1c109d100347245113f334b989ff000cb259b44fd1c4333cd0e5af425ee2276f02dc09ef713e17f13d43f1e7885c999c9cdb79fed73e491043e5293bad8c4ec2999af41edee9db461c1d3501f2758c51dc6975292394aacf52c70f9b574b23cd1485cb717051f09af5c14c596e9125bfdc3591b1ca2ad1c5067ed6a0234376a13a17286f015901dd987fe2a1586f8fd03cd81f166b7003f808631bd8f0f89f7404d0ef48e696461d39a17504d0919e7a20cf889c306917f5be6d3e4322bef22340bd94481deb008e9eb6a5fe8f07e9f08962e5f70031ea76a9a25e4980fa50346e3dfe420f2aa0633b868213fd41b4dfd37816e975e175963bf66caacfaa0d025dce3a8e0a17e1518ca76b6c5dd08e8c1345ffd49ea9b0cf344dcf53b563b8b6ce27c0eb8e291a8473d448b8e6ea75c11f69e249b2039ab4d699439258d1cc0c0573502512f6cc43254c6dd130df5d3430cb30b51688baff7653c76e93cec4e13b87b827f70b8380c3fb29731c167848cb9fa8137976baa9cd326a3911165e7097b69ecf6eb6dc39c733d16462c3dbd009b4424c2ffd2e3ce0b422fbef5ad309faf222f88d3f9574cd75532ac40655f8f0f35b1539615f76a1cb99569d0671026132766ffba3ae1d1a1723ef8b0cca6589ca64789b128060197a8e0a382c86f666e928538fe266789b82d266a4fbaca3703409190c772809080603f6b739dacea5b818f56ecb51d6642a9321ef16498a6223c8c4784f9d4150f626960c6f290d0886a17a276a515d76c424e3fe68daac02c2c2e80ee5498be186e2a5c1708fd20e14e37b94eeb592780d03df6f15a555d043402259bb96ea12658823fc959f9f4195d7200da3eea287534d3fa5e1db9d8c65dcaa22058ea7eaae7ecd7574b2d256d089af97f5770d84d3f88d3a41b3c77e916c25c84e79fd91380ce6eaf39b8b0c363eaa11619d4b962628c4a7bd132448104b7ca55fd3ef994b3c404eb56e9c820199800dec508401f2093b860ef9b2283f8e9ceff4d25675b16ea635919cd024c7362ca0eb160c48e1b833b5204562364376c93f536d2a512c74eb5bb7011c1cad78bcb657af839bd6102bb7b8b822af0d77b1f3170f723e7922b366cb950465a744eedc19397dfcc88cb30430ad9539603da14e597a339db74d80602eaca16a6838fb03a6f4bcb1a2980c6549560d4fd51b5f347ec8d6d7dec4cc4f39783c897483f8deeb4f26cc95ab3a7b18abde05e8d2638b2f2b5e845973d592beeb200ab3533157bb37e9e2cd653accdeef3d1660c225c0b84902ac81056478de9f8661f35a730f61d31fe29eff67b38e8eae432b80ea0c80f0b8edf87621b0c96b05d199ad49158f8ec0d23d580ca75e7ce8f2ae6e3192377071efc7229b2b12642617892c119d6f2163f8d629d0f76849f27192b953a2c7cc2c7526092bcfc92c65d945dbcc9d209a7127ac1ebd05e62712539ea8620ce4859463766649b4a512ed69e6979373ac46a2a51704c6562f3f92731beffd49fa38cd2915ef179453d8d86de99234770aa43777f20a72813500d816f81a70cb6314bc3e8bb08eeea08ed9dcc7354eb8a704f99d603fb48072920ac7421d65664caf92f597ee6c9b0c6641f84242e1c8b41f4701503a493d91147064882837f4058409320193c98052d274d626e7e4919ab595fedd163a7517a10b35440329957a087a116337a51a312b23cef3c8c087f47222c76eec4c605eb9f549461a15b4a9eca32899df01446614e85d0917023d464db47f6252bb1517bb166c8cc20b90130cc71d67008a8c839eada09c6fa9aa4570e2837309e35228f4c3aeb08f42b01939065cda6f3bcc8ffd3cf70e7bedfdbb068a521a5b615a7d80215ee91cbc13a5f3dd18007e5f6159bff62d19c95d8179f1062da52e5ff68e6206d1a0447fa746e60842a3976ca347661ad309710fccc874c51dbdd9b0e2090da2f2f6640a84d02d536ea856d5fc4b4aa8eba6bf4599ace51178906f1bd0c82a6fd8ad4699b7acc5d30d2ae7a4c0e78bcd9f3579f0b4718af87608b44b9f989e45b7fc491cf135870790244ddb6a1696b8a7273a04c6f694f0ed51cb91f81139301e50c2f1b16d197c171e14744336d49bb1295e974654e3b02d5a105f4b04eb64acb6845783c53b83ad0ed1b9a00cb0dcec1e341593f60b787bfe3ce4308b87d06606da7b42a4666d67ffef9b165767044b633415d510470968c4073cc0399246c31606dec19f9205f0f6e85ec7235498ca73e5972ab9944b668c78556039be47189c2e9867b3ec8c34aea9f12b6feb7638d32206ab66b1ec7bc64e6e28e605ee2708bbf4284dc49ad0b0a59839c69c14e15e1d58c1770ef83d2fda1b9d0fa7edc1d22a4ac3c896156ded9373d4a51978b90c88381de3c17ec97d303848ab3d6f884086780222a27205e03ed6f6cdd73093cef28967a95a460ce3b76753918acb27fb5aa841bf74adb84825bdc4168744712f0ca489abe364c3930d000c08014e27f65f5055452a119eb01dbc45b588825c4463b3c8587d440cccbc0ceaeb1f042f75061eef18d92a14cf4e0d378624b27fabaa5e18b4edfc0347eb2fec1b10ba4f45da22a1e08bfd4e751f85f475c1efd6f274614f85d92f4bc6656f2ca0ef7aac1ca30842321a2d09aae5fdf0a6c0d8c840edb9761a392dee6173905100adb780c712b99d4940c7f0cfbb42526ef15d5b3f6e2a00c3a9ad45774ca69f6bd961c9aed116c1b91851fcfc6d9c88bca7c7ea58605cf6331caf868ca4a965e31e48584e2ac0695068d80f1918d8253bfe8a66584a33ba68730c6479bcb07164a1b45405bf45b1b1c9aa003ddd363961d627ec2721a83fb6ccaaa8304e3bfc3dfb21c117695dc91e3ef02abb056568f83cdee6485b9a3a4cfa8bd11deac196e4f1b0ff96e393307104f2af2ab06a8a197de751b848e312cfa896ab6fb7cc59554f5ea4b516ede71686379471d9661df5a28158257cb21ed19389189803b1f9de472e8ec26353a81c2b90ef789103687fa1c1b18bf85d8f540bdadcc83c518c42b1a314318a378c138a39cf8fb066dd504cd8d8ac8849e199858b9d85353ea64810bcc929cb337ecb59497b6095a50da5ed0c2b5189ca0fa681a2411eb2d32ce0e20146dffa07d046b26f7721db2e88a587b7504b0201978352bcc271537563b9a50c9ad267d7a112c2233636a7e5b15c0edc0ae3f3a101234490834c87ac7da5fe480acea5464646f77c03e8054151af5f6a3d8b8c7e53fc53e8a6810a5c17be21d734cfc462731130221375a8b71a586959184c5fa5eb026480058b96b7a500a59d321cb2d52371a3f64fb975955606e5e3851979d2730ac1652d6008663cf7faf05bf61ba0496799b495a4948de996b33eef8dfe985db14e1604a9cc2d9e25a4593f71dd1d315c5d8b8222ca1397ef1983296062af2b0aae94d4be6d5275b11e0888eaf8c63e46b03e7f51a44d3de4d214107ecf20f6948249a698c07f7d4a42d3e009c256a283ab94a8ea1c30312cb9f72609ae92188903586f07615c839e225b4e63397c772414815f666d89a0222b6cc4428886cf5ee6f66e553081becc8de082a291a5990a00df1d9439f43526fe398e9898ca75a3e216f46042010dbb2bbe4028959d35f491086ca342742375833af84f8d248ad7c9491dd01b62651fd5a996718734504e6ea20620faf72441447c15eb4d3fdcd888bc6b624fd4039a96a32578927219c54dc6853f6419b4ace6ef3de1d679c74b9da9cbf34885173bd5dcd62b4a749645792bc0137661e1bae838b8ca4d540de005792b6a76f54c46422f6e22bb9cd4780737b3ba3286a951bb9a47c5344942766f9d4fdc42c4f933c9ca3bb98690af2bad749070e13e306140cc18f54e97700ae054b42f9d6edc9142db9902abb843be2644dd23a485644024d0e4a9a37eadba0e3bff4e0ff81061a1a4922aaa066136d1283226957a237ce61670540a56b53307386c999cc2f7f346a599b6ef3afb9c6a4ec18bb3c581471eb5b41597cf324ebb75614eb2b72fae41fd4a0345e33de4146ecc3daf8bb5ce6eb4b40b1111d565bdd6ad259c25c1476cb5a3c4a1f81f1e39d46762d60703fc85279d1ea93c81bde41fe36d2ff4ad4fedbf49dfecf5a8e32a14094815738da035f3274711a134cbcc1f769ce01b106e9a0c6c405cc0f3cbb9c8e63820d919e3560d8ce7771de01855e0017a028f7f4709019f97faca85d71e955a47c07a054aaa37010fee271410722c72c8f233e1e093241ef5f051279154ba4d88004d87c03b02963d9c392c707d0f305331c573800f72a4e32ffd39e8f398b47177f07219ca19cc767fd5732fd5dd80c371099c32f1abc4eacd92f2a03a9b4d4cb4afd2a58be5a17fa84cc4538adb27d2177f3d06d3d1c4ca3b002c9647845be41c3092db0a01c250075fbd632c070cc9ecc87751571b4619232789462034dd2129c995cb4c676e5b5103a06290135339834bb713c8da2700bf4a632ec734665302b6338d4d0d0acc3174736e9b3010c2ab5a67f276cb2375889578fdb7dd03ff6914796fd630fe677c3c07c81e4269100826d7a7f5e6676ca907fcb6fe51f472f6489128c6c82a21413e93c17f64c804c8fe4511120a6597bdc32206d14bff72aca29f5aa3c4563d6c2781c952adbe82882a6de25fcd1d30f4b0fc7ac2692627062ddbe59b34ea6d6c43d7ebcfdf034d0a6d8bc4d381badeca90e4edc7bcc966f3098988bf552abae5fcf0c479a06768eae90cd75abb8cdff9ec0b65aff70a803632ca5c70afb5afa5c508b33e01cdeade52a437372b4afd1ac565f016c10153eb90f2cae2df2551f4db7c16544de5cb5ca9644ab50ec3da4ed13fd9df80adc73caf56d49dc2b6bbe74f9b1b587359460c2d2d82af7cd9930e791cd0dd347085067b64fbb9034685f1ce774d96e61bdd097dd7523a9b4cda78707b82060875bb5b22463accc7284a7e90c320ad2e081d07099ae9028a306723e4993ddd24fcc0c2af47e704a1f80f284480da81fdde36d492deaead166eb784c9377c3fec1c0903edd110f981b8d2a5b016694394a018cab55abbc76e31352f9c70f547585c31ea5ea1bb96217216402137ca70a541abc1cbc00f067735561c49ed491c770ceffcc3f2d17e3049f7e857311a6563a96ca41cd6aca7127e9665903843274c87a7d821133c6cf47013714241e028f043587117814559bc7c756c096190aa8d2042c3a43ab4b2a53dfa109e98f26d5108cc484d8ee5bdf6672ae302d962c87382d7ee3e3b79594fbb8ea8219523283388327285713067c3f28f6367d498b2debf5496a3c9d2b5daca724a47c64c71412d6425bfe6a085a0727e1b2773a18199d02ed43159844f785ce55a60c5da9b50cb9e4c4a2d95545ca795177c22beabf84d1073d59be5e96607be8b1e3448c4a5d547e1241a6be8b8018b27dc6a40571b6f42e93f4e9bd14a06b7a9b44df33b6d2cac0573427629f9e75440664682c419a172399959dea7e8a6e0b41c8bdf9803920ab8c897cf3cdf4793fa68db01fb5a37a4a90d654f8b60f163a022a1a4eca540103d65a90ef1955d9f06bdb394185315b17267e689a63a6af9217a8cef68fe906f9a42745818402cc796ef349b1eaca91b530abba7d14ae01732209a2f398850fa1c41291209656cc5bdeb2fbcdc0d4d8ff91da66b27b29433823db1b29bb827a3c88a55cf4268389927797453ce3c81506642cd13f65c56db54edbd14b14d3a0cff64b097284aa6a4ea31139480a1efdfcc42dfcb7ba4d70bb0e60f1f7d3faf35ac2577f048bacda473282527ce2d5eac5a23f6c2a99bc30510daf310c602a3f7edbce879dd0554dcde9e6758b7b49c05f696f84f251f4f5731cbf803b98a748eed037fc93f828c81f4fea2fe5fbb6b1b168a902aaec4390b23b250504bd04c4c12c371cb8b76430c11373c59cab7bc3f0badd2fc26b06899b5a62c01bbfe4230b833fe9b295f8f8133f4fdea6e3173308bd97d2aa81283075eb8330064ec83ee4d8cf21ba85ec462a0aba2634cdb3781244aba0dd06e3de8e276acdf7cf3df63c3673d4320d086b575acb5dcba5ff40ea1cfb1da95d5b32502da241c4a58198295e47f9fd4766d8b723919ee800c7df82d70c157b874c9da5790b03cac1fdc8b6a7c24860602c67d3c3d9965560adccc803fb5281014539009b7a5d66191820a5043b97dd7a35da2901b37aae452093380cbd95c14c0e984b9a7640788a5530f77cdfa3c12b4529523ba1643b66c86a5594eb958721d22136f26ae422d8568c3626ca17ea0490b4ffd5f5e9423e0d342d0285308218fa6e77d5795029f6741edbb346c570eb321b4a777529a9ada4c279cdb310fe84e620858c7db6fbf65bbb28118fdee978e640cd2ed9fc1c31f45de78949a3fec78b4993fa4ad01fbc3c674a8b0a2b56d9f6e7d73175e4e60a5ed2a265d5506dde3e39f5a0b7092dfbc5e703481171071351e22515340d053b8ee95dc6444b69c8a5c9f92d898f2aaf547870c6f4e093393199320f40c679e4423ea3da0379c2452ac8459a37f7128b9b5d3c134b2ec8308d3c4848b12a0d28dce84da880212f22db272a8706424d418f6f72fe7fc642d932ad8d1fc5c018825f955712e8a151f407b68346c164c1d3ec8f2bbf0911708b7f54b00af068430a54745fe42f1c20e07aab7b1ea1b284d90b2c1037533ebb1ffc03ef0192db4cdcfaefc71815612169b3fd599b5302a740188a2f19c10170bce81a8db8e8bf4b0aa97a9a9734a9d6d2b9681457e6634818c11a62b98cf5f31bcb08b45f833462ae266034f4e93ec5b8f0de119d32c5ac1916c6e58064eab35eca7c6aa4a2d2201b604a4e52b06b0a32e6f90b6ccb0b59065dbbf8f7cdb06e5bb696cbe08a562685bbae4782ed8140a126319595a54881eb1c6c15845b4150b071a03713add5a0d808d82105e1e8ba38caaab389b35ec297e3973cce80d02b826a8dee078a387b4fb1c6b1471770f4cf2245a3f31d078f4edda1e5282096476c6ebe1395619eb960cd8c211d8a74968f3264c1bc73388bc46f011c038a2ec8d182d1ce29e501182d1d458f581973780dc03ca6a4312cac3d5cbd230c0b0538186a873665b8f3d83db71cff6077f616d226c91555d40e790d38e07301c046afe1f3f5c01b43416ba02f02489aadd0cabfd808bff459ec178b9cbd29480732ded5bc04b98d56134313f4a0990ed8407634ac5b15db117f43993e1839fb48749a76cb1b8d6e4fcfb05cede96edf2f8caf4ec29df7037c1dc72421572bc3c0bb90b89c524d339ee10214f0aacdcff94bd1d6fb6342e9ad712b68a0e6a8f293ad89044079391c2c1cc504936e34d58065c8b290b10ca88bd3b00593ae2198194e6ea16472c28673990d24696bc6e76fffab3cc6e2c276fb4ba2961716f1b7983362047816e6050d7468c88665e7c412cd4d94d8f0ea48af2d9c6b903d8529f5e34257671a209a6902c5ba5d5a028437deb361091310a1346181bf04c5f9d60a7bc373f4d131747331c725834d3dcb53bb3db2f643055cb5eb525409b92ac2a2844e9ca9d16be71832130cdd0509247cc83a73a0fcee829cdd1de208584dbbe75d6cddbd5f7377d74bd69f770fa585a0a18c31f5f65042a671decfd22080d9e1b0bae4337f63d754222af12e899b3e597bb8cd9a462fc8ea5eea4105b129474409a33dd9e21e80339a998acc6e2b8400920b4f0b0b4d05141ae4d78fae68f18abe9de81e8a06ba7d0e1ad61c474e15c607ddc08f5829fddeb55c304bb6d739bdb0aff709d5fa60f9c6eb154d3ece0139b50e4ef614b4a9508b7011195c069a1a6f2bfdcf2c3c62e366d17b099ee700f027227b0f7074d781a03407421c892ea71246bdf66fefc2481e6fcf50110c9c2f3b6a97678edd4bdb5d346f06d284830750ac1852a4d8f2bac8b49b2abc7c05c9e52a92f53331bc411aad7079d75f978332614e2ae874440b69d443e4979b798a9ac5e3b716db55f74b96e5d472aebe5182c52158592b4254d9a27f3975564d5991a4553cef1a5123779c934d80c40ed5275d62dcd14be758783a9897405a1db42ea5770f4fb893020608ce9306f24a2c4537e82ce4da84249e6cceac279f0b18d38407f951fe82d59e66ae6b26902ab13ef934a09b481255187df5b62b4e4d3cb5be5ab8831006d1a1f24b72bdf54c438e04be78e61686e56f01a6d3ec3878e9281d0391dbeffe054571e0dc27ef7c1befd3b40ad4bb6e7cdb20f79a4c3b17ce07ee30f2e76ac8dbf668e1471227aaf836012b0e7bec73ea0fa473ed84dadaacd9146065b0a6cb6d343d6c23e5541803ad9a88c31321900bfe127d68a74ee067bd31f01b80a25b1099032a50c1d885c37f9ed41180e9f6e1f3e4a0000c272c27c1a9ae3743e44c05983e84dae73a6cef81a98c405254a1f5a125369d3103300a6204c0700f346c8cf67e16500c9045365942838ad4808f0173443820e865cfd51d19f8b6f923a238ef8822d1553c5606cf6f05ac4bc802aefc1c84e61e2ba4c99e34ad35131bc9f399022011f1cb152c7856f3c00219d94cc4776a704d3e5f014fc100611d0546971bf4540c12b48fa8a583bb562a29bd294f710e52a123fa38bb699ca71a4e390d2aec93871ae840eae45762af13b7b63f64e23d49b97ad2b269d58264919ecf12b6a799f402496ed882beb3609e9971ed68a6508517e874f7bdc11bc2a650a8a83b8e43381da97522a38d44627ad8543542acb793c14921232ac4220f2cb2445dbfbc57c6a3f82de86d908a1d053a38ea22fe4905c218f11c728d06852ca95fb2cb4e0c8bc9f3d6c91467710310072c56133796f71111074940c6618c2d264b9df70d9c986794d4536b5fd341093d1e873c2604c6572639d0070af08657b9882b343f6fbad1207818debd20409ace36328fdfd533fc29f2a3693f4c1099618725b6c0a57bc621ab8e838472879738da65c985b27faeeb5ba80717b4058463307f8099de0c2f819223d9884d7079fe88b425ff5a17bd5f5773435adc36268cb9ea6e638ea58ea985a44297e78cb2fe188d9ae62f35b1e9ad1c193a79c5b8447347c6158f9c3a09d0c2458f003feb50c66dbe2ac68da20e2e87ffa65fec8bed0dd9f67f3a641e9e573f3608e9e4306f111fd8c0c8f82b4b1f39b3f403f0dfe391bf53f6252689c48f16cb3b9ae36e7214251427ccdcc3255b55f4df33b8b955f8d9cbd90a44ada1d5c4c4537d7ba306ac5e287bca2f474499b7305e96d9022688ba990d62ddfc224dc45e97f1f41397e1fa02df9604fd5f42e7bf5a71708f66a67a88d9f8a849623016399115341cd3ed45d4ad95e5ca63ca9b0a245bf65970e2551084f9c2ac36e655f112953230a7605344ccda6116b5ada33b2aa5790c4627bbe06fbb7affe16d9024a792b2ae86fdcac4fe5d6c394ae148a29609fdd191c7d759098838279fca92f8047c7cb62dff8f45c6c9161b9fdef9449edb0dd5f2358d3ea8f881955c4632f5c86710e16b552c5619a9f4a41f34bba7b241049e58fdcde3473581ef08a4e913c2d4e913a5ee8c9ae43301348343e5c5da564c6e197f0cd80a3096ffd0d020d5f08250c02eb52457334905b579aa0378ea703f43ff679c4bb319b78cf4825ca921fbd08621630aa10ddb2d75956ba38da31c3bbb5c3e8082c40addd78552ca2d33e88b0eb6a702b6d42de284a013ca94736e613b9c860894f1e34ed1f3cc7d652f686d97bd445fd85f91182635eb33a128935791c92976383c0caffb3984f94fedf5ff90409e43f142467c00dfd716e641ecf9024ada125a6e0aff3a8b3bfc5dc5026c4018afa2c0341edd13bd1a634e47e680972250499c1d021955fd24f1b2a4e4455e6d840955280596632596956b01da17a07ae2d491c81bce0bc4df638373fe15bbd2fcd004676f025c1f7de762b5360e08f0234a22800e0ec12cfffc38f5fe8a542a878703c38316a26fc202b3f6fa5916ff52238d2e66380f5c3d4f5e2a898acb6a8fd623e5586dd7b1e77ee0cfae83a031ea9220b10499563d32bf1aade08fe0e4ef42f5344d17bff24b8208ecbc2369b3b25ca13adb8bb24e42ee29c2c61fbbeec42140461a697de878d0c2f711eb9ced34977045ea0cfff384180991e50cf536e8658a953ceba37638f2db9f3794456b20ab47db2473f262890471b09b620e31cfaf8ea6a1e1109c8ca4b5f8ce049303f082f81b4599e2b2c5710ebd18562df7ae194b5f788a6c2110bfbf4bf9acbde15af6e74cda6ae07ed72803eef9e2cf5c71a8ff83679c4ba846d901e1e219dd42ecb90e6cded7ad19c63bf7d5cf8cd4d1aa1839620265888cfd46b5a608e7f18c7832d3983eebd2d3acb6c231a7286e2a7a6dc91c790dc486f5cab991406b7b8926f63f94880d4aa41dbcb334531efcf715cf6ff0ca35ee22d983f7eb1bd590f27f08e2f9f827d9bff9ffdcaefafd2af22d7ccdf47300107b52b0011f73ce857b97041556cbfcd7ee6bd1dd9c445dd5b8636bedf3ef79b7e63a5adf38670f266cb1fa2722342481f57146d102ffc271104c1ac4415e87f11d9f4801fe156531fb61934fff4de9c5d24af8185171f2a09312f2f8083450f2b4d45c04109ebabc44cffa0b140218399a8117711dc4d35d4cd8a30b3e69a4f5dcbb490f8cb92f204c8c7c8b7a4cb86687d3020db8dd7dfa28d2ed82b26ff48028002d50fc418e05f71da02aa0a50c170a13bf52a058ca4cc7a0004757b1f593616e1a38a713945947a025aa2f6153c682653d06acca546a8979d2f2ee74000cdc4749ffba444c59098d920ab9646e6932c07189357942aa4f85863c11615e05ac6c6dd68c5e6a798ea72bc2e56a365c87a3a4a57e60129459a20ae9452444a9dc1acfbbbe48e2a837ee7ec421e54043e95c93500121b4111e4e96bd749333cb0d5c8e4830942323ae087e83a8cf9ed8abe69022b3b5bf02e3e2890cb465cf0a0b6c127f177a660ad6609b8a416a353c53a8266b4b02e04005224626f5714e40221377a2a2a6c331b21fc61c5801837e935df1a4793e0e29740730202468177f20e63d87e5de7990980b9d267bb5ac596b9e39dcd3f4313009b71a971c969e84f4faca50d1dd20319b4d553b8025bb1cdf7798f5ef684496d772ee5b2e46d7738475fe449df78eb1654268d02e4783e9da08ab7cc04e59286895af07af57e20139448ba09c4256da202491b6baca7e12fae0ef4e6a2aed8424be4c137210eedac116bf8ff67c88534f8a873b8ff92c2ae8c00ecbe59f0a2c398fc5b04f9f5c3dd93008e4f183d2db4d07c7f3513fca2a4cc8ac9b8ee650232babfb9c3959b522e9cecc61e480ef71518ea7c180d220a65599d51383afd23a6c0778c2941dd22e9dae658e255e9904a4be91af83db11eddfce029bf25509253e90dfe3a7e678a825744e45414c5995e569a9a77f40b3d824f6f1d9d70e537647f95024829e2b5d2b0d0458a1949e599c0a773988204433b512b229ae0fe4b8fff48e57d4bb01825a8b0cfb287890e2e1845b017686fcc1a477fa9323b5fb27466ca0f64ce4c8c0b24918bbb5026555f8eeb3116353d99d49f4c76923929ce96c7540f9dd2394af6c525a5547fc5fb8072c9b400b2290e5e117ab052daaf55edd60ed2e9eaf182a5a20b62c24261a9c9e983c1b7e0dadbda47fe7067e4a3edec58a0534aabeda8fdc5d40ff69b1d29013d12549d592b5425ddcf60c9385024d37f52157084f45b7044ab002beb443a2c66f519d2736fc1e155962418a7af1338f3ebf05cefa4586153a60e6612b71d819a6480021959e6d489270a104d620db371b2d88cb9d261cae9774b32db05a8153c8e33acfdfd68a04ef274641e386d80518e990d28f75bbf29c3da88ffdf04f6567960f1b7ea97e503677d9a7b08be79f8565c0583b27a604dfa15e86265144f58e5a81c6c9edc36acc85512d44ae89338dc31e771081c6c92e92b4a0287c24e978dfac0159574ec5e0d734beb166a544afddcb3068042114202611f414b83709d6e2ea8437c7f3aa7d051bb1ea2ab3ec173659c28fb36ade99d25eef7f79092ef546fd9069f2f28d307cec99a9adc526e08c1d81d882fcc99e0043b292cfe916b2e0ffe76b9bc4f63711f7e720960fbce40ec0037b1e2bb4a605aa9eb611cdec05fc6799ac20fc87ca7d18da32ce19c8f01654830479ca5a37912ecb7e4c9f6e6622878f25be386fe2da9c1c1fccf3f71ac1dadb2b4bb6f7a31d5ced17183c55f25a384b6bbd9008f6bdae734107562b45c4dd851b768134a3532d778ce1062eb3f1d91c2511594654f0853b60219f923e300e28c5630e5cd80cc4d4c6b15720d718d9dd3dbd70f462b396b10911b5d405bbab312e70ece067ac183398277fe7d86424411525d2ad2ce48a03a29abc3a73bc662925e2d0c39d480eefe569619a081113c0426226c394fbf056bd6fc66f380fe1c36262744d44375c601c65bd264f4eaf073e2c64cbfa14e725fd6a297b3e899df87d2e77a30f91aeb07cec890318d92a8af36468db04fc5c49860cbcacb0b22685ffb1224436f08574c90672db8a4003ce44fbc4643581e2e721903112a19be149684ddf62a453bf75117b3d93646f820281492d79f836813c63eed8720d16f257240cba6f38033911ac4817fa06d49a03cd7e4b96142b381fabe7688f4778f4827d276c65ffbdc2ea16c34661e021f51dfd56246a5848c006103f89fc044656d433583ed82576c3dc9cce09f53b6a7435654aee451d2bde358fba22f9295dba7cf8c9ee640bf16579385bf0603b918e1131c7003daf1d9fe0af0d3f51b25cfcad4eeda3e892c092b8b866c6d9f4e9ae84a037e2609ab322b25907a401d607e7579e695b042435bfc3717a1944efeb75ff8d3bcc2477f0582cb5d1237a5533968eaa4d8c62c9373ebf2cdac716d1fe06503f8642cc1d61bd4eef5fc074cfda02e4ad1ba44f0b4f0316206db4516aa0a688b030916b56a12f388f2944be6a4e46177dc813ca07ea7a767e48764eb14cdb56cd3de088aef88a9173b569bbe6852470afb016b84c0a644a7c53b981eb465a7af9b97b34f893f87ab55d61d205e99bd19b00fd63445bf97e05eb762810f5f9d29cc7a8c9c3126928c57f18d3ae6064e8ecf21c24719bc06bc479ae8bc46f1947bc9360b9ae7abb36b24132a4ab6da253b98b3287e4a9fc66889e60a505b95c19831581c577fc0764beaef23dc95fa0033ed066b6640ab4f680c2b31ab9ca4b40bf050c5aec254c78f78c3a7677c24f92f299edfc1bfbefd17095a415a073f120461709af6ff1250336c055a0c3d562c0d6edcd7c058380b933fa838f797aa9aa3ed9467a6e7c70c6eabb44c38c88cf1416bccd585ad6bb476fae0c2831e146a0975305f615cf8bb9305f4f48a0941da78bd78bcee8bef8d7532db404769a4db0183ddf90a768aa73b94f8b3ae69cbf0b4384fa7991c577284cb9f3f43194d4833b9a6fbbe774c0f9e2f6bc37bec9da3f19d495e4fa489fcbd47a489dae603ebadd506a72861a3da8c127b269858a85125678b308d5789d8a90a245ac10eb835ea5fcc5d093b30566a454830d92ab4a017fd4c7d22de951eff98d448489953c02e95429c87208cf74d660566a030a581eaa695ca076fc2b32f98ef138629458afdcf08af762bac6b53ff63fa88f1fcb7ce69cc66407a290bfade0d2b89313c5eca3e8bcd810d61b958eba5003602c2c5394d9fe1df1e4257383db694535d41369e0ec07a611864c1e0de90e5ee70424a8db325d12a11db2cc33a2412d8a1c21f604bf7ccb66ba6385659a6a1f0835279b97df656b8a3073aecb3527a851b82411e5e061477e92ca8d1f7137a838b8967300e2b6712b7ec1925be389659f01073fea229cdfd9c1ce76307d9a65c7e56a8779dacbf7c0e4680d5200b27f04158e500ee9f3154c3778184b2283ebc145088325101f3fb7ecec978b9461e235eb43823c77dd1d7a15ae317daa1057a8c8147964d7b8729d6049836a7c253a288650cbc1d6c04dcb5764cdd2999d96442149879c77efd4c1c45f13ce97a12ef5c2c313947d4f1c490546bd12a2df99618fc47d59bbb400a7126a3f9e87be4f91cea3b15cd66097fb979cffb18a87ed6ac41e639ea239a411ea369cc39b05d823145aba63205fa17bea0aab0fa988d795026b8c1c5fba27b035aa4783f5c15707effeec09497d5b76333b6eb56008619a85d66e0eb8b3bab7cfd1d64524006e658225fdcb81eeaf0ced8022dfc8a2b006324a8826a3b1ca560fb4e8b4a545f5b9ff63f49112e29bcc239a744a11e1138868bdeeb1d1b599a617466bfaa12f40b77c9d0ca94ca875e72f7aa8afd1047e74204e8c14b9979ba8d57fe8ee8188294b88c18a1914d4aacf5111384557db64b02fab1e80f5b32408795f6694a65e81adb5939c2f7e3a68815dd28b1b3a08bfb5a6343ff1d19d898f3b1f921c04a422f32915fd3e7603e5a16ca3218947cd0f8ff5f80ac3568cd8d7767786354aa0d47ac3f25ffaf0b181823a0ca255abf6010a4106dec39e406a2cd9223ee8063e24fc5c0034fb751022b667d012bcd6a1d33f3535a70e9161b2e18426b30819e44d963763332ab85ff196d4f717e67e48482e0d23887978252fa3501748fcdf7955d2c269f04496b3d2ddb126b02d48b842234c263304124f8b180133c79083dfd00515115380917da0fbe55cd751d20a37ee710f20c933febfb06b21a638c43526689bf0548570a5613573308e7db2d143166671717143c4b6cc6e69d3793984a139c28d4210f5d58d1e1c0ca1f59a25b9257efa61fe9d7b8bd3e9ba6704790b506743a35623a0b0b5b389e0e1af1e8465065b6b5d4b651612fbe5a306c460bc094e83ff6edd8d03de30379e4c726367502068802f87260e1af16adfb17bdd4ab0c56a86b54cccfdfa6e8f351a6d40d4ab254a04a3d57464105b11b6cbe179b22bc2b423e3488efbb654a8071280ac230e1b4730a1a7afaec66cbfffefc99c87a77779b662ad405d12b1c468f6e04b85c62d3fef0d3e3676ee2fcd005d0ddede688343e8b20aaf3dbcb46d95f94e335f8147225c0a6e2bce62cee1254bd4e63c81f328e46b560b67b3e517a196596c774a6b5d6a150a16348e62801c44d806f1ec2a161392c46b22318ac51cd7e9e5eae455769e63639fb4ecb59147ec02b32a8c098085ad85fdb4850c9ecbddb44e6f72e9d522911ecb188d1758710be11e469c8b97b8225710079e0a0377e48dd74ce16bb4d326635e275d3f8a4ab5e32e8759d2484e2c2e89111e36ca662f3a657c6ebcc44a8a6d7c7e56b7eaf335b4035afe160443ef789b101deec297b7f721d80e57d4ff7ddf8d66144945fc5ea12d5640246a0e19b231ef0e41cd4439e1110d3846c6c99e1291f765e61ccbdc4383708aebc75fff45ca22a08b696f656abddeb3383b605695e0e910b0829307ac80eb687ef96ffb05b07ab014b0592c81c8fa0a8a007eff3c42b7c4799514703be59fd3d5dcd0b2191f4504e5f500967a60c8218d3cc92d47ec1a206941936e7dcdb568d85f377fa039cbb5fbd79deb6dfe6fa01b03b5963a9c2a8dadc52196effeee3ae7a143f277309d5ef7d42110a0cdc6402adc0cf5c9a13248a91025d9dea5343d151ea13a43802ebd82cdbce69af4ba0736b27977d69fb9c5202b305c61cf73d50716ea7326d9a012fe4fc4bbb3bd5759d4a8109e04967b40bfe467c220f00fc6db7bbe87d059d12b42c3e9dcac4b9ef1326f84f69097a9f3dec2cf8537a67278a812ab98961d8944d032b36bf91fa2d84adf8f57593f95dca5ff0bb793d4f4b582817921c8c00e0ac62cfcdd64d71810758a6f3ff930a2f6048f4a0bcefedb50eb779c22bb8574121caf0c18f420e38f935ac62cd6f5f52cde18041d3e5e9f8878e64ab6f2e6479cc58159c957579aed50b3a0e3ec3a8fea265d03c2073419522503999a5980394e91dc8a2659ac3b4ab0bf88e4430ea72228532a63d8749a1b1549712a4b9b348286e1f6cc4474095cf9c87b9f18d0e22eb5392392a9b1436fbbadf308ba0adfca4d9483ef86be35d6ec0135604f821068117edc85a147fa7cc314411d036c61f6109a8a2bef51216ac19755e9755c60887827ff9b339d326703f97b98923405709c32d0228b3a93824ac7a651394440c72e2c080f900ab345a97abbd807c45a1e9f00012f71013070ed58bbc2363f1b5c35b8190e9c9baa53586f4989a75c06e67397ecb9d2f9eb0489a4b6768c3b14fe4b38cf3f0d208944167c1590698d38d4ebdde64b56b4967a84c8eb3e9a119d6b94617dd26770407148403eada5e945c30ceb29a0ea6375fc1a46542d5a72066ae2d0a5d8101b7124c3862abd8339f2d2546b2a738568a0e483df57f28a1a4a6fb18140c0baaacc3a08ede78aeb64d99bf93c753a7e6dd7acadfece5d3b282bfebe55bdbddb6dc52ca94a40c7109230904093d478a9d4b1e53d9eb0b997a870f05f6f620cfbf7a5e5d3ead33c84a6badb5b65afb436af8c925776bed047da081edcbdc39647914442d3b4a6291eddb5187b53f615eb2ad3fad0bddb26fc76b39eebbb99713a76d7b3fe742bf5e88b5d67608a459f6bbb0856659eb516bad3d7140cc935dc21efdb81ff0b4d6da1a46e99fed63f24c6b86b5d6563badb576c4d65adbd67e0c121e276c65a7c90ab6d65aca7573ddd6da0064fbf6559c8e6cdf729cb53766f6a7d090b5f6271425d9fe9c4da37e51d13ed73a48b06f5fc7be09edf2b7d65a6b2dc771dcb5dfb01a5de4c794344b06354b4affe46987a7eac1d9e7425505126bca866de4ad591acff296ac5fc11c1d6fe55cee6fa8eae1719bf94be5a3e342d593fba1cae787b7e44b9186f24d34d480784b3e0706f15627f59566c554c145bc25e52dcb6f9bb79277ad93aa947236f397142faec91be94292d64e0afb8a126cc1a914f37b63f7622ce5c907a583fc0913929fe54f267247ce584bdb304874ca559d72d2f20a20603ad4809d5e21f0d0153e5d6856bdfd80f485cbab183f28a99e04df1ff1cb930f53789b60235d683ac2570142280007932b273128fd092488dc194046bd907e39994c64eb72c174f60064880e0939ed92474c8632c57203f60f291521a326ce0fd89b27064c9c3a41bf826b13dca35939fe8a408ebfa4484f405a087fb8bb7b9f389bff046dde01c483b8601b736a1512f4c2b220448ac0849424c586dc3562940e1d2a5c75db3783588c282677a8dcf14c75bc4567467e456cd4196212f36149d7793266e0710e358b7ac0072cc5181598d2c045789cb150c763b158cc8711198bc562b1988c2836141b92c56232a2d8504c46141b7a80bfea89e9a5d87d4f4fd6d012562c765990a2873ab1582c3683e60d538849c48c29116a16a54d6a8d758bced8fcd8d09218152645b17e8930e4846866c4440f4a34a4980d299eb4e96f797dfc7ff8f7f8f39012348147b370ea59260de0595fd5c3fef4db50f584033201e4d1ac9e1c0beaf030a159261af0cdbb7241df934272a773f732af038b78ab6d591ef1c0257b10217ad4832cd32eb0e97fa6e89c0eb8fbce95748b4ed80cea167d0fb6c3a77b9932baeebb2ed4f116cd79c06582553d3a9d30060b1e250d48acc93d54527420a21b8460011948a0980dc1c219634c39e28a295070444c17d87b29ceff5e8af2f4c3f43fdd7ba16a863ea7f75e8a52a41f3885c0198ba2b22f55f351351c2474a159314fe0b6788229071f732901941964682cb1891448684a194a5801441a380421d29f30a794d24c55984480fb7bba09a594561ad42c4a6bd7dab5524a617e4aa16696536b8f7808cab4831b4c68c91ce2e1874c1d87969991ad73880bfd5b680f8d46b30ec35d6ed775ddbd1f44eee0c8f7be90f66e7767153fda759380dc3b4494eff56e772f18b84ff7defb40f7a6bc75ffdedbac7befbdf7de7befbdf7e23782f241852a1f9847bd147b1a77a04cb3eec5f9de7befc38040bc751f0516f1d67d133893c89bfb31f7de7b2f0a75efbd5d77efbdf7deeb994cdd673275ff752f4fa6ef69cf346db6bd253ceffbb8efe380c81dcad3efbd9096ed7d10b9936ac9c54bf6bc9759be20cba31db864cf3fdae5f21e480b9e77a40397ec3d09edeaec858175660cd39593c789244751c1bccca8f7be48bbfcbdff993cf6bd7f41ee70ef3d90dcb9effd84c99deebd9f30c81dd37b0fc45ff4bd0fe2affadeeb787f0ac77bbf70c49e0e0aa4cdaaaa07c4bc11fc5154f3a50f3625e1fe0ffc9ae5fd046fb3bc21de17f11e88f741bcf73058c45bdee7b46b6a60b2bcf7461dd9c340bce5f5536f9e589062d04f141ffcf5653022e2f0678af4bdfee6116ea93e0b52acef03e6cb972f6988f43d9f2e1d35fee40acc2f99a3eff27402cd159833f83e20ddf23c69b349d8f33c0f753ac19c4e30a893174a60da3e18c069c33bad7d5a236f76aead17676baded5c79ecf79c9938944a08acd878a1c308aa8862454647a0030ef508dc41964739dc9ec8e18bfa258729ea129ccaf2280725a0c8a1091539dc00460e347818b8c6196464a12dc030533810783573c112a2c66209077c096ce38b23c1150d4ac31cd83a0d8c3a81dd019b90e80ab0a9045509e6b23cc2210434e0e084cb922d7008b24cb0cc8d3a81515f7418f87485171ca04279e04091fd8103455017e00db23ce2000e1407ac411a150c1cf3029701be91028a04ae51c5f28065a4780bb00d209c087cb33cba41079b03b6591edd10a34f70cc17b702abb4d429300751542eb0064a780cf089088b1dba091c93e5510c893fc1305dfc0aacc117f6088c4fd05d200931e148d894e5910d485020302acb231b9cd415e02fcb231b866c88297d49dc6967edeeea369c81a5deb00d246f6289a03388a031388389c5e10c255f9c0143bf00afb4a460c98a0e2c4931b454822e968ee8c0120fd6075c23cb2a4b49281718ccb24a973094923c4a972890e8529445170fdcbaf0e05dba1cd9821f8c8e0196b1420833442002333ae0841931ff62c69121ca10838932523043192400a30c222e65f0d054cad880122f34087b31f024db8c4bad8280cb94b6e1559655b834e929b8d010c405861390c1c5b720a38bd68263b2ac420615940a7c23cb2a64185118e00db2ac4286105830075956212389cb702acb2a6388e14660992cab8c81c50a2a1c86319c98628c24cc186388aa658c1d8e601b59561923c8666fa55db33caaa1c83b03a6365dbe723cf77bbede77022ec27314629373fc64356bbe4db3a8124ae4f95409b61fa859300ec293f0815ec11a6459050a24f504986659058a18cac05e17126018a57a049fb0d0237c5140b3c0d8895ac32611d426f88be228c09d1314ec6089c0a72cab2069a0bfc03032e81560ec02ba84515b501d302acb2a4f5491ad10f6e665d22de9a44fa801ca0567c0d47c135468d7f83dedea9f474a96745f9ccab24a145f649ae59192581e535c125ea534f286a77b863313a7fadbbff2d56fc3b1629896b7ee8fb64e905afb34d5acfeb13e17da5a2bae2f74f719de7c0f467ad1650fa645b30733ce7cc3c023eda413d98399d983e9207b305ef6603cc81e4c2b7b356262300c0c2a068542c59c3ecf33d5e8bacb71d6c654eade356ad4a8316b481953a366a039279247804f27cb7c8125385feea203a83af2089c00ae085d4ec6f102f0dd9c72a0000013026ec5b06a4cb933e50d08f982f1818c071ad8dce860833005e2780e6a543433ab3c93a92acff76a3e5c02ccc1e3c8f33df093f922156ed0c10d1b0d3c90f9c006083558312d1c020c0050394e375f003c1c534e2782003e6e049be77b3a3e992fb0fc3a00ea7a7d388ec0f7bacc17787e341eb0ffa0910f7ef5291b534592bf3ef87eef03f0a797687e6ca59af055fe34a1d009ef428d24478ce2a14a8a3e34717ab0434d3e00a5d84446249bdfe795ca7dd62c239fd19068b93fa64acddd975cd543f5333fa37a32f3525439d815819d110d6e73a522a701ff78f0abf790629e8b79a48bd4cde44d77b0ebe5c67b67d41535eb06ad5d37bedf03f0bd75e35720cb5b37bec76f80326f034a510350e6bdf9d978d819c9805d918dd0c4025c23e4a898381d038e9d94dcdf41c881e3cd181c6f51ce018f57c84aeebfb2fe2b7495dcd865e244eec83b34bd693dab33535cb94b5d9fb31cf7418c8b1b67ed4d0b50661b5c50c996a3f62b6783604c8646215fb6dfee7e9f032bf042f60a4c100a915111155acdca9666b5d2e92b98250c2512268c25d99b4f20cdb67f2b0d01d7bfd99353099655b828cab20a174ef2689a92fb65135956d9c2963dd4376d338fddcc4882e1a408150030a0644f7a31df0bd9f4151c8be47a3baebba71db7f3d2acfe157861debadcbd33342db6cb79a9c1c6f80be3bcb48bc69c7678dfa9c00a9a402293e3824f3bea9fc06e08ec9834abab2fc05c18c78582dc92b596039a162a960b178ecbd290bfb8a4fe9b3780d91635a5a49b0cf278af704af5b483eab86d012509c90a91996d59ee7d6a7a7ab9b760bdf6e97b38724fdfeb2ecdff44e931f3abefefb7343198b7fa6742a7ff353ffacdc2fcb958f72af03e98a404b126eca7b5ebb81a37426d8b2556a88cca28f79dbbd7e7686855dc57db5550e695538c67fea7863f74466b4f33045efdccab425afb91ce6642a9f2e69e821c150e0a7d7f1a7233150a1c52b39ab3526b177785f3d30e8e7202a879a159ebd5ef14555515fe4c517a8bab42deea27153605fea13723ab90da6046a2f4a079d51b117a71a6e6475a13deb0cc52344213aaaa1491bc3813d6d004059659d5bfeaa7967ef734e498e068edeaa820b5abeb44802975f1aebf54e07bd091d5d3bcb702939420aade538135af7a29d2804780449a074123352fc599fe56a0a47929ce8041aaaff99efe07c19a23ab9f79b09b79abbf06ec6840e94f609aaff97ff055f5572faa6ad800232a1ad008cd4bb1e6089038f320780448fcf7e647034af1c1ff999722081af99762cdcc83e0bf3c3900489c099394207e0d28459a951d3bface31d1ac934fd02cf7cbaea081535404f31ef73f332fbd65df86aa50eeb0cf8214552f4f0990d9864f562f4f3e56dfd3a1cfe9fd762ffd55f33f33bf7aff4be4af9af08746155e225f81d25b7e894e700efcde03472234734b38254433aea85d9d51bb4e4cb4abbb343e6097f974a2dd2954d5a11e866e62599410d12f985b129331e188723f6d897a371cbf7c29a532d9ea55b2ca7213a12a9fd537408aabf751bde7d4c115e8ab57853faa5f853fab9b5a5155b75275dd0d39269c2c072ccbd019508886fcd50d0d651a131e3747e0fab4e374823dbd05a9ff7d0f65b34ca83781e3cd5ec78486b79335abef955b6b565f287776ad34ab89a8d7bc882de5a62cc05c52371bf2f73ad6a7f101d7701c92edcb9f362442b3ff774aa1842f5fbed01a18974a93b87e39de2b59a95d1ed6d98cc676c3a68568f2a8aa51ae239838a82b954b6a17006637b02011b56be494207599a1cd8035650656fdeabd7d8254bf7a0f53b72a30e77fc29fd5abc21fd5b77a5ce5cfe51528c57bb958b3fa2fc82d695687aa97e2ca5381b506d6a4ce28ec8a6a8d0635ab5528dca77f9f724ab858bb96b4eb7e4b1a1f300dc721b9becc7ebd864468be7e43eb65e284202be26066dca47b851312ba3f72c0bdb43f9a78ea7b380a09b33f17c40959e1601c8c13ea90f00b72e088ef6ce2f445f2d75dea56ffbd18e92ef55de2845ab01b5886ca10f21bf3d77582552f4f2ba842954f900c30413f517aa87ef5fdab177a3148869e55f8536fd56661cdeab7302f8628da01091dc4c0a268032a8081053c4c399222469212c4d5afc21bcf1448d0aa4de5af5abdaa015254fdea8dac5e8a63379b097f80c4995982b87a245354fdcc87cdd1843f45449a5f8148aeb87a151824a423ae1ec91555dfe334a00c45449af7b84ff5004efc01126964e0449ae74e3e34342ff4e2cc7327950f8d9de57e997b60989d51b26579daf1c4cabc550556f9cfbc919f282c4891e6673a51e5a16a858e082c35cc20cebc8f0f7c90e2c50c49be7cf922d63ccd1ba1093b9ab7ac6c8a523442f34768c2242588344f131ab11828071fa4783183100c06136742a10dc4d5d784485ae2ea9e7c7830c416a326427cf922ae429535122dcd5bfd2a508a282e8c58b62c4f368d89038216b534ac20a531796e0d2781c76e769190ba22232a5668de47c110720565152d64d97a9938fd1fdc6e6411f342278f87262ef08905d5afdedefc654415c6f033c5d5ff4c51f5abd0f4d99bbf38252cb0cc3dad02ad92b73aa12ee87ab94b360a8b3471fa91b2db1b55c20ec30e39bba2d59e3c325f8efbfb7dda71dd6b7d0ec910ca33494103e3a14e52d0c0586bf2acb5dd5bd36987edbe0bdfc39f1fad6a6c81c76e36933b4672c794fbbb114c1efb2b37b9bb572968de86dc77337fadbe5fcad44b1efbdc4cb6fac37ada71856499ae407b84ebfbafdefe3ca1c0fd7d0b8615f02f5f52084d5a52e08231684093d20a34698139a51c592c09312b68b6fa0905da0dcd11fa8d5c216ff5af7e05de106e33af7a2b8468bfad9c52ad5de3154ab2b56bbc44576e96ab8512f96b154651d9da955a3734794c2fc09cd2c4e9efbf42fe3299c1294d1eff1915e8a04d9a38560b79d37f9792727f176bd7f422f7dfa5eba583754aba25ed9d107577f7d6ad66646bd7d4f20415e93f76b3dcf43b2ded1a2f92fb77b68e09da95fe6ed6af4983c1603050e990fad5dfd5baa476cde4fe2e4bbb64152bb3dcdf2951bf48ed1aad52eeefa9456eaae4af282a6b6b96966e46eb90ba596764a2e1e889c59127e5ce0894e5e4e1499bd18b49c2dfcbbf40da3e0f3beddbffbae7ec3ecdc9a35bd6beeac7bebdb787101efd32d57c5a0012640891a26c6197ebd1eab024648b6bdce060be72420364fb23eb841c7ff140ca41cae1813487bca139c494f1b8a276674783475130564cf77b69268e00e6e901deff987e1889e1bfd0480c515432cbc81a90203e3f42931878f6748f4f9126308fd08466d18fa1028f4f33715ea62e308ddf70647a2404ecd5ed1a9fbaa60aac3cfdb72debac78089099ceb07a58339b1c1dee38b21f3589657f157ad42c992b28732755b0cbf2a4809946aee14cc239729a555127ea3d2f67a5871a81329d81b001cfbb93d53cbc4e9a9cb44913a26b90399b42532888bf664c48690a29756260b7e2297c556896f49c3cf64ce996dbc391b5c4834707f0386dd3966a217fe5b09190a7a462856355168bc5ea91fee2587ec7d40ddd61dc6985166de8306ff5e3fe9e25b5cb2fc6a9d42c57f7b0865bb001b631e5951e3a682af498c0a35953064bb2090a10a87e1378f46c79710a4aee6e020a12b9bbb9d31117b29a459d66820a3d3c3ad9058925b9bba517247ac0a9e720cb2329684829238f2caeb91d726479d484073206c372299919aef607591e294143f6b4c8630e335ee55c37a66466b8f791b9e04c972fa01c91058d16a84074793102045c0c214509a8881d436e4289a5dc6f93231c85e8cc099be1c01c39e04cb3642e0f1f13549099b13922b2e5569647342f1965258f396ed72374881182f02655faf10c4110750ccf4204920c5b95d936c036e4abc76b3e2adcae9e14863dcb23295074929427bcbf6d728f3955f258a51fcf59ee23294759ca943cb26cf5871a36a0456cd0830f1091c51037c4a08118928ac0d20128c4063fb0c15fbe945ee0b054243628453186a2102136084215e27cc1110996103dff1cfc994c7481020bf105939212fcd8542122b1a287b70730dfa3b3261f1027097c18c2267a96a334b49137f3035d7a48426c30842a44a0f942f73481e7c37bd37ba1e9e54b5aadebbaee81f2bdddbdde83a7f2f1335b30134ddf3d91991fa09a1f809bf813809be87df7334b9b31475e068491c44513444ba60421022d91c60eb22942f044134162c7c0053a88c08b0f3b24b98926cc50fb80cc0c1680e102b15b4750629995e59111601c419965790445966fb23c32c228c7c8578ed1d0114ff8a0c409b8889ca7258fd40b553c64be8f0099ef0365094eb05e90c6087c64c42c7bfd71a075d09f0381f2048978b6e1fc02a4b259395c3b101ec5b36d6ab31a50b72288c8fd2ab46b12e1a58611b2dcef429df288082eb9ff61c8236ba2963cffd94e3f970e6289c17a5d38d30bae165ab24cb328a5b4335d3951b1d65a93576422f2be7bef3d55607ed162488bd8f7a7052ccb7865a062b4c07ca7d3e90483afd8297097e5511654b24cb3fc280ba32cd3ac98d38e9898fe981a6ee3f3196641749445139497845a4c9b455d5cfd72f7d3b0dddd53506bad5ed8fab65a5bdf5a19ba05eda74d693fed97009d596ab7cb4c0b78eeb762fe8e1a9ad58c8a031ca90d6e682063a3460c86419d3ecfd45dce56eaeddfd3dd1e4ad97a6102753717f4fb6470b37cfc32ad3d4e699d4ae6f7e19f38de32fde397bdbf4e1c1970a43fceb8da7e48a47377189ebfff0b9cfdb6eddd1b4a60bebc47f048b3fbdc3204672959f347f9b4e528c722131cbf2c2718947e99b62ab5d249efa5b5d65a2b8d81d62fc766adb5b6d66aad8502a572f47e2d91e8d5c9fd3ab97fca2769cfaf723ea57f6564a8d55afad126b6d66aabadb6d65aedac564a6df28c7ad05f7b6db2913b5db368179492753fafd22e77a19437d5523a84545a924a26904b31d38b52b7e58994ab945d06fa2397b91f6df67eac997b2a774ecffde879073ff753eec03cf72d7750cf85a3906f041606449d402a6fea7f5ecdb5e3727dca7193ab3fe9043ed4a44a6ece2927731c13983b5d4c3fdbdce4eacf09e4744d3d507bbad24a29adb5562630bd5f4d195d0aa394524ae9370a994b54f8521eb1d00a2e4e991cf05ca2311308ddb944856ce128c4760567add4d65a6ba594527b9262630383f94dfb1514a53e9217a348a04e1aefeea76128e99c58d4dae187efad94d25a6b8d7d9856192a858b59ab93c3fa8ef1bec7928a918fb7fcdde4c5bcacb14659cb3985a3ce074ac9b2ef536b3df627d39ff7ca7ba97d49052689135e50c9348c29619f64c9443a770a1fbe17cb64fa1f56e25e2c232353b10d32f7c33223f060250c193224fd28cb5b2912b0fc8539165e02d35a5399a632cdd1f8fa57eed8afe14884e6a20e6cd9aaf434774c7953db9e76d8f7b8c97192a2460b4caece0bd02eb0adb7721c570573f694c2cc3494f286bea540b9d23a6bdd0277f7d65a2b05b656e2508ed2a62fe4ca75e6e6178eeb5c3b634f7265adb5daf738cbd55abbfe1e9fb6ce0bd44cc36efa14af524a29a594524a29adb5568ef34fcafb1386ca0d7fc050e168ad94566ab1c0d0caf5534a29a5d436fd7c3ed5b1d8ff763a5c58c3f1f3783ac1661979e37f4202cf1f656ebbe80e2bc42653150a31c8fdd2c6b95977f0feb272f5de5f9f0db92530773f107b778bd0130a9736eb8e4fefc7715c288485c34a1849b032a54174945ef27c99f9e5f935eb5e2cc351c8d7ac29307597519271b37c9439a173fdacc0f3c70e92b33b3bf6fab4c30a915eae1041b15c6d0d55283c0d2720bd640a1bc2abb5d65a6be540ba23a69290ab0ed48f397295c9b5be4d9bbefe957247f2f4f8a660fae9d8f7ef3179a4c4b9ef3f31e1f8290c8351279db0f328afd8d30ed3db130266e6f20f8c09bcb400a4599eb9f087bcf18731019e2fb558c0dfed274f0ab85f2d47ad0d85ccda359c8044a259c609c1f5273fceb9702452b305bf5308b075c7ce992a900e65b33a900b29e5422235db4fa1e6cb972fd95afbfd36bc40cdd9e2c9f66433007796471d80c96479d4c444cb1dc5941aa81012e55f26a2f8c2074f2555ea48d82a79eb0edd2557c915e2ac4c9c7e1924249b8b6b0d5ae39568f0fe37400fc79c7ce36dc09f1f9bf756a967e5b0747a74f2ca835f85d5561e3e0feb20ac62e6b6d27e000932a44aa56abd1699b0eab5565ba7d08cd529f4c1cfd4ea21670473f2b94638a5f768621d8455dc5cecb7b593d13aa28e497fe7a4bf83d20dd1d0d0c8e65037f4a4e6a548e335e024f2d6ccf47927d4e93b3deae4de378d682893e77918750abd944b9aaa07cdd77c4df8b37a9a508502124f9fe99abe13e7993e8b0227120d386b3a1c8cacebfe34d473604fffa1ee92d394fcb55a813ff3bfa6260caa51cafd7f64f5e05c9a49465ae887e8af097b488888260adb6848f531a85eb5c14bb18d88723fcd10c681f452a4098dacfec82abcb7365a418a20acc05fe2463c03fe830006a9be718015905fb2043678993d986f06fc8b7489a8d0148153e113d506e22a544d9898810648117cf08d80a2ecbfb4fe4bd42e28b376f9c5b36ef5e3af602348110720c3015e649840802676f05839a1003720a0844e03ce236781c2019e246007172920a00b5201051864e9513f8489a38014d0f0578eb716402b55c0e90454963983d5dd2130c05ba82c9cfe16268f0720482e72ff046d647c641a063e2c6ff7795b1440c39336f84e9e1ada37c91d1ababcb14f796c968f45f958a4a27c96dc99b93377c3a7fa58de505ad3a6053e58a63739a6fad6aeee97b53552bbe49c54a95d30797e6fb9e5f9bdd4af16e753d93f3393e4d1264fb73f1ffb6b9e7ed4bf3e6c782538fa0dcb1bb9428b29dab429cd8c80662d0989d6a812b5e5f9d488d296fc956adacd5f53c8a6e4b15ef29714e79c484379c232bd71377852ee80334fc9f3c1b29c7466ce7e79327f9f76d1ecdfc361b21f4d99b453638e7e537624997e2d9bd5a0b51eaa50a012287b8f3f0fff1c9d1a0c0693c10683890e83c1320542822c607994852877418c38cb2c4bb23cca129425162f58b6e48921e075ae8f4319086c5875bf23b94e58fd29547f481195ad2f9056e4a70ad59fb1b9a4fe1c9a4cb8e44ad43688855355489066d5ff7c737d9f1f3d3c867891fa17e354eaff76b9efc2ebe3de50cef7ea7faeb83e4ee14fc972c5a95a8778abd6fffaacfa3885e54d10d7751754f5e0fe3ef737c4de92deea2e94203769dd9f119e0588dc3c6b364b5076765f0a9d4bb360ace0512acd703cd102491153e4808548946250e9000f20f0a2848c1c66c8ddb00c3262a591d52fa771e198c386a34dd3669a2673bbb7c9a38e51870632273ee5c74496472028ca348f564624b3e2e4f4a3c75bf375bcf5c38d949290e4c987dbdc143acd5bed83e5ad938ff7d67caf03afb7ac4ceef8921502b44d264ebfe76e65fdb26189a0f42b88dafa6d51bb64bf82b0ec480929b9dfd22c9576c9a3222fb9df22b50b26f75b2bed9247342eb9dfd6da75a55df28828c9a7f4130a34fb276f8fee4d40627d53f863fa2e9ca71edd77a1f496db46af9d7c72bc3553de9aa0aa47f70f249a40558ffba637d5bf0f247a169c4bb9820dcb2dcb159c4479828e72a45c4159cb13bc4ef397454a61eb342b7b5ba3e546aa25f55b196a0a7e2b7382034a1c59e9020b2c8ac47e2ae42f201da8f0e206316a10a38725b1df6fbe34fa6d8516fda684472bcbfd46b47e8be42fa029b12199bf80c47e8ec867fe5a6dc0034b6446fe92b4fe4b7491ae91bfa4387465fe92a2df966435b74a347ff110519b89fd1cd2cd93fc2545a55beebeb1dc44b9877273b5256bb34e9a25069eef219637f2472bbb351b583c6933d6d94eabe56e67f2be130a06c3623a6aab61434603b9056be26830c7504a59997fc33b24babb37b0512fec9a89a8eb99cd669355b92344decc20341b8d2693a5601c0c06d3c101a40362b3dd1b1e9b88c8bbbb9b25fdd599bc1e2ff4da853e73a3d9ec6ec163134d9f4ee444cec3964aaaa9a8d3d315d46760bcc0239dd1199dd1199dd1246aa34af4b68a817556c0b4286d61755133d154ac5c317dcc5f3fba75f3974eb7e6df96946e36259acf28915c0aa2b1d111a1d453439d6a40f485887ab169516ad748cfd8d2ae91a291fba90ce8177777f73279fce97ff767a02177b8efa732903bf7fbe917b9730079334579339f03b3bc996fc11e03b0401d1226cefcee378801a44e7170e93c546da0039f54044be47e378235d18aa8eb8108f69447966e2dbd257b3630d8e4f126dc89189ce6b359e33327f0d84a4a4a4aae14f32197b907a0113c5af0d192e44b0ef3d167b1201f74400308d3a7077729290bd1cc673ef319954ec4a22df36efacc43205fa6efd1a74c9ebea171e8261d9337a6b0611d0c0458123cfaece65cdad54433244ae55c9f75371c757288b23f0d87260fc82aea170944fecaf1a6ffe5312cd2acf915c600203cb94413a6c9e495a3bd5494544e8e1cd99a9386f4d59c1972524ee54efdfe54d7138764c704a80e06e3d5876a0e019ac02d00b07252a9534a89540edd406803ead3ac1e9d2504d99a2f803c77f234410e0c183935eae5dcc701b28b9c9d30f5c89b0e73627246808bb46bbc3f13e6536bfdb75d3a4848c5be087aabe57c6a7662c17913cf322b1d8201f9b27566993c052821371724c81b1be6a83972b0008ff2966308bddd6eb7cb5ddb90e79c56b814063c4ea2a2941526886a52ade653c321defa54d705bbcd66f39e2963ded8091b95f4a7cde750104f6c936736e1c41793266ffa81d099147366bb529b524a2985483967bfb8fab2359fcab5c28140fcd542ed993d5d80b832abd55a12109387fa78cb5bf3e7bd184b2db21f3ee43dc85d41bbaeb4abdac903e6541edd9a4f02951e13a787aeb47121106fd130f0d843fedc639c4afdb386baf1f4d2ad4447b3e63d2aaae5b187fa0826a10bcdd220084fda58a72e55d02ea7406c361b9d5b60496c983c138a29c584c1449237cd85d3c8e80c3c6133bc68672cb7b7e67b956627b70205011ea791ed3679b4b4cb68ba3bed89338d664ea764b301a9406c365b14262b9168b41e3a856034182d07c79ef23eb13053b867161bf0386f997e29376219e518e9183537ab9c380dbb81044b162b64fd3ecee41a13673ea533fdea6a331d4eb4a328441c45811d250125fb58c38907a80cd96b4c1e99e7af200a28343449838c5b0a441d0ec000031931fcd0c50c558937db69b5dced4cb2a73b274e6e3db86cd992e728693d4ada926c9af7059e1b7dff93675513ce7cdfecfb568ba042b7e65fc9a265cb893363fc9a88166ad7d845e4c69808b9e3dfdf45f437752c59b922e4d4bba224b9e3947eff873071a85d41a220f7531f79d3ff5e8facbb67f8e4821898178c5f6ecfd1ac96bca9f1d9399b21902fcefe38a7e4fe6ff28830022ac75f5cf8f6634e27a0f243f1922669a9ee96bc9939dd3a48b451d24c3db3c1c293362395f37ba6dbd9d5e03f8e90e58b2079dccbe7c89df938e4ab936477215ff7b91f7b05b9dfbd4c9e962271fadbd3c8fdf3862d43e596b9003bac5d49de92adf9b289dbd56a266fc8d7d3f5481a8d46051e1de90a972d5ab220219dde3badf0ffdd1378f4983369268a1c4af77bcc63a84e76a1c36e98b3824ce1eef6578eb7609a9632ea8cbc8d661bd5da9501c32d048335ac615c6ecd6a28b7dbbcc5cc248c53b956abd5fa67129306a565edcaa1d590c9a66cca9634ab7b82f4e79c4b660b66ccc6106f350b2d72612779ab6d9d74eba45b77f79cd3053905a644ed1aa58dc2eea5302017a4d4bd16671698a8c6a43045a903a091a814cc588b9a142254230200000002d315002028100c0605c3d13c8da264d01d14001078884e584c1a0984b1288a612004419441c610430801c418639021aa9905a51a7fe85a1a777d885192c87d40aff48c6e0fa5f7525ae33f22ad57e2a6f4e02e8d5377430a6840d44c56d7cf023609b4b447e191ab24e6ea31a6943af791aed44f623f94d0293dace141412742f6770dfbe247c1d780bf58ce72a65429792ecc405794987e6fba4a9c47593fdc70067caf59d37e0533100003c0338e9205b4f9637570a3e6b7f6bb97728729e82e340ec52c225559d181e4839cd0c692430b92ceb725d53696b5ecaa2be5e5b1efa37f2ef04433d35d69ce6b3b9f41cee6a803a03af45383da9119d541d4c578cc7eb11193c9aa29a1e03a2f610b1b524ae2d7cdf66c280026f2fca0ab6fb38f2e53170e9c5f6e18ec6de6ca06a716809f4039ade48963d57b8152d6cf34889b3bfa34cd747108b28fac8d9be245b581a68b30faffbe9c242cf5e280251220bcff0c0a25e890dbaed9fcd716d530058f311375a33fee5a9e4f828fb8ae3460241c58cae6db47a9129cd681876c5d8cc570d689ffbcf486274054d8954afa2251745dfd498dced8f872a9597630951bb8cfd65dd29edd95ee6ae562741bde8967671b67b21dcbcce1a40b725533b93b4102f7f5ea144dc7b901d0c7888af9eb6f8fd524e7dee7fe2dc2e12e2d105da75438bf0c77b1cfb4b5d1fe726d01e686f17083b17d79751ec3f05ee7f144fb45f5d97f3568a0fd4abdce800ec8ec17a345cceb544bb3349342098c271d2362c3eea3f92d3c04027079453842eda52963873408ac74c4b76eeda3723c10b8a53c32c222d63b8a9a331966ff3266542e38f664b1c4895fb4f849c826d1a6f882bf8ac16041a4f60e62d2d17b72a20d9822d35f6d4a2381f6153a2f71f386128488047ceb877822428b129248fdff7336f40103206ccc2f01a0a1d33cf243aa070c7a8e2bad50de9257a6e994c52531688b1b6f92d7bdae03444409ed8cfe7a8799c6dfaef975b71884d83b7686339cb52eab4a6ff711a42a65a30b141b7deb90ad98d24e861d839323c568940e7b5e675692f69067c8e5a69af2306f808ee25a4094e2ab5899a787c33256f978ac4024f04c6b262daf4d3b513a8ca80a432b50a5533f1a22ba62e7803d6eba8847dc0ab13b598573a6aa191c184915cc605bf1fad864e4420af4cc9b18f41a057eed4e4bff0dec7bca91e17b7d4ff02bf458c2680a7ec93113cba8399222db0e858b25ae9e622d20fc7a009688cb364e1cc792fad0f3377246ccab6c7303ee26de9623f73c581a36a4f39b25d55641c630f53e1a0a41383768a153ba7d2101186dc668f9418a5a22a62a8160b92be1e53d44c8a080a6930975f1393b91bbb3d8ff2e7a141fe95ebe0a00e1c4d7475898efcd600622321ab0c20dae70c0e1ecb4270b71d3f9f03c8bd1d9c954a0d9ff6f82d7b7be50e874af8a46a95b8b6b95d40ce1aa5307cae6e5c5d4947e83d7c719e8f4de31c1485cc8c07ac0d8c69f67b8bf383b380988b0bb8d203f3021a2c2b479a4042297099abcfb232328902f00476c67740b1d4d11ad894217bfc1e9a079c7ba7ceae95b0c2bb4818928db85405476ad25912b019ee516d802fe7596ce15d296a2674538561f350027626094d0b5df2bcd6a97257eb3c4503f2c19606250f4207cadf90dcdae3a77ea33ca26c467df28cc7dc14c3b1926acfa17581bbc359b79721f4ed8e4e25e3cf6563a41313d250420a9a031ba38a2629430aace99912374a6bb729060742803a0406757670144802535787a46559a4423898c92b45ab29a24c4d64be5b0e637f1c9988f32281949c49f3fc539195c882512e510cd8ab25bf93ceed047fe4fc2eb1ef28a1a7271953925955d4d539481661dc88d38020b80bacc8f5e526b4ff81b279e5b529c946a77f5b3b71d415f7910e6203734d4a2ff4a2188e49c12619c8f5a88736af35c47f33f8fd0c823426ea3278da9268f85d9c54212270a0ca20af9e806887a34c5d16707c5d55fa5281489ab79eb6029f59e1db07f3e867af7cecaf311cea042937d75179b9881fbf2cdbada23ea38530fec219633515c725c341c22e85da09e8953f81ae70f4e2008f98d5ed6779b041829d06b5560cf04692a92cf7e14fa2187fcfc532bd2e396daf3a1e795bca44362ba4e3c228a46f4305caf6f84cb4f2e35477356d8f3732a2dc98e144c4a21724c596a7cfbd694dd168202dd4b261aef7839aa2a93967a8a766ecc2ec25d9ff9c54c1d4738f5cf23c9f832d3dcbc694862c8cee7dfee798edcc3b44be743a8ab4370d05ee6e18e2ea31c0a552f1982e0d9b73f5f717c72c823997db10598d0633682088d64b44d135e1a285e736f4a22f007f6b11df078d06ba34fd4433d823a8c5df47d012930149889a8994c4479901b7b537a479bddbda0bc50e651b43fea1e764798f83d11a6b4d894d917ca7ce14cf62af0261b6e6d24ccc95e859e3199b8e57cc19be3e9da92e6a403ff143eb9e20ea6250a2c06a8accc2df1cdeaa8a9ae7a6ad4ab4e8d51b754578d55cb51d4f146720fc5bd0efdbd181e46cd40e827fa0b6beb3762b7fd80ab85da06530d067f4eeceb976d9448702a81a200e28c307682a672101a96471a08f1b234833a00fae7cfd9708432ca11092422bc2c7c84b50d3d52e970d07fb6240dafe1ac11c26a2e8e7223ef1a0f8842bcdb7fd6b324fb6079dd226f5fef30b614400afc5f9fcf91335dc48b8c7a7f00ce006af901b039a7e107b01fd67a0cb98ff21e8bb1d2849e4a20044d685ff085f31f370f54cc9f414249344441e66ef1516305f2408a5e15102542c44df76a203ffd1d6aeee24712aaa43a5cdf960505d6f31ed52a6591b77251f8117d89c211dab7ac10d6fc76ba2e67a33412fadb79a9c407622723b09ba9189878ae97de91a2fa26ac149fd0aec0bfb8d8796a446481dd6f7a8056b87b23c3d3d97b1983fd07f356848cfeb4dfe59318fd02ba80be24cd2d5701248eb6f3a82a4e9c4a4f3a65e02ddfb3b255c8ffee125e55b3fbce508a95d5fc3abe42fda6bc0772b71a5031b27ade7aafe628c0ce7e393ece5c785626b35c2b4efc692c276684f36330dcf3dc6a25fb8e63122f7c45f53a8ae28cb3b236b5186c2115e194eb30a906913e3d7488d6383acd4bd3c6e025e92123d0bd47a4edef48561d31f20995beb5aa1f7463ed983e9191f7ae5750d4612d7802412f5de84a4a6472027d5912570f26435185b3014670f6d051c144cb5e48398bf089c56e5fb6c9183c5c2a7e67af3f7e97ce1ec66f500471bebbcb8ca10974ab0298955e9dbc0209fab23ab322a9818af32cd718d629f622a3e260d32313e9640b6582dfa66e50a5c6f6622bd690710f568373c6d72b0bc76f7b860034b4af809856be96e5c773b7b4ba7708d5f8d557d784bc85893f6ad1b60a731718a47d3f96c39a493f591af339bb87f3316a340b0d4311be41445f6f33e862e5a980098ff7cfc1750610459854971c460e8f22280ff4957ae740f659afb49dc666869bd6e0fab40e05b540d2150b18ddb627ca5d3390abf4a350cf09915bb9d5d1fef83ea2d2dc3f2ef341143dc430fd611615aa135d3ac688a29145eece13ed36b4001b17dea4a69badcb013a318f4849f375e56ec9c133c8ac6327e20792ebed507cfe12aab9d1719eef2fd05a135456821508a65e218067cbf7cb0102b4ef8745631676cdc19c08699f1be33416fb586b79c9a214225f967803cf33d9708d72d9f95811c96e60158b1e0f4428ca46b9262e77b6a36fc3b49189b4f10d87bd822ebe6eabc17dfa4d5f6096d104b553a2aa4d3a456cd6b762c7977149113e1da06d4969aed25cf439067d6ec64d6fd4e932e44e4db7f3a17fde3f68b6a271285aa3b015baedcc4768dc78dcac760ef429f56f68e8fd46c62b9f796bb6cbf87a62e188b0e833b060b74f96c1d9dc2ec0eb3e0b8a0f093dfe2f51526b94bb1336489a151a76063c77a050cf054b588b88cc25d6fe44ab18f652508e84f112c9f0cb485c9e7374f0040a6029dc528e2ef4f85c52c64dddfc8d8a23bf4293aa146166766f82a1390774c1c1fe99f1955fe0f70d40bf7685159594535e002344b1a7e3beb82bdb9c1b8efe854a337cb149f837288debb53e4c3ea4bab2e76b5dee5dba6a12b475139f11bb7c163868d2340277077ed765925593fc528dae3592f363944857ee68fa1ea0d13a76ead0e65488bed264438ffd258c9a7993d64f2d79c78997832690050c8a00ab8b07e6b8c15301f930ecacda9ecb94fd64243e08484ae054990d51a7297db65933fe79640b2980c66c9e54a6166ca3f49afff92d4e8e178444d89533ccb0ab30eb47728407dfc0097039efcea54087e3e5a98184212f613acc4970110ceacd8810546e21cf004e0dbd519b4e2452b47dafa5b5ae974104e263cfca04cc11fa7acfd015c054190f45a055df99616fe644f8ef13c5f024cce9d82cc218fb5adaf659453ce9892be6ddee96d43fdbf9732414840a1fbee24fe422cb197cef1a466a41f4d6cdf326aa0df81e9daabfa057aa8cb4e4425270d90d36a7f7cd0e36e9d5507f63a4040d5ca471f239218e411316bcc48e1de584e5c4db6189e7106618b50f5b69ada78638b4535e1ae2a14e78424229b0379d2f46e77f23f8e2808bb169c085eaf72e31315a7e0fc2c26b0a182958e49c16ebca6fd44d3b23ef856d6ea91e1e30e5cdbb9285bfbffc4dad89d53e8a15dc56f8ce9875ef7896839a33edac765fddc33aa5fedf380bebaddbf04987b6e0a1c9c37f0d3273d3381a872dd1ce0713d61d8ece664ef00044ab9c0fffe7fa3a6d71ad5053b92d42c83e8c94312a302155430a59d2008f2c1a94c25dc60254a9dda262f52a635363d8c8ed0e74f73c33b600ee005ac022a4b90ac3fea275b6c2701e1920c4b4daa4f3843934db21ede280c6f2d9c8274f3ac5a7abc3f80862a0080315c09948122df49f41c63ba88228db5c6202507b99b222104c097877ced0260e87b8b4ca912889181931eb014359b74aebb0e7a2c5a2d722977b29227c14699cfc5b9512aea18408e78f341ca83e1d88ee779c9fac7153c8a674a5824c263585b27ba960dfaeabdc100468b497176a25344e231e58617a7ab5d894e65275f9bc9c70b4e5beeb8b0e61014e3cc139e737159fa6ebff2bd35bcb83ba07d9262565620903d8de499c0c23ae198a95420c486d93e8d7c09e8f824f9774322ac17a312e16cd51eade733c36585ebdad4d0c96aaab1d7c0b51566cf83abd526aa275438d1a7819fc4925700788ecc9238b5c576b9e558924c69906cb273d793d9de3afda06141f9c502f1ba589fe310a3a10beb7271fc1b3e630b4a093c7c810242177580e6672b354d0eb0955489485977a31788fe53958859206532fd29f1d2e3a1c10c907e86601530ef84aaf4089769a5809809a7f4f527df9899a73b68fe9c62cba007b30346198f7f7d232a6b18cbc1746b2d18352f5d301d120bb0298cb3e6323669f9ba5dddc5c625826c045ac08c64d6a476c69b5f8d05c6b2720cc08c8fd259e81f040cbb603c70331492d8fe4480a35a0da40ced2c040c6c5acff020ba3fd31e30c970662538195af035bf7163e23e3696d43b9e09f6ad9faae370b99e69b9f0c3788b733b8937685560ab455461c24f4c58130726dd5d302a4349de7bb5c429a25a9015ba8b5e49a0809216ebe73f027a66b5c3b4f3ce441a72453db45f38ad61d6fd2d1badb4fd2146b53a8807b1dce213be619a1c7421809919c74d8723b4b38042622a80e57ec3d365b63247a3ee798c2c978645c5e41c67f31edbbf27624774d4289df7618d18198cec22da3863cc45b689159e4cce1f8a445002527f7462da2d3453baac6f1da37d5e36cda3aeafdac7cc37a74c32e1ffaf0cac765768c4564b27c0af6df29d0ac1e1c375c99601847ee4bbd3ba22b9041cbb0f4b93179207908af3f6d0be0b16422f96bbc4e4a1015307524bec2db1da1b935bc3b03c718057c9adca46b1e68b3d76cb80a70bedb10fd51846b103a2e96410fe9c060e45d8ab202647cd71a1294afb3f618509399a99db3336646c2b51eba6ac1c14149b50f1667e7d44b082821ef5a57243015235c6bcc89adc733b1cc5a77da34b4216575edf59438626046825bd67acec89c898eae3763b3d6736cc9dc9ce5b7ce9b934f397de2c9a7cba9bd131ae15327b47ffac615e06f25a881f869f602b10a4495d2d61bd23f53d1fba24eae8080ad4e125884a0606be1eeee215dab2de727713ad7a0e7e4886e595cdb39cd2148e18a4580655304b908f22756240bb4fb1bdbdebe8531cf1d8233167448685456f962854e3a165a0321f0e73fdb166433de4e1c159d37355f743b318a42eda84769ef0d4bc199add74dd2821cc221d0290a40d8c146eac62e7082a464b50d8b85cd92903d026ed08bd1417b6b7966cb3de824b8071f7ae6de560091768e1720a0210faabaa4afb9dd956e6c35f20e123a764936b0d224981dd69fc1198a380f8fa824a7e1f571e052cd724ca784993e5cca1493fc119edc26c70f4dc8ff11e0da2e1b3843809689af4848ca93904a5011803c7aaf4b9b55784ce5767ea2124c95ad8013b33d39efeabf9fd2301ebab776732ba25a71ed053927c9da620b612968db1bb8f47e93738a14c9e59993169b53d686e4364a6e8cef83bda916a7741e83aa62cd3ab517caac605471ff48738a49f6f94b1741637b78e8635aefd47ec8472190bcc7d1bfb55534315b6ce7be88e82a9f157c46fb21fd6b2b5ffe326de769b9ce087860f099e8d82ae4c5613b0ed5b4fe3adfa00239d4ee2452a2dfc9d3b49f3cc9c58963bdf0b4473872b86d071db117ea4eaa51d7748e1807eb2e0dcc104b417d9dadc81853b008ed29743f37e6f714e2b62599f917ab82d0af19b51522921a1627ef52cf1175b285aa3fff2adc9a581e2277be30b9704a7fa330bef5e4016709673efccbf87ed409a0a05e677bbff156c3bcdc382f06c0f2c2458ab27531edc3932ee822c352bf892510917ed5d6d22c254beae15e732c97c05bd65b84d1c5ca96d0e0028eafdf03e24bc4d195478c6165f6a9419ed71880532755edbe2a035c4d862fab8248a6ffef4f0c2c6274d63c131f920d22d112f12937bc224b3daa134996133a8aa8be7202da02263c38c0a9bad0024086905730adb0ec96e93b445346c46c511213969690e35dbb67ca581d5d91e30458fddf1872eeb72c2a7fa999cee0fd55d36d1a99b099415da011a642b5f57e8f364fc203797eda7498644165f7495e915d49e6ff3ce23583ee3bd02259ef1be8fffdb7f9244832a094af9e11780e123ce539f6e254c8e1d020234c54e533171deb53a691145253ee7a0d18f66b4d5b453ac0b54713cddca0f0ff529f192f15ea682af35d87a731cbb0ef70e1ee76bf206626393d7035d1d433c23513b953db9a1511c974d02c33db61300668ee76bd0d36f8695d696e20301aefd4772e3981d4817547c79fd712c2ecfcfd396164deb8352c650d2498a010a8ea08f6c6135882296d9b03975357271504cb18765b49ea117f80130c9baa3e650c375077cb0d12a474660c45c51826cba9311cb99caf5fc2a05680a196a4732faddfd3783c85abdab17210ae0d34c2c1caed82a5ec1a79d49881cf96859b2544383cc1ab4fd466c84a1a13f575ca668afa8dc0846971e41941dc1eb948f90d05c654e8e8dc3fdae7e4dd9bbed284a766f8253dc34719af1f2f90a35aaaad388072efa229d17528399d73d42675ceddf824d69e1a34303e79cfe1f03d2a1859e8f7e9ab77833e2452a0a3a4c93183f4283d4b43d6ba849d3ebf94ce255322ef2982ef73530a4eaf5035c0ba59524b96497a7f8fb0b32e297208580b7db87e038f4aa4b569189660b2e601378913e0226a221559e36bdb2125f60cb0d116bea261a8c447272decfe028111574ec5d64feeb04247d9c394c9582ed4e6f88e3c3bfc17ec7021cde50428f9a01fa0f4c312efd82c3e4a41c120bc0dfb67d083a1c74dacfa01e1e43e10d90a212159bc02c4b6da90a94168aed2788e6ba8fc15ed0209ac870d708056c692a9c01e665faa8b51b582cb40f815dcc918a8cb7c5a405eebd67cda7e17544580d31c574307d20d1bb0b37d4a86b7eb8fd6829f50bca0757f0cf74d9f0d0a0b7b0694452cc4e5cc119fa2e6ecfafb86d01532244da8c295d0643fe760c03f232df7579520900a85285ab9c240333ab77a3cc0cc62bc318b5db17ec798522dcb16f648d73a75872b80f63010c4ee4c569b2a216efec85f44c0bcdca9d441e7823b95163c86bb56ed284636e9e8b9da466904052836758dfc2bda2765b5fdb801c835771fe0912be7bc9ced208d64115a0df0dd5fa93369daafabca66782094f88a5707fff4b1d06d7a57dd63600aa889beb3ce10c1ccc5640fd136d00f83d995ecf7af47751f16d9e158cf7dbbbbca212a9fd09b0193b1eff6a48f99e348a53eb628bcd10abd3490e17123e063065cea31885e089742b98b383101a64ed0c37558153dec32ee1d427b1c2e47007e8bfbe89640cc69c52fc51d6f1c61f118122d0bdef2d12a77d7e0d9b15fa13c24deb7b33f8da05bea7d615ee0fd359a6e65cd8b9971d56c00c910ef7f438fc6d03a2dfaaeaa92bedd92dbeabc300490930aa71503f3b0790b81a9a57f5fcd9753b74ce5d92cd57674a3ed9c709eba603fa3ec1c048df395dfb6860d8f9d98a6887b88a892d25772537edfd42b2bba366b3c97eccd65ab47a23b1bfe542555342b4a87084ea8d330db46b8c24f28dc8693a1dfc37c9b54a0c6d399fb63e2ea6edd74d3474a1f2bb8606b612d8f3b7d35d09c7996a1a9e26260cc3aa5cb0b8f5ff3f50040fa356567d14947cf19cd50a4ca873cb6d1b729d3701759a969480a9bf282cb26a094b395c13d54f3b6cb7b47bda177c6d7bfdba32f8aa0504d4d232a27e70d8261bd3da39eaa9b298d2b1b1a427c9906e879633f15d7530aef8f04b227a5308e04b416cd286053c2ccb735c3001755be6dc33e154597d58850a52eed1564162269adfd1e0b916311305085e9082ea9a428507b046cb4c757f6a94cfa5c17ff45b30420f43c983e15631cf41663b7da30eb443ad542eec294a8b96a8dd8d3722b9954e46a9973d664027ad50aabf2ab1d2629fe09cb5f7b4377844dde0b9c3345517c0909290338f155a04f1ff27560133ac5f4daa3e6b1ba9fbc7e5c8932bdec4014b97d1a31797065fb2dd45908c845556c073f35ef139ed37d1166a25118b2051eab7391bef3f7a605341cb0d4ba6574bf41ef06b4f96d24a32b6e1a5c69755612d7add4c7d3bda06c6a5a04e7695f6b48d6f170c6991317d7c6a84095bad862f059552349eb2276b6313b67ee1e55a9ec06304cc1744f3f8107a8b573e9a4587ecee1ba614a88f4d2b12b7cc360635bdd43e5abacfe55bc9edb794fe916af9bdb7909d6cfcc716d5b119f24bd30376be60fc36950fb147c022b557ccc649791c97a4869de6c8b926703ff70a1f3e70e4c4af229c7a7c6ad4dee04ad894e2d7123ef8f7efcef09ba35d9afce4f1065b545b88cc7684d031d1443be10ae574d32dacd060abdfaa18c17e35f16dc3b8a884aabf196717cd62feee856fd34c685b439caa0b9c5557a02317ece8ad7950dbe778143c6dd1597ada80a6e2ec1125587384d671793f13ae44087414e08e79bff7c8bc218ecca1bc15d724e75f2899263818b5b70e532629e60c86f02ab02f2ca47cc2e46b38d66fcd2f9e5d24aa5d69736efef133c766a3f411e4b296c6b314c716198d94c14bc5c1002a227c7325ab4ecf794cb72c0033bfae3d4162a30dc851c5fa0442eb12b893a8fff6c70e34b773749171bef1e5863bb2538ede18e65b468dd43aaf9507609722fb5823e01871b4a9e2f51bd16d3fcd8647ab7530f46c40341f8b2c9c0ef711ced0e53aa7d516edcf99d4d4e9549152d6801c310d94f6d5cd41111a7e924df3353d00ad63a306c78e0c63c8b567c314324b76723494eba6572a2360212e5a36dadcbe5e9c06eb2f361439dbfc92a42b3c0acaad2ee24326d2a1b38618d9a697cf4dfb8795388d224ec8755250ccdd130ac0b398cfa02ee1313d9184622a0218ae2a0966c696a19041c8cc2630f8506b96829612c5140ac4dbd9c0d134160a29109b211d5554ae678761053f2078f62c82f4383d3847df0e8ee8a8ea8f26baf898ec65014f39297f7957b3e66f294c5b5425e2e2125fcccb6ac6cb4cad6d36498bd5a1708980cea745658a3b9300e43144402bb634544084646e307b950090156cb0f7763188bc139d2d1923008a63eee4c02d2e056afd395886a7377c6360b67234abfd83b8740ff1abc5f1991fa391e6ef45a9ca5c2edca3dd46235b32ac2167b19dec28d3e7dbe88303530acdaf12abee902ecaf47111ec089678ae1f2806990efb9c7c8606e4db8581564cf36494490397b2eb03991e47bbc7b5b440748f39965aadfa41faefa3c44fa58e33174bf3f44688be3bad4aed799f7e69e924b879695758fd127ad932a3fde3996b3c3c2cfab222ad38d2730d9b4b9c254ca5d53d1adf59bcc3243c66f99639ff3ee652cddc560af1407312adbead67c62e0f6ca55b15435c5c7825faa04d053b4efc607d558f4ff10534c5b6416f1f2e73deccd776593620fec82140483cd6f018bf2b2343a88376cf2d3ec577c8d2359248dd9a0072f759b7841022827f7d77f095efbafe460efab7260ae0783b31f78ad8faea01a7701f5b22abb11449dd1dd2ed04c6b4d9264f8377ca01399cafde425ed61a9d146d49281abbc23faa9e22e369e91e80ed6cb39af21c0136e94fcf5e7d60fdc9a4b13230ab241c92940490564a489b4ace0dad7c2abdeff77afcd08c0edeae346bcc7a210297634529deafff3e277c6ada8645fc877ad5d5ee8c4289fae4e6dc140748cd3c6e5c40ade81295f96b3d772be97fc3e14922d40df41728ee790bc21ebdbff287654d0536a0fa3b7b0a85d17c8e081c7b2c2dade2967e9185436b7536afe599ff2519ddaa4e75aea28b87f4a91db876285810970e1848b716d86796e9ea165307ba79c78f53cb59667ab39f375a2a05c35b031ad9213264dfb863c0ffc1af33f671ece620cd63203bedb7cc0735843e1223a668717a94d746fc75d36ce832fded3c45f87c282f2651c7e8a97b283e3d86dcbb1c0333a4dd995f16d04bf7b634c802ee809447592642196554a5eb01ed90f10e676a081febeb48d15df4de58bd73b590dd7596f73c1dc9e8abe6734d080e8bfff847350d42fe1685198ac52e6f7db728d851c206124b4d54e3aa38e1808f8a08fe7972c09dd2568a5fb0623f3f29be19c4b761380e6bdc18e0126972b987cd8ee6726adf96929b0d87e629f29d5008b48d452a0e1b7fcc91313b6f3515fc05026a2f8e80f2ae7b2124e855ab876c6089b5230790754c21fd10c16c4c02ecc3ef2ae5240f3f4c642e3fa93538c613fb4f032b5b31f72c08f6327d7ca947e286d226ec0452c4fd3abc37bf1b9f3b464a117efb810e92977930cca4b393229323c8359313ad9520d7e4b42772a711b1735c4fbb9d2a53b023f332af7e6bcb052246dd996243c72522a5dcecad90a5c7ceb8fd7b7b862ecd3754e7489911e5d060ed1c1041b9090054a1bec826d9c237a53b09d674c5d0df1cc20c149a5d13e557a18b4d6b34ff1262a5a003e462b96c3470d0a6b7a9d8e2526741025275c08a2dff7931b41854f7abc7d62c54b55b80b8c505fb726b07cbf98fc6fa4e5aeebcb13f2bfcde1b862211ed9f890cf5235f56c07732d6764eb97f9031cb6239da9973781c8b2ceebdd701532a56aebcc3c24732444c0852181b7a80730ca87634ea43624e8db9c5ce8578a70b3031ecf8a12b461af74a3e14730986c9cf466b0e26ca2ef26fcd1d77cd04d5188131b34f001a10b5414098d6f5da503173e45b88d9a88760fc4c5f3bc8a44806c0387288524df0c32436060c3253124082cb42438c938819dfe243ed8269adb6b09802e5b679abd74d97c1fa93a6d097ad3bcb194692382488407179710eaf35e4c4435e615537e278656362509ede911ead16d8eec03cc0f8989ddef37919f0b997d7fb867615f12cc4e4c0838d54be9c9ffc527a330ea2526097d64c05fa322d71b8e15b76270f1b0b78a69fc8746a4a88a7c53f1cfa83e4105fe2db6e821ea2d3971e6d597086b32d5f56b8c26453b3a6f6d128618bad72a74e1295538c2f7f822d639d56c62abc2c6078635c14b24ed4c6434709857fc8b1bed722c28136712110aa2e0a2aa58e8c116a9ce9c2e565b408ba77b1648ec5d3127f0a01d6a3bdab5f1a0dd8396398760da8a45f33944c5671f2a4718a458feecdaaa35d358614c7c2ca4f0e50ecff10612b745de14ddacf810fddb20adb21db72f585b4e5ff3aafa33e36cc19bcbe08f865ae38d0d496fe58d8f26ab06f5a4facc87baafa00651f036e0dcf5114264f6ff03ba8f68378afff430c9586700683f4f44a239abeabec99b375feca9e41e97259acf66a6152a8e80eeffe7459b735fa67326f2bb733a5b346e139f60706fc942acc73ae063aec97ab4f2218311b035281bba0c46bedcaa8366d4fe0f8076d70e3c311fbf0e290151a3363b12624716cdd24ae8e69686185af807addfa15b016f107cb99b47497a530383081359e6bba05c87f475d1b23d3b582470097a311dbb6f9d9a2cb8d989460da2cda5d4b297115ea0d4e0054dab57da439fe0ea7e2684a6e66a5101ae9e12fd7db2bd733b7b19310387ca3033aa3ad911491f5d91a7c503dcbc5dab32188cec044b5b08f845232c1434bd394b3d9dbc6e11ad8549a904ac9b0a70ac063a883752a52c50900f33dbf95788c51c8505a6ec5a225976c61e90347c01689ac40deaa14c774868c2a4130daec226738fafa9739af3b8180e0e4aef67bc70183928e4b99d6043f8ca48b671f4f7a8f0425922368534a2127415e1d1466e6b2dee65cbd8b564f8159c78210ed983773130f396faba2c484fac3ba78b9fd3fa1b07978bef097a7d1e96dc09cfbb22d65b466bce93dff07599f8b527bf4afc64de5b4192561a7e51bb9e2a23ea78d703a3f1d795062e5e19b823c32bca965f91c4046d4fccc6f23f665fa3247078682630d410c9dacf7764cff0ff53534f8c75c6db52444df196932a73b77298a2b4d00a9dde5b43c142e3dde0ca9f1f38d0f2d9b368c86566d9ccafb4001dc179e4a87c34539b368b53ef91e7241d35b209218d6702e77a4f98cc4e42cad26e49dc89978ea2b6099b2aecfdd5f5028f9029ce66530d08fbbb19e6a975eca1cd6e34ab64a17c94aaa87b3d0d029d10065f0080fedfb86092857382dec205439a0907d3a7293cd1d649420a94a33c84c7540a649c9db3ea014ac2625538048a25bc59b4f358802a884ed2db3ca4741d85cc2780cfe189c88fb63355b755bfbd9ec127a7aa6976184dc440788be3281112421aa4777e516bd9ce4621f8d236feba3c0522efbc57ab0da82c0939d184bf08c4b25533f80d61935827794573dc687f6cdf9fd036e54be78ccaabeb262dd407e41435207828264489103fac7c2d4b35af1adaa1f09af9c601a08b0ca586eace8615aa7d103e3d0ad83e903615e8f6a118ca78dde8bcd4b39912a73432c5bc34e84290d4e4012279b43b65cb1655e2666f1110aa19f9a73156e18060c818048caf0262ac41f8ae5e38833b7c82425612ed50d1bed0b276c7397d07844079095feffb2e00c1e37c2d110b0a7b486bd88a990d64b079d2813ed05e049a0989b225241130270278abb4fc0e17c527e2670ce25c24e01bf4f408c532101ebd9a095a8c4e5173285a45cc6fce0105dc1bda4d93068268f899ba82d627b3fb714c584a1bb4aa214a721fa6a996495aa7e116bc2356537ae8f82a49081d0e9fd72c403136090d635efa1722c74e186aa71724cda9a8288f26fcb69209bd660d4e46fbda283abed223efabd1502064ea936b855255984e8ed4270d2b3a674eda3e2216c748f4cb11f7a68b682ef09e11d8a9a1fc7dfd6f9f634006d4a85f17799130f2d491b98d8e2ad601343e9e647e6038957d3ced3dfae744cf643a140f57104618e681355917d2610497b60734f98621f8f751c8c2ef063a36d56a587ffaac9e89070aa63637761791c2e0d28725c038caef0823e16eb8a2497fa442c546cd9af35226008900df195605fac20caee2dbc69cbb173720689b80ed988fb41ca8935961121091e4faa45140eebb59ef9388c603938257b168a01aeb4fbe4a21a6bfcf158bb846021056fd00e3c222537c9117f310f57392c1e3dd4a14c14233e0a2c06f29eb1bf27d6631ccc22d7e8596ed0c26b1fd417f2872cf8c9812af82100de752f3f890bb4d8cbd831f32d7f65b09439efc5e2f540d7f2da10ac036499da69836c1eca97e3227285e1b05c9a15b07c6e8cbd0fac8d2f9f1bbbb358f8182aa33a9652e730af68c484205102efa062eb9835d6ae5bb130c8b1c134ffdb1099ff8834e9dd1b0fedd4a0c0e289a79617e6de14a7aeb8dfe8e9a6a822ce44cbaa37d71835faba54a92731d8c2d0d518b73e728fa73a9fb8c140f0e344329b0f478f317ac9f8453c09baff7bf42b02805a2b7ab8fe53365dd0af01e7568ae20e59851e147a6e4a864b8a8badc14a59cace2478ee140de1253f0c0f4df16cf1c08e9925b59b56021164be41cfb01413d6afa4060659ba997441909cbff186c9556165ddd82155168c8ba819e55dfaf380f15be214105ad52c67a908719f3861336a3cc3caefbcc854e24901ee7b4faa3540faedc2c86ca4151f87146ab498be96853798c57f27c66942386f295dced6cbd8ea485dd2729e6641e6d2f4b2934282ba5de47f529748b92e416390ced59c89eb6987e16a2801654f353b1ee82ad7632ddeb5e494fece8303945c5f0d9b5ee12aacdd0c7a048be0800b4ac98e523763e20f282274808229ab72ad8fcb4f40c8af6ead173885b6817b42703fd7448f680221ff6b126a1515f01203e650a16904229263ec059e09affbe4b290a66a98d37588ff7410455b634f7322b16eb036e2605c242519ce160ff22c2cf53206bd363ce6eb415c35f2b1959d205f54e5c23685d1d5607520709ed243a3728a7a31166d1fa01a98af13ccb30c3a0e632fbf99d1966de16a30fd02081490cf5e6fdba7553af8a505595abd8d3397fa922dc9fef76d1ecc18565ab5e21aa98dda63852a82b2a7244ee83b58f524544dc342fe09433c8c692b17fe2d55381f3e93bba37068d20925150a4deed14fad37152333749037174c33f66eb04e1be68342640dc062b2b8adefde467771a3a734391376c1e3cd7fcce4de5c6cdd967d2e78826deadbdcd89c39e75a0ab774c690fa1d295ad34fcd9c878a2da978c842e5c2a0a21b6ced3ffc162485a316a6cc4bff3020f205ba9edff3b107bbcda76ece2af7059d6b2dff5cb85d4aacc8c0a5306c95e508337666577a728b776222886b7093345485dc95254992af5fbd761422f5c4ea6f8ecffb6ec3fb6d5cd46cf1a37844482462e3ca644e682a2659d4401a76378b9937f51d5a2e90b0b4b06e23247fe2c194c628eac0927fd56afc221135808c6d7335c9c88324fb8d6f4900d0fc6454bd2de832239d8383786f41bd0e007d5448338daa17de4f616740dcf3cf9b6a24a01df4aecb23036a48ce99504e1302416b66c57c186f997678a2bad773b9dafb403bac5f07aab89ce15fe902bbaa459958c90c49f7fe40cc2484474ee33e479274648708723fb3a241b14f74ed65ee6e88da40d7b7f0cacfe6f58acddcc0de3634e46bd0933747ef050828d7e7243b9ad19334a0e6bb3520a0de3c3595064d06496e18222fd36b5c467ed20667a3f38774353af74dd60312f1f67af767b2fe3c0cfa5297a91f56a5053144ad67465a3cb226086cb7e895fb10cc1e6155efc464bce84772853a0a5c5cdfbe049059a8da964cc24a79c38cf48ab3c421d460e2e51731c8440df8af3a918a2bad977a7a300f39b19d370488c16ae217763864344e510a08ef9a2c25b7199f150b8e19a0a107d832cc1c1528074e3cf1726c34f07e14c6f83f4f82c7463a11a750b761ef2bee6f0ee52c8bdbb1860824258a3c7c637ac7596f09c6640797eab547f2217c7dea2968941d58bccecf6223c98f0b36d82d67e692a79b05e6d64f12a71b4c7d1a684558a27c9c9d40b8cbf094119f7464c7fc8b69e733139c4078bca119c2e9eed332d6eb46de8a145a4731b4a407bc2bbfe18425fdf8c21fa9d217e596d5e5010066b61899c618f23e9779e05fe19ecab7fd2c73d4110d611539ba248e8aef9de301bbe0caf6557f27ea30fde8855fc7ab8ed13526a6de140d5cb597f3d5776922bd5132c4256489eb7709eebbb1412b52afe789a4989f81bd8699130f4b0fc3db6913a700132c513b5c11449a644bb450e124912989bbf78047a103f4a82ea6899f48641602c17cae7bbb8192a64a34544e8da0418a291b9f1510f60167d8f9042018e397f54b7c898114cebdac6f269537c3f1e9241bbb98a09a4ffffd3ca88b54b835c8fb1ba6c9e3ff41056e562a9e814954c8a1237f2082288858f34d24a0b530c771914a3a61cf141af8cbb11f0c23c1f7f25f68644c0850ee158053e313e190820be961345b0dfbcccc0d1a7ed36ed9c6fa20b16d26df787e52406458ba108e6f2369d6d368dc61ace4ce495d9531eacdfc023e1d1cc2e8f0485d4da30d987452f81c2c206f619db78587c0dba1f1dec3c9b18f051633cfbd6507d93f8145431a0c8222a4826501f01986eea95bb1f93a75cf21199b8a0900723234394336dec341c66c2877ec6f43da9363a90ce0e798967ef2c90d75ba5c6b7557021e9d50937584a899d94368307a39909d7547e3218a36b9a405de97293efee288cbd0a0db1173038e448b08a8d19b9184bdfada2d8b1b2145254c30646bdbcf9f4a10946f433dd0e6f0054926f45a32b866439e12cc56bdd1a1bdf88cd41c7c34703528471b444808d694930bfa8cf5b2f46d6d0987c21c7df5b3a0ece3f4356aa29a89a2e192ee40cb50cee619fcd471911c89fa44972404d6b8867bc981934849e18c6e519786f680065de2126c083bba31dab32c763b94da4c05edae6a959d0e56d915207f6a3673ddfee84677658c7db2c8fdbbaec0353fd08d58347e900ee350e2d78532b5f0d0a86a8a14b788404a6244d011f3d5398f1f5e51977db66c6b04290e0870192ab2de02673d4ca7782f726e5302e783e87e0a182a408cf5d9f5d75e558d66c09c050978a17387e7208b010eef465ef72204861e8b4552fc9409354af0a630c5b9fc2534a588e9518bd95c138dfd69d43fc7c8b062c5eef4a0746aa1d3edb35d259654dfede1897437727eed45bc5f176d2ac89e5705eddbf89c731b05b756230a7ed4e5c1acd40cc595a1d345beaabd3b71675715721230f522a095ef9fd825c4375999277485eda6bd4facb9c4cf43caa4c35cd0754ff1721e545a70b54071e1c5acb0fffe58dbe14e2f393062e2f0b5369b26f65957628263977b78109e87fc304777e24bba8c435b4806f761b68ae471c8fd02caf6ea6b0c406c71ecb43f655bb8eccf0cb01b661dbe83c852410cfdbeacd137e1a269a8ac1439844e0306b5130780aacc1feff9a5e4f3ac110abaa28717e77377088c2b6458a2245a48b7b22bdc238a0bef478373e74ff786b820a456693c686ae26314547e3c250634be32fb8f2a941e070759b622843bc9d718ac29be2a5a7dac3a595d2acf5269dd27de1e87411d5e8dc451888a1668201d02d6fa7651d19759b7cebfd3dab6550212d03d5f1904532f751a63a9aca271f2258ff4396cc7b58d49bb7bef5ed77a1a093fc829515b21d8d947a969441558d01d0c13910d528570d96c6ddd6cc9b6d70638d37ef45e12f7de84e4fb02964b33f47b7145a6962135ac0c9d42bbb5fab0861051fdad00b9680d32f2fd1a1f046126f303909c9eb3af9166f200ff1efb148d3a95737531d46bc19079feae372fd5b2b47ddc1e14c405cbe74063a903ebc0c7e9822b983dae1a25f90fb8f345c94f7c220cbc2f9a5d3d4aa2978d3a87e5507aec85a43e9f24d4f42589e8eb51ce6fe5412f5a37749cbc1f57559086031dc8f86f1f21a6ee0f8fa9b40a9809ae1cda39fbe3ffe28782ef1fadf97f5b975fa05a0d31ab7708bcf58a772c06d324271817f6facedf3c5ba699c588c3a4746ceeb9b786edda946583e6459765c6d09f66b1f5eb12aaf42c069f4d113c15e630aab4c1cad43ce91b5ac26b465a26a0c248b40a5d31b9e4a327c2c515a47e7ca49f96f54a5494302559f96744c1665d5f90f8838e299b9e0fc4b66547aae701c9c5fc6074d2f2dbfda957ce8491503114b6c4f1da457218f2687aa51ea5913cf25a78e3045a7d7115c15d43da6f3b14c96076e838d3cc09acf23f182a8c050456f9b75cb1b835f8082bda43db89b4b57fc6c402743ad385c42bca46294234c75d98388aacf001ec40efd915ca1c4ecca197907bdc32b4a73e5f9c8e3410fc9616801cfa2b17a5fc409f4ee02956a4f4f0696099a13b7ecbae437efc5883767e8e10b590416b63088e5e9dfc4bda4869cd01fc42686602267d7cf59464458e9ab71b4d5f5e50eb8e002f9cf5dab98bf6a35972b6b5daa4fc24228acbe98a9fac70c8f68b85412471d4dc5ac728c28d23c4cc80bea7293f0b8485d0d0ff2ef0b1e9c93d1f11ac03b53cb16df76514d34294dbebba3a7c97ec84a20feb7cbb96c49fbe202a5fc6e9fae48ffa640ed90eb2b4b93a59d5a0dced588c43e019383601010432160e507a57935da803b983e3b1aafbb94e315c2b580e53d8a1c352814d8f2c782b83edcca68304de3434ef72317fbd630cd84958940a360d1c49ea991a7692347ba3519b7934a2f0935e63f7c4fc885c4a30c061ef516d9f0303d50b388f9548b549c3555719104d7590427a001406bdedec3df4d363d9a103fd058727478d352fc79b38fab8e586a8f7f6159fe852b706a1d0b443eb9e82123b40ed7685ff533b735fb1790ce709c6b7931e4a8c2156bc11579f072d05b02a2a66dfd86c7da48c7327a8d72ff8a3db08ce05d8c5a6f0ef0bed7f5a81582807ef0499397f71775289889d453b794101d0372627ea380b38b9c362608a6fdb7d6945705d50bddff5642e67a3e6839d110faf73b85ae2bd30d79175d68742070e36a3b5d336aabee196c423bdf9426a51d68f9e5f756c9c7c2c9e2824210be714ec7c43c0c73ce3176fbfccaa0cb67b20e4c05bdf2f0c2b83746d6a9092aeb2a11b236788006b1f72acd0f2d9f05876571359970ae78d1a52d1b4e1fef8f6dc01e8e9da3e89d9f7ade5bdffa5303fe89e5378dc2607b0100b26c53a38d5d016a01ba4b4e5615c37c3fab51dede4d6cfbda4a12d05cda8785cda7ca07939958e16f951482e498e15e8181c5147c80d284c302db90aa405e38ee530bb66fb919fbac9156766e905225f7264ff602ea5169366b01bd4a848d73d7eb4b7db4379f282977b43c4049b74dc94837a5b96b47b463966d5263faa32c5682811f5c422509ffe69b1e75fc5248d7b57ce53fe9854641542d7eafa8e5b1a9a029ed035a344a9d529ea256e57599d2743686a279644c69e58b3325886bef3e7ad56b0c0c05e48e7b15029b31c1cd270a26da1cdde07da89134ce24664cb081f252d40d7b81626fbab9c39ed7422141c6006df0697319634678dc347d96115b3a94cad0da82a10be433a6b034586072e96c7a8fc24def7292852a2171f414dfd47719ddd63e5f6f8339078e04f879c50620f42a0b1671abf62814b4e1ef5b3cb33294a8f370046e767dd07e70145295e3ad70728ebb4435b3ffe8004b54492d92b1124cfe418919a6dc0d81fb486477b2202d82754875b7743294c5fbf9b489797cabdbf57a950a39f7c7ed7de4b343b325f38f2d5a3334e1f5839788a05340a286d36ea4ca2ca00baea32405ac1953b7e1ca058e29c541d609d8c980294d89afeab8da5e12039e72b0d179fc231d5508d1e9fadf6f90b918fc471d0842e9cdd74bd80a09002de667950402eb3e227c26884337242d708bb798620ed604b4e31618a7db50cc82c3cc1a4222230b6b7c0c70caa8a08337239018051367747f7aeadac15a7fab89f87c0c58ab8993ab3f7e206f6de590bd6361519c6b0cb6ec2ba0e74d829128ddf92b8a2f5aa881b90325fabc7ab97f7e98408953d01062b6170249addf4303c5706b3bfb95db84048913472f5b2809bd593a1e9561214d93713bf4aa6dc3f20c89ce7ed87fd3a25ae423054fe4d49c5b4cab35730bd5e12ade6fccdcbd78a0c01399e6f066ee2b0c50e63c9cf08fded7e8172d38bea9c9b046c65967637893f43fb4cfd9b5d0522fc8b8a47c6de5c7ed1ff0e36e6dbe3aff0bb4fbe7261d4c47ec439ef53cb0e740759e5417cc43b4f323f2bf1cd4794438df5b2f9f2feaaafbe84567aaac06ea2905cc359a046bc6a7b22f79f941420415c500f97e0f684dcabba3b7410c81a3782c19dd4e61b4b899c7df868305f8e2bab9243e39a914a7c200c696b5f8283d5ff6f6c68072062c0572bc89df2f06dee3ec273fa83faef4c36fee39183d2087e107e80cdfc5b3ab5b65d4f523f241e5dcfa09a17224fe1cabe732c26233b129dab42a38283d0ffb95515e5af21067aa9447fc64644832d21780c6f0c8a7b72b49feb81a1b1e0937d16e194d1c15e6d666e47ac9356ac7fec6e9d801ab1c7b7ecf538d6f3bc0a67725f17f3ee1ce2c5d6b0ac88bf2c2e25a78a3a9b0727c7f6d5c435170dc669070938442c6f19e23669b5c5d4a35b2c6d854bd63484d5b7b32af988af0dacac2c5be7481ad066d2edce60025b0bb3b7e34fe64f9f5e2cef1b396775ba3d8791978dd156ee636338670cd4da1a4d6b896673967994c10ec495a95f8b5779478cc1ac4f7ebaa858b8ce0cddf7f2fc49890e48027c26cac72d534f11e48420ee75744ed61116a1701de447979bdab11bd58688e289d6fef1e853916b0f84d87751a112daa69a7a05d7fa33de0c8085d10e232c0290737481f71a9b44f3403cb0780699d834b67bd7b528503cd7f8181cb1b3419b5568692111ff817751fcc3b70392770e92357c96ae9320af172d32b22b409b85c0d804b6ba391cdede4df5233f0c205124aeb9b2850c1d8d4bb58cf9bcbb45c76cf098c457ae8370c92e6b9b6300cb9b58447b5797c05b8d311601b2955a7916db08bfc918830ee17c81267d1b695989e88a4ef8b9b5e8d5f958c16f88ae564179d24ce6cef6d22135f436c3707156f8e74e01c98e31c89816cf815f874dfbdc2b391a08c8997a45de01c6b0d3b569ace8e981e6edcb41955c74dcef6b15b394b1ed3c1f1cf7c93db2137f89292721680b28ebdcad8f1db9edff163af79d21a2831ec7abdc1b5c86813c372f74cd43c4b53074dc87f93ab900b27073b40820e3721ee687a74f74a1e5fa2527d2bdc2266cd6ffd0fb96e5cc887433817790a8b129a5f12ef1674b30c24be9ce65c227a80a025b52c00596ba90e782f29f93fac7196856d93fe776475e9fedf3d01e7fc90ac308d7ae098a1e80a85776c35c41926ea36a0a87903d8e21ad1f2306ac448e083d04d157cbe309adb2f0dbbd9e211f1ebe8a0087ec149a01a5fd779bceb90446c4121ec47ecaf5bc29ff8d10bfa3f55028004a684f33c47f83910301f5e48be41bdf0001d3c49297b25170bee87ea655fe822803cdede813c39f64e48aababdbf05b40d45e1ba4635b7d8c485a0e71f8017eab89e85206a6d2b0809a737c455a3bd92ac7a60122d002a1af08017a7eb6780a84951677f2aededbe9557012f56fe0dc6c9b8b4b8c10204bc18cbcccae62c6b8135c08bb3a0fd1f6d80e24077425ecd49a59284454536a2fa92efde940ae0c527a70f098017d2b52fec8d8a38df290fc1f57781a693e6abc982f5dbdd64ae9c12eb9a482cce2db906c8bd8a3736f45649cac797a9e1e2868a166972d8f0da868b354375df79b17f8372f3a09373b684861221b8f8e8bdd0639b50658b46119d7aafece447c84c97ae9d5b0f2f24d57e09c4a459614ad3f91d80326136127025c9b7080f47b858bc181a28a29c82b2ba01d39f73f74a86e47790ffb00f66fafe8a8b0faa005d28208ce4874bb4b101d30836dc69122f26c25531aa45b4c548638ed840dd5d936816a0862aa5cf413093706128057e30c8e7c2cede000a3fae50e3823a34b54485eb24293fea90420ad9c92784717282799ea46381ad8e84810450c34d6101497fa0dac3d7b72329ee32d9c056e10a122a180ac6db916c1960ff2105c273e3a3082b1066c2c50986f21edd5b5ba58b517f214d853ca49c02b2f1cc096fa83a48c8fb9cfcf07c2eee473f79267c2f70cafe81835f2aecc406227e2fbe4089df25f94c5f4d6921cfe34f71f47c0a31a69b5292fde877b5f85e13e8119adfe8e7713087af5d404c86a64576bde95fb53b96bd185630580c08c79efa8bc7522006f463a70c6a22e16af49c88d78b9d4a1dd449d531e233d2a5b91942ed231b62efb0162ad5aa021ea47cb1314bddff2d4331c2ce1ead174137cae72ab86aae8ee1262302fe5a48345d0bd5fa5e8b17a7be72ba204b771af5893e71409054bc81091dc8d9f3e7fd20a1f54f8920639155c6c691caee0f6bdd3b4d19ceaadee0fd79d339cef7887bec06af6927441200bf6edeeb92c359240794346a37338a31a7a505a166f2f13cf95506125233ef0ef8767e6f017a1c99ec95c95f158f85bdf2073da19c3a4f69377c722bab65f780dbd5aad7601dcf8c7c6316d0177e61a9999078414c8828c6e9516e5026a802b6a222f6958173073f0f489aeabb8a44d77bc047f85a33e1335eb99736c27fe85db100ad5b385ba658c0975eaf3c07c8d3a7856625e861978f715bfbd811356886860966cf907a8c040197242bddfffb0b718d8ed53c658f2f4a23b94b1ad97a4c35d3a7255dfb23345f5dfbfaff2ad315af19c3866059ae792a5249e59c1ce2e54ec0e264a9017f9f46caeec17a433baa928fe83e9e5e993032f5648fb4f172f07169d14b36accee1aa6b81318cf7b45a8bdc1f6acb325a0631bd1d9aa036956ae1ec8f8c46a4088d6a9f6da28bbe256c4bc1ab47de2d7e8409636f4b6070e53aa061deb8b64ff21015f005189028258523ddd0a0617004bfbcd5367a5253fcdfb3311ccac2b8cbbbe6c94a3b97df3758d6a87f5ca547eeb0a512af80646510a60ba4d1ce8bf54be942c4d41186687e80a0b328d405940357dc59abf0a5d637e5900dc34422e8267d9a0c48ce72ad0b540966b8bdf094cc34d8acd1e6d5ec773408b7c3a9ef2ab05b4f5585bcbaf975587700b40e92fbd29f4577ed453d713aa8257b6dccd9ff47a6c416624bd2f1b906b1c0b922e85a7e7cde69f59c3bca19b14e60778eb2da11aeb9d513542ab0e7124a440a9d1c55cea1016837bb28cc03d831131ae6425ac93785a5630fa5035451e7f532c6ed62ed423d28da085c14d02735f94dd08e41fdeb9da4d4c1a876ab8fc9e03c6bfc591994ec4a1caeba46b08a326a8ebae3c766a4829535c26306e337a2e4bf040de3f8b250a75f74d2c6e9892fc2b7264e8371a1a1b52c7192c8fc583bd8ab1b785ab44284c3602447509a98d8148a25397090a93c21800e5f94939cde72e2a626db38366b3372741ac45d6b1f9b84c4e121d0428293c7b41e3e98d418daea28c14964ca6c80bf951de53ac1c4ea44b385bcab73c60d4045bde93a458c90223628dec8fd5856bc50619b00a93bfab21e47ef79aac2a3588efdc7d6b1447bc0d3d6ef9f914f2a20ff9174a0090c8f00b4ab4b96c6ea6004861ea827a78eb1a8e2ff848ceb76080a0a3468304858f63c85ab589fa6cb72f116e7aa2f27c3cd1d6deea5c4f8657b9238452edaaf5352bdfb5a917e76de3901fc1efdb34d04eae84df40752e490d0e20481274fbea4e44f1c9a35a99fa72811c3a9a58b4be0fcef94b14b149168d44c6b30d45894b4cfb58cb20ccda849b27fd9b4c63d47362ee07c2addc3633297f09e58daae9c983702db6af4acb91a49b2074a40b77cfe7c435cfd7cb92949bc60609db0bad79757848fb66b59b39dfae4e1ce4f4899f2cc53e183594a2cbd230d5a650fc372060795ffd4842fa40eddf44cd6c9e6607d146aca46d9b617e8cb1c6b7df4ec80c96a38d119c0ca36070f818fc0996a79346b6b0a0b2128467cc6bb1b887aaaf58f952ae6d74d11952beeea973b04d1030f8397a111e3e24863fcee9d276e1b606aa89f2431730f4f2bddddceb3461d42fb0d9b2e777e9d690cfa60fc2d1dbfc46e73dd72f72a7bafb7dde9e5167d428faaec9d60c1474dc39e57b3b0a39db7a536c47a4fb2b277a7c1fd49bc81628d8271b271e1265817796d732d6ed51dac85c6b4ad203e2aa821e0b27b9f0a6ad74c2300655926fa46a60165ece114ee0ac71198d1462a463cfe78906629b729e3f7e2db165cda25899b904b890e2b95baf9c69c5a5bea46cc9574642556760338a314e9ecee7a1ca19b2693625e8ab142ececaa1b5570c82fb4ca3ab96fbd7947bdb36c3ea6107fa0341a4f2f30212875099b990a2eb2d0c6ef7e31c6d4b00ecb5651c6cfa16ab272c42e9491915d540682a180b68d90cd719f55182409783688bac2770615ffe7d03ed21b02382fc964a3fc25c74cfc82417764730ab8dd06eefbfb2584e41274070124d6e2f6e16a09f3386bbbb8d5d848738e8fd24e65c3d4b8286f1b7228f3386b87399e38ca3edc51cbb87ac285cbe71d7ab3ee30b7f8f82c25eeee05c75d30c1265df8d670934a92cb8eba002b4ff0c4cfb805db93b98f8e2c7de24bf38e1716772d8ac35d578085b80afec9f89413cff44b2d8e18e6a69160aa1137c0812529ebdfa9ccf03fc0e5446e8648f67054ea9ce89d3d3708507de0d48724ec22bcec2d6ffb74fc9ab3fe11839a5981e5a080f3a4e7a323f83b4dd8c6660ebe837bf1f7946f363456ee61e3c01eb642bc70a35a2108d7bd271a60687b75b5a0f9f458f77b1b88a6ed6812e5e260f7a08865f636ad9914fbc923df09154cb2f44884b6265f4a7b4ca5c57259f505948fbe5d9a43290a17c097389ee6060edc6f2006e0b3493951e5cf0e45c94a72af67a7fcc7e229fbdb9b9e239029fa9da2a0bffd349a76d1794221742a7c1919a769d21458ad6e147d5d2d9a668a62657c8336783d7bffce1adeab9e1cec977a748b4971be849c6da7bd64234bd56867a4c41b9d0bf23e41dfceb5ea4325c70c68f51901e22eadcfae7add1f6a5e46b5a517c5b25403c7ee6fb465137280a2baca43ffe32467a11492d24bf40252512edf07984c9f9ffa117cbc123a56e140aa1206648ddfcca7286902d5fae1199aebfc12dbdb58a7b74661fd005a50240059e94ab764072908835c1e4e242d7d135753a40295176ea023efaa210cbab5ca3bced5faf0bc6a28500c225baf4e20f8b0a73840dc7f9b1bf9c9b0baef2d2b712225a327a4089b04d5a58aa894c321af599138d2fb292573a399263c3b24c2313ae04998152b9fb64d8793d2054a0ca4967842bf5be3e3259adc281b183dcf12590c785882b68cac8b503a71ea285e6ffb19251c42c0dc5930d192b64567577860a9d8881ad56c3e2a267c14d81c53bb0fe63d923b0b6371b1ba6126d28ab872419299a586c04682bb49c3b4a1a2acbf831bf83e2bee0483920de48cc5eb7502472920be08dd1f6633902409bd545d7d3509a78c3876ad51b39bb52bc2fb5cfb420d89a3d997fcea3f983e856ec98bf1dd1b1f8488beb85a134e8262e60859c37230b3fce8337a880e55fe3e43b0624bfd23a0f00fa7c0ee48918e15682983a25e0bb760ae7369e835d48b1e1d725d3675b3b8345e7d852953a5347826b6d16364bcd4a2f22c18e6637d062d257fd6bcdf4c172ea1319f41288c201f0f402b68e4906b683a7e7cc5dc98b1c48d3f950d65dff2b8d42fcff1f1fbb76a62b21322e3adbf6ce2c85e695afb9fad43fa8b498d5a5f96dc62a7ac8263d063e2ebe236058f762aae42d12444817025a267bcf933108445fe6dcf3e66b0fd6079e3bdd628e33ee9742cf176ae3ca85b8f1b6cb85874e2c39adc6cb7cf322850156bf2fcb445cce711a76e4b04b2107456873aa66a5e27829a0e58539bd4fbc433b2f4a3be603739e872a9cd9add805b748b925fb19cef11b24443e6d0d4d3ce3404f4cdf14f4f18108540d40c6f8f960254c87017ec19b7c0bdd2c66516933c2614a9697c438593a9711c6a20fb2424e28d2acb82f5dd0f939a79de40268b31602f2612f2117732f31f606e366e67b4869e87979cacb1fd93d945cb799794a8627d8c926a6b0dec58daf6f95344930bc80d0d8c5be88cbc762545133a02d1231317887163055f78db782f084fd2a5203afa4c1e4f9d94e7f9987399c01334fbce9921c0c639df53a8f4d426ed4b83ea39118e0c085e83f837595b09765ef81a63be2cd464b9b84b0c5d485ab63792f7652301fca368490ea8f67f3b5faf424ede39842399d52a7c5356e138909ac17d6abda1b01acf944ad040b75dcbe1ee759afc5189ced5363d099d6efd2189806bf0d5a50b74cea5f97bc33a395e1be2721cb78a7e7caae99b2d9e84e4f7b6a4604e8a916d9217a7a098c83badedb4cb58e214ed1df9312c1ea379a360a6e3a5b3df4f8df42a8e67bd564ae5db6399a68a40ce1bea7046457ddc2c65f90c9f6cfdd1fa195058d101bc043379e7b6134a9f62d897ec9bc92cda10162897181e1453bfb47f17103377175ec110f10302aa9697f1ebf9c31887cdc20f9d7708d3a34084e4abad00600f5e72039cae9353ae5b7636d86e62cea4fbde7abf8fd7ffc8bb0cce0551d9a07c416012d5d1faf535cbbf187c6cef101798cb7e647c79dd48eb85245e24e31848b92e8e450cb781d46ca18eb82a25db18e55ede8e56b91066e6c27a1b100b10df85ff9566ac35d90682be71f04675a921c3f0fa48d28db41c48757189583f9066ebca1f215c24eb4652372471224746769433f4b7aa6eac0a79b1d2c01d314e88b41725dfcea9e7b13858e7c546e4719861b5e3589cc7592d7065ca774b26769eeb93a939354cf6e79d2b35832a263f0374c4026aea81645a20923a4e074dd3fb7d5e2df94e8978d87192b80e7cc167d579a67b789b9e9ae00692734c2202f78dca2b4487b99ab96106214075a77ed409013160b349fd33ccca239788f4b218e57db8fe98935704f9d6765b937b6f99524a016a0638061a0626dcdcb091f223c1849b1b3652caeffbbe8f256340c78f7b74f08efeeffbfefbef53c197d897335c670001086684a1fddb0c0b73461a43d2104388185d62e8b2e5901a0e9c11e6dca49603c78623c16fcec963ce808eff03e4ddd37264e7040c1f3080f00e772ab4d404f7b5cbc36dd3df841dd51f08f770a10875dc2b39803cb05f9ed4d1ece940bd1d7f20b1c57ff1c56742a1f105d01764889009238630bcde91ecf58e919629d944fb773533ba2daed4ae3db9d9785e47abac5590d46eb3b1e11e9a1a36a8907528c2d44ef37c3e995aa1ff33f224e7b4e51dbe4da15d39936d9dde9f9d54fff5f7aeab730abf6efafbb4b723b5b7d1c028a8a685fb553abd0aa44523729e502e3736f255c80a59c8573c2424149eaad0f1fbbedaede3fe75a7d38c8e2cb4fd947617471db5bfeac1eaa654e0a4ac92e38f637491ac10d5ae3d096e1daaeef9f36cd108ab802e9215a13a5b6419d69491c2028b94ace9a21509d5a08a8a480a15484d90e95263c31ce37af14a574365060b7d966bad0c7d99218926444d4aa46083242d7810841f78a1c5eba301f5973ff385eed32474919808539f0930953f47d421533eb89f9ab6bf0cd8dffc3790b5eaef3ffcb777fc39f46c66b44779e45674ab01ba533481551c75a7c841a87e2f526e6f9db0abfeeeee66ad4ef77318d4220a56f759ece2d102ea21103841465691ed4f7044fb2d0ca3e0bc36204d5b5f310f2c9f1f966b99240ca63b0ca85b1c51100bdd42e24f2ab36a863425a9323f0c4395692a4f89557e965dc43b38a20e36825fc58390214041cee10429c2ec2bde910515d86b5f38133082845f49f8b5fdf8ed0b0788c7b92f2520eee1cadff55031a138fedb1b793908b48545f8b57d08374a287351110c2df2be7a59c5848e2c160f170d951fc8f270e549e95af9f20223265b386182830f9830434fcc9430bae105b444d0226f01ad525187a82298247981430c0931da6c8a2e37d6b8e0827bd80c1e685dcc3426a6a3e66619c7b158ec0574d48434214d4813d28434234d484b525a3a0df1214d4d4d41d0511ec92379248fe4916c9247528c06d362b5bf43699a4c0a12b55f4b6209cd88659a265b424719934bfaa511124acb1eba5fc664acfbe1b8480a1d7dc887868686868e2412325286e35ea9ec434a4b4c9e7812455114a26327755227755252d2ac93601e732125966921cb8a64321915ca62c488e966315dd4464056875f9b7d5ea46c5952123725252525cdb0b333760f4ee43dcc66b3d9ec9be3401f7790d5464c52c62d66269bc966321908c5365693d8e4433d6b317dda828edcd446b5857ac7bf5973ce84386e9a35353539a163cf9a646d34339a19cdda68d646b336aaa2858beaa502695156e447558a6a7462a118c762b12ff648b63c72084f9352d217819eb598d96ce6039d71534fa9d23ba35f91bdd3d4d4d4a4f1e0365eef2d041f3ae79792a5c4822e3145ddf293b3b83bd2124e784cd55ffa4f1eaa3f752425cea8cf85c988734f614f56df1d38f9010c2d3e507902c6cb6b880993830e484bc0c87879c7aa679941757f2040de62b9ff2865dbd496015dc2f3aa7f90ff0ffb53af41162ebaeade9ce9828e4fc52460b5bbc51e6b2a3032a22e92510f28d44542a2a98d665f0ea3a6da6fd3cd6ccecc160901b0f2779df25a5465a15fbf5feca7fd5fefa0fbfe5c3dba858491e052f953f809a2944242228903fc43dabb978b2a1586aeeb00afeb84508b5b5f84253abecdce28be1875291346161c747e88e20813314cc6847931b35a045fe0ca29d942250535f5848e2cd63e2fa5a1e55df18312181a20b1a10b11927ca1850e5ebe9039f2e267b9cc383da98139ac08072a2120c03c390179608cda2f87b8825c41ab03043a7252ef8cae309b94d49cd42e208e6553dbb82f68b6252d9d240f50f2371f2c8fcb6ece1e7828338c6631f88a8166559a9a8d58825253405a525216cea2f603718f0a5358f1b33a5be8d25c9e2b0b3a725290b7b4776e675f028211d1fd3456fabea419868ebb9414b4e44bbee493db79948388277870a159111428d8105e789863ae4c19a30c116828a9e1c5529aa85451c11530c4386101b74b6de3e609d57929d50ca5a9a9617363e3c68723049c1c22782390f06058420e00026082785212d98a954f3104a0cd3306c09dc2d0717242a73b31112075d2b263e6948545f3c309354e4314e0c60c03dcb081078ed3d2017082b023020e5a244c71812724144a68e201c0153d2628e9b19a692060006312a0c30413174214b023099f13c0d40da99ff571aa32c451418e5e95a10b5efdaa0b5ecd610f0787015c55a16be8838eeefe2a40dbc19624eab84764284a4a135b78f0a62d3070d896980c5a80c0a44121434b1972072d6060d1a245913c4349092623c6d09310d2088aa241ff8088256388a041564466465175918ace00e2f3a36509475da41a54515282dba54b5e39fdf98dd4ce9de537b5e3f6765e776de3368e97d3aac7b59bdce49d60ed96e372c8743c9bd652dbaf2b7f530f20a1b620f757caef1c9e615237f7d6c2e8baed9dcda5c6b9d4b6e99e0447cd015ea68cd706c78deb1fb77656d76e827543ada692efd3a38d311c35cddba4b671f3d4d90047f9a36b1274700c6b7baba9b676edf6b4dfe11ad1989b01c74d29dd8f70dcd4344d6a9aa6c921dad4529e724ae6343b6d9ebc6edb36f9ce71ee477a931ca76dd2b9b9fd697b6fdb50506ca454082b079ebc79644319e12842a13a5438b6c671a739a736e79c9afb9139e7e4b8d39c737b97ef9afb9139b777f9ae9d360e4706ce599e0e5589784888631cbb21168b7152320c87189a3d9d2a6f6bc8106983413064c3ea9cd47296a7697f1bf26cb6342c98fd96fad115f59cf721e0e800a38eac09006ccef2c8d6fc7d9e823ad26eaab750b7ed3bee28f8888fdab7cd5f630e4cada87dc7b2dea159f106cac8a554b051fd3b9ede06ca147e7c64dea2d9d594d33768a47d88eabc595b4d85da5c7ec76d2e96f86fc2fff472966703b5eaededbda28df106e4fafb7701db622fbcfdee8582de2c5753cd9039af76272f6779bc10d0d042f7b9ba485a90b0481951c20b2563b89891c40ec8a000151fc098810c626019c3b3c69ffa7fde44f51928af161d5633852f4c475099bdc00ca423236231a002043249cab40d5494e1b85c314601a4177f9afe946159c240d9cce74ef4740ac7198abd85e3d4c291ca70fc3c47101a70018c0663ac74d1e288176a7852a6872874e8c2895e41c784e41ff0062c4a480cddc0a4f4f22aa4f8f282284561c870a56ba0a288bac9b95ed708b3edc37dbabb894d88a20f075158575891a3030b98546c9ba2a87a09d5a7b8e2ca0fd5af88a9fe2216251601665dfee5dcba3fe5d321b24041c3ca1cf2471bee2d2d85969d1bd450fb065ed4fece91434a29b75409930f04487e100b42727c5240116d727c0e63a490411df748f640bbba48520849116382c287b8028d24a46e22c9a8282926abe8d6a050555d24294775dc230d46bdba48528c48826d53930dc4e76727bd51655da4288ea8e3a7044527a5b3740f676c40f9bd7bfb6ec109ca5dedb7d5b4517a926e7316f5755df8a8d796ce97eb3352d0df5d71cf819a4bb947320a33f5238ef164c931d6983de6dfd88c21c52a33b37c180c86c4a5b448513c41eaa272536cafa57c6c134906f500730aa08e9e1529aafb4f2b5d50ae525639d6b0d8277a28a223da889ea882a6888a0c3d14f1c95c50060e39246d6162cf9872840ba4b0610c2b57b05c2ff607c160f4be9d47d07904ed7719c5cae93c74fe1cd782f6dbf373c7712d3837d7addc83cb812d6ccf75533e364db6e82dfa635552f08bfcf493610a411fdc150ab559ae171d00b6e01a4e037604216838fa8f802b3f03796b3f5a554ea890fe21fd40fd413958fefead08eabf7f03a338dacf2dc4d1c2eabfafe2f222fd166c715947749bc34d786809c788c4c0af493f972ce22fc3a9bdd4ba05696db0bfdbaf4597af9a7ecd44dcf20736c45afce9d06b7179d8ac808e3c2acb90855a5c828ed3c8a75707357862071dccd27802a380172ea8c4844842c394f6d2ed3e4bfb915535d0ab9a5709ceae5c3b97a0f3d83afc768201c1890607ffec20daa7c3cfb942c79ccaebed8218d28f862f8e6ef0a18b171879f162618a0f4f344162062894bcb8cb97137b917e43be9d57bacde9eeee6f2716cafff1ef24d2e1f0a7981c95808b255c2c1dd14107259a2441446c07a32364d4e0880f68986079d817e9e74ac21b81b822a8fbbcfbfb22093a1c7eae29866e73be8e33bbe29f93ce54563999a9fc3a6287236498b1d4658a178f6912033034fc00cb931a5efc2c172bd1f52ffd7d917e24e83667dc9cdff0690d3a3ef7df116a0eded12c0642fbf75673c85a1d3f81b53a23d4fe1a41d0ef834143c201a7fafe832502195b98f144145ecc107bf5d198264ae4908226b894795560088d22aa3c09c20c244459b4a04c0a60e04452172fa5ad4b0e8072f09110ad21bd6a11e9151adbb32d8f0ddd8aa157bd851dd81d3dd89d0d2c57470ec345f5caa190d5e9572141478e31713fb26b79b6212d1c732d8fa3c0c33dec7dbf0fc7c08a2bab335f4c819bb25942a1f0926e09f115d3e075a9946c718a3a582d76425afe98da622ab9ab51a5714e2ca6da42298b12baab93824f8fd571ede0d1222b595922fac2b4c3ca0ef1bbcde767796e6affe95da7efdd409cd06775baae8e7b1474fae9abed821a514286c887981332c8a1c90492f850a64b193d2cb1c309fc7de10499da0481fa838ccc704318494451948485ca8e21a00c816485942d43afaebbea57da515306754df394fc4d7a1ba77c709c8e3df2994bec8e41873435f960b94155d5e39fd551a18ada4b35a250aee326c9ddaedefa5df5ff383917c72d15a11e84a9cd798fd1aba3cb0be2e2dec53d0e640381a4504ff9f8515d418142202d72386e123397923fd30c95121857729e3842e484ca714ae99383472b25f4e5882c570f1dcc6affcff45cb53f04eee19fb32925daeda60c50556f753827f427294907f8bfa469343c65b52b1e9fa6741ebbb3e73cbfeb401b20d0ad3384e175e8bcee0518c0ad2fa82a0c73db42c0657e40a011ccea610a2ddaa441bb0ee04b30c1002f533e26c895c1e5657715f7fcdb3f13c702fa9efbe738830ef0284aaa285381e07e5316a0212ccaf62888c2bf299c1b21d67edb2acfa9f910c28d12babe3add98a94182d7edf265ea87b76baee2a694d2f35abb72c6d1193d1001a0f67f54e8388564d8b155a1da2e69297566770767c5fe31c7ced762ff7ecbe32f25d87503f7359be886628b523af88393a38e2c1556ec7731cda31a2e472c8f5c9e002c8f7f8ec94c8042de5a61999c38a8aa0b04041db7a90ee11eaff2354ed5504247968932998c13d3299d30f37de3975464db6208e2428b3201b12064081130b14db2887ebef64720e887e52dee39707d253de46094c3e51d628b3f49494949493fdb18d89699a1fefb5b577766d7348de330b0ab7e1d8c33b59f431656a71fa50425d23b3d60f8b1addd1efefd0ad89d6d47fb4ef5187964f1705c55fef9dde62dd7aee2dea7bfd9b32757071935276af2eaccd501d2a307f783337bce96b173e7ce9d3b7156e8d79605155be49f93d2eff33df269d70167598d46561954d51a2e545ce1846d4d296aefbecd13526adc40479652fbc5d5168e2854ee89da3f77571a77774abe06ee144e285506bb76ca87282a6958e48cecbbbebb7c43ed96cc5255670fee16122742fa024a6bc314d11c2d24a8a22f906a8750fb798cd1a4f6fb748b5fcd4e6ad770a1e35c1e146a7f4d3f13749c9ce24dca4db238e796829315ba3abc531aa734e6ee6afc5de966d3aea62d8b7b4e75b5a0633ba9f4fbfcdf3ba56e3651ed3b175050bbc7ec75eed1ef45d5ab409b1950a2ee51dfcf4d1824d2aacf3d95aadea7420ff45687c5140f578b3db8888b8250bd89bc3e55e9b4d4e86ab4f44bd50af8999999a76c51545ba08bb40511d21631a8e3ac5e6a79b610aa3c06111862985e777777f7eeae97c95eb8a9c56566a2010c7be126662202432bc9a66e7346a77142f9378e758b897ce545e6fb3392dee19e85b88889bce54846875596552e6466669ea7d3e9c4343a4ceebb398ed31c468323f1588beeb0163d22e8c84baa7f37f11997450b21092c9216b0ba4bb3ca2fbbbb5d2e31d5d4455ac2d2537417f17518a477bccaa5820c2c5a3006105c56a0840a43060c49a9c9141f340b62556eb14493850db597b2f0b234a5f66fca59b0a5899c1e2c451c750d605ce89d71999613e22d2e04724964aba8a31131a877be8fbd3948d0b84a15280c853029b17cd5cfa24041429aa05f8db840c911529040a2e88c1c5e0230d261872fac00e28a0b5eddfd1dab698ebabbfb034314e1a5064eb0cc50c30b48161f4c2126063d882df1ea67b9b82bdde69cc07d79e7de068e36757b8edbb8d07f0b998a425d242c84ea16303f40b678a9bd5140c103ec351385fefcc7a19faff6a5828276c0cb171928f9024c10493e60459534b03c098215315efd3e3f3ea0a91fdb6bbf23574ee3c2717bdf4617aa0b36553a98d3224b86f399a040fd41fd3e3f5b959f53e3a75c5b042a88a0daf3cb658e526bb4b0d73b3355fa3abb87bd3a5ebbf6bc6b97dcdd5425c327aa16a8584059e3dafd520b3ff451affa6bfc3829fd6244746c2f474f50e11eafc665b2af11baec24f3563735c99a6435344d4d4d9486d6d0c864b23eea388f99d7a779c66278c66262b126b7a17766d3f2cc88b13c5fb8c7ab799a6f4a8f4e7d74fa8ed6d0f451aa534dd3477ed44735a064d19f069c4c7fc4623931be01f7c5365ecce606b401912049f22f8fb206e84fc27ab9943da1df9fec01faa91b7df3c471a8ce461527749ebef5160e7106f43a7e52fb6f23828e5f6df9fedf27ea5839bf2d244b4a2b445ec89410651edda0b34f53083afe9651c31296170ad8055cb4d7298c327f5cd5fe29c39156f6108857fdcc2c4ff9e05e82bf3acdbab1a272932308219f670c2d364784e57af1024012580aec8ed6454aa9edf60f43a269d2a5cc1112a389749d4ddb34269ba625fd284d2198bce0538fd39826865e28e82e92bc4e8f3a8551b807e29e4e52fb67113729a03dea2275e1a50279eb6366a6b1d7fcb91fa5cc599d15b4108236d80287383f2ba7fb6befe312e49eb914aab8bc455368b14a091f0e09ac01f87bea4757efb4d594807c95802acaa85b296fde06e4d70db82ff74aebb7abfed1e6a5b4793fea1d7fb2ad56da5622a2767b71c5b6daa8b7a8dd495d6ab76703169935081df12a62f328e826499cbca248556d8df96606eaefdf3dfb77dfd9f8efc6df088bdcf86ee004c1f1dfe3f86eacd02f1be10fddeccb3475faf429ace1e2b2e599cb43371b102788cd8db77923af1b1027c8cddb781b61111b7ff3465edd0db06160c77c7503c409f2fd8dffc286f9aae7db007182dc781b7f236c1b737ae10afdeaa106828ead349767e6fbbb8ae5a9f9feb6827b3c1afa4da90bf9aa7dd4a8315dc85b2d8659f46f319e6a315b13f2ea788d0736eff0a701e5aee8ef42a94fb9504d51703aafab66dea767c2e521591d794835bf471e3f68eab4d16ebc17641d7948e9467b1b705f9b929a6c75fc899b509b881a33a0a3cb768b1055be07fe588ef37c741dcae394eceac3088d82fa4fc98f02c71c14784af9e03894c7a133c02b177aab4d97b9aca66f96d8c5812eefe022d4a56905a50c29a5949288c2c65d62216fe5cc206fa1bee7fcb6ee6ffcbefaf9f8a7e1b0fb446094ba213298bcd8765d6a5a056ed4aeb103dd346d4b69cf9c0455554a7f4f6153eedad770f16a3f0b18c8c0f2acea55206ffcde6fdfbb93e2591ef95c379005212d3610747befc74d819b6200976140d76e42c94808384ed5401c7eed650784c3611015155448c8428b8d7242bd70971e0cb9e7c53da8ef4f21a777bcef9e796c8af48eff7b1d6bdc1683829676e9ff7b5d351aa9db5210d30bca781011a69fb7508f02f7e581fbeab6203e803620bb3ebd6d5aea47d7eddd5b2160580d28b43d905f1d5884994872e58a97f728b0484e9657f70da2c0a730f1427d0726d95ea850481f8008f74815d4fe790465e1099df932e774b18b579d7200b7c0fca7f7dffe94f2710a4fe1c83f02ae1b731364a1450e705e82b6ae977e2231b86b01ae9eddd1a46b975c8ba5b26b9ef6c4aeda9e6b09fb91b03bdc7b58a38edfe99ba7273281ac0e50901991d9de12c7f5f0424a2925b364aee103dd694257e9935c900fa3feeb21b2bca0cb3b50a1cfc9a3363dbe8f8b239713333333200bf5ca8618120e7906560199253af612d5736d71ac578dc3f66c4b96875b3cd42beed9429ea161b03b9c825ed24b18468661300e6c46618ac0c864b2a0e5719655c0022c08e91dcf0667148191c964aa1fd1bbefc4ee65577ac79f61b227cb138457658a4a9502e56c51d4c1e2e182c118c6306fb10c2693c9643259aa679a500a5a9e9eee734e4abfef5fbc01824e5f6d31f88a11b3622a57ee34e7e9347f797578f8cc283373dd5b85efd334c992b206531857248b876bec3182336f3f50e78d37f6707987162a4d27d69d3513838bad3285f8e1de7955c1c3c5098157ff59de0104a4513450d65458aa02a564560613babe722d9df7cb1302ae2ff8e00dac8e6b1d08b303238ac3e1f65b5fe03a7edacbdfc21ebbea9f3d7af4589d7e5518745ca61ecd2499846c3374dbcdf06871db541eef50fd6a5aa7699da6a9c0cff171cfcd8dd5e90789f4aa5f822e0ce1c0ea348fcd6118b3897adc4379473ff3c6bcf1b3b7858e1ce6b98e360199dca8840d18353d0ad1d00c80200863150000180c08064422a16838a24adad80314800c70823a6a503a168963b120c7811403510c328618400001c610629041886a0d23f02d2b413ad4d9346a1f7049d14ab5485223bd4413aaa58e048801b348c6eef71a829bc85159ee6df65a99d0db6247dd70b2ed6b9f90cb8d93edcc7dc9a5d9a6c96eb164bab4e2bfd0b5b6dce7a77ca5623256a4776a5b3c758f62fafff21d4a96615c901971d282cf349b3c2c754496b03d9708ef98dffaf6b299fdd65f756fadb0a5568ba9ab102e32d8275cf4d258da179f01f36f04abb2c440696b9e72f8590ecb6497f1009f65fd2e06d68e96ca7cd87ce9f28b4f94f4146f3e28914a9951be2d6da9785f81cbf5b13cff93f90d7ace881600a1f22d2449b93d7b75fde42c648a4d1f32f3c85dba41fe560a9efeb9c332459eb990fd84c4b0130b69d8c4eaa6b51ad1a3f0b995e48b9d3f596f3fa425f39b5947e586af6fcb1a91ddc7c876e6a30b04509f6ba03b1a7d4dd370b20b4841e1ec849c11a87a77f1d8faf648a682050a49b062ad6cd170e5ddf195a564e79cd79dfbf9c52ae90f59c54b0fe6a13251a1592adecda481ba5f80f8bb095479d0637f5d86c7469e745c57d29755ec91acbdf8e224fdf90023baea09dca54ee8f136008864aa117603f75913001dfa74b2c9d2cdbfbd927cbaedbea96d027a3fe3ad91b5974b56c053178a1fad7be8adb10c1fba2610c03f8ce472efb3ac84726bbc40d9ad4eff68cbfdb2479642b2e768fbcbacfafe4ba1765a6b1f3c36226493808f67b4fd40809ee44531be8514247cc25c970b986069b73cea80b73a1128ec830302bb4cc85a66f21c024dd67275814f7fcec206a6c4a6a44d8a981b41c5e0b02e9e193be8bfccfd1c029c278aaecc4233a882f368830c4b1e162c3432e5e0f2b9322a522d1d28e7c312f6da14f2fa31d65b1142222198e0c6378e0ddef83c2b7ac519e06d946d9f468660398759a86029bebc246e3f5a9e24df2c35fb4cbe5a4d5dd63fb40faecaa502ad965ba4c108aced29e093c59a38349893e55d880082e518ebc86a5942818b2a81936a751a518bcb942730140d1470c20d989eb835281cc129a920193779f1d031b47fdbd3be954780c78e47ef2f4b54f378ca255807c515a940ab17a31c42a8688a11fe0bbf8223d0fc63b91c07159b30099b577817cdd600a9a2715e17af53be576d605d90073cb1183d4095e604f24c54a76f68a09d75d9584075c42c8451d6847c974f51c62dfa4c2c72c672fce4075c07408dbda152daa7ffdd5401fa4b4ce93b44d369d128f0347a363392922b58aed65378a44254586bef378a25a1be6a6423ba83e8483bd8e338dc51631445611315b40ec7e96774b22517eabbeba2ded85386bfec6134f555e83d169ff49a7fd9a603505c217bfde170ccdec3a1df240ed0aca0abf97d05fd45fb0942d4f571911cfd922afe260ee578e04737edea82f1cad74993917ff840cf282750a696f22e4d766d368521210918d757606a2d40e4b80f8af3619cb009ae717c10f4adea5c96faba407a2c85074131a3e321c0ffee84cf014c42b43af85a39bbbbae38dc2da69b4ef2180b3d4d6ffe7beacf0b4ed7b2e5b9113546673c9c36859edbffda5b95af324180f0d15019a309018884041dd265aa3bc09b3ff20ec65fc5ce563a8d993d1253e907a2de5ae17fa5a53dc3f6eeb3ce4c2979c99007a519714c28003ec369a0b03416f3a48720920ddf5706b98cac401c4d63fbd0846cb616ce10c1bf059016c849cb5923ea7752620e915d91f0499594754b4d0673e8509f3af73df429af6860a533cb9fdd7587a743068c1eff63f835504dc9163f24ea90b0669a51d2ebf00172b3097fd326e930ca4e40169c30e489ed94a814dc275689265c2d4e76799c99404546e9d668e34cccd22a582ad2812c5f10913122c243510ef6d2aadad160fa22c0552e4469d1618f60a1f563094606b0f488668c024ef4eca93484481b80ed3f879d9a3ddc2a54b51469ba97c9db10797aa7225d9b5ed0867cc5f397ee0f434ebbb99a1528225ad34479a91edeacf6b234e6a99344ab2eba1b6ad9120645cbd852c55d23570ac4f012b90fc95eb2978f286c1cdfbaad4961018629621fe3d494265e71d7cdb661ca37dfef066c175a2c449bca9ae9dc7c7d5fc418a46101e7799e544c860106d51541d5be9ab843e3aeb602fed5c6507892f6ce5f9fac28354caa44f06a692e4605e96dac8a41147c09818b6b2a5e37e23ea92050df769f4c7a6ff7d3c7cde3357281b5c055bcc6a53c34afd10110c1ecbcd0c4baa4c8d40323f36865cf18b0586ec496787b96e642755d5b74dfc6340fd214c10fed6c1ae727281e26a109cdbeef27b020bc7efe775a51df5c163d5c018ae027aed758c36ab8e3f0548d9f27cafc73e6236f0b7adf09cdcea964bfc6461b036e0a15b8aba72fd8a2d8b3297a6b53876951e20d14a58542e1117cea40921d180c156e4c1dd48bab1fadcd446fdd7243bd4fc58eca9749d4e19b30b1b45a414de2f783818eb861a81219a6f0c181ae55a6dc3f9ae52bc953200d0424ed1800257059440025e196e3a1280edcf36430f5df8fb000a1a80b8d564129839b2a8561990959972124f13a806adcb90c0ae7b346d2a1d41cfc871b9dd7659d57be8961e11513aa38bb3df7c3c250092059b0db44ce579d4cc6738ae34612089ad301e6ad88a5bf9d3b38d810eef437e0ae5e42c16f6b64bffbcbd4d1052eabd1aac5e7999363da1fe1b37d993094ae73687fe31e6613e31ee6137535d53f312d382a1c3c83e00444faf3a8c403ddd563f3408ed1411847d8139f031c26544430eddf3e867783f736e53ebef6ca342acb26a2384225d6b85dd9905f1d490e670af61866248374a1e5741fab465ccb539940a81ff90ff207d86f5652e5e2c4b5bd1659adc189b6a47f362c7717524eb1b438815711867b790dbdfda6854b7e10862b4da8228a07d08f87980df30d9bd57c3f20012db0fbf97f385979274af5a366e86dc254eec691b8d865b138d4d6ed5e63bc06c36ffabfe22b8f8fe59a9fd839b1b90dc4bdf731bb875bb5fa2a2492a1ae7181a15adbd5d6501f99b69a4e8248f9b24d78615bcb253f459676be57e5997a9ba1b993a5f9f2f392fe35a65afe7b15acb5fe47d780234b0dd1551bd7367a3b8c5de182fad30a1c47a2784239582598f43ed773025e2a519d1c3011020018012f53237ddca119dc96787a8de64d60269914e7f016ffe3b790886d22f26a218aaff115d12a7d1930b165da96e72e113268466ee457c8d76343ccc594c3f6f60e73c9db682699b87ccf77559915b7851f25c98326bd14f6c265757298012870d36c0abc2484d37a9899fd95230de26f1184072aed2d2a41fb545aeb940f1e64ed21fa77355dffb91dfdc2333a2276273cda1e2d124a37dbbe914c88eb6a220a608fb999d8db60b1f876a2c2f5ca45b567f60ae6af8001231d1991388f10d9d8e942de932a9bc0b1ba4b08cf738750bbe4370689f3cda6b2b9400af2599221f068df916eeaed1bfa8e1390edebaa3414289551897fb85b2e81b79208b9f6e04a356066b44231b995c2a0927c4535eb20c47a095e728eea4366d27d28c503b58c7e695b6a3e2cb131bcda70b149739a5b36fe9b1189088033844e8a191debd3e247ee6d3e1f6a3015ee9826259efc0cfe640295ee7f4c563e791aef688e1f1c29963f5adaf92988905c43ba59fd718652f9340aae4770b04d99919bddbad9e72a81c372a889672f03f8483136c091b81bcd20444cfa816c61c65d456a3b947a1cf7f65a21b1528f923e24efdbf76553b775e3f77b0ff9a680c8e98cdfd5907a87427d38ea7f2eeddc90d2161f58ec601f372450f75e3adfb9fdef3ca70a509595f3aa30eb58d9d84e96184b94c2449fcbc076225d220c43d43813ce11fa7cb86c40349b0b40dcce738505c2eac49d42cc8af6bba4072bc4546fa93d2146ad6081df8461d34c55272d9a88e0f91a147a92b0dbeac409e5a2fab7a2d34a96b29aaafc6d41fb3f409bd69850cc9cc24c4d7a42b7c4585950221239c90c97b55a0b49ff0925a2f16c25141a52aecbd4239e79614a334845c68c8da390304e5bdb733e18cc2e9f59e7e46ad86696e3fcb8bf22fcb1e56f18786151ae1a82d2239791e5c172be4f33b26b9eefb859a51d13b7f9bf543d2b1dce52ce69c50132271a34c4bea4f452504370e52873c2b9c7d630a036c425f01f19979aad40969dfe27b5b1df68993e1c1eddb6816c1a15aed77c3fd7c85a570d84473855fad6aea474cd1b136bc11962bf3ce0c56dff7593a44abe4b3922a4c9c7d575890364bcc24a86ee2690d6819f39a3b6a2af56526393ed5e0e820ddc678542a1110e2e770cb45a5279839441f7d77609bee22f4ccc5aeb72df66aade420ad8342b0b8e295df94a41d7837e7b50dcaeab4288f8dcd1fafe852d25f71f3bb11930cdc24125da831be9ad091c1b4bc99da0f53a8d3d911a58de582637620a652c7e93ce100cdff11a833ab21b55b20241160cfe083321ce34727a01da51e2521979e256c8ed2e1d5205a131541b66d0a2c5cf1f11b7688d88b3c22089c80ef3fc415080a03205b91c082adbb1c715c38d966ab29db0c6c38ec1761dba51eb78778d581d41555ee31b85abd93fbb6ab8c3d15bfe538f34c2bd1b875a9f7b7a512bb3939c075bb49dd9495152512097d3238707776f3cb83e1793d74b39cae0a7aee351ed25100a9dccfaef595191026376df6709f0833a38068c86d27582d31eaebfbfc010cbc03b32b1c093e148a83481878c2501552127d1a8dbc8c18f79bd362eadcd98b048c23559b52dc9d99edd743b3d45e613cd4b3ab81e2dca09dcf46de8d04646732b182e0953e76f91c6784dba58070ad40e7223708ba7bb32aef89d24a04bc8ca378a1a99f8129e3275c8ec0af114d68c90090fd2a9cc99fda07184f13a2dd1c57418edc749136e65a14213cf759e8fea64baa12113eea2f547108a76b6fc8349b55628ba422d5fe3d3ae1ea0c1d594a62edf850f2bfa4a80635bf8646b10e00a36edcdf6a74c2fec8d89c9079dd3a5f3456b7dc4636eb6813e59876b2d94b8bef9dd8c56fe4dae1867711a5917e67e34ff8b68b96d203520fcf6ae586f3a1d978ad50ce49656181f05edfa4a12793e0d4129749b82e34ac6513446b4b34ac3dbb2ca1ce0a9c7191d92172ba5e23dce373b5fab0602bf10283e615deb2d67f8eaae3d808d376f30b9c81a9ef76535fa012350dcfec5def0b36f758395a509915c301181ac9f70ea545dec32ac964e26fa675001fcbaa0dd2c342574011e6d9ca5a2e5c09b38b5373b68bb1a409e63c46c40a87814526b88b40aa77ca276ad8638918211c737603d49f45e69473d1a885bd47b9cc576c0101495d05726b4eeba46a808b1d0d654296cf56cea84cc943b00d2803c57b3db8e32fd4a92db2cd22890da0965a7f824fdd11ef970f04fddbaae3204151aa9e9fb65e28fc9b1448fae1cec2db4d9e86ffa57fe6d4493b1eb1add75e04745805f3abcb0b029d58bda1237b4422ee9ae6e9bce34249d583267466342ac6d7196fd404023d96913263b6337c894f60747464a4f942e88e0c2890ac2648351cd2a2886c7d580397b18a5df1c40f8a8290bfda07ed900f42d561ef591bf0f4a549044fd13b04258de069a5f5b4aa4d085c9c767c59b84fe65a69099b216dbeb5c0c57828d1845aef5a6603f288d699c693eeece3f041fe5a5079dd1e0f4b517528670683c2b94447831996d3cc28147117d0381ed7061d4f66450ad668c81442a517eca05caab062019f98798018c41c032ac8cc9538af5c2c57f634939a7b9617e1bf5ca9c8b825789e47595fdb71ca3b7adc8b8a800edef0d4ac4007f0ba6ac8dfa6391430c6c535580ecd2378f5d52bd8e3e5b5ac278362a64f8f256ae60ae52996ebde9da6e02beb6daba1fb9ed2aaf45ed56a7ccca39b045798514260feab5c48328ac6a6f578c0323d82793feaeef9594e3cf58b0c6985fe9c0921dff918927edd9cc68726fbd16a42adf86f372a48c1ba814d47b115d0523eb312e0ead13f0c120989a103043ae7f9ec617b2ecaffc5418a2b3e4fe0be5539e90232e1f3d48e82b55596375f3415f93a49011f12f317789ee2174e0bcd61175fa2bd0ec4d35058dd7274742ff8d1419e4ba8a1f8e11bac72055eaac84d7e6e1678389f4d3a8a3bab80fd874bc8f6c82c3521f112e3f6899c84f5d85e08c53dd47ab372ddf198769207056e9c877fd7a7474aedf4b5b0823e4c3899baccef49630ddd1f356f9871d1e9fe79c62d9d07493555e16a7cebc9c73b534d4720a66e8facbf8c434fdf2e357a0e98d613bad5eae220dbe1c4e43d2f3a15f7f35c5621fa0feabc4f21759df9185fa69798475a0c49d96fafd64f1f6f19123722bc102cd12ccbd215ce30388067a3081246d990517c70a7a15ac60d3fc5eb67b9e00f1d8cabd10fd10acdb9a7cbbcd581c6284a2e238131acf1cd306878423c181b0f039878eeb3ff7e29b806ab69086ac6ad6e64f20bdc29740b73c349d0f9bce312530993c088d1b153871627c169f260927838dd574710134ac63544b519c802e79d621811cdd8a6b30d7d1813e80fe1c4bf315c0366152bb55cd4d560cdde2e82670691590bcc99b32e494c2177ef082133ecab06cf1e1afb6e7874b0f892f57fa645e4512a38f17c5b5bae4593f7c2bfc1cd251ebb53dfd8761f2e0ed934b2ad1ad617173643b738b91128911ca1a41763c1d5826b02427e983f38941b0048a338691d3896e90b47467cd5e14909abaed54cc0078e2e18347b2a6963c73e4b6baeb16d9e81c329d623178e68828159e9b625ddbd0b7b7e9303c849d076fe32b65b901a487eb8759245ddd75937de555e5eec6ddfd3bb442a149236d3d1c0180d8478eb50447862c75433d802b61a671e5b0325c0e3b01fcdc806b0154295fd574bbd4b55a21255cd5cc39a344637f76059ad2bf456ca529c94baa86371c6e5f228edb39cf144b0f142e63b340439f4c95534ad4c1b3b72eadc95d20ba6ca38c75f3f69cf88e89e7e119b2e6644d37d017a1dec1ac2dbf114cf9cc0716abfe424a76f9bde2c7996788ce9595b029cbe4eecd95d56e14a0eecd513f70a71b326360a73f1488be766a245dc37503dac5de857e8b0b57c374c517b7acdecf105c43c8ac4baa05a8fc38be235a6796be2ba6b59f2c0880a2a935264f78929cba59320ba0ac0a97844197f029992ee7193dc21f7c08451801e86030874516a064875b6374fa790e4209f550dc1a192b9bea88cd510bd872edb7d354c56ca155ff9597fbcaa80c588467ec9203e834797e2c03cf80294eb09c106809e75088a0d65ba3bd348d367b2f5539d99bbd5ab79c547a75fddaec918f050f4aaceb3886fab722cee08320ae0e109b969069787a894b70947fc6094c8f328be72b76773b8b3095b97433e01147928cf68f956ec1f924c9280a4549fb21c66a7e6fcb013be2927a6fe9e7517478a62af8a17a820ae133f9e4616b84e74de5033d2f9a639f51210ab0245c073077d13f2659fe3c223eabd3f8d1bb0e51c8d17cd8df79f7c04acd3b0762befc4c74f5e93e02f429a2998ca4548d1a6f6bb518638aec25740ee9868b1e1bfe873c035109d4f74362ea2c0e2ee1cb4175ee8335d806d7ff98c0514796ed077e835c1cc998d866b67716d9cf2bb96d3bf2c929fbf85e5a90ff6021104041d361221375a900d13a6e417d341943f63b1412d18abd79b15dc3ac98a70d8a35861d2858f0bed4799c82ec4427d577ea2b884b82d02e2b7ef5cd217d8d80c12256017b926ef623997a26c4a0c9942a890d8351169082bb57bfd0487f6940163043fd80afdc84ae1260e4a1af7da15b2b296475b484bda17b4f4389c813d877701499e74b44f304a955dd559e74b03c2f4f4a0d458759328a3c5d6ac55c154fcc9878bac41655a8cf4bd981c184a06edd3615136c997099c79f3085b98c272fe09fcab1873b730b6ec4500ff3c15a8e56aec50c1698a58670d91b694ec9e0d51a953f5b03d822981e06a2734ea1ce870aca5de472ab34da628ff4324f74bde0e63a44349150075270f8e1f883cd9119394dcb725ac8aa5dea6f4d2ca9d407a080873ba0c3ba3ad26181cead79a6fb0b6c6f851ab156c3de69cbaff28f66b0b01b291f2e499f6268168bd2dc6bdf4c90667712a124cb32533944625d486d8568ae0a6273d44c7374ba319ab471548c2d3cc008abd944b351481afd62c2e7b0cf178c3225f3475b2f36ca335527479ef2518092cf35aa19151e896a4cb16c4235a6d8222ada51eac795b3c20b00c80a6564d6bb41cb548a235178d11acb21ccf3daef045ec16f85406dbec99c01251651912b4adebc85a7f02cd7a9abc1dff35e2b419524e15e21ccffc9f7f8c9fd98301033d19ea4ef8ca4629d538b45ad2ae921bfc707faab883e9188659b594cb9e3d4ebd07218315958c91f8cb7f55a46d7a0c95981a7757d969983a3cc213887105462523df1a2a51e694a183008b267cf156f986732c7131e1f7bb0ebbcdd91efe17119bc1768321bd114b5e1881b92c1c59e027c60498ebb5faa8c76537390342a1ddfe7c8c21345c900dd0444a33cd02b42c94805df5d3a0b5bf60ef5b00a520620a792b59b4f4e25af3515e2013a396a58792916fd4993fc8def9e775b0508683a9d184a2919d5bcd7fdbaceac0841910390861500171d34d65fb5ec3a0523c81b01eb38868eeaf1b330469c67787296650fc46e0a8de57250bc7c04f0ba98e47066a0eb0ef491cb321886f0d9892507aadebcd317267d68c520a268890080e054ee74938e22bd0fbb9c38e705042801a77ac010f2548d8367177d34e5cabad509c883481949b4ee4dc4708a08cc15415d4fed06853f4ee64bcfb222173f4e50150ee30521d97143081a53f7e7569881d35f0d7919b06134cc24cefe327c63efff8b4b02af2027040b04e593d1fe6e8789ec8f8bcf5e616ce006a3ee8c3559477905af7fd282ff9ee85fe9891a88852cc660d27a3176f4d88ed9990af234533f1d0eee8785c9313c81dfaa8bd688b0f065c5e7ea26d136f568188d7bd267271b4ac1d71ec7c85d0eb163ea19b63e0e12ca7b53bdd2df4bdc891d2c930007e6573d726298240e49d73d639ce6b2d6123761770a405ec1784564a310d00b8e12d826e63067da374876c63c7b540e8986ef8bb5c140b87d47dc06abcf77c2785c420068bfab1012ad640ed82c1ffd376c9bb3affce635f22249e8cc1b15cd59cfaaedceeb09e6b052056166d281362a76e558a5d3a40a7c9b67d0bdb854a3e5acc1522b8119ea393e5f18aeac48461414fef070dadc38f775ebf1410ec4929466a68b14b5ffc8c536e9e075218eb698a661e53c3839b7dfc4badce7924fc541aec8ba0ed790009822abd63c8a9ca8dd959e8a006b8ce875f8af58b48b0fa5978300c320ccfb731015fae94d022f4fdcf61414307920a4c8a2540b6bd67ca04a97c60d27e11e3f0c24d4a529487599c384e789b49b1c44c73ee4c22f19416a3a38a751ebf6391621b302abe1576a5d2e5e4dcfd6b97751a86e26da0d9c15306732a936792f3dea57c95ff48986343294bf7eb1f900103ac351176132ca7e2703e9d3a12c9468172fc9b9dd23b15a0d40b9eef3931fcfcac496ed60948bd29f46673dba9efd30241465db61d273c5eea74bd41b8cb56123f203e1bf66a2bd4daa80df9278656c3940c3783aa8b854717833f5cd4eb79f3c8050eb89274a74e17ddf4919f29f0b85ceaf216ebd04275612ec577c9e77ad55c56891991ad8a94217bc6702d3249020ce3b89a9b142b4cdd88c19cf77159890b54ed70e65a43fc2edc30a0ffb5f3e6be06ca306da7a5ee28cd9b0bf562ceff1b53bb615172891643e42437cee68aa4ae7b0102f5987e3f8c7b08411367be1192e39ff9a5cd8db68b89889115531c342cf66b3f4c1b5593e012328484e44d122b26b18a8127c6ebb50f50b1d41842f4599d69d8425da06b581af0bf7c5770085f6b3d3d0e58a0407c88196800b44291d84ae02d4694c580e2f32ee04c11e9db0a23a75b2d965f4ea5c95ef4f4f6b341e2e18fea8f477853199acb15fdc52ffeaced8970915f28dbba2ac9ce373a7090847a390e7e99ab54c3b3d820e339e88f0e5505838d4adf5189880cae34039c106a5f83b0f5dec3aa1e0ef82b8b45335fdeeffd895b003c35758566ec472163f2c36d79150c58c0a3fd01edfa1be1745aa23a0ccc3d007b11bd10e7a085a0c8d0060e339c292d4eb3830b345e5d044d5a0c68c80264cc35c34445e726335a696ba5f7be5eb6f00ffa176d67ef0e6f73a20132dc1e1e0b287cecf6ab241ed0e48a67dc3bdd8c8d9dbf2112816fbe9270af437dcd0886f6bfd11d87927cf2cd0c1cf807ebdba09b52e30f66b6236fbcff0d6a366d955579f6004039851b9631994e648af5202e05024f8c6ec208189e8f9a08392107bae958e7d9a80dccd319122b1149cc5027defcd2f39646ef78f794edaf4f8bc2bcd2225e930896d00e4c030c5339f52d2131f21d3b88df9e0a46b7fcb83ede8f8ce644d00ca80eb359fc97edfa2c6532f9cdafefdd4b8074c4b6d74baa1760336badb0ef92be4b1e2a18e8d3eec9632a8b1978717bca51cf2c0250034f295e252c15daddc9853d935334c9e39c753770fdf6f50f542badbbe0e336393bb89e1eb0eea5c8cdb664ceb907aa745368ce26849509b34164257f53e560cd1d53ebe8e300a2a531c97b7389c52ef63194df6528672954a311759b663afd9d6993b103b003628dc2d318efce2e2f1bcc10ff91ff58346a72d83906d2362055306368a071f8337cd36a9f027f88a61a0e80b9564665ae426da89ef1053caff12f4426b2d343e7c08788b39d31e765103c1d5783c745669a4e521862281171ed9ff08511fb20ff3f1c6372662a40e2900275135f9907886d44011a53f91e350d03f7e7c8ae7539c1f35fa70e3b8509ec9fc867eb489975a288682446da323ab9434fa23d339a71cd4e57fbc26e0d849bf4491a6627b92196de99dcdfce8eb82248d32028f19af4221576060a1b8c984c51dcaa705bd677aee31c534168d899917ef842743fcfe8abdd5bc282afa296b5200fe6b24a8488c6f9f7e9492bb2815cea40fe8b3724767af51b889327d3e545894beb90ada542ea54971c4d74fb9ae9b0f09756ff04ba5da59c387b46fc8598ebe88a848717d4c2379fcca221117dd04f333758a5445568a0bdd8baeabbcaea01794a194fdd5c034d03a0d8ea5f30e99210af512d8aac7454995efe2f53c63a529c070fb3756c50afc284a7a450d250b97cd28d58ec4a98b5640fc4cc68e3957d07eb4009768027b70c5ec2714e70e7e29d817281e8f59d9334d91d69774a1c65ade75a89250a95f18a3d362c2e5a5511646ebb4fe8a1b0ce6584439159c364c7c5079d993d384468cbe0302b0a49bb436c70185f9788bd56222c2e1569ed61422c101adae0828653591f53a6fd08ac6694d542200d46e5e19f0a480c26b8c2817ed94f3ad736d340a8d9a8440263ecc759c55d47ce7a92c387ef1170b42a6d1049b9f56adb0a794c7051d203aa71b833bdca47f3afadf4670c66ff791c7fe31c999b8e22c2021d3992fad6f9be679f28e11cd8050b562f262a12aa6365939234cdfce149c11930d4d0e44be3c312407b22a34b99d409c14f4b5d80883bf8eca507e9c63e914b21d7d4c25c793d2097f4f480f4bff3bad5a830be5a3c8dd1342ba0654372ea5bcb018e8f0b262469997886bde2fdd24e2c17b24840b24e3599e63eaba7c56eb3d6da136ff1685b181595a2c9618388b21743069db435cb26df2de1e751cf809c3f686a5e9e20b57633cba7db00ec6b117d3911776684642778938fa5089d395624bc4dd31c46ee1c6b96eef61942b1d365d917c725e7f3f2006d820455876c460b7a2777e5695d9464b3d44806f4e1922451941fe00c98bcf9ddfa4c3bebd24fd712f1605b5030a8e50038957547e9525afac6516d5ce8ac8fc43ca713492c242b34487125ec6a183ad0eacdc7f8764a63bb53d5d7f9289df2cf53d85a9955a09e63fd00c8e6a53010ac129144e213aa9a90dff60897a0c1853045cdc0d35fc245d8741274bfeeee21e10239b01aedef8c5ad1229997e577a41ec5d1ba136ebcb851106190aafb8c5c884d3629ab7c4d3b7d94f9a4bc49039fc6453e482d879002a2c68d63a3786d8488863f28627bdf8dc7f94438ced2862036fb4946016ba5991f9fb637cc5eb93bc4edb0b3456fc076b0dac4425d72d81b536495bc1942fa0d5ef8ad87150357f6342cf20b637daafd67cbab70fbc5c0645c07c760a51201d0bff0f5677facd9e38baf731e92d1e4139efaf9e193c0c96eae5f7d4e329feacdc1b85e3361de327c66a6cfb55d29c219c4422917f52aceee77128f2e3db943d267db7afaa703c625ed68f64b0ad70422cdd05ca18fbee677420d03bd8dd429667ab88456c4ce893942ba1eb7f6c2b3481f7f9c0b02cca8f8a2bdd3658f5e148d2387ae2bc726fcbd1e2c0af716936a1f3207a12a87ebd30130455e9ecebed372c1a9a57070ab3bf668569d3225c504e411de210b07f796a1f0f8817b69898ba5bef2a0c2c83cc5636206c2b7e9481a56a28a5df1fa39c3d9f4ace8707a064cd5d8cab52df075a421b15f6a792d539ba6a61157a1b717582d97d18598a1fa10859043d9823f41a43535c8aba40d1aeb2f14087cfbc2aa7f32905f2556a6373eaae4bbf0d41949a12a4b289fcfc0377d5f1b673844406fcac7664d31b8fd46b37aac19c63d4997473c32a6b1aeb8956c4e9d104d9a8a2c6408cb91685e240f49eab5649dcf463e5992e8230246672fe1e49583f61e9bc2754b49a9b04dd85d55d1e701636784235c69e52e08ec21cc2111473c9ef0ed48a7a0e6619e708d1cd08ae50a78982426ada6d87a7f69355921b4f9ddac47072af633e07803e25c62d1d40ef2a31a4ad036088231a600f5d2a4c72335b3405bc7337334ad835ce9095d6b7b2abb6b3fe275dcd950facdf69050e6fbbc329a492124a8a5030d8805170726ee7e18c670d74e48a01a8b0fc982b0e36b1fb2d145ded1b369486ff2c1a37e457f67cb4c5b085abf55f1e3250fccb8a0746422d9cf264649f7e075aa2e12e7a030adfbcf53dcc7409103a412e81f7657f4e5687556933f2f26fb75e16762d335e7a6eb39f05a2088f22d1b37b0fbd30a801d99fad466b20d46a02a8fc96cf44e83528aa8f0754508154c61fa1d46f48fdf03189194c9424c6853bacdbbb2d0f022ac481cac7b6089edb3bb090e6dc6fe3fca6a2cf8f4143d35433d5606ab31423ababf9382e3bc1a0e48e35c980cbba01c26cdacb0b4a21c403e8823fda69ccfd8e23d5eedf7a4784b6de596c54ed57ca66a32632c089c1f786dd4a6a2e9aa8e63a6ed4c8dcedfb273d77e796c352119962fed7f335fe572817fe8ceb4e5cc0dbc2b32f4521a58a3cc79fc970fa968b81883f138015b94796b261a079ee744d20bb571c78069c66c62266091f4068f41c0d8d09c673f74c305c414bf7ec2f4f0a0db6708577ba21d21960a0780593fccd119a33b35c80bef5a0709e05829bc9bad2b375d6f2b55164f680456005ef306b60a4fb9ad1124e4a98863ecf46ab6a3cee6a253b19c4befb995ea862a58ba98a49ae8f1a7235bc33082be8cef678b4581d3a29a902eae55dcda8c001580cd778d27d05f3df5601fb7bc8b71a4d58013b9ed810aa1a771709922c4f8ca4e378459758bda4098329aa5f788c0e65838d5f4d79cae63f1153c5841803b1a6d0aca9c67c14662c57111dcf3643d7b08790678dc0739384ab87e2c452f201d0167cf57fca7e46601c6c438473be3b514f91ead889f201bc722caf09a5c7a5d91a45dfc627d75394c5fdd5561606a0a0c844df25123be54ebb13d8e09532e207dad0298e60d89b5dd2ca6b4afbb56897c8ebed48d0322da01c91625155e7ce245486b9486666e285043bb12ac30a3ac9b4dd2435dd5203ce988a603f9b7284580694064405b2ecb0898fcbcafb78a5e89d5713a7fc958efaa7d369792ed0f1f007954e00e4d8d212e2f35e4a7911e2b256f5e357e842b452f55729a7792cac00cce11e5beb573c887a79c228b6015ac1de5e974a7d9c5238d9eb2c4e114d8c4ddc429a8c039ac8dc8d0fb4d85dd90b2be7a2cf6951216e2cb7888014ce60c96ba144a207614fec292a9b8fdbbcabe44268f8ffa3ae18a7017216cb8ee7b2e5d44733f669b120df1cf33bd7a4cad4e99c16bd560967a571a6a8f96085045464bd60004339b3df41b3af873e6f31ee8da996b5128b20b2d8a9eca19e6cef3ac5af032e3ae880f8f5eea4fa652612836e5f0f0f9435541d50db632ee585b5e291eb0f24aeb4b140322d9628f49e816827e7f08db4054d0df241724d0c1b42c5ba42aac92d3704591b4c8a4dd060e9a1047eaa8909686acf0b73932471ad39767f3bb6877f1444811b1e24f14dd28008f20b3548c605805a1b76c922e55f6fb10142d21a962a64ca39e8f964f8b99b0193e8be9840da5126355d02c5f2eff206e300c9ab5e912647217b91bff4131aa3c4f2c7d29481daedc9b7f2b6af477c1513e9c7f2bf08202d815ddcf13f50b107904d4be7280d24369faa2644d539749122fecca7d0135b1a4b3aa9ed44e7c88d471bc16897ace28b03b009bf18d3413cbef7547c8a4d5a28f4a4fb976ab5a515083221d4a79fc053aa81a74a3fcdaaefb7d4dc6be4afdcb33b1fda5b27fb0fbaec2ece5111d9f0cdca5a4b61f32bfeb1bb6e6b9e3ef0bde9c6a1629992210e88bd39af33285c9b36185ab1213b038918d6a2e0013a73c41d5aa0c6730dbe22f2ef80c38841ec49c661d8fd42bf0a3f8c0344d90c32a19e1f8dedc624aef1980c6683d41699dfc2404314800064dfdbc05265e7707f0cfe1e4abd774dc4a6d8048703281ebeefbe3aa620c020ef525b9b77c216f1e5a97a60a8050fca46133e4dcba3e9a78b566dc6d3c6e9a4987e7f2132aa21f1c93abf2ca3f84de39ac3eb93240d3389c02256c3f8077613b64b64a74d52bbf39998cb10e5f8983249f6339b6aeced88af88dc09f261ef6a8c6ec112553372e4e95cb360a76b29564e0d881c73900e34884dea41c56e5ba3fa8ecf0b93a48ec643607cdc8f7581781268c0a03949bc3782ccd72d41b3226b6477e5c3a1e9cd9b1876e0be523806c76c1e0387cbd75f4a1b0a1bd1a2e05e97a96b8d9e8a7558aa086ec255f281d1ff0527ec5f6525d5154691229d73282a4831b13348694a7d83d504f9b96b0647a62a209d13b4eb43010b989d2a43add2bc37c3b1d302f9439b25ff840f6b0894bb9a214ce2ce68cb18af7d4f580f30f1e1eb914d87fafc2dfd042cf59868e998078e804f923930b6e9bd8f402cde56a20e6f617f6122a00a551809d0ae3fbc3aeebf7b1579b797feda26eed5d3b715f7bd497e7af7327832fe13928b40f1456434ed8eba236e7ccd3b5ef3180746e9293960bca8888f8e0d7063f25602d2160a69c691ee1b0e936133546d42fd72f1e906b6244e9b550942ca607af4aa5a6eafad1ea2ab8b220de1bc6ae8c159ae97661932b6d4d9cc1bbb31c2f2d01ccab6593a90f2d619f19832cd940fb789336f373a6d9a9b4998ae365d24939d4e23f3a80eef45fe217354a4af6ea773f204697775a172d929f7e6c88ddb157d6111a7efc2879a5df3caf8bc913d4f90333b11e7013edc3fa75bc34fbc474afd58efc0ff277cc9991ac50a075670e706da83d0c17fd741a21441342625a53f81bfb6118b84010e0c71b76455e1498acd9d03125e2e9366b47273e1d4376a96cc9727f35245809f5c281d5d89fb0022b21229aa5bd01f02725cc668d531ef8d071f276613440359b00cb354618f3325cf303b53a06ac17e3d560393177b741db46a0cef3243cc4aaaae4e8761e5bd5a77289f53d5033adcc33f904a0735bf841a29ec5ee34f782f38c080b196a5f40c5f3c559440734db4ffcee676ec6884b6ee1194b029109d889e55bc7528fee30a8bdcdeea1a67d506ac0350cc417b124bd3f3491c00a5915bfe30ab7df387117a661943b0edb0097691552fc5b7017433b5cef496f3a01c2ccb75a3661418090e9c762c29ec25745d8e0995399dd62da6d2311315589d0055be2522e0f73464eedad10cac0bf415a4b67e5c79ce0308cb113c324fd429b1a1061f69d0e963a682ceb3b4ecab1f23bafb444dbbb92331d475eebc40ebd926b3b10727b01108f6eaf11e62b20ba4f5d35600813df16629c08d76e5573ee34d82362120dacfae281d4b64e2932af54f44abe11e80dffc49dd85ba7bbee967e3858c47d35c6abef32db2391f3a1a57afd282753fe792a26bb806c23de21a03a074447741adbbee4da1960085b6eb963fa847540c54c939e3739c64a2688f367c154de1db816f6d4c447c2751008e58c6d690d57e00307f81f5a60d7c890ab9ed7943b8d54806dc09cf93004b5702fc3ceeb4fd6bc66b2100dc508c1a3631c0da5696767438108974987f3dddb1febb61a0c4c9ce3e013cd61980a03b375f0772bdb4dda36b1e237dd43ec0d53cd6784fb71c4571efcc561d089bf45c13d8ac156a16bbf662efd3ef3b140db71cb4e6ae755a698129dd1bd588d7f8a61a31d1d81b26fa13f5f034a50b9c51453c416346ae7dfbfe5e4914291cedb2b8143464d15edff5558d0d19fa29dca01940ac0134e4a07be2a59eeff71e196587c8180351bcace52c869ef55f5c4f19d30e5e7c75019c03bb77120ebe85d25d9acd0c68b59d21c291922880972e2fec9145f39b030397c2b7eceb541f870a84b5cea6b99019e8fb5a8ddf1a59074c7b22db88bdacec31ad3308c8e9806b0a551048f171a1ffd4eb98ddff97091b5c1a33a1fcac9e5e8970b777e7eb405369979d7ae39474e02505a0a9b0e396d414815f530b695c84fe0794fa02a0535a8e9e2c0c528721c69af9c1166dc588942e362e51ed2df4639e4fa505105eb815ffaca039611f8676a4a2c578aef30dc9f7cf569f2bbf05527cce62800854102b5a90546124a1f7f36b723c6dddbe81106399020d00d3eeb777040a7423ba22d509f50d83678920ff1663a6ddbe772da78787a608d73556459c9dc3b1b0bac2b27a62346d410465ff33bfe12c96e866de1a49fb8b22f1000b14e239069ce6eb932b1098caaa81b4ebd20aef222f96a5775b520c64540662553eb01b2ec8508bc595c764f98ce24fe47280f892c87bd0924377715a986b802fe4288b62522ed05e5724f462315f3e50712e64a88bc5caddfd2314b99612faa4f0129ddb9e88210545782eb1ed59b39a48b663222ad6b6a13255c599d0b046949c83d2e78f42442b89d6e3ad96f7108c1957105e09f7fba66246f4b06550214491dd72f07de800502108014b1e725d3751cde44a96082b300e6fa4e80be2533ef0cae08630232b8d7308e64bb7c252273d2334aaaa1df6d79f54417f3c71401c44be8368247cbdd3da177816b67da9883bc140469509e3ba24b77bd768b25fcd4cc9b499c09ae1719b8de861a3851d8227a1d2b421be73ef395cf458b5fae778a699f7cc759d27f76c3db1ca0af36676cfeff164802757664beb510b2589fef01b4c2b5610a5705488ed015b014840e71fed713ce8b3b3c133c14c4f5d80ed27d28b6655af7fa75a82a437859d722de6eeea48340bcb50c644de4291f23399bf284aca05da6b479ae27612f20178db75e94e6808ea464c05fb04616293dd8620fa50b374626355119cef9f41e6fd262d1398a841fcf16f2b4fd6586284c6d43e2d770f0d06b56ed8ac25c44083035b004bb605bd8f4bd434adb81e7407640e3866b3521553400fb597441590af72229026020aa00d6d968169af71c74a705a52c975cc4702057218c25678baa96e57c8604fcdf03a16c0fe7b1af35e0aa7fdf953b185065ff2dd483ed02f2a4ce50d07e2ee3d78f664a87f226270ae2bdba58148f318524d02ae26b3ac29ebded7263e08d798f53a92e7c544b083795e1d01b1cfef6389668fe2e745032dfaf808561f597d10c81b44d6e36ea67fd4bc691864fbdd725847c1221e48dcf7a6296cff6b2d2c3e91043f923b275095660a13d3220e3262dd423bcc1a4d6d831ee197ac81ad78593e92cb99758eb69218292a0530f5661999feb700c6a1de823160fbd8c868da7e0e282d23078f9e5462510b8df33482c021b03b9dd09023244b83b081dd3a4eb9beb9f0224c432b0d916cb3c889169a65e3a1e6a08bb8c03b47fbffbcc7803e87e91cd3fe063d8b5edeea9c9d863344e2dd8b3490d4bbbc848ff0aeeebd399c51430277e81c8c7f0763f41b9bb7a19ca32a3f9e72775325059cf6ae29d4216f8839e71465fe959d185be690cfe1409ac0d08032c41221073a66aa0c9e774088d3eb6a4dcc1193b07bf974f3e94ad832aa284364099b8d700795f521f7775b349bcee103d2cc9a357ca0ca2927f1d3b3ab1a961af76fd76fea3650bb8942e987a2d350deb3d529cbb285df769289be813f83078490d77ecd7b65ee769cbcc2c741f094db7fd5509d2ba268c0c88d8360af038fae9f74b7a1a0e2c36aeaaed3c373866030ec00593dc81bc8826c54007c2dbc69646b1d4f9fdc64d26765a4f413cbebe097e2b205d44611afc40171c8e64005785fcaba3ab0037243e88da200c58ef5befd7b3f4d4ce5ad0cec068a10a993d61b455d71b04d833d0b6d47fde4f8bd1dfa548e796f148b52d15ffca7c5bed40f9a0b5ac6aaa1ebfcc8ed3fb0bd771d627f96a93ea478d77c4019fe1932e82ff90f1ead1dddfce1f1fab898497ae2a46f44b776e6c0e06d85137506eb0e1569025f8d796c74a488ddf76c8fcc4c7d128cbb326c1bd9c59a0fd25944c42fecaebc91a625508cb75c1753357f9bd6c032efd5533506b136f0252493382c7422f6f30177c4fd8a5a7208259b365a7f40b8b52187e60f84f2f38ae4719a0174a7d6cb4fd944c32fa9b90b94053650e89ff6146ed401564b2b6535c1298c77ddaacd5ec28c4e55b3cdae363852111e3f0c4551f2298a4a1d5ea98502bde80d6664588d40666e031d34a3559881abba8668616f8a0708e7b98c18b371d637da5f112c391c6c75013e431862c71ddb6848a19da6c8d05c136c955eb799aa9f60aafad1df1cc16b7020e667672446714ecbcab352802e31c6f9d8f15fb51f5c12c7283d851964cb07305d6d1a6268fc537bfc7702e0d7f9c5294541baf6aa4c4b1ef91b01b3e782384db6470fbb2cc2848ef96b6213727ebe8d2f8443ca908852d17cd8e391734c1b7e8b5ed9dfaf8442f94c865db319704a2e2b1701370f020aa4ec4d422dc3c4f65ef3fd87918aeb339aa85e52c6d562d234a84aa1602965538342a0795611d1398c08e194d2f9baaa83ab97e43cad5be9902c38a1d9bb5c215ca8a0108cd31750dd166878c1b11e156e544e6e5c324f17049a109091a1717d83f67e224253e49a4ba5ef66f761dcf2433fb942bb65a28c877cec96054e8323ef8e7d99abe7f9e0f08dcae39f73569478087e7d3b3a6d32639789d501c626751b5f6478283edefd736f0bb46b31e2c31a9d5ff7b217580289b77171bca7b518d0f005823eb4d9907d2d499e843ffceea50332491250005274d74fd767f217a9dc4807317fa26f25f5d45bcfd41be4f420523d18697ce665578f3bdee2e4e84b81f1461a6885fa6087ca5f8b8720bf7e044c36a7ccd522750b5e05e1fc98fa830aa2bb48247c91cc345b45146f1bc11705a8c1a5c0cca6ead9c7eebd840bb6678bdbbfc18e81865211e0976f2a189e427650316d712d83f14f04de1ba9b582df285e75e6a257c12ffdaa7a48a27c4cca8c58d21604c48f08aab3cf547468bf088778f4e75bb151969075d2894f9d334c12924d690b8c231c01ac55749c964036a5ee1024d34d9e927eaec4b7404f91dcf5b7f039376307cc2d33265027e9256a95ead74449fc7a00d46c2c8d716fcb5cb3887b0bc78311b3fbca0c08537a774517902891c190480416f2ee9207af68af013746ba64cc45e85d346eafb30e1e37b1074202470f09dc792a9d86685a5dee7e2743325ded5a2f186f65b371974053579479fb5acbab2b2ac496c6e44b3c237a0a47fad7e22545b6b1d3153acca11ada2f0413461626e2c75f979151d04d3361367b1e77615be0c5996a9bad8432b3207c2a3d5b8a212ac4ddb6325b80bb9573ce5957ae17c496b0052df28bf9c30fdfaf385cbe22d19ef2d9d114d3c2f7626429634cd0a7d1700b95a2afd43d0c676ccdf8a74d80a5115e88a7215ce321776cf2cecd92c33a0862d178d3a2decdd7c9c3ab71db714df5034fbbe9a87e8cca6e76ef33ed63676ecfcd17420a01d767cdd5c3936bcb2e34990bd12d053657f289e67d6b4de80714418a9144592240d5be78016ddafca4aefdb594ac2ee81ffd18f018b9c23652c99748341c90a6395e64d07a01fe3747ca2a6656b094891c00c2071b5efb609d39e0947a7c687ca5f6d3af0c2ff71477912724b38616ba099cc9344b96b15d5578c462077b2fa782455b0afb0dd70eebfa39e1d9b113a2f82cade5120c6d81d80a34164befe1675b713fc41a017c2051545058823b381d4dcc6cbeb9a7ca38800fe15799fdd7f827448697c3dde934fe4d245c87b47fb907c0e7a715dc16313436fe1ed256bfe713322be83b7dd508cd0c34b4bb275b84b9086c2e5700f9957d0f5b90cef4df1fa597232d6016a565805f1c6d6573f556dd4997b00d53fcd09fc633b8d1654d1d579a7bce1304867dc08e9fad6ec932e650cae6b3df0290bb1bb2d2a4419f9d7d0c3e9391a31ebd0113c89d0e91fbe917aea120455b47fa95bb4e1beee089d7ad68a15fee9c53406e40097436d93206813ee60f414bf0e04444c391cbb8133097bdb9487c55803535eb2438d6d8066ac388a45655c5b5c84e9ddcc5a8b23df5010ba36cfed4e5fb8b8c2ccf6c9d3f89079fc6ee29785cb5e774884d315abae0a690928537755fb2b4a1fe166ea35c8aab8c3595da9c1e619288f85cd52eaddf932e4fb25f7d716e2abec13cce0d2dce7b92eb7963b70f5e460e3acad36eeed193ef737ede13a235d5c580da89801cf59ed2076b2b35a07dded0a7d2884c77dd3e09e31e3643a942ea31ec5d5b39f2daa8b321106b5ad2fdc73fe775919669cca4c5268e96b452d9990dce6381bc2f86dfff32073ec08597e13f5c5cf58930f105900433e2881d41339c537b0bd422504e87a3b2241f9db0280a9bb4e205842018472fdc236b746279be88700bf73a793526032cfc73cdae4aab65e6f750242a33a208931dbe45c56c8e4c0c6f4224ad25ce45685675fc06d0c550f64822e1601d1c400b9e961a48fbeb70bd5cb363857ce3a91708104c0f9c5bf93043f789c04f0e941c537822ae6acdc550ac78e5c14ce00a95e8c4d746be505875ac9377fe53d6ab8e21d76ac703c6098779f7eec0f658e21da8b0e07b338ce61ac88aabbeaf5499139932498a25a1a5c2e717dc74622a2f2d309033458a95b748ea5bcc62306002684701b4f69d4007c0c09813dc13219e0cf09070adb3d4e4469ebb17c5877195bac28f143d073687d4687e17216ca1a553587a81443a4068bd17925a9beb2bf28ddfc66c01bb439a99bd2fec4f0119c7c2bece0381afae1ec0ab6a48d7338bbce1f95b2ead7a4a91892433a69b197e3bcf9202822774bdbce05493c83b300ebc74881cd5e547fb6dfead01d9e285104d3fe8857dd228f0aaa0b545b8b1220d58e1310a399ed479e29e3c0d165334a21a0d14b848af35ff60bf2aec8c9e2d03cf0efc435d53b6ca141aa7e0e82728710695168b1b219ced6694cc7346b91d33de3a2a279c3d218ebae2f955250a8891b0094d2a2e95d4dc436a6280f651d1bd2ab401f150c5d0a5202224f82f5fe5773f24e04a3093a86c1099ae943d98e77e684160a824fb1afab1d01712a2f56dd2b80ce5999eedca1c80be00941c0d9c07fa2850c7d3abdd85dc827618559c4a560cf23e0a1ef631745b892e8a66dc766371556bb24df30027f5726908bd7f29dff14086f6111a7fda590c4686dbf32c3d251dedd30aa4ec1d6ec472735d2d3283291b492ac9dc9f7d321a7456ec73eba97f30c7e3d40d5356bbf390cabf1fbb0a6d8d24a3534228f68a20718a3f4b03621b5ced8b2560c1f694c77a6c89f5c93cd32abae379c69b13ae7ceea6cbe01ae32fbae6f8344ce8119fc4a4ce63afc3e04431b42867b529cc2f608fbfaa8df442600dd1c3d14c2837111bce6fefcb500fcf1638bf99a90849c4324a2d1d879605db55a659573502c6b6c4db689772ecdc0496a614cb81e437af40b6cc356c3292bfcbbf38b97c36a69e901feff9d631b7ac8dca7003784a09489bc566c95b42e42143ef2ce8ad0cfa38ec02f2915a6226e34ffa408547263c9868d12b089627342b2dc5f606b11da1a5ea4ac4c1bff21b428c150b58b0c522162c63c5022b6cb18805cb58b1c1024b2c62c11a6b6cb0502c16c44a251b84861db6d862873596c4e26b1e33528543f1d528b48f79e211c54aa59d173f6aae72a99ddf479887a6523874ad992597c2317aa14728dd77a2a566c81251930fa5924eef2d88d2323915db8d4b5c62e9041b13b2a45c4d1c02dd00e2e5f0a72d5cb25bc25823805369a4f81fa6a1971499669f96b072d602bf6cc9b5261f91ae94e0e71f724b5688faf111742921f6a168494af231adb492c1c71ce596aaadd56347d14a0a988f4525446919bf6ead40fb7737a99e002e21943ed097ac0e1fb873e03d3101548d02ca91e9515b3052b2d21ca92a89a8a9b2ea4d808ee6c7e2a69da29da0ab6ac72a9324db4464156634bf77d39e28d785b60dcefa033084c121ce518f232b031cfd1edabcc594e58d04afe4817edcfd71104ac55c6c7e1f3276131112da44ca94520a050205150548760acff3bc25f67f4ae93c1fb96772cbbf2ede77ef3ab0a52882eebdf726e0852386514a4d3f3a70e4b11173b05da823688e4176df7553abe126118c1ca92e4b0000828bd20e5e21b46000971fa43ba6ba64bbef4c201147b9a88210be31c13c6343fd850733a620878c603c04419e7ec8888c11640e2b08d2f430e010083220878c3415f214f2f808fe461a08d2549f6fa53e1ce5208830823ae6f75f1b4eec977d47db28ff3aadfdc031a788902113e471d17f8c43ba136a68b8eca2e7750f0d6ce0d45bfd120b1bd04fe97c1e1775ccb00163ce490b2b5444c890faaebd67efeefea5388e9e8b47ee16ee10d22d7adc3966c058d53221b3cba418eddc4b52da025379665a7da6946b1010100c634f29b1da2dfbe5c4f5e2e9b6f6c7e59af81ac92ddb49872cebef2f58eccb464245c03d1c0722bee348bc6e3c4a4eba7e69e84bfac5371d06a3fc4f2c6bfaf2d3b24c63ade7a9526ea31f057be33aef746ac1039b6f40916f80f00d50908bddf4f532b5e94aa5356e3f3feb64dfaf310614c4e707e88797c03d9871a8bf0ff76cd79f04ee6920a62c5ac845f614d4408d666a325becfbb89874272e6cfb15d83f06320996a89f3b261bd77f7a38d71d039db451c44829d1c48b890c4837438c2294d8410923295d902150da624916465574c0c2e4ca1248bcbcb0422504b9c96cb14fabe85c57302cd3dec6457f0c2bebe8221ab6b471f71f9d615896fd9817cbb09b7a46e74dd0de21ac0c1cb0b00169fa0e1cd29aac80f44ca0114f620c2fc8ee3dd048025c20bb9f540af6365216fbecbfd0b88de384ec1855a98112b769d86b3c2720293d000b734617f9627d6db4000ae2e3ffc3cc3c328dc1be64a4d20663b2a3b3fa0102e5fa0e124e4905a21ad79f8852eafa0b15a91966e33a9ccdbd0ff06e87b55e0f6c72ee309333cbdae39bfea4cf6773ae0530fdcf3ab3c71ca4e8e006561225d020dd892b50ba3863062f88818474f7a798db303643c73689652b481021b1ea603acd4d11d8be863ab89e5af033f26c618ab32891cd3dfdac858b162c16183ac08bdc12450b97d175d8ca1627b76996699bdb074111414c61c2fae1872548e7c288e845449627be2421fd471ed75aebd6b271dc6ee8b883e980740f7afd85784e9e93c6d6c628c56837fda4e96561a98b5ae536223f2638a07bf473bf716995d075d4c52afeb45a3fadd68f8beb6d0a6f4c7220931ce8e4060e999090465889dcda072e5ed0813442b31083dc4229f38db0decd437582025bfe3701d87f07f7cceb37235c4fc00d3dcb440a85284a122a2622b20cc3b06e6acab22ccb3ec6e2ed842dc75ead344debd5aa57bdead518e43a7347688e208490c3e33ad50bc75151e8c52fa1b933ce39bec6711cc7d1a8c3623fae3cb3c4fa330e2e00fbd94a29cdb00ccb28f5db3d69a536ac695a054f57268b2da206de19e230533e1c36666905ae9b58f2128b252f75fd252e7644dd3d3febeeeeeeec352661b35cf46fd393fe61b2cb61e306cbfdccee7088f5626738a43613efa43aa4571345d44c9c9c68608588b8e831554c2694cce5665f7be5621385bd24868ae9fd60bfb28a564458fbadbde21baf8151fea500aed718c2faf4252e8a8e695ad5b4aa69a24daf7a359385f83dcddbf81bdf0a984980eac9992f09e0433592335ff2707d20934cde0099ecdcb3f1333642fa47481bd67e609337c0182af97d834f6e3c0d38a4e5a08c29240e55256ffc0722a1f9ef718043381e0768c49d7041829452f6d56e805e047a131ec19f865984d281b8cc205837bafe1df60173f6cf9e4eaa5125e2fa1645368254f770135419ac0db7cc74b8fe335f6cdf14f7f42c9aa8721e71fd59c06ed9aa79cb2c858de13f5c16b05b66a923907098a5922c0db13330ae899d5f6263504ab314dfb80bd92a234113dbb7cc52591ab69b76d38e7a8e65a94c952199cf5aecfc6e3133a5592a4b55a3cdc5bc25c8517e055f11a483d5c18de38de3bf74bac2e868b5b4b4b4d4aa9522d56da889b0c20c33482373061dc8fa5bcdaebf0d17faa33d6787401de8d77efe68590a3392aef6fdda6b3e6260fb6a8fc2ccb2ac9ee057fb4ffb494f59826459a669956b9b702800161b37706519e089ceb2c694a0b1b527f364c67230ac874b8c252ca7090fac7372b44c889cd68f862406ab1d1cdd50bdc0e8c973f29c18a5185d8151fe1de4a2077a0891eee1489a7fd01dc310bec9c2d2c7ba1bfb12e66e59b61d19b202e64f87a42044052122587c44805f302e5d25ae3377c6212b9444845c677ba446328e7367c8d2b8340e595a1ac7919786bc3c2eccc35a5a7262b2c4e7e34b72842a8a1440415c2e97cb05a4b45d09a1b36ee3e2139613798c85f9d3cf13c8648c5f4ac1264f600c958cf91846f2f4322f03aec023c480cc2294dce53208be430ffc017e828293a7b7311f130e29c00464287516e4d11164c33a51f361401d41f661de863e30739e42a08952b90ddd83fbf975a2fc85ebdf62740fadc35c86aaea5a5da72ca31ad82ab06568d1042dfab70d8df2c75a8725faa10c8c6213886ce0917b744f3f07effc5beeb13d7d19d6a94fff06eb6825d0102ec88dd3fdcf1d202c2c4f59d82a1bd11be748d72a954a3577faf56ad5ebf59a3735c755a93c3ffdc0dd2d5e7abb395bf3887b4c4c704f13dcf383ee010269e9228cf2ffc8b03be8da38682f4716063d83ebdfcd60cb3e62c275e6b77f877d74ba366cb036517c4022dde90eee71ad8942a23e4aa205057684c4848b5e4e3ed8b28f7e5c649e199665187d6bbfefff8f8eba2cfc9b94d299837ee6b9896bcc094fb0f8ce9086dea66aa5789ee7bdac1934b6ba46e09980cf799e93e6502a02d20da8d01c1e1f48767696733d27d386c8c971b9ae5c7f4a35ad8f60947f1354b096e9fa37153e037717ee2ab8741eae3b0e9fc360d1e81e985ade979da5fbb2b9b8fe4ce5084b858abec21bcbf533ae3b92cab2429336ab3691292cab176a5d587e215d7d3a258c36db0549567c53f4b1d52222de7e0dd4315f7b2ad454b45c4d6c91165ce466b025bb302ce36c1c473a0269b55c302910b2b2507a55692c945ea92064888fe0abee4155b825bffedfa751fe4ad5e7557051e8a52464eed821422efabf58452ba279820f037e20311292017e003cfebf57ab5ef5aa5740808258271d6af00a230582125ba8bb63d8cc18a6caa8c04eeb030cd40c747fedc282517219d7bf83c1969cf4415c87be3f06b887863ebaeb4c1098e10f092efaec7cdcf3f90132b1a794324ca53428061912cbfd87837bb0aff910be4ffcbeeffbbe2f887b6df202db402765b2585b637030c8a8bb35a0af56ab86d51b90fa094a29cd786064c462b96a522a85e445c73bece83212a1b411c675b5d62ceb9e0387ba0b6b861e4823130552c82e94b27dc7158a2ddba8a7b052124feccf9d9ed248384988432e1671d18dba478da1efed29cc4940e182eb5f7bb065ab6e0f1969ae69b355592db2257bd99e3e0706690ee446758855ba7d6f141c72b1555ba8f2d2b7c8dcb12915521bf55100a0d80d04b900678075680e92b68d63cee7297b1fe7d1341e8d47ab13ec3be79c9a91513027d0048a4e7a1056cb0f9a0a1955ec200a1ccc39676be19ea6405c742017667bcad2f7f11926b6ef13d593dd3fe9422047b596ebdc4f79ba5d356e65269ca0799a66e2bebb01dcb671dcf6a3c7372ed26ae29b9fcd4d585634641560943f8f205ad85148885f4a5e459b204949419292c614b00034cdaf937588996575c5fa4b0d068dada00f8dc5b0253b330ccb22d055aa608f6159773767180df2ca6ad071073336583f4ab339338cfe5743770371207c33bbd829ce3927cf3aedfce6cfd0d988081a5b7588281e2b5e5a80cb33c725b6bfa938dab4a6b58d981519115161d825c432e221c447613107614b767d73a79b18f110e2a3b05a1062dd9a84d584ab10dc53b89ec0967cc67db9805c2ed738c467bc8478480a169f6174d4ae0b00498002ae1bb8c6711c6d4616cba8ca8d57172a01d4e0ba82867d01a6b1227307018cf29f9d8499d22cd6052ec23d5b83b19a241002863fb1250f4f0acdc353c48b172f5e8a68a971891d3a1dcd7478e15038846d41c680813a823c0e876a24b9a207e490111318a414ed8d340c4cc82e94a2892e3ee96e7f7bc13b216094bfc5a256d12e84a12ad281427c048bf55247e15fabb05864e9c22013b5d2999f10df65ee268d82eb5d425b9ead6ba4cdd4d9aca62558a7ab34142cfab78bbb65233d801ba986cf676a600bd8e5421df39b68cb7ab50469e54a42aa5ebd72756a8dd448271898351e4dc3220c931300ac5eab1915d06095032ac6256ae52dee45355e534329ad29c7711c475ee2799ec7c57e917ab972905a465caa8436ac68286335c69cacd50e4c69534ae916aa22f32b90bf2bfcbeef85581f47f5ab543c3ebe4fc98a86ff39e9cca1f48bd1184a7278c2dbff53ebfc1f46f977a88a816fb629ba58e18089084c1415714fdd727df6f3e5c026e7063249c45a6ab988584546474846472ea416ab68eef05cbace64b75c4a29f1b33729e54b4546454545ad554a6b171551252ae36d1bb1bb7b3e9df9408334a473fa173c565f38d98af02db3e3baaee39e72dca8715c2a0bcf1dd3572e6c9723aee8336612f770dc23734746f9fb911b4d2faa2abb22ea2346e26e718c17762ba1bb2017813a95c437bee34a1c05de692d18e53e441104cb4e72959de4e2240deca5e6e2a212967a4b576d61cb5e25ade69c6162998bd2d8585c4c9ae101282808c6e556ea7da7795ef7682d68d083edbedc38d9db6967d6755ed7795ef75e67cae1f1d1499da46493d07c1fcd170e7d8f23643ec15c7ffbdddeb7f75d1035646cccd49059ad56dc7baf851fa843e673fc119206d4c13d8e3f42767d63ae3fc3c0b80be699b76d46060cfa3e473894e3bfe7c0209ac7110ee1789aef72e0d011a4e373bc8e1cdce3007504e5781c9f0307c7cd703136666ac86ca6126edce0ba991a32366cccd490a9211313c3bdc695393ef3c3de827c694026614016b05bcea2d28f260dc7715c97655db771d486df5082d5038dad9956dba866d6d4a87a06eee1a371bcbeff90ef00cd57008f9a3030ac569a24ac115063c138f44b989a5bc3be6208cc2d7989fb1a1e35590e0eada19956dfc7bb0e886ffa37d16604d229f9b651a4e079f13fd5e21e916f9c691a2356e78ebbc0adf0244de338d09136d08f4c2838d952f2257fcda389345bd33593a61275d124faa24a7387c925da9a3b4cce967b99abb9f4229a2977777a94e4e219bdb0aeabaecb64f1216ce9adc71ebbdc6a62c46dd38f5619b63ef6a5b734da4d4d4cbde52dcc0877668d47d3aea4c06082e6057fc0a7ae5633ad42d19a63d2313333f35091148204f1e48cde9c73ce19ffbcd37dbfc83bdcf7f738797c4870f1c3b0cb26c7c2d2d0e392d8fe926aee537847b555d84a5c74b06bccc096adfa5e29e19c23c26768eeee9ac7e58ce9f263cc3d7ee7ad20e51b6c260dafb57a17aa6aef98d43d18582cac2eceefc1b646450c368021899409a0b830eae393be4f9fd3a74feff93d67bb4f3ab149e7a4afe34fa99534b8b8a5b517081da44812c556440b76a84058494307499eb8e50e17ce80624ef7769deeeeef1a1793a67ff36b66cfd44c8771d9f949a8dc72bcf3e7344262942589177509a52459688c48c2c5490e52a48c80810b4cca97ff187e0ace293a4679ce0945aa09f5f921c1e7c75a6b7f4860241f127e7c7ebc3a8e3c3e9c504272c1086bc5bc2c0512295b111e5eeee61dde857af3bbb1f9dd9d7dfdf5f7312a7becbb0c9b979a4ac07ac645f7ea9d7fe79cf30519dc8f5ee9987b78eb7ba49b02fff64b8a7d77007b5a590bb9ed2f7f65147f16623fe79cf3c39e520cd37a62d91333f69b21cb2dad972c78b0d9652b5fac38f2c41724296430020d1e8638d2440f43f4a0045fbe28b2c19dacbeb8ecf77fd9ca1722ae76d9ca97a25b8a2cf8666a320df32f57fc6de74006972b73d94a1a546e8ecb56c8504273987587c751b4a4b4e4b9f47974b0773ac3a8cf92ec5f1642b3a7a0fb50eba27b586cc9ad9c925d24b82a27278612dc72c7f5993b5f1def984f7b866bbe98296a7f2eb0d873e368356b1c7e2ca48dc3ef38740a50ea0113714a96f99428dc2393d5db4387e2f1d32dd2c96a966518a594ce2ccbb05954a4a45d7fabaa354a948e2ed18ddc272ab62998fdf4e6d44ca82edcecb38c65b3b036eda619fda898dc5d77fa12b8efc05e02d27b02999c3f7ad5c4ced057cf71ab1a5828c82e9792ab7059917002ebd42a5954e9becbeac6fd7ba6ae33f9b8d7512e2a6c2a405ac075fbfd8eee09f6147ca27a127b669d1a2cf2a358c7bae8fda2edf8f946673e7dd6e95cdc711d64d13f0bed44fdc096a35b8b346980c38d511726312958d1d0852d3be54d1b47f927bd169813a53027efb14ce3adce49b749e789fbce44a949a8f986dbaa9661d549579fa0b115fb56c9a0ea1ea7d3b541071fae7f67832db3562782fadb979dc2545898a9cab065a7b8a71f5b9aa872b62e0bf496b3e53ad82fcd9d1a0ed577d64dc1c5ae464470b26041eab693cb42a64ab2f5a852516151584f816e5160988a6f9c04443835882ad54a894a2995cab99ea9325545f264d0554a65b2d86ec23b9d9aa88d7b26f7f4d36024844f8a86d3e5a426e280058630c01ae0206274a1946a9aa6514a6bad400d6a52cf9356c320444e44048488a8fee04ac785c9f51f34326acfafcbfeca69cf812d60b7b6805ded69d52a51c73bca66f5b06d94d63a3b0e095bf24b48072dd01d208df2e72b5edea897125baf080402aca365546c992f21564d5ad13082cb064bba7bc290d9fcb45aad56eba74271cd6c5bd1cccc8c734f50110404a3af652fde02c36a75cc9bc9343a4f559c539ce214b9aedbf8a6352d36e2d778265c8a4d4a47c0eefef509071607677a99385e70aef3e717c78503e4402c2c350517471c0ecc4858b41d6cf7621d0161d30fcc1444fb8f5a4a77f860305e6f335e7f1f2b3c5872fd7f8030f7e13ad72f73c26e50b8bad5ee7b13c824f54026eb92a5dff5ec2d87521388c4f42f741aa47d0aea40c149af5de35e3092224ddf59d0f41dd8e4e9f4a770e8f41de76d601020cfe1f171d1b3207bdd7be150f6726206d2c8ec424aa97f8434bd07033ee90298b2a8340e797c58a2190000000003150000180c088482e19068402e9f26f30114800c5d7a366a5a3e178963b15010e4300a62300aa218000c00c018448c420a551d07d7c1a9b937e2bec48f571de1198299f8193ed174a91afd55bcf5c446b76b7557f9c559678982f6ca7965ca997c32a596f361b0369d1f77a698a07e6ba32d02240acd3e35580c219db05145547bc1edcca36443d03281855e8102ae54a9d184e4730781b53f97ec0e389fa556b5664d15e3c68902eb695e5f890995351ce9a51963fe011e87f9f3deb0ed15e38f906c6afcca2b6891c66e673f981d51038d41c48cac5c54bf6c39802f87e5d58b50f72a4957f0520f7ad21f48adc9e8ce3c75bff1fb8a0cea1691f1043c6b4d30eb97056881955af58298adf7373d5209e2cabd25ad8dece5f50ebf84059e0b98ae448a27534b0065b8baf01f436772b77ae345a29c084ba17bdee35bcd8fcc97c50d9549d09c63bd559dff771a82f631bfac5f66085494295d04ed6d7121547228f41904255b57bba46350b30109844cde60b67bce24a0390ed87c0c093cb4f193c8acf1cf95d4285bde12127155d2823ca79e8f1fbf4c2bc40ba73da0a2d8addc85d210ec976e71d68c2d86d8526e2ddea0a33d414d0b56b3c67d987a628dd91e5251fcca5b0654169bcb3634905c74cbbe38d3e68fe9da91b212fbc995bdac295cdc80a5ede9fdc5c4a825dfee1e3af83ec36602e138c70cd419b83b12f8ba43e865e618b482cea01b16892bd4c15be6c578e7635cde0032791bb8b66ad8531a602eba004da6c5a2985d2cb56f371bdde5dd2ec44604b0c90b61bb069ea4c44583e1c00097f9082ef6e6f200a49a1019c6299d31fd7f1f94339a10523ef1c0e8caf6dd9458f343ed6911ff700b4b78a9e5cc15072f89b78bce15677a27a23b47d69cfdce303fa4de7100361d19a01b9c290a02461fe0c14b9bade32e542cccbbfa60992dd1721917dbb9dad0dc60422ebb6edd4a855b1b4085d8efcf57a1b12ad1055e248b568991e6ba0d20850821e089bc38579e5095f6ef2dec6aa2be9b8730dfff012c075677f3b3d822e0b545166e8fe83b2cdc74089439a4004fb09011824e171b83b2a83572fa4f9b071db3febd9d483c04cd2214c507173052df9d5c32c0bee7421e82f8bb45e66cb4e0907a042a165be2cc97a3512e1deb4bcfda223d53a4971951f9c5274a8e97e82bc5bbf7ac211887398186ae2690e6bb00981b7dda8d277d474bdc46c56a441d7792b0db18c19843002e62b4e6fb715ce6377ed81283632723ddde029d260038281b54485c71c1a5e3623ec769aaa5e2f95531a48a58d6c506a2e2c712561ea1cc3d44f14392eb6c49c9d85b151392bb3429aefebdea6507417f1767a62b4ca6a290d59b46014943e35c4b9b6f781ab415f40178dcda0ab8f7c8aa08d8893ed4ac7be505da1d871fee116372247a94e5c675487d2bb5913f699db470c2443d380ead0b8229a3667e46772ee49147298d1ea9ce1bcde32b28c18f9e8bec85e7b8dd1f614605956d3b53833cd31fcad21ded69a2ceb7d8346a063129c5c85977abbbfabd37f55c13fb4df95ff19f17ce9157c19b1e9797cf3d70402ab423cbd2afd4af90c675da4783ce969732bbd5ee4bea56abb4e9667e960afb36672580a7f9e74ea45e0b14234c79123bd148809b83dc292812878f35a3a8a078a9e4c636d18277bd1b314a15766ae0c9dbaf828d02b51cfd635628211976707e4a05211583583489c1d041419d1eaf176614b33cc00ce156871f49a528f4480087f93f0bf94be94c80a982d10ff68b302f2486afb9245c8104bc010f07eb4825f228a8a47fa72d8145478a915d74c4b9316baf4704ab6d05244fdd859a35ef0896b2b5cf5a180d83efec256c6c495f477185f6a78325c54dd621a2d6a315414853331c6c5f2e9e1f2254f4bf2a57d86a5841ad2ac43a570178155e84c242a977da6384b3237e083928d4a84eb33f6c43f1236ca2ad18d5969ebcc46c53ef7a0704548dd13afda2263486ae0b596dbd999344c180d40b383ecd82b616864a5a2f6de0a1b72b2a89690e745b52ab48f65fa1a702a8ee10b24d9e8c8d152e2a52a62b86b8523febee3f9172eeeae6a3b56e7c7f78b29459878410700beae9ba5f984502d683188d2f91a231eb4ad8984ecec623adc162bd0baa3b1c069a2d65ecf713021ebb5532c0bd3ea17578af6f6f4aef6dbd8edff2481866008ed6340dbe2bab3170840e3d9bcf0dc08b8e822343632cfbc60525ef52e8bb28b1f5a9f59617012fc3b45f27f1605beb62e040fb769cc3cca5e0a71684bb221a74b8428287f82df51f0a926123eddbaa01a78b4aa0cc45cf37c9d7794ff62535543ac70877da1c1eb85013ae8b01f084048d3eed3ac6ccc1a5d8fcc477d0747b6d40ff99be070791ad296cac5e044a5837330120b13b97e08095ffc8b1a1d3396e2a1632a634106033706c1d52643b7ccb31d11c6e9ddbe07112eaf41ae804b887a339931969f469455a38be7151d0e0a8b0a451377f1a94b7416076353ba1ec9ef1734aaf02218410c48f077df1048ae001931ef8384a5d6b256e1c3bdb0f1b94a62ed199176065a324d8cb78b4aac4b66d5724bcde1c476f9463698c56a9923d0b4d6f81ef92e49d2bb266da472a06d5dc68ef6a135bdba2fc58defaabf8ce5520889681443fa046454fedeaeb1964ce0107f60d03a41b96fdeb5c0d5c827f95d0fdab3c6104295d7fa9dab8a30e50efbb1eb835cddb45221a06e63cc32478e0e7c97bdf4bee0a8fe11f99f14348c21f71397752424c4b562a8c3677d8490e62871dd730dff607b6c3a0cf6228142889e550dad0fa268cc955798cea75a9b079a98f649e7b53395347641fa42069bab735802ceb7f591a165982d788b5d18bf6ce0670334c360ff16c405cda41b5368a2b411dce784850c7652c249c8aa4d5d6d00a1b6202858238d70287f60d35bbce4e233846c1de242dd1231ae2420311047762fc81c778d960257556810c6a3c09f6d466bd50cdf9196195ecad0e24b4bc9ea3f8ccc4c909526c6c973acf059d7e72754e9c253131294482deea571af18fe1e4ec11e0b27cbcd0d6d47e86f1969c575868fa92aec9d5ec620fdcb1226b5171f191b1c29c478e2309d5a5eab3e95a99ad0021f203da245bb62210606fbb7e25799000d0d64df2048c12b928cc5e516e82d6310ec793e01773191bb311beae525b8de472e891f37d9a730ba5a4074fd4b944248ce1eedcdc899ddb0d35a95777118fd8b2ce0df49b0741030337e2d22305da5701fd6e160df115e8086b14daca5adbdd5c3b44da805a33042295a0245ab5478ee659180b099e50cd9efa2bd6898798dc7d4559c2158a21372c18bb272b606b45702dfb9d18e20ce5cf503749c2a7674bd7240dade9834de0ad8936aa066c3578670c5b1059715e8655bb479e0f55b0db423f4da1c746115782578f3bb58f9091370dc295891eb65806fd283056424d7ecdcfe2b0e8915ae83a637a2b37ab44702d5b4dd5c0896f065650b18dda3f3e45eda0eae34695f9b0722a22aee20f45eeb40a84941ad36a08fb1a2d3b0c5fd60c81a8b3ec78ac7a5e3ed911595624a5f15e7d9bad4bba67daa4814850f0c6be3a32f54c1cd772c293ec1621059f3f8c42130533ec754b31b47e7ec74d68871f949728ce5753934e846c505008dfdb5aea75021bf2d60523f51b69e1caabb84760689e726b61494dbbac1a45619040380b949a3eafdd921efd044af6e7c9618d88d4a66774faec96ea77f4591455ea4a85e49fda58e5d20863b0d9a8473fc75c2feeb98bdd81c490e44ed97393cd1cd0728e108da5953f42bd47e049c82af9bd3d5070804e4714fea3b4f8dbde54d189f7ce06b652a2af5aad704b68aee5038b3d1b1d48073a236961e2b97ff7735aa88a57d82d2397bc6a73254bcf22c3fe152a928e18869a6bbd034c2562b08a00d6efcef67a3fa397ed940a93357f6ad8ef8f3047c01755a0614ae91159d8966cda0c27baac78a8db9fef3f82443dc6bd1617b011894fd4303410ee9f38e6b004dc18b7a69a83b05362bd32410ed7bedfe194618c7431ec762100ed9baceb6811f9b635e8847f2198303e310b69055799f51d18c24f7836a2379391e4063ab04a9f4f645c6491ff7af854c105993cda855834e6f2fcef7e5a949395f3be978230413b2d846d7bef3aa59d8415f27070a43996c5e31ad08ed52b1eea0b3b8b2106529b018baff4521faaa6d6f0a3e6ef9a4e4af4f4997484b1595358220838fba4a13a5e2f10f59919ede893598f4b7660d4852988c977b8b471767a76ca51ad3464c42c1bc525abd8bf4e893599afda7afba138913d366367720043799b8751cf5ae722ccd6a75b337a4c37cbf1de8bea7f2f0f5988d3d3e222ef7473d103d3ff51c8a94418b807be29a247246e052efb265157baeb0ad05e6a7f638b90815a3b1d3ba924078028bd0b2986d0a0a6548bbe74622f09f6b2b234f4f6012041fdac97a22eb3d45c8fcb37a82694f21bf53841c92a39840925b286ccfae4164aa638a0ed9a1e31dc2aeacec32bce3a4a11298a222521409b0642b32ad06303f6a703b7761583fef6595c76b2eb7f886c29bc7ad3bfbd3704a78725667f19d69210922e8b7b35258fa192a4c60a0d4f1a6634889e760aa1c1448cf2f9c602411e672322d6d31d246240ef7456353ce5dc40fa250884bc166a5eabe36ec7e526e7c65b98bf0c27cfe3a2233601d417d804a409e756ac33f0661a290e1c810c732d2bcbaa35cbad8ae632f140b449e108208ae7486a1938dbd164c603ba37528e0d80e1f17e73fc3a1156d62b1a920680d7790f30faa391f01bf79a747963b26eba3703da2078de17534228a1c910020fc3013a7c9f649e0f662bff2b006fb24c5d1233f4fa0629d4de7f3d997079241ba1c882604ca109f7d29d411cfb5ed1a2757f36576bc69d8fb26d21b94ba3227da22c5a939cc2cc132471741980dd82d4ade65c5e506fc4439d245badabbc82a4ed348854a420094b667f85555f8b940561e02c3e1dcc33f00b87ce01e10ce3fdfe58702d7f45da0e78a7b01fb345ef4ff7958eb0402c8ccdc1ce92403ad4c51e0edb94028d2f0d1250f7c6f9c44e94ee199fe468f5090630e61fb513a3c98f7f05db514465ded4d809b3828ae36300bcbb0342b79d064db0067e666c1973e9533eb0f98d43947088f661040ddba076f8d08d382084861760b2e809af89bb0f27c3f020578dd4fabbc871208032501f1091030934c7bb9c624e63b24361ae9ceca36f0bcde8e25e0a75aa036c6f80cf158ab832c7acd28028ce25cdb270747d0b542a9fa2f2d77f482126c9190cc69f9dd9a6be2697a1b28b6db9cce0b83279b43793b5731d7a0220ef8fb5ac6a0875ecd9f0e8d1a3f9bd9498ccbc0a88243bdab657200265eaeae9d5b6f43280c75bdd937b338ab893a1c2f090472542608b5d07c0f2cecc2ec8a96510808da349610fb0fd8db92761e357ad61612eab3bbb10440a4e2f25cbc73058dd25bd8cb60e2bb58949104186ba96cd16504a15b49f1dc9b929d8904cdc1aaca00d629a534b33b69b5a9643908674b285ceef1860d5307cee7f70f26551dd1f2312c48d0f7538d568458d22000406b951e3ef90ff21715da416bf142fea88896df17871a6d3b6a4a4cce44bbe8731c2832c66d84dc3ae0f378bd8c37cf274d5a4baa92c936626c261c30b020f96d0602447c3a270688cb058c44ea847525769e073a38cf67bbd476626ec96df17aa79800374cf27002f684fc77774ab70d3945ee9592bdf7c3d85e510e34b0ac1e10069f0717e218aba26586b40ab553bf8fb6c8abbd2ad392e78c31e19f59f0332f9cd8255b56196fea35c6f7e0449cf922512b9ce0eba76d5dfe525ed270f2a85257cde435bf6b42f2e9cd092f97e35b2871327b46b470fc24dd7908d96ed88b906dab94c4e9735b781d70a1099ede634ec1975221b51b04772c8433089d3567768806865a63ae98dc103abafb7676280851250167ce068fb9853f5a926acaf28839d80516202faf0b41178c11111ef5fca5e63dffc012a513e2c90511a837345d468df28756b0a69018f99c6f4b9885c2814689e4fb1273f8ed8cbc433d981f7b0760c98cd52f2953bd1577526293a6cad768c1209d1a62456d05fe8148934015fff6ad61dc3dddaf1e50080eed2911aa25a73c37cc05e76d18460f1ea6e1a718b8caa048a6eea38cdd6b874e83380db47694c3a073e1936b3ea7b81c8353cfdf190fa3fcee9212d0dc388e5f92f2ed0d0a78315fa6ea42f33977f62b1c0c3fb2686c0edb9f136eb52d6ad0501d4d55e712ff4bc4fc1950ddc892a14f58c787b8d6e7de41412c54f81fa645c5e4064fb37037c4423ac16823fa4c0c763b0e7bb2a12009f0a61985c88f15b903ee89cb2443a77e35d775f875ddf8ce5c1eca78a7d0d64e5bba01a787dc5923b2906f61e073f75e98bd4601e34e531339efcf7725bc19d0addad472b67820cdf4c2de5b1e267ba35b5b44483efed253598e51cf17dbb04d60bbae01dddedf9881049ef330a321e32706d267de441a82fdb382fd8bdac4c651334bb476f3ffc9d980298a6a1ed1efd7a35790de0fa09e7430631228cdab4c5051fa1fe4df287b02d329ee9c7c0726694f843c083ebf85ea7ae84ee538f863c491e8717f8ee846ecece3b31af72f3ff2cd639f742b11e7d609218a5cb4c46e4132c1f9af00837d55d9cdd8d9b22ec26242cad545244a7c0ef5844e82bca072afaa069f82c31954ee201bc6dd4c81d6a77224f01bf3f14276fe4ac821d4cdfb4b56ef0e2653b381141fe0a0f386e752928c6df2be66bf712f5a07d2ad8540a23cb31b6794921d2fc044f957710d2ffc2cfa39432cc02eac6e532695959e01921d1e547775db337814a68d5c021991c873f2b9bcd08ba8bbf08051f9b0fb5d65445e8d2027f097e93dd70322806f25ddb68b087148568f3c10ccdca1d411182add1d06f92d375735ff2ff019042d01b99fc248a215fa175345d981342aff8c1d52ef837f0854d638c085ecb7c8ca665e05562b64d349172d37bf906ab509b35fef2abeba6db1005292b20ec8ce150fe3a635287272f1a484164876bcd7c9ff9d369d15490ba5de5f340e186b0dbb5bc569ca3b4fbf0c9bb6cfe1877c5ff5bbdd31c886994ad54e56fe1c27170c6160e101e36089925d5057e7955773c4c56acb1bbabb8dd13eb01e1aa8fb0106a345cf124a7c58b80fa1695e9769dcf8de89364acda41069d0c0e0b760c6ecb2096862423a206863faf4d0ea777c77ea0e3c3606247c555e89aec67409aadef4023530bee189488f1f1e04e0696aa417eaf6347a6ded350a4aa8dc1d288662e1e546fc4c9d5470addcca761a6b64c80c312b57bd16e2a2ee3f252157e573e41352b3ce1ac08ea3d9c37a57143bfdbbdb3c24c8464cc0ef9d24da7b89463ce1d8b21172168cfcbe40b0b1d8931503f2dd5c28550cf6cc46831d39db87887eb6e1a19a80ec2d45d06f8958ee5b8769511a0ee6c7e09063765ae9c75efac13da4d99571e0a0b202ce7ce4870d38d7dcba33c52344682e645d674534d3306dc6e3cc43b2a32b03d5072f2445ea0d34c89d5367f1fb81d8248b3c53fe9cba390f07c4fdd3dca4317de56d6270a30f1d6eef8aae1c96bb787bc01c4ef2d9aa8546e08909323b47b814e291a9a6793ae5850c42a849061fd1462f745d6ccb688ddf7815015b45d082ebeb7b1516fbea83a08276e65e7ac87b3486a4d06cf8d8f47f007d203b6f78797302783bca42ea73aae0c2ad82fe34b3f9c32bf35732f51eac460e7c65acf656976db4a72426ef54a8da80ca3e9d65e4eb769d4bbb2c12c955caa1a41c3b44fc852d5e1531f80ac2aaa6afe76c945366a3721a57b9830a23bbfc2ff8201aad25a29a199d69ea0d3fabd4e58631a875a274c4296ad477acc8248d47ae2bb604c34fa51aba18282cc0f4f7b6a8d0e4ddf4c5d61109a1e9ed3778e4d1bf1670ee9bbfd78a11ef494630e3e3d8bd43a9147d723e0a880846195d36142c27a0259f604a4d226c3e479d03401dad6f171ed9c5ba901819b336e55e5f14cccbf3d3f0667496dac1ed95e1a994d41f672dfd6aed2a25546a187e96d2b444328693f247078a4c69f6dda0887078465db6f54cae4f34ba44dc318a2e4ab1f95bb312287f2e0c426183e9ae725e98680e4998e3aea25f2a5a32c15f74ab5c2fec20020f6ceb97f84b6108084de2782e62682d80c846d933ea0ff91e4b8369cc2f081e06344291e5a80e58d01ca32da1b5aa0c0d808ebe3fec81d7fee9b2fdb71634c8ca0b7ccf846ccafb3d6f88931cb4533d1334c682b4d33ef7b81db25115eb00f619e908fcfcbfe65118ada177977675bf166afa846c6eb21cfd0eb6f6de95fa18cb06511901adff872d7331ffbc3e3ce20a18cd1346ccd440942c517d2b40666a277e450a0ddd1fd8f8325ba57a3eccce1b0480900995fb7aab6cbe3c2c17d6a8ba55b76d90494260589dbb765a46fa4ec680fd750fb292928e94a66ea35ed953f49060f5ad0a4ebf0fc73ad6fc8edb4794e46636a27d75f91e624f036bee505fb4424dcbda1c3ac5bba2d0630a3ba8caeb78fe806bb7d59c213d093dc665ff1c4a94fe4b3fd297f3f95d3f790dc25ee9c6f125a503d70fb307bce582dfa1d614dee453708e4c4129aa1c588c708a6b88505fcbe31adad97b591787b0331426d4ca03740e4fa873fd8bd30a40f358c4df71226785eaf7d330a099522dad352fa9d1976d71c123f977713c90305b75527706dc925252fef4b9b4d2df07c6376045ebbfb473be133a412d68607a52ba482b39ad2164d3e4e0cab77690dbc44409834ee23557e09f8e83124161e43340944ec131decfba046d980709445dc0c45a629e5f6f41c6ca0ff0440ef89f654e48d6d05cc31cbeafec0efe8c3649e70efe11e860bd26022c335d6b5bc05d64507b0457a50464fb0ab65ceac5f35fa28fea04e915ea55d853f74371e0dbb2a0a38b6c2edf759753c90e719bec2ddc348f943ce7819ec60754b986fbe60c05ad4e4aebb827e02d36ba38694257963fc143d3614000c2819385d719c8de51c4abb5de07aafb7ef92ef938e1bde823f5ce2b515d3cf0fd33d053063a934041af376740b086a2f5ed5032a93b80231d72e2cf08a6bb929a80f0fcb224d0183fe13d4379665262094981c89ff4735c9491da3d3757c4c166bf7c3b833e38cf7fdbc764b98866e8c50f142a26a6fe08559993a12643e42ec75dfea0b90bc5eb454f28827b9cb2d6ef3022ae663ffb17da01f438848c2e04dcc4e2688337d9efe8b79cd5d9c69e655ea689eb6f335eb87486f843b681f9a13fe4185fd726dcb7dc5c122b13ff10778e41ff63b19affce380189460e8276158b8127df4103e4a2b79d03b98c2993ec62628a28e9547c647ba3aff5fb6900f8218cf0dc325e7f49559b2f907d788d80390db596f398930b6490d3a72e5d9005d1fe82e39e983a42f9e642e21716bc2b02e669e2f454d8f165bb77f9c2b8047129384d743edb0336cfe1eccf1b419c34713a56b040ced7ecd6dde89414fc53024f5a7d9b2147388eae9f5205dcd1d618c19f7bb1eeefc506b08bf033ca43eca1e27800e07374a2ea422667ca5b85f7a8369470b9de07ed080d1cf79727d51738ca10fb77b9b8831094d365b33fd390707f077c6ba8d7d359a44478b0a51abe2cd648fa54b62532bf4841cbd4234208abad9af026a2754c9f7ad0c675df65165159005e22174d9ebe9053235594fa5d7a887f0499ccc8137d7832455fb642b01789a2b4e8b7a93d4560299835170318579edadedcac7f99be8fa853208d04deacfddaab10b038ef0e97849762fbfbbedb1f5e44f9e3d2b7d0f7c9b620e25a83a9dcd82aac1f4fa006f4d04cc8c967d44ab5b95516a5689513849318fc1494c99c8efd31ca87e2fa5137a3b0575f092588cd581df4f7372d88e2c4d0d1e10d216dd94f53d9d13ff7f0950c272e69879ea73fdc6957da9b0239c1ac1244033c8eff8a67290b8f44e7e8c241e33f86213a43fb6d149607b2a0596489d7e42518149a43f90dd9a00513ae2b81ffb31d767e6aec59e60265dd7744faa5272f4507ed6e73fe96aeca6cec7f9b57b95729b68f4fe43e28fe9eafb6c29128c168a74686e4ffdba39e6ceab7ee8dcaeb6b0668256001b075e3beef63142d6f8b88c99ea600203d366d27496bd7d38d8f33ac49a7c2d18b05348e9a811fec408a05df6c1f663021c7eeb99f5d49ecd13c96c5cb97e6ecefa6e6b602a5237c2f9e565b0f0480e76f9c428c117fb548fcb20ee844ed25d2a5229b64a5fe480d4f34e94467a00779b31e4548ba44260374389d0cab285aa9181be859a75173e7c3d0c6de24236b930bdde31b19a558fe7e51976daac3a7307e0e1ec6708971b56310e833741e6b70acd665ce76952119985046eba40f40bd771dfdacb67c1c88bbb44c2830f5b196dc77f8da280c6aca23d6983552225af5ed9ccb3a6e3e78d6fec39d38d41e8d57b1277c9f9bb5efee10e780a388a0147165aae2eda72bd15cac3f8eeab8208c1f6b5d53f3d5c344e9b70db204ca7df5dc15e74ba4f84f3b11d64659f676b9fd8e3aaaff37811cbb2f144f2ce2e9c768afb381bab1011fb65b16b556debf787a889214ec1f3f4a0b8b02a387851014867f02abb9efd86c302f0eb9896bd6b1dc9a6d1081a4bc7935d6fe7df059cdc550234e41a140fcfa8868d6083ac977dbc996097e00b49c02b82b3058c774095d2d75f3dd9c47d5d353f9085a6ca007f1dda4e09aa518fb130dc4cc88462043a61939ab5ab80e58a70430d068ab4570fbc2a3e8b1b4a1a0cd579f1c6870f4d0a9d0272b506d1665fd90413d84342ed92e110988b8b85c87d2397b4d7f70d5457f692c964ab0b5989606fdbc33e44cbd3b2ac42aeb2be8bf247a22ce7beba8c2d4360bca4213f166bb587c249a29962b4bd3254aa8019e8bea5e66ad9fa85905bf62cf0c751b1629ee68519e72f3c19007435e7c54142f722c3117274912a83a2947c83e917021c833d8e89390e64604fc8f94ac5edd02ce09d605b7692f9b269b9ab71559f46b672168c6529d6fe193dbe96f25f7e0f9737b1d40bdeeeeb6e7993c73d35c4352d860a8fd19fbcc5812aa7cf46b9ff74f32c87729af8397434f52e16abe6c321667bdfe55e5bfc63f9ed97f9212ccb061200fc3b733b5bc512940aabfea8be4e950fe14263c3a893c5e8a47f04b4cee70caf68217a4e164a7cd173e18181d54adbaa6f32216606032709ee92e67742eb5aee4a484bef5884bb9022407ea511bcc88033b55da4b7478522c5641d2d1423ac5ff71563270c722816867148448e227de10178c0c4cfef39c8010fcbaa2dfaa7c5b48ec01bf274fbcfe49a42a592fc64d4bd8992e46c2909ac942b670e5fc341f49d0739eb2e6fc62536e85a6977855998e404ddef6b53511140adaa5ba60f98612902081c0935ced729755ac96d8815ddbeffbe26bf9c0c6adbf1564680b0ffefdbe9e007f7494cb37d6d2e0bae1cdc656cb07f362214fa6f707b9564a38988e52730e55144b258eeba151eee70427b81a4156c79ea0498ab5a0bae50ac904de83c06324c0b45645f3c461a2489c6ad4a7a5c8da5d85616a5d515972ee6e9ac678551638dffadc03fea8ea202e14f1974bb5b635e99c4e1914b7212b239e65a7f6dbee9912fa0f99d9028417dcd6b3e5800291823edd6b8fe03adc83ede5d47bf804c49e073bbdaf7c37c22619a94eeed76da765436517d2ac5c92985d4911a22d3da01cc6d77b1efa9f865e0ce3c44a1c6316f901db9d0e26077dcfdb9458e0a1dbc089e94dd655bd8227ff7c12614904611866f5615957739eb332c14d9783cd6e6803a3cf91931adf2e4b6e062a397d6455b048f152006abd32f46b2029729b8126f8cfeffa615cf9633024749b0d770859b8188d0965ea82d7a8d52bfb46cf95b62048c056d417da344a47b325b824e8f0bcc24795fd265f520544aa7f6596c31c69fb92e8479bc6b6ef1fd04e3718ae9d87f268c04785d4a4c80e8d3d0db971cdba6e7e4c0f104bc3f634352869611a7752f40f3b1910e880eec4663e2c80d18520f0b933732e4e7aa1d9fd6208a304930cf4ba49e043b84c0d01c2bff4713d32028b839d0d8c2727f34fe922454fcad89a54a63b5c18a26ef33645569050f1fa8a781566d494c3418f5619a0ee9535009888624717e3c7d7b5d878ed206d023d37bb3ff76f7b4a7379b6d934c0d580341b8d1f9be19e0246f0fd70a1799cf334493a67eec17a6e9e0784162b7aeb88927f153f26e1eb8947576823953889f2e4f574f960f41f0c30c4167e4c2caca0b2a0cbf7ce7a00e126bbca4537ca8da2da29b2a4083fdcae83182abfde2622f40458312c8e9cd4b667ddc1aa5efb29e98e32afb55fe64d8f4478e745080ce2b06450e8172445e839b6f58990048d045926d1029a9c0b3246a77bbe5dc26cd81a0e10b3720d8cbf801ad0b5c7900a0a350817efbcf1166421c152293dba91ceeba9c03a0a59b21a64140cba2aa3357853ade81d0dcf8680488492420fbe6c6c2622cdb8550749cfa4b888aeb1f163520fe61fd8b39e61b1d2b1dfa42de2d616d7ab9808d67d538d0b328b5dd4922d4b780579ccb954980b949caea95d09159a202beb4f6b1f191a607be14e969cd67bf230c6b3b48ec9b37c20a708b4acadfed185b4a285fbcc5c2f8af7a01624f3488e36a02727c2e7cd5cd8681c9875c3c78ccc628c6c800e99deb58d6a324ebe22514604c1437086f094f9baa302ebe969341ca8c8a3823af03031ca7af89520db6072d2a57ed8d52ed3f374f638652fb8e4c84babb4bc82afbc145696b208f0b6c26c2de89b38a18908e8fe649a05f64da13104a49c49b971f84a662abcc3eb5a01d6c645cf31ca6e52be80956e8d91f8b9896c90ed544a1da2e1924949b06a67969def00964749544244fe9b63dbd6caf55fef4351c42050ef79040022237a5735e05496d50728b26da4987b68cd9dc0f4c923401ac31cbe2fc9754cf0d19b60280e2c50318117a1626696a5813148e6fc4b2e476d5658997ef6d940be21352c7c2c5ce807a988e17756891b25dd5382d8163754d8dab0a8b6bd9e53d81be50266302a8d4e4e8d77bd5a61f3a26618cf602131e87e451a5c3534bf9ef0c61abaaeea63db1f63bf04dcac557356307e52009465960a0e21cb00578c9af461262105f7a443621018065e0cb2b071ba6f8bf263e65a74e9b12eee0c5b50293e4651e5923f1a11f272ae75f01eebedde6559bacb11d95f47b2169dd48b4bfa9cf8f80f573dca5a105954562ad4d176010d33446e76593097d545574b9881c78a1d8fd30fcb0e884511a79a2d80f824299108a2c18043f9f21cda63449f45b04e58e9a5d479ad2bf915573b1dbe6be0dd8c66a6abd42bec249a72601a84691142fdbe3d6e9c36c9b1aa18ba3e2bea419976cc0b7a9cd4449c50c7d3f67417ad84a5233d38c71676a54e8d8520f789d5cf0056faca6e1b9689d761cc5a5e4d458f1d6ebb17f94613d2681be28b33d01a99404b7749b345d2e0726b7e10f37eb0252af4c40e07ffe88e24036bcdf52fa6486e7fcb6b5b6b596c90cf46027aed051c76cc743be2272c39569fefbe635e2c24b3bc959658ccb5fc03044d5eda48fb39bd9f25845f4cfaa1f544a48caf8055878b6a89571070a2433ece15ce2d812ce98d291d8589f7afab052d1f8d4d7629dbbe87290626102737959e0274f76a7ba5c19bded190effcb5c43df38354ff774fc87c28c4a5f43e94edfdd6f1f5109ebed8dbfe2489391def175b4e0d87ffc37ea2b9a9ce990653d1d47c114c1a99cbd417d0bb6cc13db0c6d77a21763f2aab320d44286ae63a4598b37fecdcab8e1cc9a2b849cabf495d0f627428622a7b754b8c46d2f4efafcd1e9cc301d46a556832c22590bf44e5daec34d50b946aadead6daafafc0432b13cce4bc4a3510b4fa4de3a73d4eec0709f352afb4ab20aea161cb4c0bbd99d47c0d0afa0dee9c0baeaf766c722a359d9ec8a8e7757a96c2181210aa2f60f20207c3debb0f578767dcd299b493a559a6db48572c0b65d4f6f5f94256574f393d38dc6f2e781511f501d2a215a93f4644f4f2d92bced5ae2252d3e5328a0267d18839c471f6c5f554f4a4c3fd04dfb0bbfb20d873beaffac455d6268d3a209b63c728e2fa00fea05cafa5dba34beff4730e21aea729630d530ad2393d5206b667dee473e3a1c20b5f3df97926253ef2b68ae75717a125fbf21a388b5b4c159641fcab6d13a3a8a9ec19047b1ce7ef6999bf6862e8f61c475c1c964a3356e7e378db6297194c2b3c36db2de8eadb01644b1730adba83bad1c39b734936d2b6e7de8a7363219886d941227092660e01eb93d23a81f119e1f82f745bd13743d999d004c9b8a533c9ca138edc05588253611a58a8d849ec6bd329fec28fbbcc25090617de08bb7265c22f1295a3efa5a0013e1011a0807e5cc99bdea788aacb76182feed2393efa49c58b081e78ba6a6b554af0560d66c34d75b4dd91a6d1d4b2d38744e652fa2cba60c9a985d9fa015f30013e3ebb8d0fd5d5edb157f0cabdf4909d88d11fc108bbcc0932853e05f35f2216e8e5d640e7c36ab059e3234bff2f85fe0d2989ad0d2006d9c8aa664dfa31b042e88b98c9aba96e542709ce2d83f052731ed676c5f93d1c51fe8a86635e75c7eb58e13df6909b25967bb83908bff596cd2f82a20cb3cd66e96e9c87bd2b0aec228609600c451fc1fee3ce08470bf89e5d8cb2a5b1ea247bbbbe01e8156e27486be2123f973f0f9f863cb1a3ed1902379c24bf217404e7964482a0cdaf4b036858fcd5f51045591e239291171980205969873f88feff0e1281cfcd3c74c98520e3d4c929057142383c48a720d22c5c7f04635f43099433cb0a24c48f638152e2c373c16a64a617c6afd6288246c5f41c611a82e083ec8875c5812528df23d5d933c327eecdab8af3816dd64e1ae06027b87a6ac812b44b973df66d1d219679cd209e8d1a51ae90c81aa26bf17a461768f4b9880ecdae2cc88d1c971a7d45fb4a435495ace5461c90495d27455edb471603db9bf9cb038f7803726eae88aff077f93c2d3c4c51afc42389bf8436478a6d53f8526aad6fd9c50f55a5dac7e61dccf906b6bbecea71b9a3c2ad926c15d02da874b87bc7fa5598ea4314b90b6f4a1ba4930ed6f09369b498e948186e2182a956439468c433bcaf72d44af133fa025c5c9be38f56d4868f417b48e6689c84300aa220afa467092cabff173d4c29458536a15791e53e24cefba1b6a5dcf13c622fb17bc38f80cefc7fd8a9f4623cc5896eb1daeb15b2d61212f4441e0bd1a02daaf809bf4353456f1470c604a9d4308caaeb891b4cf6e5432e32fd99c63f27e2ac9eca43e73e9b02fe8ee77e5fb5b3db099d8b2fa4aa04b9059553c478a7fa427b1e40224a62bdedcacf8704715d1d2bbfb18cdb0d21d95fb5083fd6aa77d1daa314eb4668435bfb2fac5b994dade9493a48f959ea94f05e6b29d2deda10c311560cb390f00255f1a0ec3678c768c3925bbe233d9ce97bea5463c25c66b233f995c5ba92b63e668c72de1938ce4cf31a140a3102cecedb1a6472b168de6b832f2427af0654c1f20587a53d751b9760216c8b8baae1f985c1f48d66a0e56066de0e76a3479c529182c53f834d03a2142cea9daabac0dc42b8fc0c3356421ae6d591717116403d05597f5cec2b530b8cdd508be0f35e58becc59ea06a02da94bae2f8c2a97f506dc49bdfc5d7550dbc87357a8aaffba144c8ab822abefa6461084999701a663dd5289953fef605f5d0456034549587943fc5eff06586e1cb62fb55e45e943aba96baa3abf0355143e34cbc1bf0dd97adbf7b2a8ff21c109ff0a5511b6a0fa0ff08de66a7e84f8e32087c4b4bcb5ba3fa70802dd2a181f8b3216d6cd84c6ef55d3fb01ee8273ff3c12a82cf73189f87b0e4b81c93ea3f0a62e3be674075290a82c5b4b8dc54b21886c44736663b6ee147c9f8914265cf6e7538aff0629384d399cd9c5dfea75c661a2a402f0e903fb00438dc72df28126118892078b85d01481dca3745fd0c609be325987fe9cf02b7c28b2ec3db811f2c80ab40d86b4274a0578f9e2a50f07e367ad9f25cce1541ce5d74bcf07b62c6e05d77b8c4d314876b9d3d0624492e82eee0d35d0bca0aa899ef2de12057e7057c481c4821212e0fdd534ca3721088cfce7f3c5e39b9b5d2867bfae49a9c7cc62c1f7a0c4cbdb4553598b4810d1b355e5488184cdafe62dfccc7d348dd01e1f3d19977479f1eb25b351fb41d1c3c72968646d59a88045327e1ef1632c8924049a009acab33342aba9c31d37c238a82d23b4555bc3d83d61bd330983adf224a9e0ab5d06c4373ee66eb1c6f3b0d74602b27f71b48d468b1d340c5e3a423adb1079b8175b5c9287695a40b96777863c018251d3ee267214dff0db6e9b56e0a1db96b382b0aae1798edba97c98cb0079a30d968de3f4752b071e6a1b3802accc7ce2d06ecd463aaeb9fbfeed3408d0301c997081c8d64a3efe65b629e7c5299530086d4dccc3ff0f518a738daebcbf080b9aca963c76e93cde93c44f873357523446696a77ff493cb78ea870c4402df1ab5dcf5e55c37a0b17649998d19a9c8d8bec7a9a8b4ed2a50dc8c002c335e27cab05c0f9b820d693e6e7875aa7189e6aaed7eaece235f4ef1e982e4d49baf2fb22911c5d529bfd58bc6e48fbc40324f6ad18ace85a49a3116901c6156e7109e045194556d3f510673fb624406b04332fa7e1f22603fa6ff204f4468e12cb5ae21a861bd417b97415e1eb3e9584bf6c0279ef55719c1fc643baf4e1530eef9180d2b2360443bb753ca5c2450eb78ac9a658289a740db1f37c51761b1c3bd04be0767843a2b5da2052257a918d059b728cbcf1a847efb28c54f13fe494b48fa7029fa94178445648c5e0abf155af04d1124daa2a685dda5a5a18a5e822b23c1066380959fb0a8fedd6055cd41139ab8f49411ef1c1918279de2c326f9d8469a92c4e14da7397a6e7f334a3a12d3ad87d496151a394c92b1ac7a68c39af9dca27ebd48b5587cb295466080af548019573b13047d03f5cd72ebe8e46577a8d09c7b17cb43610061f261f1958b62a00e193a5bc5931403eff190e9451f220c6b221bb2f2fbb26d6c1a8aec78b86db38d2fc7054678096caefa5247e000e7dee19d9449ad0507809c7a806599092dfa61a402ee8b657774a6c870b5fc45b32535b8d36984882ac601ea3216e0041538a42b2b7829c69e24605c84b5e3d2e90694333e107c0840b1aa0551af6ed4cb1ab2c279a59395306544446a6c931edc8c6156430b535b966f0556c7d496e87a5a4f2234e14515dc2581f0a5acae27e92442a57f5a466dca789016c9a80d98559ae762ad0855737f5ab0ad4cca990f7aa9b8ec51d22289fd85552f42658dff1657091904dc95d8ab2a1d5a64286f98716c152f24a05f94654c4095369907798b967487fd61a344a515b7fb6693f829da1b8a893f442aed95be6303993a72296b158d532cccf902768744ba1bde2d7fca9691c50a9c8dd3e680eaeca26705a27cf397dbca3e0c9fe71fb220699ab9958f25123b39d46d7274b392be1f7fbf18ba56b7984481dae0137aa7934f89b2d97af2b0d0e664c5724ba181560958a3a76c6f804aa82a2e875c93187ff66a05edb0bf6ec6df8e051190088cb572ee20c65b1ebc2b830ca7236171b203e609cbbab1bb334d0c157100b6702a38c50bb2b1ce511ed5ff77b0aa749d16f7fbc6e4574e1c752b129d8c4ba82574e8a0fdae053ade3b905531e2fcbcb6f7887533c7c2b0d182da97c1caa988c1bb95f6207469aceca9b34758c83b4fdbb502f151296a00a54520bd280f79b9f4ba4d7f36ff43d72cf9297f478df156a05738361c84f50bb328729f076a744de6c77d976f68fe56bb68516f02fc839b386f564a199cb75829406d8e6f34905a337058c0314e706d434c0d98b9348e35e69d95154fff975c5ab51fad6cd6fe79f125f5f1b49a674434faf3d036698ea738c3af650c2141d6564adf77b50c37f87eb5bf0c348c012825d94be69741bd0b85c6c9adb610c36dcc98322b543b729d6930b5744687ee756fe75ec3f4c32603d58d0404c4497ec6ddedfecf00f9e9359105e7b855879ee2ed34c140ed6eae9b500443be64180b5652cacddbe1e6551d72cdebfcd40b6825594de3cff9655c83bb5905e4c3dfaf67bce62797070eed6bdfb26a678e5c9888c2aaf3d4b6834c020108f9b94878fc2a927169b511d01f59321a81fe2e24a535453b78e03ad1d0051a2c190e113b3fde9564e2d2b3943d374807118388e8253f1038639538f17498f186a1a26d5766e399cef0840faf8589e141b671fbc474ce278e371d4e319a611396e0e833817f2c9ad881f2972a61f82c806c040969cb1507f04060022d507e56ef0929ecfd5126f7a4ca3102328bc72187bdef3a2b56e63ea9b56acde63ee162f0604516ba059204c49b276e46ffe3c2a583ee3aaed2791854599153006fff70ea278ca3016538d4824ca0a58520b9182aedc3297be08ad347b87a5bddb0e5a0b2c4743f47ff8b5e4aba8088b353f726157418efc9f6014b654985e999b1d3d132b799249f89fac1cec5e020e542ef78d7684aa5ac2902e9506673be91572ed49143ea884072cb7b321bbfa521dce13b13edca6fd85c78e8e51dd91f863a3c02e7a0469c8f471f05d18c548568ea9290c4242a67a47c7310d8adb04eeeabdae31911d04f77a612044ec220e3dbb2ab3ee2adedb2584d23f3c0dac17a480560a9db14cfa8c8208f0e1b7c5902aaffbab569047e641d75d383af6b0d9af8a43599646488112771fab229ddc86b402a34da4e180324a8a8672f5b6eb6f1b14f4916d5607664666b30162af36096697cad285b79a4ad436cbf617eddfee9098c89d78984ec423e8755542b0620f335a181780bea2f9d1af28ff97f861fb1b986f6860d5b5030fd1cf1d553dca108c7a70ad91ed70fa2fb3404abd9cde672adb481d205425c9e3a1a93b2d5244e4977b755c281980c68ca689d01bdf6f6a3ce61e84e1c589f08f4df6c19f3b82d6e5151e4030a20767341466fbca26c6276652780c2327789c2afdb93999aeaf328e379c7b2ba5f648f1305a5b56bc9e3094155464142f9a64d855366ac379a196c34c66fdb1a8ee5449b02665ada89e773a4c87fdf4d6f8b3ae77b7b989c567c8b2b32d745e7d6b6167ca80599513ea05f0860f05a83cf816d51f7d33c19cd5cf596a9768541efc7532b08df100e3798d0b06c281396131406c076cf214d4a07c9192af2f167ae23075e44e38579db6d3516bb55181ecbcf614a3c09fd242fb1252faa73e0b0c5b82eb20901ba607b8b6290bcbaaad164cc9562f7576d8dd7ba3d02e3fd2e8ead1bad525071cb10121ca671dd70dfee4b0db2202f33dacc6836b530315636564e04cc0d948cabc6227210d6635b44a153f11e2b8f74a150a72fdc90da64829160a7533904ee17e762a1de9cc8f34aca8e94ece5184ebe0bf3ea4e8e7a35e29d22cdafaacfa7141966f31af981f2a742a66f68049480c0b31ba8ace82e9ca146437e07323f87762685a03382273b1d4ba2290e641fa9a205fafdf23469df978500bfb8928c8046f798c05665c1b8938dcf4089621e97ef959ba34a139087c58b0221f51cc264dffd256b34abb30b19cb2ab41e2028b8d5723e416fa9fa311a9c444f85894fe51870e9b2be125f45b9394e46d65abc6e525ee0e0de334663c10dbfce53b2d2286d00b6f2ccb732ae249bb02cbd0d92ecdc28e32c3b746799a6ec19903fd627ec7c6a7b6e6d090fccaa38d3e76c0176eb7dfbb6f315e2c0617a6e951b71f1bc80cb2019ba3e044873f8e4b42304b0a49fba3904155cd1f89fd50f9d588d359e3e53f6b238dcf29e37e60d9d2da5f2f2c3b9bbb636dd2b25290482cac008aea297fb9fba1d080a758ca8c1c73f4d7ce93470dfd81ff28cfec383edfc76c17c22c201cdddc35d2d7ab3da9cc4710397240c4cc354c5f5548fbc5178be6b19200df108def997fc065c1778fd647122f40e91082a9d13a332125ef78d93fd1eedc303de88f08c56bf78c160d17b862cd9bc26541e101f1bc3487feedfb6b81d1441c93046058d1d5f3c452be73e243b92232eb28e9f4b31d61a69aa3d6166589421fbbf952abd099302467dd3d73ade0abc9c8485b19e5c7157b16d3cf2acdb9b96d5edc47dbbe87ef74660712b828b4314ea2b4308634a77164aa259f26fcd07aef2fa568d0fd37456f616cfbfb319df857c828a81610d7ef161431a28c619f6c7d414b6706bbd4195f0d3d08f13c94d113c06f9c9ecf41ac54ce88662ef7ac306ada45f8ef9908764ff8dccbb4fbb366442bc3b29b42b4dba0458b6508cff762833b7877b0bb295900f312f7d8dd99495f68fc50c87c00d767674c529a9221131b7f40e669b9995b7549ad49d0e46441bbc2bf933dab7c1105fd54d7583f8b68ab14d4f780123861e06c65218dc6526ca9989d2af2c2c14d1e4b30227a30f581fbaa1814eecb7c09c39ba8792b7c56fb29536e2f1b2990ce23e0ce6125b76d932461faff00e58d99789e6f4dc01eae7682d7671d9e522f2270cd8a939e5c4f3289fb1c9707d7e542927600d476056ebffb6a3e48fb845c491c36966ac2f66aede2d565d688248a1c67514611b2918e21f13d4c42df76012d412255d2ce85ca5c36f9c414110beb69dc303d3b6679a3434d404b31d238248a73fb242cca97098b1f99a55642a8a57691e5b899fea56c26c0af76cda70fa8977763a713a6c131c5b87b45613e032de1ebff42b91c171429083c1424ee31a60ae4494f2e8392068b9d67cb951112031352422c41390ecc32e1f87188f029224cc3f1dc8a1ee9a1f0773839ca91cb986094b76604ed662ee998618a63f22be44a5a5da92372b68a3b45a32a1318e743a7ba820dd5cf99d43dbde315aed47003203f074f9d4a81734533668e64054bc0883e0528eddd1e354298c2916fc266c520070f34c2a0c21c7d8f3cef957ac07385b7b6a87b169167f40d52e4b45f80659086224be2687f59bbb5019f9310bf94014e6858b3bf9cc3b001dc0fc2d645d9e70dd68281fad665897a414d44104dd25ec9c2f43886565c4841c11304eebbdf2e4f90aa2b424760e7b63dba13e06290ca4fd9f3c943eeb14ddea9fc9354a0b45e950218985f0a3e26005809cb6b46d3ff1c857e01e70bc01ecd74140f4c28dca074fa5b02dc41af40832720425b59ed319a3990418c94a7a45001e925f0a03043d4d96e722c687165c848eed93d3d022974999700263de0a4357e42a9e52f7c207046f8a5ce77841467c9152cbd38b229548a86d32401075194827f9703d3fa1c43951cf80747836cecc59c4a0776997b9711919aa2ff2ed616d781e470d04d30dd279088f25b1a6ec1deb4314b14136165fb9ec59a56e756e8f4d8a282b9297547b80b399101ebc70a7a2017dbd946b599e5a71973b42cc952a3465bc9a438e3a5598d05f8f2474d66429a430bfa1eccc46d4aee80084863515570a5f6495672355054cefdb6a34c76161a1288f61b32b08b4ef6cb71ee5348670d16861c82cd9da5f37c83f1e8015f4aa441ace721499e759cbd03432355661588c997b843aeac4b9555c2f3bfc3e8ba9de67b832e5b5c14112f45b6b7fba2b9813b3f097a11128c2999500e909682d9a49a2a535499b0d46925a73c33b54f73ceed03d0d95296bacbd4fa1b862817ed28fc4c37854f374a9066d67cd43db363d66218472023022ab02aad746ee19d5860e80ec8a2c57c827d5872c2477faaaa0f70f6ef4fcd6d6aa8c032d50827a863c00d213f0f24ccdd25212c216244ef4ae1096609180e64ad5624f9f22007d401cbc2cffec1130aa6482fd25146557a1eae53a42909dc1eff56dd9877f213e09e3de7df78a975d86c13611788f8c225d4ab1bcda6fd9932d0b1a033b02342e032a98ca895920ccc29a0e1daeea2bda631db2625f94f4887c25ff4056630f745b4df916a61df291aabb01a4be9288465bf8ceb31af3b80be0d7747ae0bb56532708efe64eff7b774b30268de18b7d03762b1fdfa4b5bddbdade7b4b99520af8077d094b084ea3663feba36dae6e3b71bb0c2db7df031d6e3f0e11f6b42cc64d8f447f5158e100175cfa4ccbaf9c22fe49432c8d9ca73f64204dbf9253c4f7c4bf1df9b7d6ca3486a20a14365c50e19ad89806d822095408a49481c40c2633b3d8833a4926552a37686e8b4cb23636555c900ca5ddddccb76500e8baa694524a297d1e95ec4bdf47d7b928188c262b12c108080a27dc4a1572eff0ea9466826daed01d14b2c7eafbeddeebbaae73bf3b4694f66018060371f0efc81ce87bfe11c0eb0175d64998cb3a1d9c22f6146fe70e4477ba5cc83b1fed4141190751da0714846596c14a56925966ef19e461f67a89420ab73a78dd4b148e6eade709d70c1b36db72bb179d66ad74925c382868b8dde370a09e713b5c1a206ef73c705038ddee7d388dcdae4de71c2523e4dee1ce3efd618fe01d883afd522e3f0d90dd8ffca0b5765f00895730b6bc5dfb29752242dea9f2634a7d7eb0d216d45b0009549225e6109a2bd007d43d338fcfae676616c758e5905f98d33a897e1cb3fe201e3d7ca4b9fd4522f41bb1c01349845910d9a3e84917c9e648b229de10a6d35a6279b5d29d64e4cdfa4c6f76afc6692567de256c1a2ef318095505fab58c81a62d779e3692b0bcfe5fce7acf4feb9f43bccbfe94afbb77db079fb2bceee391882ff891b17ea4db00b0d749b014c2ff7d0f97511e6f91413d8a786453345b4ccb34ed665e59bf504abbbb8e92bc4373203384826932722ec3b1d3ef4384a212c2f7689d0c7c6fb53ecff33e8f2c211cc7710c43978b9ff52259027feb791c623224c391682ccfbee3b7c46726593f927cc5cbad1d1c33ef7f6caf8c3775ffc8b853e73f87500763ebbbf76cbbe6ee4dd8f2b6d3ee6edbfd1d5989d86b7b470c6c9f6eb54fbf0e217567e6193ed87376ddf5fe335af8ac6fe62a3d60b1f4407e204ad893d1f4b3be99f56795278f913198e7f2e4e152c2563aa381e5f46a4c183b45098272dc5e15c316ebbb451246791a245bfff928aa9d116596e75e15c272964f0b56a25a4ee9be2b2d53da775bca660c7f1efdba8e99d963cfe38ed97218cffc496c7721930baacc4fcf19ed61966996f270fb92e537a3c3c5956409d4982ea8ebbea01ad4c33befbaaf76df773da80758672cf5fe4490b03130b1dd51faca02de68eb06cbdf826557efa810e0fa4ac22a69a79c9b59fda7b4efcfbfb5beef94b160cd083d62f39899d9fb3e9debd5659ec73648f1ce40dc3efd3290692595b7363773ad944a1132c1218a51c4284cc476d775cc1db7a03417fee52c589fb988570599ea2461fbcf9891f73db7bbb159777b6ecb89e53fc1aa9077ce6751944047e5390d7cf1ea941f4bb1cbaad3aac9fef5a4df89d07d91910375de7967e432a9aebbaec8a8a3d12c55d4cdff572868612f9bb9aab08c03c11e62dea4b9635e782b3fc6d6b50e6a659a9a5ab4ca57d5c46b9a6ceffa02f2698d7c552ffc185691afbde0dd44920f4d958a2a35ff19ec65f6555eaf5e5ff5bce0fa6b04768af39b20e9c03a93245c135701f581d38f21c2b666c69226252ab31d51a732684d1c32bad3420095e0f6c20b8c9a7ef3860958f3015a66b6356682c13853189b425b8769943097d92cffa973bb3d02a5374f61cb5bdfcb57935b611bcfbcc95f03a6cb24c864ab9cf90bfcae256c7929536f12c4f81d0c23a0c8d5ccfabc03529eb26953ea3e7318ac3e089ad1a81576420a435cdfbf9ebe6bc6d36755f15f2c16ab5faf13725ee75be773beba2ce7759e4712725ea78cbd9ecd19aff244ba2efbd6ca5fef7a7df8225d4fc7a1f0715e38ff7a170e8ecb153e8e7d1e7170702c0e0e8e75b95e24e822c11fc952c63d251749493d8dd90737e8def0f21615aac1a5b09c288c5848642108884dd8effd5befa4eb8641803cf84d1a0531f2c61fde9e77081a710fa53370b0defa9047510cdfc91851bfb931a2ebba2e2cf6f4e74182376cf6a62e917bbaddc7f7270f1fdfc92126d037a2b4b164a74e3d3782580671191097d12a562397d1a70f961eb8ec2badcb74cee460fb73ac23b68cbda26b7de48686d24db77efd7d5ec46dcde7dd3d0519e844ba3cb33d5c464118e5a16d9fa94b6c3d53f0e9f84388f7604e2ca71cf29b83f35d735a13516ba6c67d71292d69a412e3cd2dcaebd2ab28977e43e5e07c3f8c68f92acb91feb7ca5376bbf4414dcb04a5b6412d687cac265d37fc280f1f3d5e642c8f4b3fa9caf746de6c3d75d7e5013e8f1659a5df4919653d083eab5556e92f67ab37f38085bca7af83816ab08c3e0f97511efa2059e43cf419d67591e4db4597b5701821b4aa27748fa22e7d24c1d69616cc89c2d26f27f439d027b0d078e90f61217ae96f80855a0fb342cb13ace1524a9f9bc6bce452eb324abb142c4f28ede33800e7ed375949c0b1e5110d324b6ae60a2f354d706695fe1e0e73a02e6d1797fea9c105ff06efc000fbd0cff9d3d2663cf83b33c81c92298f252db091833541764be8537641cf7befcf6f6cc2f6f5feb4f6c1f204eea11f365f19a5a1c03cf4a45d4a439871bd3f81fe83cf224be807c57f3d48b262437d5f4dc686facd7dbd582388ff2adf65aee7f155c64018fff544e3bfca1dee713dd2e5f1f57a22beafd20615178bf5df235d90f4defb919c800389250558a855cab8c7711fa9e353ec5b4a3bc196b65e0b7bda95a2cb9454abd1c724becf5322ac890e24c475e990a3145e64e87b0fc26628ac5023a23c9cc77bdaf42778c1aaf0bdf76c9cee0797c58cf1c4f5b155f848f8de2b8f7060c0a166aef059b0d4cc2a32ca439bbe09349a7c1812b7cb29decfa857e25e46696c52296c57ea58225d18415d19e89c812203316dfc7e18d3c4ef2e4569e0f7fb596340be0661383cc452536c61334642f8f110bfb404fa0e82cef5d7b95e823702e9b704fa2c35c5964b752e25598a4a8b7b021923610c7f7c3659a4f860190302b61efc4a870a1286ff953120df3796fe64ad8559d9bb94e728cf149557519e7e91742bcae33867b1f9916cbaba7cbfacdff6c33c078f60d55aa9bb7b183bb2f1000ccfb9c060c5cb514d55d788d22c6ccd75be3b5c180701a3203d6b7ae29e32cf8c3b153924fb8a64b3acd5fac005bfb9dd1596cc3dad6fb1da470480e395cb51569eae5f2bfbe25d1d8eaae274ddd3e1ef20cbba8e3ecbbaef8e69e8740a7fb0916439c2035364e44384467a72c4131228545ff4a083e9629258c8d2c5176e8e982ea687296e5c8eea614b0f56c4b0dc88318cf0c63882e52d8cd1821d438658d7eeee4fa3bba625ba098d857d5398262cac1b08a094301165c3d95a618e8862892f59aeb8c2052d4855c66c5942031951b8c922ca0730a27c58c3c242e3568b4a92c516c5a44454921b141656940bb830575d60e982c60a245c14e1013223c0414c1566aa9e6013d68ed54e677c27e4d9813e0f6485e2738eebf58cf3fc1eb0e390cc32f7a3ebdf5e5610e81d3fe43101483240b1f0851331559890c224c7f214af3b0ed9d7e97964827873724890eceb894db6bf8ee239e4b66a37b66c149fc7d6f787adb2fac8456c7b24db6e0a168dc0294be55530291cecda99e3b880d371880235db3d70385c8f071ffc4214e89b3620786d087849ee691607fc7a42582f64087887c030b83b10e846a824cbbcbff1805b41e86ef7dd3842bdac0f2977a5d58502bdacf2b9c7232570bb0f86aff30d2e47d9a692903102b2bc0e83cb51504949d220994a22820b25aa89880e8d1d9fcb514d459294a1c133064c03753c88410e646fcdd8f35bb7dbea3211a68c2b35bcb0041328a683d9e1660729258a6072b564ba11e1185e7cb1b189618b24f3e4dc977bf2541829601043a40d19236298eee58a2ca29c345dddc228629e5dc3ddb399a68401c387324358018379b65397eb4419aa2c6a5652c2a031cf86e27215c0658b0e57446a47da98674b1581e4440437275bd45011822acc2d3e7421c3892cb668cad28559e3ca0c173d544151240910dc0a8e5861850d0db729614cb7428b1c94f8c10a259ad88074e58bda0c46402143c50bd37f02679c38e18446071c4c241aa444e144ea8a199250320fe0049b355161fc20650c93b96802876b228d175eb8984820b0a2cc92a7128c208b2b1ea8dac2892947f8b0268ae9af866575a08090fa0108168a44d1c1f42a26b630414582345dac7122b0f0baf042f0fa22f6b0e5a7e58ba803b3feb993f1d078ad963fd8b530c22f228b7157ae7f75f728254258d8c72e472971a2c4764f592b4b2852b1fcfc856d9bc711d658f7f26fe845b4b6477e45acac7dfc0359179800d5092958b58a7a180509653f0b9ad92020b5d16f27fa5da3b4c654769245324ff07ecccc228fcc5ec73ca3ebca202e4b73c35cc83b39ee1c6eed564e712d5c516eafcda61c075b77dba29054ddb6b7a390e48ee09c4710eaed6aadb47a33cbd5e02db40000597c7587d0282cb69ceb65783550bf8612769b9182c51377531146eecc0d4ea0780a2550bca439e22667e68927ae926082e90c530b5a18c80a0bfd93049a5a9bf9828a13125580b9914348d1458da508a389146e0b285a5899e18208a72a32bee4e005cee43613060d5035197235b8407586c9912936d3a60b93b9f3c4009c40c9358f25c838999d0b26bfc50983c81240982b88305c618aaea31fbcc2e4b7e292300aea768750299e98fcb677c842224a988ab0e198a240712e4cb72423988cc4d05c96c650027e612a9c3c9112c2cb132b6af80ba6225790f8c28bab9c0fb18485adb9388165044b543ed440061435fc90e6092c2e4cf962d3b266298a25d0c18471bacea57a7c868d19354c4e5a8e7892e68b29726b84c812450f422c75f174ead581e9d06f39b5c11541252a072890824822a50b25d44ce1050b9e85c154498581324588365b6e5c3166cb921068b8b069304b408458966e4d7aa9e915c4d211d0cbf2cc503079f382111c98a4b12121d3a40a109071aa4d11c4525247df7459ac5041433b97e71f253120f8828c27c4e01244850b1daad8a24917298080e2fb8eb0a7085ed18a4eab1809e3848d6819b350511265c4a99980a0657663a485b18ce5db1d10b5e98daa27b220b334822da8309b27a4d8a08ca8c209ffc1481170c72261cf9d1d99d3ba467520411358b3dcb401ee0a141b8e6c9162c2861427225686601283882b69e18db17c3b08598d3135d87253b0507a428a72a405125c9102ca49cd956e4906da87c99c8b1a4b646081cb539599280818a30b5497366a76a0024ac98a2f896ee684d2122face9a204060495280dd1024e89ca12f72e4a3134356d4272ca72458a144b5bbc99528012b0c00589122c5106e783521297167beae848291549ba62062eb46d4951fc8073fd290d83a3c177781294ad83a42a457c47eb3a97a428ac2c494b9c742183402386164b9858728314c315973356518831268c5b494a6a91b17cc12c45de285571fd95146153951ef62e05550c5dba684a13514f9c09411932708e0a161e9a7c99623353a5c812e38b4c3755248ccbcb521fc643ebc0260a23dd7129422586e66243922e45625072c7351569c105d0eba2844d13ce0ac917225130696a620974239a612f9bcd9048d26d01db9510f9e10908e28848691c53253594090386164ae8308506a41f9c88606a491119a018e981880cad20ec09a3740c1122507c873b17db9ccb65098286285da2805cb80245ca124b543e381531e119cbb77a1033a6484b578e30224c143137d8908455521321f0c2030c4978b8b5ce80b25fb6f02e2ca871e7925ba20193d7654c75252c1871c4dd6dadb4fe0c0b0b447c399b25a81da6c482aa1cce4821d3820d69cc5a466e0b1362b8a012c118bec30fdf529085fd3993053925824313087679d2027361e1c812ef92450dee5c7ea6e48d99169ed257d356d428692e3e0baad5855a6badce650b93effe9373459400503c29e3c585248e98ddfab25950adac5b6bad1504025bad56ab3c59e0579ee0ad15c6ad23d4ddaf2ddcf00250096e5e9630598363375135234c5dc0ae0fabfff565b3a0375ac400821e4e87363b9011c6142a8008220a242e50c8d4aedcb0459595272b96bc4b3bd004445b1f56ffab184b61a44869d326c7c6ac3fa334012401c5932590bc3083087cca9b340e54414adbbd1760fb6dd89d18376dbaf147a7c3c5ce70b8ac652fa55314a17750201ec4e7eb3eeffb60569fe7a67b909256c779bae2d0ef94dd19681640312d7c36c181dacd97db3fc481726e8b21a3eaf61f755241e7ec94edf8f385fe84092088469b00ce8756c4803cfb62f0618e203fbee87924a1004ff43c02f1f145e5512c833fa2f1c62c7a367d3c8f40cc272a8f623c3a9ee88f665ab8b83289defc0c48be44e451b780e687297305961566515985e7431e720049b81b728ee7217dbe88643303b22f11d954646a6610a57d1d7c00ca130cc07b507af03c4ad8f794e705f70cbaf50eefd63efe3d8fa33c83703c07e539e3e037284fd906bfa33c9fe785ca13267b0194a7d5e083ca0c9e569e3e8e437e7f1e88d4417e53943ecc8b4bdf83f284d10f40795afa1d942748ff879cf99043640e52e41efa9d8dd2607eeb1d23fbd0ef29cf201ce539e3a03c651b94e7f394274c569e5683f2045f979637bec667e0dd6cfc8d925d463e49fe6340f2bd80e4bb430ea11703926f499a648cfca137df0719234b21044842892ae691f92be8e8108359853ed1fb78cb823dbbffef6c0e7482525c720787893d71d8f81a5fe3fd3db880e4dbd96c90311aff51d520633462e53795e6bac8d8cea96bf2d960bd3f3b1b093f9ee87b24a1003ff43d02f1f144e59127c513d3c7f708c4fca1f288c57c31c28b69225d18795e500179f21405e4e9615cff0966381937833cbf31ae7f0e79561c9f61bce73775d2b8e73775324e47244f9e8285deadf342c31ffca684742d9aa40f3234637a65ac7eff596967eb6e9456812f3294614bc3859b1298fedd13a56130823543d4921841e209d3bfb3f9774ea119f347e98364336cd107c9268f0e18806d0436b300a5354936bd067b5a11a987eb505a731b665a4973bbc884eb7d254f9d5b3b9152905e5a96d05f6b3c616b9ba073bbd34e515519550f045de625782cdc69bf19f3cc00c39ef5fabbe840e7dfafdaef3db086ad1d9141f2c47129f879f44dd0a15342de3919c74c29156d0df6d4e15106b9ac8db0fca707a2fdc2f29f202e0c1ce2e8c3e803c740d17e9f617e6666a97be4f9f73714e5e9becb18906e66666666666666666666666666666666666666666696e2a7fc95bfe3f7d863b37233735fcff13b8edfa5aa55fb0745c82218cbcf207863a117efb0b5cbbf8303e0a5a10b4c6b1d14f7745798c7bfc35117ba21aef7cd6163eb15bdea98b807016ebabe877736da39f58efe9653fbf8773230cd938179fc67330eeee9d938b86767c3e09e9e0d837b76b6cee6d93adb9305bb0f75b4b0e1574548d4959f165e98e655511e2d38166251c19eb85566aa8eb8fe7d8685c29203f676ae773431ed136b4c94f67a5f8269df0550b01d3e9bdf00e57a797e4c74aeec1c1dca49e3a616f6ecac4e4f2a476939efdf59519a7df76c384f3d9ccd0aa7b49f95e7643b2e3d1be5f9a83cdbf5f728f6ecca50a92ec7344f8a766558887ed5f592aa2b5d14bdd893bac923915bb12795a244afdbbd27e549497d5a3e2d9f964f4b8d4b4b21b4c63d3f2d9daba2b40e06fbcad3daceabbaf2c10b1816760a9b3b6833127d24022f588a536cbd512997f973c0de167fac8269bd04f3f887e18c19b1d83d3faaee2b2143eccd09c1d9b92f0b5b9decd9b90f04ad3d3faa8f2a1642f7f4fdd24b4b90c965e30f2160135b2bca9e9d5577847b10c0e6f83c1a89efdf5455b9a93a7e4ad8b3b3a24f540bc5b56e674541d0dace4a2ce9f94dbf1a5349939efe57c6d66f341ecb8d8dd9cb5250c4dc13ec5c84bdfaa3ea1db5ec5c7f54b050977d867bfca93fa54c741c6af17bb84bb127575d7d54e377cf743f2ad0da8f0a01d41ccbb6a23cae83c59ea00d67ed8a3a4fc05bcb69a8a93716f21aebf2cee9e56e7f53aa85cbbaadba5070666a0925335b507963c10f596200c10c4840c0a4af1c84b267bdb19087658efdb0a4c0e54c4640895d99ca189010e7cb097e4432c3fe1964ad8d0870b3ca56a9ced63975b7eea983eaa03c294aebd85cdd4cdcedf79cbc1beda628adaf3a2a4ae3c67552d48ad2b8caaabbaa794c9e0deae9d6573667babaa00d63e99f20ec71b0f44f986ce684a57fca827a4c595ae688617190317ff191cc908cd1b0cd1590097e82f2682cc71f01f04862190332be7e9cf1482652f8940422beab3ca2a08c01a100f6143c9269c12399341ec974953120aeb76fcb23fbae4732731ec9d4b1a183f3a4febea2b47bd3e23c7cc3b98c2f59832c02634f1ae404284f7f8c0cc25327901780915da33cfd1590295040b66d02b29974c8becd20db49893ddba9a1faa90c7bf653e35a0be5e99fc04bae5f3c58916c2aca334579fa6784b1674fddf60f432789f8daa0625db73e7ba9018acb3597f510d72bd96d8668d9575bec57284a43baa284193349a2a64019c3ecaf5a282d852750ac88c1052a43dcccfe7acb19c37615a5d59bdf4cd0797afafef44b455b9e354a0d2fd6ff569f5cd636a458d6fbf8a33516f16db1c84ba9093af5e634c63d39107b3a482dcf91d20488263dd09be7755dd7b9d72c96e74561a1f23c16932b2656df3979b85b1256a42e8f3fba72668d588e62a2e59e94a94dd20b5b9a80714fca449b34d1c2471b542cfffb5976f723ed0deb4834341231cbbaeacd9d8b82f723c5db23112d997bead780c27279b64896939df4ac6fe3405e769203b172ded81951d65f24c27ac9c38d0dc52e36e48ad301d175507ca6db2aca490cb75f00733b0a53f7d0df79ce54bbfd3409b5391047394973fbf9a44d86e87728f4752d41012d2e18c1c18731d0c060f6932b38b840060b245c7069a629e1f770a67b3613d7442ef6f4364e036b6861850cb197b670847d462e4fa40994ece755bec6a9a8d43dfb2a037d75cf15986e09de7f4fc721efcf1598eef721879dc82391e7fdeb52a622ace7284dfc6616d8390450532ccbd3fbfa3d288b3cede5e7f2ec29af3cc179f83fd284beba5e9e7d75a39ea0b9d4b69270d49331b7991240dfcb212ee314c4cb94c9656dfb8fc09aba1bd6d4e6256d2db127d2f5c76181b8c532bdb5dc9601b382b2b7dffb03e45115fb22f8b10e0445b03caad289df9540c0b7e5117dd0f5e203114b155a7c20afb26d94c7a3effaf1cfb6e9e02ac7b2a1288fe78d2f7adfa3917f28926d4579bca7a4d7288ff721d938cae3fd4832e5b16ad2fb1699d454b924dc778eea7a6fc3c97e2568d58d1d2d63ddd357813e9b1ef032d6950a60b37e7d5a9f86a40afe6cb609924a484a48266882648b5401fc7ed35b0c4032592553ef7bb8f74eba8df278df3c5814f88d0d1c2c0afce69670bb50eee11b2421acd0d46aa43780cd224a48a6fdd77fa4eb41727c4b2af57fff22955ce551152020f8475d32e5f9ef7d94714f95cef5967fe883e4478a642ce3eef7e0b7c926fdb02a8d4a63b9f481299647b3223105b0d98f64b6b9f4815944c9551ef5a047af84642a8d25eea80a10f1bb3c32a23cf4736d8edf7fce5acfc28d3674b06c86cfa6e8916df6f8c328e97bf0bdb1016cfa7b4420197e93ac17c95005d2ef471ef5d20726ab8cd552016cfabb5192529bfedda6bfb9428844bd4ecd18c2369d5185eda73f6bf698bdefba92cb0470e7b48ab0d5d1ae635965ddda81eb815d59eb07aec77c74bd6f923e8b6cb34596ccd37dadf5dc8004f07a65734ff70e545f9e07f2b08c7b1470e93793ccd3551e06805e9e12202f654aa3267f48bd6f57292de17d07ba45c5e2935d37c2e9072068a7c5b22e4739f1d05db1e1e528271b7240206014c4a341260c162ce45ca022cc0b5b76487a52861147648872b2b1ae3fe86f5b8913140b7b27169e807125a4b1f32e6377d671998dc57aea1d5dd9b8f6e1818568d95fb8a78e238bc5fa56c8a1e7798deb2f54887ebd61c78d6b1c8ef5f405d33a284a6b0ed4fa1a7e7dcae44049c6af4f9b50a72098c7cabde01ddfd7a72d2fd613eb89f5c47a7acdc8c276b34de3b2fa6ba85c56c15cb39a3585c665d50bf7d4ffc8fed23ef5c3ae7694ba824005c1b44e8959246b0c0bc7ca519efa23c99222596048d6169616d60eec531f24594fdc53bf5382baf5595498a77e051bbc62d5584c2c1bcb897563a1066da01378039f402850cb47f5517d559fd5775563622122ffacec59abbccb63e3b8877ebde21ea806a1b4e0a472532cd49fd377fb9ebc9c3745556575c5200882552cd420682d0cf67f594fdcdddd552cd4b82b16d3152bc947850307787545f551751d548725f47e7c6d5c569f2f9804d65c56ad5c56bbe7eebaf7f83d1285152e0a1f18bd6388fdc428db9dde956e454b2701f754227107d006de401b1805b48136d04673d448417d3807eaa02818a7d124efa028cd55ba5579e2c00196e7ce8ed380bab5ddaa7ed39a17963a9aaff6d53ea6cfe64dfc7b62a119be9b7f515c6492f5de3b91c61f9e574d9d28301ca87ba0d3defaa3c510baf7ca98f7dff3edf18710d0fb367281389755fa447bf8487a73597d17e9564c58500a04e3b2d6923d6d93750ceea9b91a23c1f5af7f952a54a6aab2ba62a1be47f65520e27a5bc64878a960fff56c1eb9ea77a3918b47a319e5a95562202e074e813850cabb7937efc983f2b478384fcacaeacaab794c9ecd73c2e1a47253545535b6b06757036b1d5367eb9cba5bf714d6cb6f7b874eedb212f6b4d70ac9acef22914c5aa3364aab667dea34cbb9e29eeae559ab6e7d727d955dd6537d10b41debe95657d9542c296e7d9d27d63f742b97554a1d0cbfca11c39e6e75ab95d31877e5405c45ab1a65b2f22b16456a39074784bcc3cf1f7e53ddd3327c009027d205c005c07b64ac3cfb7a187cf73110bcefde8825dfbf6be240351cc8c6d7f81e7f906fc3c6534a698defe11890648cc6c79e6ff8cfe38f72a73c53b83b4f922778c90f8128061800594029e591e802f2ec7b41147a7fbe6b62c17bb57a3dfc8837decbf1379e99070f2699c90420fa9ff71b397ef07cc740e8fff99ff2ccf1fd48f7ec6c6d72907e73595f8fe24027d2cd7180283f3e83cbbc9f09588e8a21c9b5f1373e04450b726edcb8f16ca2d06fee0fe9330c916cde085bbc51e5e743931c0a81709943b9ac07eef16fea4bc342dff5076b6092088aa0088ae087e18fd7439b3b9ae4508e9f9ff7f91cef0ce4c1ff3cb3d014a63789fee71bc7ff7c6bfcf19383fcd2744d5cd645416303e0792ecff5df9403310b6df0fea01216e2e0fdc125bd23c70365f0fe601307f2f9b4709af9fedf1a16eac00c0bf5bc9efdf56db13bbe2dede36f3fe42047063edecdbbb98e77dbe07bb877fb13f46e19f8308e7570506e507a2e00640c84fe1c9fa33c3d28a7102555b121c5fe7c8ef7f9f1f969fdf8fc940e440ed2a15cf6437a0f0ee53cfedf0de765acd7e0f40eca1e92c2c03dfe7dbfefe071fc069f43144d72084739854966123d0fd9d707c945ada60cd412cfcf07a03cc15b414f89a33c2d07e5063e658e72830dbcc3e5f8f3755b3eb69f291e9288ec5c6bec47f5a571596b8abd31e5955297ff900348c25d17167bfefc043f5e53973ffd90ddd9ba269d966e8b03ddf80abe0abe823f61f7abe0cfbf9fabdd750af9f96aa3b40fa7a33c419ff2047394e7ebe6c8510ac9f106f80314bdf93e3e45642c4739258407e18b3e3c0029c2ff90df156ec6cff8703c0357448af02190457f00f2fb215d2194df54112902f955e9604fef36a583857ededfbbc1c3a177dcf7f7a23810017e00a506e5edbbf9f8e8d0a1e359e30f1d3e3e0f8e3f7c44d14b08452194473120431fc287501e19a0ec9c288fffd023993e4c20445ff445e5110825d12399e6f7f0fa9483ec3b445e40834944c658609233afeb9edf2d07d9e32ff9c17f374aeb6e37f203d2cfb48fbfce9fa3ce6be003207dca65fef3e210c92611d948a6d8cc1e87fae628dd0cf7d0fb537a8e7bdc24633f4ff4530a21e1c70ffdd0fb182a8f623fcfe6118d37e6d03b18dce365ece7874a108cebf037ff9b2a41dc0f7682fff929bb262ea3e0cfce06060be9f89e3f2fe0f127ecb427782978661a053e0e347ba09fa70d7d8e339ad5a8344dd5554d2b996235220000003315002020100a078462c16028caf358dd0314800c7aa04064421a0aa4812486511003310cc42004100000008620a51852ccd40e112993c39c9f0bbe44fc4afa2d9a460bbd248a960b56f80cdd6a87d2409199d39c0718449cc39f10628e7e354914e56b0a11a84e5071dece2bdb4393a7c664412dab83a3c26e8f97dc439b0492dd05bcf3ee0f2a04a8e53584c5f6896ce22d4dfe929e662e1fa23e98248ae87b22046eb927e450c43c43cdf1438432a69493835d50eb2057d723a32dff72a4733999750eecc989942b035cb9a77ed622ecfb2fa6d3de556b5e561f0cc9181e2dc9f7fbf1dd5748aebe31a2dc87ae31ba84913d5ec9abea65a9a04294b9a3bba5fd83e28ce498ae80f082bfb85b1fdacab4cfff0ab612c0e76989f6b85509a66ba4bc15fcb7d63ef3b6aa640dee6f461cc25376a06b614af63b9cc840f41627ead42de25cfd2aeb983c0a86e177395a92c0a0952769cfed5497b5718291b012a6fc4d7822be931f9cd717d1e60d8ff5badcb38c30941405e05c9878879f415151ba4bc1fee9ea3b4dc206feb73c53cde6b6041c929bd5fb6d46d8a168ef2ba287549344fe48c31d2000407ccb2611e2354d71ca1c3e2e1c57c9212db40db819247440ddaabd3ef80c1f90f064c08ad8bed2fb24bcce93d58e882cc03d3d77e358eff4cc01729d201ad99ea53758255e39f3adcf5229cf4360f02a79024194945a6888647d2807b8dacd1f6225e07b1b128914388baf8408dd85b8821242f0e5414c1659986a4b7fb737791187f945a1853567eaf8b3f81acd428a39f172079fc0ef3356c12a723e1250728066ff8da180c6354ffa654fc4e020c1dc4a33a38631d024082adaeb217de5f4cdd3daa0a34ef7f63b39aede2c65413cc0eced81b8d7c56e1834a01cbfcbc7c8d76ee5a9abb0f1cbbd8f9e3361519f8e50c6e4f5f5d111024de94a320deb592078045b9c55043266db9ffc224273641d283ae4238f5d54080f804b2c13ce5f4f469e8c0f037a8b8cca73c8b8ad3d309af94dd45d6c64d59d29936bfd8f443274e4d10169185b0705cc4564f4a23a905ed484a517959689e32d4c4813d91698442435e704a3bf4a7de65de4d09d2597b07df36c0576ca3f3ca8eeb9955a73357af8b02869a64eb834defb72da29273630c0cdae1d42b68a6118f18d85203b1d3e62a841329292a6b2a7e80fde6001d09f1f8c48d4c665b0fa485a5373e9e6ae25ff4342619658a4a7476587ba9d95c5c9dc39f978cdc7969171ed8e2a46656985bcf8cbf013ff7b54230f1dc0e53fe364a3e0146d318c5255267ef6eb56e1f5e43521fe850c12b12fc41e37e4acd4962e0738a6619cca6229ec04896bb95ae8999970de49fdfdb79486258f703004b5c2024a5e31dd2dee858ed7fdd5747b7fe1c8c4f4d938affd6d224ebd78d93d734dae568bfcb6661f81307c4cd3ffab5952738b6feb4e85496bba8af18170da09daae3cf0c688e73e438dfbb33b5f903b054029a5d4fd39db984614840f55d621d26b08d220c6d6928010d239990b0eac254857203b2792f846f13792f9c3d384d8aafbf05f839c60fe6e51578aae483e55db29661cc34dd9f929651d58d778760245e1391477b705d2c11e80363910f7dd79dbfe94eb6700d38060046b00044bcd025485788470106f445f7760aa0f350bfeea552e11b216fafc413eed55c4d8b981066dc975f3ce174105970b90bbf18bff4481f0e02ec2882cbfe383f00a705852125a045422ad13ec58b8d2f158692dae94287590276cc1611db23762923b7ac7782e9f47bfc5520ba4bb8a5eb2484dea094ec0f0a07733633aa1fb22bbf224f664e1ad361863f29dac4a71ebf00137a2c875c5b6ddcf1ba198a2762aa193ee69b313e23ad95affb7bab461c481173b1901c772392f612b62560273044495467ece8c04924462a02fde614c4ecfa02793df8f501d34e4583b63ab8a6bdc596453c4bd4032f28533b548c18838629d0e183073496a6d575ba65f9db4cda5d3b31858ee5139d25c82d17446ca06772e4c5f9c612ff9df5446837d5c9b9fc72761d93e4aaf8fe41e823a3d258bcac0c2a7f63e42af41c1ad0a94dd38d1f6a6f5c8710863f30d0ad6ab50aecc163a92ce888c27f29e4b1f8049e907d058703d467251fbb0357175f92eae656ac301e9925803c5c3ca945fe25edbad3829924a9de92bdc20b2d9eec3c5df3b21d18a5f729211ada1cc54712289227cb4dcfdfe7e87a71d9f57bd16e059297c42c012a690ca7d95630d6459c2eb5480c6d16fa317d6e3e65c064004ec6b109c070f0ca606fbc5c2f8a1e5731d75aaf3e4468908b4443de32676c0b03d3c4a26d71cfed66f76427a034541da17620d9c6ef538f8ca4054659a77f5b04a59c22325b3d8541f77dd799314ee13ec754a0182118dd299b2b34b74046897a07541aac1d6aa825f0628dcbd2bd616ad89314574d030445019178e391bfa94379bac49b83a12759083bbebf80537a1a9ee6dd293995d024fe4001fd0dc67e6bf89ca5d0b975bacb6df714829191648322003e546a48b08860cbc82760d32127e7bad105a67eb4ce820e96b2189bf79dfa590c0c9f5b062656a279cef34590e27493c1382fe66de81ab7910e5354c3da106a4ce2cad0508b4f6fba14b9ed7f0929a10c87f3c0f2d4708c33cc145fb450814cc52cc8dfd2acac2d404d03624c5c76fc95843e817424a654eb8860222403c0fb9d2783a4d97af105a568ce64baa92fd7b067a4b0f7d1c5433670b281256e4b7fa8a1c1eaa0d371643e4687b74bb5cd964acf1a0a89028b3b5a9bf0c67a0e6285cf1a5cdca779ee62f35d187e8f8716a5795dcb968cc16c97030dd129c02bee0182e215b5b0b27577cae6d1ce4c5a570330cca870d635fb8eefa757dd6d2fee45701d0121367a86e1badb001d77e5b66e06ea36926a5d30c8f3cc2c6aa8b5ae6799ff40d9b9811850a015537705ccf8d68425c8e7a7670da20e254c833f8c02710574c6f4e51c7ee7e878ff03a1433b2788920f4ea88c6420fb33161cfd53106b792c16eb850ec10f40c15e864355fdf07fb12c0b26f4af0958a3b3a43e42291539cd920e7378a4a06df5d46dd372f74a168f114766c114e89ac332ae2e50b6c4e8c0459ce0c9e530bc12b5a80e4a666b007184e06d9ac30d61eca9a1193766e0e6664dbf6f0d8a4fb54e0f490d2cc77b07671d3fd53c340ac44aa416684ade069c4f9a73d62d22fbefd8b1d3a2f2415c68af98be95b649f101920a9d8ae9bc1b078a8faf079ce361bf9c28d4ffc6878ea1407615a081cf483139aaccc70d6ec86b5dd913ea503c299dadc187fe306decde962c67cae489b55abd69ac69c0d5518f6315c6ad3ccfb6ba6eb60bc54384febf516484bc58fcb0e33c8464bd551eb991bcfe7372da76286fe689cbca1c0e299786109c25f04e6897528ce4b1f1e23d6ec69698f92d63a188ad5a9146605cf0013d89c0e41243347651bccb95630478fd79c0c63e440001f00f0d1d16041b19be1b81042d7fab31a39ab985689fe6eb6d1a39fa0e08d54b83e049da62cdb03e35e7971d42489fbe160ec7c3c2dff39460b282f20874e7c689846e9a21969455df6a66cd685665a84f8d8124af0dda415c0d504aeb7fec9e954b94f599631bd5f26c05433569d3ba5226fae972c1bd8adcb258e59d2dbcfb6ac863de1163b2afb46d5e2bdb742777eda03e84277427819f7c4582cbdfdec140a113b903b2a1fd1fb5313bac62c52b14082eff8e488391ec74680232f021a6847753fb4f1b924308a6625695f5e7dbc0b272c012a155fd6aa62acbe18f2da59793fe8d75887aab5447f3d3cce3098790c8c46b418868a0a248f2a1653ea86df27dd13bf4b95d9fb9c6d47ad29be55c6449918db4c575852d6f26cfcb37f29d85081edb025e41e455f106dcfbaf8bcb729cc7b4a0565c6baa99b756af55ddb51a9d99b2b2b42e55dcf77bc3030306dbdfaf15a6d9a68d0e63c19415adde41290aa165e0384d010a03a79a00e87c8067d579c0958d1f0b49aac87a7c7321c5c96ddd8b7c7cb1f6c2402d2a207ee1533ae16acfcb6c6600ff6b43ffdf495b3280c5b749f56882110169d807cb7f1d4c9eb4ae7df6f147508cfce7a5d947599854597e57b1ac05d680c3304b42ec3f7ac42fbeb7e95d97fb2ea8ad4ca5f0a1836f7b2658f08586e5c4657846d067451a058d4f75d889c7b81ce4418d485f83dc812cd3a9c8f27e0a3cc4ba3a74aefea1b6f6f82f16aeae47b2f7fdddcad97175e9c3b41eca650d3796425b55fbd9e66df5761cd307e3b50d3c3c867945a372213d84dd40f413597226c29993c4b89c34a8d42f518108c09fbf7021db046349a7683e2db53dcc01523329d1272cd1bc38549bcd6edfd8060c81c7f8e87fd2c5f4c74aaa4ef6b904bed78f17938601f89cbdd8a0d9b6688c0af3b03dc286b2b49a6bccab41cdd1705fe43087150835b39eabde1786a19fbf0bb82ff233ec72a8c23b2b3068ee8a7ea74d4fa81deda436020a3b72c66055fd6852e7dd2bc813f956961ca66b6699956d8a31f8a6fa83cb00039debd81207c352923ec5bc56e4a508cb8f179da60a3668ad025f949f07dcfd79475803650e281eef3a15bb56bf961f7aa4666a525a3394daf61076ed866d13c553fc31f1410473e4696b86cb884c3a78dff2f638e7e628e8309dc7cf243c60334b609a51d8e91476ec24fb7457041e71e4479ebd3ee2b50ac8f361ca025e02027e69127c59736c9db7c0fdd39d26e3893372b84dd929fed86f82a0a035bccd0474c52441c99f81ed04b591a52794122ee6462e676ef4d3a681d0bd16a4dabac3457c3cd0e1179f18fd41a5330afc642133cdae8ee8d7d2d5bf5be4d3d0970d4a80de81e495fa93673cd76e0ac245fd5320019a4cd5b7bf0d488346f4dc23a44c046ad3549e2941c679d6eba91233e91336bd3cbbb084bcd485c392419c4bfcb69d39c04c19d60ac381a01efcbc3042e0f85150f2146b5d09ba9179344c7cdb876a6fe608aa4c62603efba4757f2288de355fc28e7761f85f404ce4343848ecc3fb931ff07df80f121ee27969a96fee24ed4650acba702788416dde88e2ce710acceeec8dbaca49462f0af94f8df067247140520ec8021ad170bb17bf39e6ac852e8921172e3ac7056cdae4116680a72ad74702eabb073ba285b41d9ab95be7ba9cf0ee65675213d436cdbc610a3fdf1e0bc744978484720041615daa20c3c353f0c93309203eb67c7346a9fc7bfe7cf15e167fc2e1547a2ccd0fd01f438be01401c11a0af13d656585e59e981c761656421e40d3d05a28924d31a6e3643d25001611b86953450ea445b80ce2d053059ad7b523bbd93a5ba6d0bec8a97bc5d6bf7bd79eff34f7ebb0f22f554a4f73944d977daeb76336686ad4f2ac8f63fc0a323a2f7fcf55ff5059665638d8848cc7a274a7263afde71bf8de098b2967397056a3d662590949cdc994cdc255776ee4031ad2aaed428bf923bb21c55e11516b44874e4deca4e3e21e0d36f7f9280b971cc298db16127c6a859db252fa77910f47f49f64addd8121a0b7698b1baebb389d89ff99ee1643667b2a14c6080d4119f95c24c730f6595cba6af4254bf19df4843acee2c97739e97c0cf4315306f55ef0f18c887401359bb7836db8f071cc4f4b339da7c19c388f160e6f1e0c71a51cc25559fe6883aad6a55e1db9c1c4cc191a1167c83bc68dc9401074372e9c80fab50f89bbdd560e8ad225fc8ebc85328654c571125b06ff2551cf292ba2cabfc6809cf1da85a71317044a1498f42ec827ad20b92dc5b33a2a48f1b8c831628c7721a74ffdc94bc7ed01751c29e8f393d5545e2cb61353af84cdb9544cf67ac4ad290c60c08a491c94a25f2d270e84943dc0c387de7fc897991db18918e4c45e4645dc67ececbc4c4e5584c9db3d9152e9d600c9cc78912703176b42e2a0f93ed05cbb7172d190aa2a5e3eac5146f85c430843fffc06235e671ccd6377809e40920fca18c74e45400ddf37a7b03ef1d786b3c51a297d0ed052b210cb50f4dcc4fb0eb27fa0cc0718f91b10d0fbc584c8e2bcfb5fd00e81f8c8d82fda6a4bc359990e43427d76214edd3a144fcb57eb7e65c6e4c379287e4ce2fa024b3fae6e275fd0c75318986c7362262b1c8b4be9697ed1c344c5eabf31f65c0e83f01b8e93dedb624105b4ba019186cccf439e4c87d50ef4d12d21ecc96e0d841b97bc51e0382870efd01970f88cc6718c4a22977424413ee9158528ab955cbb187e6999940479e12ac4eb183c9e27d6bf00257c43e7fab759d47d47c408d1a3529716087bd9147ee115b797b4ac35baf0d8a89200f3ee1b4f9233c99c593b20d7b2507a8868d3ef09d2573132f59ce91033179f23a447b4693dcd0e14a3d6bd578151e6b4fff54cc52e39bd7f0304685d64a629342472f51ee040d2f6583dca2cca3ee9ef628a4f1d00caf6afcd66808ea7d3cefd9f0cbcc83384ecac5847d6b92e5fc928a5e29574c46c6cb5508a77814aa840470b858460986f23c42b1755989f6becf82cd4f7304db2c9d475234829eb7ac41ee34f6acad02f0f6f3dfc90f0d8980294c9a7e9bc59f3461aac7470b3de53955ff7f796db4749d044c6938acb0c63c6d81c93d1ce311d85b28e321be576a07380e4c4c95fb72b58aedf7f36b701c9a84aa704974bb741f1ad5f972a9f13bba5743e40c8608107bd50030c9186645e9767d022743c5eb8d273975d8e9f425a6bf3a3a5375832a9b5b49a07263d83e46a5a6c84843a5665e567d5300dccf6e84ff454eacdb879f327ebf51ee88f8df5c7527a2b9f2049bc1d131f8456d13b63a9ec40e6927408eb5e3d3b3e8426d0baf0af4f5059dd79c6b672792ba3cf63bc26f98fc8f8f8610d86f05e165af0d2de02ad9d1fa919ee23e6ff7f42b1df8d61259aa91b581e451a702498f22d5e93e2c290b384bb3dfa647dc21f3c81d57e0c6e979a9118c9bd7503ddaf01be085a59a42e21684f0553282702db8c49ce54b49f52434c7520eb51a82ecba529c33407866b5c018efecd52b7584eff569cf0c1aa81cba5c73b0e8bd28bc9012a800a424fda8d2528a306a2f6513ed94657a890da33e42ddca7192b0ba3dd28cf791c93cfa8c92a4ea557ad0e0b241e9538ccb2a4ea6bae47fb667b636da163050faed22dc2c5091c01a3d1440ced9744b431de139b5be196239ba6e3838060f4dbf8f237283dffce9d47a60872afb58258f921e4bc219b2e1508aa43ab33d5afbb9e4abb6af63091d002a0e28561c3e30ea314a7f89b54b67143538e4556c89306152ea679ac5a01951001e521b640a356b5658b21229357f0707a4853aedf8919971ccc76f6cd4a6544c48c401de79a0a722e44c744913528342799687336206c491aed40b640986c7c8f2243469e8d1941ef5b7488f5503083a7b6943ebb29fa292577ab7c4c15b05718628152e664dee43cc97411d8b76bdf0015bb296d1291d1f244fe4892df5ab4ff1a49441dcf79218362509380e07b931a848a60038ebea50ab486a3f1aeda25ad200036efa5573c1c63577e6545686a55a4c69677b23f0ed7c1233e35e13ae9b6d4e51a9bb8b7096d9efdb4df2468d8ea21cdfe192e6f0f4a9213aed8825d5f22dceeacc3bb5f4c6b9c57970ef8b98cce285834e0e2360876c810bcc62c69682528b130c425804fe0cc8c2fc0d83f34802be2803437cdeaf7a7e7867958a184a9a3beb2ad20de49f746df4c9aac6af5b2c399e874c2b81439f95a10ae32ceb54dd4011df2e5b6d9feed19d117c6c3bf2d9f2d9fed6d5cb70fc79b19c82f88940ffb65610b65364a0a2cd570931884f59de7fb6a5ae1998f073d76b76f00fa24a497d2f009ad4a51a606384f4521b632638684882334947e21e74f1eae23aa691834088df7a1a840891fc0c88c4291c99de2a42267e8fd40a182f8601dca7e83eed82e83ea23b8558c4d86bae9973dd6861c0995f602583206d4aae609d2a3163b0894008e112a7281ae5837101c4e106a75e51db9dbb7446b8ac060fcfc03b3dea55ef830af6d074cf4d93b9bdd6df48c7d0323d804ea8d073636d3b290f4276285a89db545de4f4093235d3a945bda5c2f5dd98ab66cbe9b0818990ef5661e31a943bcde4fd27a83432eca02525c45aca0f7fdb95d719151466b38012444f72b0da90a5e053391018f91b6d8466edec407bacc63225c058d2d6cd48d876d0acb058ffd501407a9682f376ec946fdb7aa907443b12d515c9441b950de668847ee494ae81464b47cab53d451c048623c04fb62250802bec842582b7ba541a80520315168ce6295a496d74962d38ed2592126ba6841326424ea157bfc37a98f08b94320e977efc517cfeb2bc4cf226eb32fcb66587819183ddbd2acefc3727abb6eaf9b5cf2914e448e0cd0be5b5203d2e60024ef62168478f3507dbe40eb8edcea5e9053f52d34221fbdd26fc213136d9a55407c22a60a38a0900bdc72f614cb49a977df524079687c4daa3d8019173f77ba18a1fedaeca5ee0f9d06b2da5636e8135fa6a592e2693b27a6c1eb732ad8a866e3a703cf31ce96949d17481a98837f52828f0562b62a2c9556b3cdc7bf2c8cb3c9b5d30d7104442aacefb269f5c11dd98463ba5358d71623bb3fd2718acd652146e8dcfd18818415be062d92be9e57dff56fbfa974161dde38d982b53652bffff53b4a8e2c963e986599ba369fbae8f09ebf7cc06043ea2ff35f7fe0b26f67f70f508132f3a5076f1ede564dfa562c04dace3b97ebc2b6bda9495864ed3e4c730180a67207f47761f5a0420f1765efa98b1dc8e5ed746acc307119dd6d4055cae1067c88aa207f2d8350d8e048add61a8b5512c2fd78570d9cb8010eb1842625343245649ff3ebbf88627677d10200c6ec166cb5e6f5a9a490e4c7050b86db8b2d88a24e9862c18b48dd6702b569e769b2a896a2378ef8f85a043da11106e13773cfc494bb0ee04660d8f2cb759f103c78e38d2658d6e0cfe6427d018436e714aee83c7bc0bd7ce72d9e664fae0e42b6729dfcff3d09b3e8052b484513be570ab8cdfcf1e1aa1f801e7c68950a9858e0aff0255ea56a65b2d9900840218838aec0e84482ac72ca885e8984d7beff43b2e7f7e688bfaee158b6c358e55ef4c94e01e41c3da04210e086bc788d6e32aa6faadccbd2ec7df4a604e5291d1b4a7f547b3317a9c9ffa79882cbdc80d2e0a4fc917f15873c5c02520545f391257aec6d7633bed31a537cab090768bd5212f7f36764be5501b691cc7b332766a3403f22cc1df66eaedd03c7447c8958b0ba809c835843eea17195d3330fa0e99a34851211ab32e8d554d0467612f02b2561907b567cc50aecca65f6533f2215eddfde36b9571e533ea249a88ed2dfa4930e38a056610ec675f50cb02a8e8ba58ac882ddd2d980d909d6ac6a145c6ab15e0a618acf9c91e8d1dee2efb6187e555cf327d6ad11c125f3b8f3bec092f3132ec312ff8eb2a447ed026644df816c054b95631a61e0a29bab94e29417d44e4115eae80aac4edc8e9866c7c23ecd1e0c064d071122900a9c2383f5414a598811914cd771a493ae54b43a8984ca09dc08c2bf52f99a705f2225b73378afcf91795d35d89581718e93a4bc7d60f2e9a000b60d97761838bb11fb0b9a518546f58abe037431e54df37f317f381baaa28a2baaef2df32fc2e036bead09839ab7037880b6e00c35918e590eeadd3946d50f969904af22f76944c161e057af6a7103d1c3740cd804688a9df3afb75829a28405c027935f11f960c7bc5f4ecd1e561d383b79eba369f88c917b4ddadf5a9706183550a48151aee349f3f97fa00d3750433aff1d38144440a87df36f6569e8d2a120e19708fbee901ca97de340b62c5af106b7b2902347518583d893d2b4b06649f88e58ac4f0e88cf55684e5701f799b46d37134cc8561211a91eb817eaf6379d1a33f9018f36faaefed74388480f4cd40fbe06b534dc2dbd29c516ae6aa5f867430fc27056859c05aa812d5a3072e9e70c9e6c1737e9a471c9ae2d10ef1f0c2c8a5e2847d1a3901a0e7f47e9e917a3fe98e0f145bbfad9529ca83f19b880337ae50de99d3ca54cd2804da4de880f9668e8398f2d1e4816c70787844c72377709dac922e2989f2a41695fc54fed030a6397e09aaca878f8171dd2a454ac455ca29fd108181003b79193c3d21bc305f9fdeb26d82734ca3e191fc55bad8e65230f512e1e91668cda4982bb1c9bf74d7d5a5505913d4005c771adabfd677491823dab24506dc28e6e60356f9ee17d0684ad89115a881b8c46c39e37d78261c4c9f1ea96fb7e240a8ffdc11972179b774bdea980cab35d6dd2b8eb9fdead014faa033efffffadcd3899b36b498a1cbd46c8b0b6555a93df391aff08979f8d84553eeceefc16d8324d672845ede78c37b2af17ef28deb098241349f9f286b245544ed8eb0bce502e7eafe3e25f5f6dbccf463778640decafe8037c8c32b8ddc36259b33e7849b6434e0f7e6ad1809a438f0320920a008e3f564934248ff2e076df4997454bb76ffd5ab4be0148618d36ba0bf082cb46dfd8a3af35b6485373701b53c43a6edbecf69514c4d6030097e3c04a14050bdc4ffedaeffd124c5aee8708cdf4e1cf14a399ba2da3d4f3a2db0b79b856f71ce810e8a158244381e6770aa43fa939ab577384373730c7e8f39578788c95080227eca3d88a9d18996ebfe00fdcbffc26c2d328e8661848949260bbe58a11569af2679ec5893d1603ae96a56d7df3e41ec31d470d0af9c2945a31fc02d7de0ca87b31c73aab6b399479ba2ec68405bc9a96b87828263913b75dac75dcdf8e4e81b38d91a1e79bc55b6d7813c0fba5152cdb26d633c49ca6085e860f54705e6f48dbe4456e471fa68c02c418195013d32c580d083b640a1075c57f1ea27726d94b09fef5a29408e53103b362f6b8936439fe5d0cac498bcc8ab88606b4a93bd920b66bb06d002829c3e2a8972179dce4b0920609d742e180d902047fb7224634d74d959d603b7a8d85844cf700741b4bf388294cc1c96836854cda31844e57b4bad0f578344220e85863d2864c2aafbcacb454a2c6845cb1a820a65b13374dd18efdf934ea87eeb0d98d0b4d6d7bd1b15e7a0762bc74e0ca51156ae11502dbfda8a0a85130910e72693ca9ba763b12223cdd82e3ce5b4e9c1744451458df7bb699d80be7ccff27c9a1dbe8c5e95db6f08a04949efe1a20e34ae4167584079fe935262c4d13a59a15d8306366bd41481fdd36e241353ae9766a0f32722e773af6ff36f1ccc4ec7bf35894abbb4d80222bf191fe1cdca660b697ecb04700db84d1f9e806c110c5dd606396564b7a49e536cb004c367006fa5eeefe8a3d50a090dd0abfcda32b35d81a23bd732960f74fe4801adbfd6d9727cb9cd4607f0c11a1b0a2d2d2ef84c22e110bd4bb1ec6b1f192df289dccf0c35c468eba7a3069cb4631a92937690c32050216b50f86a0f364d35d6028a04b4408207d4294569c81b5f514164821fe2043f458aa26659d5bd367291a60208bf5a9668bf704d94e1d74ebb93479f3a366f936a1a8de83158ab8431a62c9072a73d2da93be811dd33bc1c83a51796fff295f316c85a5059b574e962d2c64e0dd3b8034e2f7c6b1fecb79d1941c5e6b33cf0657801f8c6fb340d1cc1a5e7d8f45a96ca42d3d5e5ddd540b70a9972f724380d017785889a76a58098534001ee31edb2495863f4d51302a42c7239ba2b0237da183e6da316cae4cc64ad01b67e2a8acdd389caf9a0b110f1d775bd3a88f46865e96e1b89c4be1f3f68c12347946c2a9c6b13fc0d957d44f62520e239297fbeb3d69aa049daea67c88eb6752980aaeb58adf0c2cdac2596d4dac71780290e84fe89ca9ffb07591514430e54fd56bdeabfaa37542db772c7d778230928e87c0de503b0df4afbda6c848cf8eeb4efeea25509232bef74e4a02a052151a1de6cfd8efb76f3369b2f7c4f9188ae4052428bec6cd62fd724921d3cfb8cff84c2ce479b04812cbaf0d47b006fc1b50e03e24c1a362d413eca8462fbf4a676f3ce2f3ec6a74b2450ee87e09c4ffface4a4e16b02ecdcb3f8dbe83ee328091f8685003534733af57c469d35c37af5049422a05ac96fe7138d5dced5a1807392d099846d114893fcfdf32fd468090b45e7f8b33255335a86a950db21a0e9c41382ef92c42b5883274248148c42e1b26974f35a1b260bfd931b27277ac9662c4f52747e6ee5f931f4dc6eb6f94473d028f7a99b42da7891c68edc1f3066d3861e955388a08dca9aa5f347da0670f6e6b5751d490902f0870ec3b89b8c2efd5f6fd5099449a992ad2f5083a806ffe72482418d12f5f0fb94ea67842628e8b8eedf6540edde1f12ed197a9244759ba2bdf55c7ac312abe131330f6774fb665da5750553523045f1d8d6b8340cd16344f4e86bbc8f4ac616529d35e6ad08b864a396f4eefab556155e2a293a575631a10241b89218ddf7d4773f1536ced8f11de9433573b03e307a6b238a0eb3ca11eb9fa8a4e370646c1264267a262cb0c053962420e58d7aaab5f65f4c50ea0c5866ea6f260039d0a42d29f50ecb611c7e41775c552f401b560b750e3cb208e9547e2e33e29adf916ece95791a9b9c2b74c95c1e001bafa3acf68c7949d1122b6ab2f3ed8f1c644084e00b2546392756001140d7dd6743e06b547661508d103a580b7abac1b57324f587313a0579984ab62e55626b9ace2906f10e143c4fac581238cda4936c5eab917218d58240899111cde565d9e445e073a1b0f6716b260a3d8c5eefb634995992e399cc3517e390b0029ec5359274103fb0b53370997a7a09f7e2455a623bbeae00e40daf80ad3b2a819508ef32153e24c0debe064052cc946c63c1ebe8f98960eb18e21a6997a5add5211599252ca43d08adbef2a2f8aca3242549effff1d91d2f20693425049cbb872c6feb4683b16fcfcf4141f191f795906333fea9ce0b3dd0cbcf4fea2b17dc87809631e7e00f0cc151dada0813c182f003bd8300741d57194bd8c32a11f55a3ed3e4b3cce6dfa1b0c26b7e3b6a8805855740100fe01e791cdf21ae0a4b825ca536723c2a1b38754aa52d5226e03a3717bdfe8ee9a1aef30bf9a7d5a9bb1731dc95e7963998483782010bac1ad3abbfe0639317dcae0d5e97a9f89f9734fb816876458be2ae48efeb79fde86c0c6329940ae5359dfacc8bfe635424968e7facea5a600ae724c88bb8bde35566ece99abde3b7e2a6fb0f03626a7babd10dba158f160d6f940bf45950601bc479904c7067dd0a7c9d894031dcfb77ea878d8349e5ef670dc4d7f7b73941b970e3c09d05c0aa01888846381af659cb3f9d5e3567b2b67e9b156a6c2bbb09f06fb7007473c241aa8c1d0e54833fb54a610af051854d5ffa7881e9295e44a8842b690118638355b3d7cd37e7e8844055b276ea8aa762337288e379441e099cd57bd5c9171c47ba058d78a07e86d88c8547224f05529164ab7ba4cf276a0c0d7d9d21d9f0bc5fe161a38f9c7e32acfb93c439b8cff7d2dd302ab95e5012544a84d002f33e0e126da62825c231f30ae929789260ec5188b58b1f17df3114999203c851c4628a57f9ea2b54270daef6d441534ebf0c59c0fa18ff2cd114929bb417f284303c68b5fd19067dc6572702265d67a7673084546c21293175058f4789573d1e3a0406912a2145b58549516691d2f560ecd4ac11b83037aa45a9e7e9881783870c249717c7cc8475fab5a33ae6c96f09372266207d7a0aaa0fe417164d95e1e8b5b7fe58f10aa2d7bc053e7a8975368646cd9a753226518f899712596e1052c7e165afc08ff6e66d7f8646ff5a78c8250e95301731db07fc44f95715dcf71fc190f30b0e04dcd5eedd660056e122139481295e93675591d5f656ed7c9218bd436b95912b16915320e54deed63bf832b66cda568f5fcb0d6870087e7fa528c3d2187f897192303ed472475ea1723cbef9f656040018033d7e2d30ded3d070a2a142223675704b80c3a99b357544c036bcbeab6586b07190d2b786c0180a8ff2c79e8d50beb7d1bc757303767882467435d8e8f6d38d1f85807fd67e6f282dc6153590dc182b3a27809e99f7f56f220cac176aa6c36ad42c6a10eb1179d5489dc75116d44ca7e715477ade01b9f311552d415261b4445c8c4ea7a6c2e05372d9986c6622d13a5bfda293db91041280cf1a42536beb67e142c6592accd37194cdeaf5ee7d066743d83ecc7156d03e82b6455d330204f1ba844cf44dfa1cb96c47d8a121360802bac6fb47d9da3b35c539b922c0dacc6c03aab2634fa23b62c042930133cf3744478b6608d304240850151433bc44c35f966e70a7c5beb5ba59581cd5e42cb013e3fd65f9c8e847b81164ccbdd9d2bdb90ebf08b2afe07bb50dd01fe04c705c40f31c805e0d702bd83854d1aef05a298aaaa313cfe7a1166b4f7c908378be3b20ac42a24f74a8d9089e4631b6a2d606beca264a20fb479b026cb5b4d17f4a83c9644487e752228a88411b5685193a7f30c24a0e3b9093c9e6b942f810fb2f9a2962d42116ed1b62a91e7ca5948741376d91f3019fe642e1e628541ecd51b7a2181e154cfbfe5c1f08310c93ff3ea6aab6fa2877e70ae6cf935a51f40a7ca5c1afb8a16ffc3ebc87f5e5cc3955a75f2734080e9d9f7783d0e1fa8f0a9f9fd7e8c0ca1ec0ce2668eb29a29ce118cf77d4bc8e5010d4471002b63a82be3131348ef702565075704c15a02e740ab588240b86c63b6a381ba591c7404155b05d0ea4ef54ab9b7246a3584749e51417915df3fbe1e8b65e9b6488c5bf15914199a4f353c9fbc00dd296a0d724ab2c5e79e646aaad627d804960742ab0c67d7f131c9e5d91987ea69481605fd5d0b578c738d189b688b5d51b0960e18291fa8d71ffbe8c40ed65c8b59071d720a05144ccc45a62b1b9cf95533cd47341180164d827338156ad9d39fdf1d949cf2188dd0bb8774a97563aef3baae5ef25c07c902ac03280cafcbb7f472ea8ec3e0e663d5a75dc27a554468d75c7beb9424088f7d7d44bbd72978b93922f40e753d9002d5d5c437e3e66dfdf7e6ad998b978fb014287916b4fe747504c15d6d67a8005c2f9e425febe945e816eac723429440745af919861a6b3b8a5a1305cc55087b7906ea718ba8ce93eed4674637115d73c231f88a1e914363c869b243acde899a06e48da3fa06ec09be9c5d218982772849a35db913700cd393995fd8e47f6ca0d233d6fdbff5831d065efc11afa4343faf46a009145f2e42cf4265109f21bc2d856002a14e329408da348771c2a317220472d741c4ebe899404c8172a49abaf41edbc343e61a84628f59cac0df28ff52f9a1bb028e4a61b4a09ced008d9d2009420909bc195b44342f29dd7db5e516bf81d7d268d190f6245e8483cc7c67303b7cdf8ec66a914d1b0c7edd268b6bb79e491e657a71db027ae8120825157ce4f2290274ef9ec77cd71514092cd06a8b89ef471827b8fc6f2db67146868dcd3ebc2ed35b71d36967faaeede353aabbe7bbfd6fea1d3a3665feaee16c3e6d629fc62c43b7de5b4fd340b1951e3a74e44a2619dbab58c577cb4ab66ac8ad59978fdd3597feec98739535138761b70aa75db868017d547ba4220d4da26f859a68c33f1e0f4bac61f61b9fa574e47f7cb93358fe27d777980905867cc01ff53641963e8138fd8f65a292f3b21d5d82a88c3013c0949b909014fca9e659e74bf975e6316567d9393e86e344dc8c877fb379e0132fe23b9e8b09cf4bd42b086c962da07c31729a3618dbd49a998d10aa5d873878dcd7c79de3ac8dfc35313d193335c960d5e75737a8a372c7bed51dd9881815e48bd1167667ad787f3432f5afc0b35271c2773c2dae69cc5aeabd3f88cf869dd084801876766a783d2895315190a1a173a6b0ba36ac967ebc6fdac76947b79f8c22246c0b214f13003aafee9d2dfec6d8f83b76421935a8625d11f6066056d3ecdd020f459d074b21e9237824084218abbb595913e2a7b2823b24329dc3b6162abd360b4a39d2c5a6066dc8b930d6618ecb817e39aa6ae1f5cf96ffff7dab1d3d41d3cb434e459c08a7d631d586ab55f58c5228053ce7276ebee9a81fae140d1f8f930dd734c7830a08a1545556bae17c406223a359e0593ba3908d9c8a114a2f7792d84d0941903a9513213257ffab793d8b111bf1d19a7218063c73a192c37b1d7b5b6f78a60ab636dc3517d3d47e83ef45fa8f5a07f27b2d34503a206c407af41f8302ca095f8daf2482c203ce1d4fe41d73ea9d585cb27feaad21d04f06cee15f82be6f1ef2c2c995b4f82c53b4411454e47aa4f7c54b858e72ffce3034b4ec185ba81415c234ce2e75b1c399fa711be0bec08cef1f34701b8dc00f150e4e9af418fe02f64fb880de51e230b5bdc78bd49da0c551c7462f936a7116817a4559f77c8fa25020322dcf9176b42ab1dd20e8245c76e02bf33369b8cc7c6748ad607c7c4ff403bdad3e735811486aa1a75c1455822826886e16f0215830cbbd1e962fd5676b1d97ef38220113c99ea2badae87e442bbfb00e725d273ee99aaec4cded2b4154938ab168876e0d8ec0dd6d4e752d8b099b37fe4d4dbaaec11851e15673b76e50814a868633b60bda89e7517f7768178ca159f863545a66d441ae3afd3e0ecf9333c9d1cec5729de2dbd6d5acb20804872d00daf3be3f89d207c0bdd3d9300555398575f3188f201c149ece9f2ac57a700fdc72dc72c09976cb10ad06b7fcec8bfec6148c23bfa60e13fdde50f46e20851d613a6c620d277ff778918e7ca39bfe14ee3739191f6e32ff819de2102fdf9b60b3d1fa83bf186e6c21e8c4df30a050357e34a9953d687e2fd1c4d64ce8c16bfa02f0fab8700395170e78f7fe6b3cfe1adb0530c61f5bf192af1f72b648cbb2eb2f2792ee797c16a4e76fd2c1552440167671e57f1c697cec5aede778a079f730da94fb7a2a5e523efda3639f03e68f853fdec006c65169e8d51cf87200503073595b1865fad66c2d14f99a7e4bb956a9570eeca60ebd0878624c91d8579b36fbe581b81bedc1035163a8cfc73d015f1a9c351817906ae650cc3a39459e7c7ae1f6135f06844972d134e00d62d821ec4ee1783bf863dff882484a85b4d65fdc5f738a6e51a3b0d136af92bd28d09e9c34eb45e8b4fd30af77f3e33c83d979b39e6c7a1c71c66e84364283cd1c49c8eb32c956fa156e5a0e4f83094211aeb7e8968ae213ff84d0fe491c02c30f0918c9bedea331cac654193907a2d7189ef27ce74aa9f5727f827a02f8b824474bae35351094f05849e16239189d236939e9ee31c678a901a0fc02fda2a07b5d5a189d639a3169042944e0bf93fd2699ca09a138472d91d5ae2fb54863212d65708f2a9286d25df146ca22c214c2bb3f1a77b96237f9cfddcb20c46dd808ff01f02c7bc2cfdf16b2fb8306ef2cc0200dfa60e314e8bf28a4531f36ee022569b426df05d474b4571e11a07a40a273bb8060a95d5ab3c596eb125744dadd46b599d86d632495b8a0db74900c40089e18052f9af4de51112d8398ad2cd96bb854eba1526543b323f1744dd9905cf330824ac35d8b02c5f4e5d55bc52901d06891b672bd19ce4680547fde68bd37f730b30f7ea50341963c8b4b71de9aedeb6988ae2d1f7e6faedf8189beb904770a0ff2ec0722d359d452f090ff5fca083ed44ec14bfab57027a409bfdfbc74f99af7b20851b6c2a2daafb62245a9032e0f182de09adcc133cea24981beb69d82fd1735e9e8dbaa11482ca21a9c84d9e90d53ff27bd14456ec23307bbd18a2b26ad4efbbaf64ae0d7b8c9e7d90ba8cfe51360faf5f556f97a064859694d784006c88bc197bc0cfe912825f025c8e7a430468caf1bff59162876427af0f0e76530307d2720ee61658d4ae4b8b5216632140543e5bb0b6222d88b1d0ecfb59a93f1fcad8648a4895754978df666c4d7e3849d85ad9059fdd4a8ce020ac04d5d36e6f3bf1e5850234d648dd68a50e966c5375f367dd644c40b0e81c42c273fafffb7b3b7476e8cbf96dbac1ef083fbe212133ad5f56705b6a3edca4872ba9d595b083f2ccfef124ad527bec2d796c75ec537c361cec57a9db95540877cd45fb5046e90ac97b9be48eb2c4b5eb8ede3d28bcb4ca476cd00c44d848431c89ae1b44c4e9732b44fe8639fd1a95c50a50c6912c81dc80aba2d99eb700d407729e4860a39e7119a20e70d00192b527b05ffe7ad7995e92c27371eff59917a4c5b9e00cccdbed97958092a212a01971b243258440074c964cd87ccc489566b5b2d71fd40a674052063022d0c3c65f50dbde81a08cd7fb5b6ce9212c6405318267cf6147244f7b8a66a6c4ec708b4b0598648ec54b722a42cdf5bc0d567ff2b120dd4d33c958159ef190dae2e992c8ce3f3e1797e17b40a0c9d7e74c6615dcccc499da60ee7766d02989526f6e95fc0c8a1ba8e731291744651ed9c26aa8146d619d664e4d6f438acf9ef5b1cd609b03146d5005fe237da726401a65d4e9b62d1852491b2dfa81c6ed5eff7d3ef6c221d92778df050b94d10433a1fee1a2074d089200542c5ff4624363f70c1811d22e77e8e41d0f2c7fc57226d0a229171732321b0889c7b6b1269453897100cfb3451a43805abc498e2f572615e959c96e6e666ebd21ad18323417c99e6dfd1e65caed16cc8d7b6f91ec64c2f250e9ceeb6af19b9376474fa56f71c9bccd8ed8e9f626635d3d4ec32b3463c59e0958161988fcae1a25a5c73bce45b627b0ba4711a7d5a43244d14cd7339732b2bb46e451987d7ef73c94c48764f7fc274779d7916cbd69a7db3602545509e937697fceadcc269c9d39c74eefdd157576949918a1d17d235fd9b1a86885381f275c922069a81ea25725c3721b95613164fee08701715690e192f8dabf07827481a457711be255be2026b46d8b2b115fdfb9f3a5c4ed97864be7bf092ecfc6fce641a99ac25a3e804482363ce6860cc2cd0b7f5531d0f890ea8742c18681a544da905497b42a02a703c9712d51788fc6e1e2f664baf80556b02e3de446b29b3c11b2bf1074e94938f38a63b09cb15305f3844a34edfa1aa1d1c0f5824048b338828a80fb373cb5f0225fef5387e2385ae0fa4a24a18903d664b516e920b1b3f0469e328c9e0c95e97dc6f33f8012497ca92f36ccacd671982c5afeb66cb671cc82d59fbdeaa923f46ac58e5cd0b8a1521b72a6c83c338b9530bff716b15a3c9747f3bdbbf9a02a9718ef00fbf0918ac69d5a6359d580ba638fc850707d618f744bb7d6f8652d1647f916b9a1b7bb49fbe05cde5ff28a0d08937045b03e0c94e141c76a08ad77f01cdfe1ad6e50cbd107fbf9b1f25a14cdcf54b6164d8893166d676c9ca691a04f95f92bd5217b684c6821d66ac8efa4c22f666be673899cd996c2813182075c4b3521831095e2ddf195d83441993f5c282ab0c198b0422b8837b5fa3dd6731d06499504c5fe0ff514540dc5136780f8441b9414996c35f19052cd5c88c0c6c955dc13438aae772a0afd6ac8d0056625d2dacc379882b394885e4a6a0fd646758f2eeeef271f29030948e50134ef4b6996345aa8503624fa9b1de3f470519f7de2baa545126272b831275b3b12f3fe8afdc5a8a36b425723a3070d2dcdc70fad115e44c320a395db532a5ef2e76560f176bcfcba7fea2a8d0a712fc8243dd0d4609dabf48b3ed5696a3c7ac45e394954eeedf593a19ccf2ba5086b74417f526d12c89527aac737a2e38778725e78008bdd6312980769c44e0f5d44726912b625d5ecb65de0efed1e3076db952c79c9bddb48b0d3a2436c5f090bbd73e8e7e9d9dc5093ad1bf702ddcf8e8f44de03653d31cfe5bf28ca1b6701953f47417b03b613a633efb6eb79405b749c2784e44acd7d0dedd58e1b2c9065d5661233a09737ed60a5f886d36351dd794bd5467efb63b8f42a3dedd1977b753b808320b60a4142e81245d642d0b82f134adedb84d3c87c475d180290cb87182dbd635317d0b4a0ece533a96cd4afc477ac8cd9eda95ed5695d81b265fcf33be5cbe80335870477d59d047cec530e12ad578ec85fccf92a96a900d54be03bfb62c69a605a6edb7036328a9b165b1958cc608ccf765158d2a1ddc2bb46c3b020c708317b8cd57a82663f7b4a86eba5bd91db1e671654ea3843b3b9615bf2e9d1c33ad087dd6b41b62098cbf763118587bc4c4d4b89b4dd9dce23cbb48f17f1c8454464c1f4a6ff73f5fc7e193dd780c2d4a01bd50ba9bfee3f38bab739f63258bf567a763ab59f736291d8d399462bae40662a783ef046565cc49cf949352695df165a67ee3a6bd6d8c05d7f1cdc40997e2cf5986b11e596db73789c273f6837b73172b06d3d5841729a3861f850e000ba3c2e1070f80ce8bcd23c8c2ac1dcf9dd42b75922a115d42b8b3bf0eab6367ba8a0cce376abd700fbd54a2051fcb925fcabdd1fd8bd7d933e84217f10354cf43e0407735858a841225e7d46e78dab7c5da1459fcc429962288ccd2162f373c3931421c13f815e1d2978e1483f5aac225996259367b4fc2fabbd6c10eeff22b1bec084a2cf6d350e76eed65498cd20e6e5819fe7bbac205d00426d9ba3131b47df26392e2e7523f8d282915380d754d01160e0140a55200c20bcc25d42bea88c6125af5c4bc3b61df038dbcc1104e35d805c71c4d7412453cb7fd1d45c83eaa9a3c7061a5ed10138b366bbfa1ebff1b8f87180a64b5ac7ff35be130d977e690f6956770380ba895bda67c6b1b8691c131c623708f56bf2c3c4f69e55402f143d192a7581a40c19612d8328d031dae2b9a28353ca14d726268ce2408ac46411fba230cb1d441a486bef5af8a8f35ad98f7994d084a16301c7b601b7184d2f364425c82f00b62426f3860bb575c34244b47b212df976060e7be69c8e2ba9d48aa20098fa1664338ce0830ce29ae5bf7e5c5749ed8c24a2510036988838887402a8ee8081d211d2d078f28a17deb48a6e22e56be7b6596de74eb4af15bdd4434d7313ced5b3556111745c2894b212d7789ea3e372acea62631bd2621f299024e7310798dfd019583b38e1b9dd8c40da2a989ba2a067709a1248c0640a48adb79639537570e7ae531bcf29fce07c9552a14a071729759edf18219abcf2653f7f5dab7f5db80afd47cda354f8cc68165f90c93e342c95ae7379980846734fa68f127d9969c8074980bf4f3611118eddcd539b4b67aa983d5b71944a0ec54c84b53a7d37b41dc42e90f8fef6fbf078686a47f6b7d57116ae01c2c26e354d22c1ae4ed622c974ccc02250f4853e1d9dce6fd15030f394eccd31a0ac28a6600413c0577b895120b0a2ff75bdced0714673d2767da1543cd1c820e788455649d0606a60d95931835be555b27a495d1b9ef83ca3a2c58eee2b66eb9f4bf9b0c7a485ba0d677205c18758c5df8f63d2af4229dd5f6f4bd9f7a067874e98e79c622f5252faf4173f389d101fb6a00e1107e5afa3678ad68106c93d3be8ad945a48e09b2f3afb5714a8b5ca8779daa5eb5621ba68785b13115be7e24cf5337b873d22b880c95537023e05426b9430ef618dc9f44506e2db056d5339fe8b66daeb86dfdaee2154ffe48bbdbdab112fd48096bb2343b87b570e1907d1a07892be32c54b48cc8f90e8c8a0e6d4f7278387be9de8c4f87c8e51ec6fe7652c0c1d546a47c9bd0004ec944bb7acaab43d90c2665f3dc9bcc2fa6244d5e81ec5aa286c893e490fe0f22e774922090cb36cae54d8ba67e72447e51b92b1f79f7f5a65f964212277c242f4de8feb33e78bf9c11cc76a86eb486dac88587d5895c6fc0329b7db1144ee503965e8bbf16579a0ca3e320418fd274feacf37c13600e14c889ddf469a5434e2cbc1438f56c82b90667aab7257ef97e4e27e1c5f62be402a7827e9718ab178edb29db0ad2bc6551dd27c46fbe2e39c3aebd4c6dbe6a5f8efd734fd207dd8b199cc6316b6ebc35382d9941a5343663e841a924e335e98d61e84bc7bff275e67457002a0438687e26fdbe94c8612885357fdba63a8dad05da42d32c05c81f268acdfba5613dd687d6a92debc42247d81d262c9475956441b75a140ad7a833c2d2022a2c01ad2171dfc410fbde277961010cae6bbfa33651e87a653ce518b27b7a2090f13e2fef9f52dca2a4cf60018ce35030592ba36fac61d21a5ed229e76e7460e3b33b5406a2a77aecb39be36a7425990d225040d5180a5be573dc803bcb8f3ee0b3347706508ee53e2a51b1c0bae055524f5737e15170ca54823ec1912d8ea7debc2440018a9da7815dbdacbc74d5c550ab4fe4d0bc1b2b05bde17b6e3817ed11b1fc8f6ceea8209258d3278b32ae63970730be2bd5ff54c44aae38157c6d35432f5364b22999a065f4ad0b50d2a4b1330d8e69e9b4feb5261b87feb04339f0083de27d2412e86e4c6efd0c18cd9bb22011659da62f0afa6ca4d5b606696e88ae56d28e8eee64c2cb320ab3665fbe184dfe8ecc5b20665b3a0213849f62bca5b3fd29e82266fb17ad2648b68df0f38bbc0dfa86b229b742bbb0e339b8b2c85e9f2e3d500275cc92cbf356dde7286d83a4d9c5dea877eeeaf324c9b60d126d538be886483bfcf0629a89069e5dbc9ef61433fbd7b09385bb2abae8d259f1a9c6ea5ea4f6f0030e3463f1e653dd093a44179ce83181af4897f49aa3b8183946f61d989b904c8bb6fad8da78762fad8118b30c6b55385ec9fce44cda97369e8b9faa3bc3785c6ad1d55e466a52197947cf06f1d386b0fb940d92d7f9b7177596a5b0ed47689ff436f1a46216415eab3a2fc4f62a04b24b1f2fb5b56ea21923865e3f1295a6e260cd2374a376624501f19f5711f40ccecbb8a2734f85215b33549ed63f0711e66e3b583a0e1d74ba431f9fcc9e31834516f5cb709255d0bc6fc7fd36b957533c427cf6ccbf2535a23b9125727a3a12f630420bb9112d27f640600c50446c27c4db04c09469da2d2ae2b7ceded61022b605dd9dc31ad25b4a7c15c85b28bdeff08bd9cba6d2fe344a5964b5d3ac5686e5bf1d90d3920af5ab108b0370710f2962bb1bce9dd62fcb3c7dc8ea4443b862cea473863c5825b099758deb9bba9e118fe60f3933a1cf3939e4bab48dcc07bfe0c5a392e4a404e2a271cc99fd9074dde6f9c606000c77ef13ed172f1d031e6440f90b7d073382b74926f472789baa0882fc897cb21bcf34aee790af849c330e809d1af4fce39a833b1373dca3197f16bf476492ea6a961647aeccf9f0187f257a9aa33630913d7336faa694731794fb37c0dd1544f9d8579da5acc7a3716af02c385ba6a28b20a5b43f36963a60c2309439f4e83aa5ecb6f412916001ab2a68793c5d6eab11433f6381bbbaa352ae08d6da7c6724fd7744a3b8cb3ed68078ae2382a33536b9e14ef7209dad0aff08caf6092e1efaeee31be7750056063a5e4d5bf5e7f4226c5e90a674c71804060c84f24e3923906cde654c63a21c383ddd39a6503e8326318ebc55b38006689f6c6621b611f49d425c5094cc721f88a324ee3a4ee14342ee8f6dcdcb930a8896632236f6c6b95621d3c528141f06a790b25e330421e285c0172c2a67d0dccf113a355225283ca85251bab4e5f78684ff43b4e2fb3ae0616ef364eec22134a444b7e2d53319846208a41b9f574297415dcccc67ec075f1f4c49df7f609aead9a9d8767a2ac776409399985248d5c854f24462623d003a1f3c000561d4aca1557a65cce5e0ce17c9f6a8ea26ab62b06c9743e3ccb8ba5e1d62145d94a443328c325d00659652cf1feb1ce086cfa549947ebfab878824a1d4a5e3abe4afa19024d5afd843e1a73ffe58fb388141604700af3f2a6cae91f5cc776299c1a0e7cae1be1afff1092ddac28c09c6599dc13f3408e454df04f9fb50b92502ac2c54cb9530018f55d63ad94352e906ce145b7b56643f8cbe4bcda592a37adda822d3460b1f1b8cc738fbc961c081ead8202919da924845a154c9b0990ca8e0ae43c42d0452e881143703d3cd7e38acb3cc70d5948ebb77e5138f2999871245355b060c9e211a692662ae3a89227b649f1605adf55b8ddbb79a9298d614cf8e143e0bac2a1717edeb82599c95883f149d0ae27373239a1c25c745910a8d24fdcc3bca5b0c8ab23c0e221cdbfda9060d46ff2a3afdf609e9e8bddc1c9d66c1c500549feb55b9992c003b5950a877abde6e5d18df8576feb91ac2044c1f4fe9fa3a111a080de47c600a999087fb5024f1b82617a0cd151c73d61b0c23032a396a735c30ceba4a070919b68fc7ab96b224a8927ae0279081f501f936ed442239b39481d7112b766c57db85d1bece184c4d38cbc5c3308c55f4f18b92b12f9ce60a289ad60ad29661bb78f6b5b315f53041358f2e3fd972ef2db79452a62403c4065e074807ab2c80dcd5dbaef0a6234ffc2deb642ab988e71d4ddb5636a9b35a6dda73baac79c2fdde3b31c61877529023052795ee8da9e8c2ce7dc3e5e54e4e0a6e90059095e4ae7a0cdbafe6555692b5ae59497783e97c73afd341b756739ffea1fc5aa7741f1aaba4f33390e04ece4b197a96eeeeeeeeeece01f7a92b3f74ff8e3fdd6daa74db062b17e86078b333b3d9f0e66ed93f76770cb8aeb3d697f365ed6e4dd3b459e57cb9459eca9960e3f5d830a0b96a6a66b46a0d0da6332d1a7466e5d1b833d3a0e9b99a62d6fa926a9aa6515a5fcadafd513989c0fd91a75eaf479d62d6fa52d221dae5a455b31bd75dcec58ab1d11ce346ff0d44b0d6f549a0878d8c1977ba0fb7ba4096dfda16792867828dd763d6d4cc68d51a1afcff73a66bd1a0332bcffb80c6995b34685c356e6e8e06aad1f1779aaea637a72b82f446046eadb5763738d7ba0fa533be0efafd318610b8e9f57a50ec1947494a3b00dcc8d55401adef4889b17218246372a2718c4fa7ac4c71f20072988343767f8b237b141e329d654aa3709169143032f5c01299823e04c873424181124fe0f05fba0770bb90f79cfad93eccafe53afded8209e6de000402e40d5c6409854b962fbf5b220bbf36e09c1d2859fefc77504aa71f2c3f04f77121441ec77f5a8a6e3a92ebcc191de94a3a2475fcce23269167be5371a4a8e3e6f99e142f18ec9ee4543e80438fe5d94ecc392754e459f980c3fe98e71ceae993499edffd39928343f2c7a9b816bfc28900871d73a4f95286616d6bd7566b6dbb5acbb5ef51d6b666adb5d63b8bb5f6e50ff94ff420f7e1de3e90fb746fe9dbcfe13edbdb6aabadb6daef16a290ed56151c25dbef19b2d5ac6635ab75aef9e8dcd9dee467bb6f729cfd42eeb50f5b1de7b2b99b5736e7d772f66ddd6c7356fbcded4b6bdfdab79bb5cf5910b897cfc9e75e0967adb5d1e37eb32fe49cfdcd3e5784638ee58cbad9ee1ea7fd2e7adbf64d2b58be07fd41e927aaf6b51bfbf5678e3796e5e07c9cea6a79c1969382fd1f8c0edfa955d6121cb2b2f534ad4caeb5764894c33e0a9528c07e6167123a2545b9b6d47eba6eeacf9fd95d37b97e1ee0b9f282713829564891b50f65ae1ed53dda4339d84f0e6aed147934ea6a2d4aae5e721ded3d2a2a6bb45ba5004b1dedadc558622d8b83dad7dee2a0966348c87d9a7bed8362d6beb1441df335a356c770159556b5aad5aead949db1b55f6deee4ed31dd4767d97d58ea40f50ef95dabd90f5dfbce5bba5c6dae98edf67596c8a3bdbb5a8b839a92eb68affded1d1d82d8a3bd2682c8a3bdcd140c827d7f215792fd0b3bdf7c60434d9369df4cda7716ed5b49ca082bcbb259355160a1a8e366f93cb6aff4b9af1fa34ff4d97ad0ca7d00879652ecc45c82c32813923f1dc771dc47f791dbef6cae57fdcd557fde199fe53edce6e2724729a5d43ee78a6536177dfb4272db218a65320172fd5eb4031dccf183478ee992552790a84d9587cd85b093c003c26d28aadd17da149d4d126e1be6981101ee0f3bc83187cd148ee1ce40e4896f9302acc4bbabe477b3de0c4020fe582a5e118b1cb5c8f185441d5a5ce5f01f8b7770fc0788d4f1ba7d54417c2fee18ea1eef6ed421895cc7dfe219da3c3351181ec7dd0de449f3fcb8a853bf46cd0622b8bc46b0be94409e5f9e2514f180680aa671f38668948a50398c53d9ab046895b4234f5592670ff9afd7ebe5ca74022eed8b1b92bf752618d450a3788e8498d51637fc6d123ecc2260a0c3f41f4630448d6b71b2458401454b60050a52aca04a0a40c0000695279a24119b6222891c0245a7ec112a8ac91ec6a9305231e51876d84e9e38a143f6ff28b2bf1015d9674fc63c49226f39ce9ec86e105dccd9226cdb4628410a4874e2361712ee3bceb5e41f669bfb8ab0cc5fe22a324a004cfb250db3dfae9bf937f3bb01e2ef80b86ddc5784e31dc85ff2b0af68fb8c1ed6bfe461479634ccbfc82801305fd230bb7d2a242004c316911c3d2045fe29e0d9932cf9fb80a48efc1179bce0cf3804cad2bb01e2df8008f3afdfa861fe0fc8a0bf23454b1200f3376a58fff6a1d0b006a27d471aa6bd8569d6f55a107c333f20fe40fa631a98190fb2590f5b7a78aa8fa38e064458510af2b94f41fe9548fa23cc5ddc5f570a4a60f73bbf48ee7d4e3a40092c85f9db1779bf7a7715d9e7bee3fcbbb9c00d03f0fb8b50f3f26f1830f3fe4166de679e7e41baeea377c300fc332f029ef990e09a2f76fdfdbd6caebfb32eee9bebeefe20dc37d75f7dee4322f46aeeed872fce09880c3ff7341f12fcdc8ae6ef77e43ecdb77aeb3a8285e62d37f3dc8b809fe66f18609ffb20f639ee69be23f2b999b72fc28cfd90942075ead3bc08f823c2dd0fa354ac6391ca3e92d5dfa7f990ccbcf55c47bcbfa19f04a6047603397e52e7f4c375fc3d1d7068b3fbd0d2e43af10947b5c4fc1890cccb879632ae137308341b41961cdaf8835476106452eeb3d1802053ea3a295d1e74064116e54fb21c33084340b94fe4c24352064116e53e37120459948339ee42f837a7ec92235bce2ed2e95a21021ba2d312ee93ba4cce59447a01679572528fb97b019a52ce49f4cab48b9c942a21ab94524aa7b3d2f7a792259528d31523947a1e15b14297b13814c150863ad167e30515b6107db3693bcd2e6470a29daaec9629315475d99931854c0f3bee31079252ca3984ec986c629adac658f1214e7529a2d9582c56449b2017a61514a52d98b8b4e82b860e5f76784d22904693155a88402e44f78b0e5f7620bab43dcff9c18cc562453a09a2b865460523c2c42d5d9a7ef0b158ac0865aa744e2f329b580578d274058b0bf5443033cb7da683b18894f983dc4db3ca49820ded6fdfcd2b5df3356b6d54c1f6bbf9409b4fbfcaf9b92dd0310895d03ae76bef9a796ed57e24cc29b374052072103588a07f4ffcd8e39fc14ff6982dd56cdc806fe607420659fbfa91d0ff397e379fb50f7f7ef9a97c12eae723461d717ebe7da9525629e5cf69e3865a6595b2ca2aabac52ba56a593b65f7b12ecd7b73f6ddcb06df65d73513965a63382ae4beb3bae389e5d9af4b90a93c0206b4dae093c6edfb66ddbb66d5dd7755d30a9b1b4755660212cd3131e5a43684f74d9df1251a3b8f707fd5ffeb4099b60360126fb4f8b8b682fabec6fb1116e2dc6add63f285faee9e3fe16fbb7fc1f7cf52b775dd771dffd9eda7eda57bf907ef3935ff86202839aec3ebb6e05f1bd20042f00820530a05015ad08a28aa726289a7050c2bb3800ca181f4a308529062a60de0598245a886169053ce8d084c48c2f3fe8f49123f2cc9f56bab421d174893377e69c139c75e668b445b5eb60578be9b4dad7aaafd139298d21bfd7aa24cb7da8cf7ccaa2f4b183acfef0f67b4f16bdb82f403385617ead554a293fbf33f7bc9d3b197544fa425e5d5bee3a76ecb9a2582afe909c5ce3cbb7d1752509f1e78c2fb812e5e439e5b51f6a4f6db6395796b539de7c104e294467adfb48c9e349fa02b3638f26b3a6bd5cc0ec086a1afd802e60e66982e729e35c5940935d7b22706fbf24370fc8200630ee1b667461dc1b4d5891fd2516d67100f5b72013c67d4b509881d97758126abf180750650b86e4fa937e37da195f26514e8e3664b083f14a07e79c133b1451cab914e10517d3071a5cbaecd059a3226cd0a2c834a91c23b23f36ba52c571ebaf3cb14d96072a29507041ac052750725486ca87264f2031c505e64a1c1d91030d3840788470e5056e872e76987ac1e6ced0d6653dd682592edb414aeac45cabe6025dc72f0b27270c0763072a47ece0c2121dca408137c871a6039819e620c7990e3dc0408719e81238478b4a03bed1e453b8468e3310f820bf004114a8304090343553c036729c2529216bc09fe32c49072f4932cc179252a05e585141182b4cd413704e8e332b58aa073000729c5939923fe4a045e500b6c9719683146074994d304d8eb31c966ec038729ce510834b8175729c55c1a24ec137729c55d9d242952b4daa205126aac420af601a5f483118270a9a036e1df1c3154903a691e38c8a0c14c98b1d700639ce3e0025b1c03839ce3eb0f45445daf00117e6177c93e36c8a0be60ccbc87136258a15a63079165394a664a991e3ac8520b630bae83e5fe3ccdec96debe4b66d92d2aeeb26a5b4eb3a89e3825e0f19001c3b527ad327ba5753dae302903c33001447e540dbc0ded872380d3ad7b5e101601523cecc0dae4143a3a66533832523460c1994b2a24b4a9b560d0d9a1af86606670500cfc6cd60fbeeb12eedab1ad09c79837a7bf7c80d6e7485364bab59a923a5e44046c771a33727a594521daf477c2925f699e9702680560300d4e04ca0615b3338136458ce8418761e61b90d951e79e6441263cf8c42836756de3c727d1ee99c3381b31e7be691cdad56a9c769c29449b27f7f93280a142aa5f46ea0924a293d1be4f49e784ebc1a3c1abc19bc269e0c5e0c1e0cde91f782e782d782c7c4eb80c782b78267e4a9e02df152f08a3c14e6ecee5abbab0c80053aa035a28105400d1aad193262781296dbd4ece8ee9edd23bd071a3cb3f23cc9f5241d373dc9e656abd4ca9fe8ed2ebfe89dc4e300eef762787230e906b4dea85a8e766f0cecf66d9c44e2925cf7ddcde07a36bc7b61b09ac1d9f29cc13799de3070ff2d83fb2f18b8ffbe00f7bd5fe0fe5b85fbaf1733eeed02f7c7cb05eebf6470ff7501ee8f770bdc7fb5c0fd97cac6bd5964706f0b70ff6501eebf6370ff5d01eebf2ac8b9170bdc7fa736b8f70accc18d54e77aefe8d82391e8dc9b5dfb8f859d3513a5c381e3460e0e1c1a7caecf00870d1c3870e0e0b601705bb08063e438c3210cdcfd409f58994be0e044c280030b73061c4e984798abaa38604b55023c8504860a8104a639ce909890322011518467e438434a9a304042aa39609ce30ce908c96826458a0b3903aec971c6020f9509be53f04c8e3316649029b0c0820730ab0b9ac51445c10a5149e0558eb315bc10816b8eb31598c660eb430a94478b4790670e5b4e27e8dae58d479ef80143b98bdc33396ad25a951713dd3b752f51094453435359361a3aa53149534ab22d4d4e50515262a86c4dbaa22542394129292d29292929c59496b6404931313531313131313112122b3a6a293f4208e27d17d2f03e3aa790662284c8084425183922a3a79d730e2132244209b16eb3f8d1fa9c9d175090100f20780a7b5916e8f879e4c1799c56ab256539000454375bb7ad76dc666be4be0ba45520211e2100113284c80843255409824020182414040494c3bb0f5319a52a26a7a728a9a9315464644a4b5b40076d1093c52c9c07775e398084989a989898982ebed6eed0759de4242972dfd44efd64eb6c2c628e682fabf539e0ce0ba8ca2b499dd44979da49656d906ab55a3f5a9fb3f3020a12e201044f612fcbdba7bf677bf7d856eb73765e4041423c7e00b1b765439b711ea7d56a497d59caf67bc8fa2138c47dc256ddb6fa423a8044b5d98a93436defc0d1d2b4346b3f967510d45cdafb0587b88fa6fdf40a59baf70ffae1deff4708408268c95ea55bb9ef4a0ec66ce5bedf1df90a6feeb809526960c4fc835af22728a8837277412dbf321e3fa8bac8f1a76815f3a245ee1f42c447c65355ee2fe213621c44ee67e1ccbe18e5f0100a0a5232031409a4e0a274822ba06e5001010b628008420b2a32338e6932a6e8a8c943883afddd64a37b7c4a9fd36fcc654e617291e7d4c528cb9953938cd9091e0bcdfd3b4ce430878dde11737f10e9616c5a09018569ca03513138d18089155c5182d8104fb83872a1c5c2b12c203c420063858593d3a52a7390e30c4c2cdf1cee487dd179b7c76ece3769277d774dbed35aa936addc9c6bd9ada4bd01cc2992e9d4344d9bf385a4943fd6e22f5dcc9140606e1aac9021444628a152b99343cb1e6a31a49123c5da07d4ca2637b9054d2aebd30a7a90d526100e332a6272d644519e5fe78d1682a6f978d3108bf6836432b23f8f2cd91f489d53647bdd294f1a12ead7cf5ae1224fbf90737f7fb4afaf7d914b3521cbd655b462a2854c59b38aa6af5ae0e8bd1755b5cedfc92da59431be9c31091ca7972dac6c367151923350583649318ac151132325aa98c4981c19cd781175c8cf22872d264746f26b1522cf97580b4a2c593b5b59c8c1feda754489932c3f2a69926592dc57f2a4d42604987e8ff384c3d664218b249c62d7c1a82dfe33c475bc25755c4c54d49387ad266b316eb5fe41b0152b7250483d412b044940f901fbc432460bf6a42511608f3df127969ed0de67311965ff966de1f88063ec891fdaf6a456d8c279e538657f10dc89524a29a58cac23707f158b1c3b6506c54340068929cf821b0987c8e3e4a80aae6a5595c1c148c4b23f0b5f6ca40af7511755f55155171519d9db42376f821c0195d0affd2f7582cc96c4406c0d14b83f877227eae74ed29922ccabe0b0a598fae357f5115bf20bb85d5236be7c014797eaafa562809be2a44560eb1e7194fdf12bc60ee60c2f9f220477825e5ba0b27f8e1927387c65d8018a64d93fa87774f62fc199aec09e02a71e6259092c7ce538b845cbc3365be0f0f5faf91c29a9e433e63ee194e233368bdcb730994850d80a1cba511519aa1a28f03c8201368d6212aa8abf3562408c1369886e1ef9cc1438b4d966097bcc417b345f7062c404cad154eedc00096b28d614731e1d315fccdc79a5ec9f13653740e6c79f23acbe60a2a1f78f1d4367e304be3d614e6b664451f6c71e80b97b0b87a28508a7a245a961715604126e264652e029fb1204e298604cf6ff1b2bd44a1d1c9b231ce24831418c060c1b848d0b60cce29503941d65ff9dfad1c52a429f85a705ba1559364fe09025c38f560b636b4130043390fb7444e2d762dd8ba9bc74f4b17f0c38b4b6a78980eaf6a40b3be8e1cb18fd7fca29c28983898092fd59dd81ff0c0af0cd77d3df5c2d11368143dc780ea125fbdb8e6dd1352cc6188b10a26982f12c7389ec3f937cc97f1a16674238d13ee684d329fbef48f9caf1efe0171285f463bf6b7150e90987f82281c399e42b441d7f18b23c51329a31c2a1bdd3a94b0272007594777f160c0e6f16e27a80b5b0b230c29bd35a4acafe38aff60e6438bc2f1564135fc27f9a285d1a24ece37247ab6b0e8bc82c9fe87a0f38f4a37b248f9c34f1800a8b8482ae080b9d524a29bd037f9612b83fd248e9d172b0b3c3e4d7df7f385eb006067f16923faff7257a1644118d141cbef24bfee0e4b86c8e5e8b260a16e2815974099912343dac3ea5941af123de81ff350287f3ca7038633ed5cd97645cc7df7ec16157492aca247fe6874d95434925a7424915d22c6495fb845dd5656419ff693212363fc9e42475fca9aa5cd280c39e72508c4b317555958451196b061c82e04e9c338b4b822bd9df5a26b067d954b158cc059894de422897c85e644896fd897cc8a7a6b2db4081c338e543853c6fb04c4d30e69627508577a66494bd084bbb11efc0bf46133652c4c112a6e0f0def480c348e549388c545457ba221c8bc572a434e2925246d9bf84c348267f7f242326b3624580a092fd8dccd95435a5cf2fec98ab5d471c74312de66f53add035ec0681c3fb42f6225f2237cc672318d36170386ffae3cc07aa51fe44a9d39eaba5acd4e5b0973f422d6ed2c4a61b54f1a7486671e14a96fe56eaa5fe9621912426f7379353a5d1c87d3a8ae9587f17753381ea9f4425b811fff1be53e04207998aeb40717d741279bcc0f73b92e40045321816dade0b6dddca2b2bd773b54ceaf4fd8e2881754eddd44c0e3612ce4ebeee6b21e7cae0d84d19221a1aba39fe1075c52ceb8d53d2afe1794093e7570687fd949f86fa09aaa346804b98df9a6d5f59a93f1fd0b0fa1d4902ab2fe44f4352c78983501cec28a8a9fec2eee902fbdd110ea31411391475cc6ab5f822bbe400059a48ef981d5041e317c8116ec0f5fbe3d0080e6a16941283a03b12ae398c52560671d2c4c1232232f25420eaf82cfbea073c44080db8bfc64a0b96d2669d7f4f776c1abbbbbbbbbb9bc6eeefeecf31cab67d44cca8aa0bd7b1b9052a8aa9424a154855e050c594ec1ea62ad3e4380b738515ee40eeed72faec385d4eeab4238de1b563a5abe9371fb46c5d2d7755a3b9df4e96ddea10766beb9aed1969d462ac1aed9c1a4a29a5f4ee9997ee983eb28631c6183597f2676ac0ed1c989a46e9d7d76aadf4eb991a6aa8648c3c43979c12c8c128efdc893cf1fd371a1a3da7fcd0a57cf98c39534ab7599b33b7e4b5f3e7c718e39c71186e3ce072479e286ba69215b69c915b4d71dadda6b7daa6a771968b41848d14eefaab5abba84ab7d53ca176b5a526b09af1bed8f2adec69dbb23dc99e3627a6edc9ca9e3627a6ede96ef75eaf87f677f392929234ee0eb1b4d18d6adc4d5ab257ec124d5ab24a59ec12a5dcd59296ac5216bb44374be9e56c0e542c77b7232a5d938e0a774405c909952fcfbb7127d0cb59ee6e2e30a199c1342eec9a71c9ad76b14c7737ee84da75b6a397dbb8db55b9b5a00552562245c490e18814a19a22d3792b5a25adad81a65f37adf17a705fb3d940814e3f86c81f436c6c8a8aba1d7742b5b5d2cb6dff8a5dbff6d7fae291e376dc09d5d66ae9e536ee76d3c620627eda4b5ab92cb9dbd5fafe3b1647c6f56ec79d506dad76c69370313c270054ed5c4e5a35bb719cd7433ef7b1090a8a27ee68aa1e1fef05763aee4759ddb47ee268d7d984c13dade7ba50ee832348c58aa2d77a9e84923f98eaa75a521358791fb8ee47e76bb227bbc53ec99eac13937dd2644fd689c93e7576defbd77a49494975eb8658b2739b75eb9296b42bdad24c5ad294b2684b736e5d4d5ad294b2684bd36ad3f3bc551ff5511fe540c56e9d3da2c23591912515242754fa880a9213aea9782b8db3abd54a9b3122757cebde7ebb90bd99e4f4464383d2d7ac112e96b14698704631ae99782b8db33333335d4c2298d5f2e28e22dde3d5efb52c4c45ebb72452440c19aebb448a504d91f15616d3d48e20fdaa812dd7af238feba8a9a9b18192e2c710f963485354d48f2150d129cac6c64606f4e2d13dded473fdf8e291e3c523ca805897e5f5d89ee5f9f06c3f06e802c8fe61b77df75bdcb1d33db2a30edbb5b7002ecbaf7e7379ebb896fbd04450c389e1aaae59e56019cf832643e6b676341afa3783a537e5bc1ef3bb18dc7502147511060a25c230318908c304441821660d61b28449a2228c2bb6a035e0ee8a69027ca19059e0ad89aa0577b3238830a202088a02d6729c5191858aa41e7af0122687511605db2c21a1609ba59a84ad161278d9018c1724315e629049f8e638f3b2e4892e611481a90fa9aa10847e448b9dc24885a0b3b5add6e7d3674e29638d49c498bfd5b2d695a5f41dee0deb1effb27477779f19e2ed04dfba53ad35d1a99d28f79a457d257767c93d8b6644233b69c8bcc9f334c8214ef69cc046138a1744317de00433292752a8207b9e378594ec4dc1c58fc0878e95bb2e0a2cb96bca5d17c517b99382cbd3cc302506b3514de4cd277299b32826419695eb53af479db10bd401729893a91358f464fa849327520085109982531693806292e5962e55504e4e1c65e96eb3d7370c9758a8742e76504045762370e78261ca4c64143cc9eeef43177991e53703a28e1772953d07fce14bbeb5b6150b5d0ace893c91db41e1ab91e5c7aec992522ae47216d5a7b37d6776cff6b993e305a47d562cb5b2a9a3b17f479e6f80b8c305a4e4038c2c47ec220ebc63eec842aed19bfa31cf1998a44ce953fa207d4cbf45a7bc821d941d08be767258f003fa316304fee467457b6923105dcce9420e76dcef90c6cad301f457fb99cf005167fe9c2b6f8640609e614f9e17981f714ed4c1e50894ad75af076d49ad90e8f9e0aecb1fa8bfb316e31877dc883dfdda7b4ee4e9ed3b57e8597bca85318a3cb5b73f7337831c9cdfae1bed03125ae1808986b8167047aa0a4527e54d3de20e64c6aad822cb1f42c47f8a666433313164f94344617096553865f946dc2756db83fa852c5f3691e5479a20b0ffac0aa91e77ce493f2bda4beb47b28b10e7f8612b7f0ec1d517678cd6b72543535350a09c0c1d354122d28390212378cfdd1ddeb76a1d7fbf5c4d0eaf2cbcfde5f03addeeb9435350029ee6a8748cda8972e9d090000040100083160000180c0887c3229124c8f24c50f50114800d7596406e56309407832448411404410cc418428801841863087146a12ab3005054476447bdea7972d5fd68661121a81f00a19168143d9bd0f94107ed25a1d7438bc2587ecf8e34e829fe8718a392725b888a2966d1efba0002461c8fcf04df5d84d98ec753a1001873ac71a77bc7e49f895af60281db5f16a70ca0d342d8ccc14b1f57e986dc0443e7033ef4a068193d8246ca987ad5a80144cac854a5743056f5d9e43195928c33249b00b610d6082afa076286ce55514616d614651cc7857fefc5dd468cebc66e97b4e6d5598fa0c4a45fa78a6bd97cf4af3f105e8267f2f7958dd49be046a5aff432ebc0b1e8e50e6fbcd4bfe5d3b141a822c385d3f94cde323d371d2ca696d19b800876fdd903c3d75583646d9ffe4797e3f68bdb53692fedf6ab44831e4060f37f35b3bf31007006617d6429590e8ea1eb61ce7756adf7b820c2a1cb8ddef85286aa206f554310f57cc190743b4ba319c48e58195f3fe75d2a368367949dd955bc457e57c93e6bb40dc0cee03e36415b9ee83426a21d4c70e123fdb0155ae88a1be384acd19b6144c32b10ddd230c484574838266468af3e6748dafd4d8a41aeaa7e158e33744e21f5e9d9629497b1202ada9ffbe7c2eefb8b1873cf736a7e6c98aff3b472c706077e99bdc33e8f79e9d1aac1c8eec7fc6329e9f734d111fbe6d73ac8fb653dad70edfe79c0666adbd69f78ac0bdbfce1fc012ab0d33624d065b63f02b18bf94155ddc5e72e4925595f10a2bd5967f73835fd4e8ae209b44dc9961817eb0032a61264a43a4ac97794b47f296495a236ec5a97044f806e795a2125079f95b505ee73107416e23780fa567f715908e6bef564905dd13d1e2790335f797b7b5587e79f6c1ef76c3d71fdc609741ed77e1199d1e8e51c12ec384f9c88fbf54e4d618357b93e7323d8861e9b15db732b89e28489699d2e6170e803319f3ff2a7a83a0e21b2f7ecb23c10872ac195534addf0291b4e0d210fe1916a56666bbb8ac809854b814f185d8360e4b7f623093690c2dc46bf093641f4c40e49bb6919c62dc90208fc3227bb4060ec23e08c5d4bcd4872d982ead69aa23b8fdce9609b4d7f8f2abea03215ae8ce76ec7034dd8df94e4047f3f5bb664509cff3698a112e85c16b725e2ede78483792c87126bce09b47c153a658bed78b681498f014d7a7503ae75e835182074bd5b88ef078aeb81b7fc0b30276f3d34723cb5b1ab12bd4944c91d37ee8788007290feb423537b55ac0550486985f7780e8a853e2b97ed495f320df018ddd99d7c969e04f2d187fd4f8e19947b9259195ba002f4cc760263b40a0fa20939ee7998e00a99294ea9ae1a01a571f917018b257ad06913b11b2e00d14bb30e4d43ba5a666451a75dffb0da9633b55a5db513b1c730efd499c9210dde7b160a0cf5471904406d78ca25090e265e3fcd7b7ab58fa9c78f71df7b7420e71a8a882e8a666b8f08619453b9073420a94aa53cad40ec3fafeadd95d06b3134e92cecbc6d3a9b96a2c57f6cdabec33d4354aa5a2fc40ad3593273e412d0253a4f5896ad9a2d0f2c8900e5b3d6992b7665a1425d1c7c2ebeb300d4899081b461bce5b2fb58f7a6850c6738009fcf2718dcb1122517edad30e5ef2ab52a4a7b40e64f9b5c1cf990142fb2d868a088ced7d90c2d7b16c8c91256d2169e6ba236f2dfcba0d2649604908fccae0d8df9b910b4885be82ae023e3cbe6de306a2e1b5ed37f083e98249c6501d734a93fefee13a54833294ad5a66163d286a6c15c6f407be06735c2aa8e34c62cd961ab50e6c0c0c01a1c3d68252edf38bd6463c86c01dd92160efc01e165ccff6302bf50c55e5065874c9ad7bcc81c2e5008c5a936018977c57d0e7ab90d19020a175c345cb07d0a378e4156fb751357d23fc2f9122f6ebc68a1813467d2ccb044b90f30e33a3b02169c45293deb56406e93a066ff6056bc9d4917d008a14203d83ebc15bc1992ffa4a833b6f92b0f5bccc44a9a5ba70b027be1b16a3e9304d672cfdb462836c23105c0f071fbf7ebcf0fa940e1c916b9f29882645fafcca87e9f4b841430507e182869e0ec477d5e1f7a6c1a36653402a17589409f54f89228c837025ae85c706dbf063bffcc96b4b622adf4e65868cd819dd04afa074551ad4d280464da098dd891b20e307988a07e2d3b664886a1e0c716e521dce06825f56f437dd6c5a14a269b5b9d0bdcc4a166d4139a2bcd0dd169303e8b9c37ac3bb6b3aee8bc5d7b4ba93c9a17358a2c8621bea7c12ad42b890547041ef63b7afa8293f813c91e142c55d483849eef29a2a5ec220dd9736b319e14dade6d4086870bbbd12ec9f433fef14b34bcce5db96e8cb59f9bd7957d3d82b2c8304c45badd95f21dba00dd5f0168965d03571dddeccaf7bf0c36e4259ca58d9a3f020f916f0ee2669abcd5393a635d696bc44d4927721ce7b06f7ea4dbd9c4593410f47f2d9fee811c0520244f3b2e83818b7c76cdb071ad7bda9a46f1db681d25ac1e445314885eb741f145d5787a7d051d6c4b7ba882f6fe705d16c1b7765204257310a8a2ed7c46380b012928e13426308db214045c9771fc820b8b431d7d895a99e06f7a2ae12e220963a197a1aa5e5193b065be126564adb99a704cbca4905db63f712d6021ec44d483fca589812e4c2de6d89bea9410d63da6571c9fd7a853d8bca3b6e824ef47694088ce288b4eddac835cf02d0f895168b95d0c9cd2ed80a7133a6cbaa49f3c40d0529440a136fa81690c213acf7506fc00f8ccf53f08dead408f079b8072b5c60aad68528ef9089d11b34fd9aa5625e58e2cc66a1bbeb72681568fba32369060a0606db2cdce110d649889d69353052be15b25d2af333e9d82b9f9411f7150ce374aa6e115921ad6643c4840aca5cb9a60cda4efca95569a79d4162ea0d4d7ca0414c93dd4a7feb0364e58587f2874ffda3fc5ffea2a0a4a1da2c7d541408c6687f0608dcee79609ad60169adb06ea48da46dac72b92099223addb8e64c15e7d3f0bb1e66e523b392a6759a31c7102b259c3b4c813c530125115582d6b79c7e8434b4e18b0a7ff595a804e569958ad7dfc30e8322a51c56cd0e015dca2b10b54661a7d22fd1ba024c98a5af67a5107f42f762c135912b25d00a7a6469d48970af0f7245399e000fdf839d186c0a056c07c4da4f410613c25a383816fece56bcc455f52d850d7378f080d001161b2dccb38240ff0a2cea5433a51f3f5c2e84b8b865a9cc03921b18167139528fb4c256a44c884fc966a5091513f58581db921b96403bffeb96c0e36e0e744fd1f3e692f01c7529eda19f9bf120a9f7bb6d7e4dc662aa6480136d22763e8f2958893cdf86398d7c83a8533e58192dcd0b96f7183d575cd6c90bc463e460fd1095f24cc7a962414d464fe2607abdcb7917948966a151619b538c1c65dbeb2a8311dfd8481deac47d87def0650d199ff9cd3e648d54b531ef1b00855b66526ef4d393cc50e290a94baee530547f4186f39fd06f94861ac9927f0bcae771a5893674e04f48abfed96716b9ac26bf3ac90b6ba884ce00329d78f2f66d24b5fad1b32dbf70ca2c1836dd11e55a0bc1f2e97a1b8ad4d2a45618a0454b43c1f08676200459da121a1e990a548c0bb0dc717dc583a8aa17105aa5c4f739d8b122093b02971c94dbfff79adca2dc5cc94e137f4e7920db34fcb1268f2a3f1b83e86416d6eab0c97256b3dc419301502c958ebbbfab2616cad92f9c4717e8cad8928d5f644131c97aae926e46423afe04bc257d3a34167d6b84486593a530bf1a18d0c784281ea63e2a22bdf8192273a23bc13d0ad29ec3fa979524337faf3d6091aa9d2f77bbb89bd098395741d12606e686b6c80c26e543cf82b573e7bda89cf287f40ea901818bb35f4b26db402340f4ebc8c5644a1d33111a3b593bd99f1f1e6ea0b646e317811eb39c7c89fba0aa75b11bac549928d56f5d9bfcf244dcf3687961a690c1991af1ea4cb59c2d2a3e243071a1274603fcce723fabf6c6cd19b1317c18a2536b9c4871e5aa569df2e787accf9e32d1a575b27e8e20d4c491fdec0939cc6d03fddd3ce3c71a1f37fc2b85dcebd47096882a2db0054c4fb491767a41e5ad66f224f9a41a3caa1b92cdc8f4ec39ba90eb329b8ab4e27e59c0c50f7ee8c8c49734cd103f8715aace05ac12582bfe907e458e840664a01c5ada2748cbe573284217bfab9d2824844d918d16c5600c47f1525e60a40464f5572393513b0f565f65667c2fece0c9fa2f58ec5a924caa1fb0fab12e7b66715cae4c136db13b879bd81d2f1bf3bc8e68c40029eee5da485ed8100abf674588f50e75bb3dcfc8fef7bb5bcab94771ed75ba82eba7db0f8f6ae5ef3c8ebc506be8b061af2b96340497670178c80c28acb4a9e43dd6fe03275979508db4a1343c857beab781dbd509fad8a201c08bd41d4468316a82000c3cf92cab103a4f72d6bd8ee26a5251e3b78ea3a5a7d270e3fd9eb36cccebb2d44718fb5a41460dea2b85860e8b965a8185f12ab5b89d6f090a2673365918c17806b28aa11cd532666ca0abe0835ed1beb076945735e16d65ef5e175c7af851c2dcaf89923203feff226b4e72db0119331d27c8570c8220b6e81c45cc1c1c2cdc1ade5be0a7dbe0f457fdaf53965ed3fbf9ccdf94f5f1509918affffdaee84bf2b7a28b07439a4bd12d679f8d7ae148e22a3499615a994aae977e4957e1fc8e9e19bad9a928d1bad243ab05c9fd529d8f2575ef37abc1ce99ca55c75aa295c4e76f589f89fef264a2e8310fa369c5bfa7b786d42b59481780c6720a4d526a08c88baf6561fe9ee742249c1922c1eb819985c250192afab6756e3ed915b18be285728dc7854e13bcc59b0d4b5f88f953aa7cd987140386496382020ae3c54ef092289f0e81c3073cc9230dbe8754e7b04400b34ed55446eedf99d4d56a4c22a66c3eaa518e003c4401e46cd7ba9df6a7d7dae03d7981f8d435c1be3f8da7d33334ba7ddb63cb1e88f1b5f6944b3c94381d5901c8eaf4f2227e41c5f09a6fa5a4ab9f64c0181f5b96397e6212511da8fca72d2f9230586e37dee006bafd07e5c20c4e3c4fb1cb41fee0ae523d07ec4c3d4a8acb83c8d8518e844d1c6ac0baace245ad2a09f16565e59ecf58ca87e8b08dfb56c642c24d605214dbaf7b27955165888e34e8d1cce6217e2bb8eb6b666c630c1ead848de54f3f4aa02ea895720b9d0ede108ceb209460ecf917142592d38b0076134422e54446957741b9d39b3ade244e3a4b20c5b4029cb56ceb07599840cd09629bd2e1bb05ff1ccd047f34a71efdf9d377eae3586c9d36470365d7016ba19205d481c25382331c50d3f0574417162743885eb57807ad213906e2173bc2ebefa094654d6d9ba692c867628dc6ae0b25b4b33c8de8e0cfbb9d44e0ead088d5458c3938f4a66354709fb79ef1341f9e7b77bd3e1b1650bf517237a4217c30e9a6b5d931edd0f1f8e002cb676f6acd4d05f5cbd6f3c5c996d98ec7d0ed8b0913df63a3f8b77ac0042219c76d97b49286138dfbbdfea7ef03b1f127497a70bcc12cbd4cedc76d979a3923013ccec54d1b8794e980a5da3c8e4f3d2dc19e78a360d511a8c0bf61f7815179d0fa78a005b0bfffbc02ccb1b660ce9eda9932f6cdf6eb2f1728b956d8b500263fdffc01cc964718dcc73059bf0aa88593318eb3811e909e420b4a8bea0a8a292ea4b54791bf019f217050e6f16c246d8d117ac08f340cdb0bcfce58a2756daa1d843a73747bd399fe6c94792a571e342fa9747ad5a0bf69084bef20053e4849323716ac21fb1ea39355567b39753865b161ba270851fb22fc38f5ff306425b05120d8400bf4d27881f01116757efba66b9c0cf65a212ab19cf2ba22f04c4cac40fa280fb0052835066a8934083d202f41af7cb19d18b082dc4e2026a84330e6957eab6b666256e3dd27a7937ed2740d202a418881426a18e6be023320b87411619bf409af72464441dba23bc58d91e6d2391ea0691a5ae9fe722f3da41c451a41c658e63e9b848d57cb98885c4da6da57383cc5884905235082eb7611147aaf0bb0c566303794f6710d6a9d1b15caf56d9fa4f125e91e783baeaaa708a15f62ab0901d6165f9c7652ca0db802ed0aa924e405b74535f1451c4b7341e308e1234826fad7c076c4f983f247cc47e23b2828711b8750add0535dd0a9a3d33df0667b6793ce9bb9485915e718778d29e7d457c25d6b4bf76a7effbd0e89575f91e9982a3cdb95b71b3f2152ad4be1815d3abd58e3d20bc9e8d66cd8817fea853441493bdf0a46634f9fa4db360f15238143b90c555ffa29762cbdcb50415dcb0360df85f0024755f0e99b429a0ca40ba83a1b3b553c7d18450b757d3c1144460a6ceef698a562770199e41118f9f2958db8d3ecf9a5c2f67933ce3904d7c59b5a5db7d1db141278fb79ffd7687df68e532f3e8324485fc96385e0dbb35978568340ba3e98421a05365702801e9359fe11a7dec399fa88cff6a9df3423b8eb4a28dd7da06f7dc3890d78580aec56b55607343d38d2d2e66d23ed7e29faa231304cbe97fb7e2cf2b2c9e3b31468c5b9dbc9acbeec4d0abfc56e0947a530c2c91355b7d77f7cc16a0243550076b92e0b36b957be9d6f9f52b09975e08ba701b70470d1601ac666a121e7c8fb8c35a53b194d6e7315b48932296698f3227662cb27b3a0925006966c3b834cadb57c2ad200191e97f094db7c872eec2e4a96d5cf83d22b417f54920756435e109ee6cafa6bfd181d243e0b157e307362b5e8bfb471fa9334d92be100af77d25a1b91b08f8f860c2feab9b30d9ee5e02321c4c831b44c361b5418c3ca5b0a64987030472c165fb4389e1518466136de8678b49fa499eb8a8ee2b9818ee2f39e4bb85e8107a35b99d3cf160689ce0f0acf26ad1c54c11d63be474e9ac61328ea7c4abe739c04777f94ae50f97ef6c540ab8bcf3fdf168084df7571d77564d699a5e06b01262f34608dc1527cc4aee45a5be87d26b9d681082543202e289467bfbce2bee8ce667a5ba7ea7ad663a7b56772694035003827c0a218d83c650816b84263f4c50ca3378eb3455b7129fe423ef0b95252053d712fa696afa83c8d69b24d7fdd615060c866212da5db81a5088702f065c804cae12fabb382833b80f9d9c01f6eb9d872cf61ee641a0455e26aca0bb8631ba152558c16e770919909c766847ba01f9083e03d91ac8ad45e9566ca3735031c496c65743b200ee3852dcb28032e34893ea44fdc27e5539cf22bd2b454e70ad58a674c7763510278387a8907545a1849e2301706395e08ff7e3fef53e858088a0f2600241f803cb66991fb6dfa688fa1bd440f4287ea4ed1c1f96834b328eeccfef138dc5a03ac66cd7da22849018cbd9c787c01402f248e39ee5ad8b9cabecfb00e20388de25a98ad5a6a819d0340234f5a047384886b0013143b56fe2d1386e6cd56f0a8646258dd02c7225cf52ac5ec8920f275b3728b364c6c17ed3cc8bf75cf66176f9e3465c3867c9a948c9f81ed9dbc0cb8c314547a765054b72fd7b10077612db70280bba7c0f6238466b051b1bc18f8f31ec7a85e5b61436e885d7651d4f10de59a9845f42827122eb7918ce8327941b3f53bc6ac2e0b128e4f90c4606688120e0c283d30bf3a5e12f3f67b2beeab7c24030604707e589e62085d879d6cbe00585c38cb7ba69a6b6abee20480430f01c900e48a64f91c226ba44fd585208bbb541c6a5b25791e1f648a7ae0100586dd2eadb086ccd297228d315ea93c918e10286c8ac30386ea0f44ed1e282427cf2735c8e83084121b20f19a6070ec26c09ff50d7732dc70192f225c20b2d14ea63c464c720fba09694c84c6717a08f9b0051fc6f6875aa830fd8140fd860d39443f960807d40a76ca3531a6871a7464bd80e60096c9a2c09a592bb086511ab033b9563ce5135ed728b692e818636b6eb08f81e2bc82cb2f5731ac64c981530ad2271b7de35006655712d718b76ffbb4448868e844e990d80fdf93f7d7a0845f7cebec27e210e710000a50428ec219c5de9288fd91f7fd764c16556fae3124d51cd07a0bbebed8f1f0d7b2e7fff5352ffd79c78b9e597a5265c894c381edd040318b5098df1245f10d0909c58b23fa27f820f10ec8f32024020a70f40400a16c58b833706f22512c812cc856a5f752420f9a21e670fad8e85cd0629964483bd8ed21e033cad4b35edbddb1950320cdb0cf05f77192f53a2d669e8078040f116f89c2e1c2628555e7713fe06e6ec4ec842a1d095e024217b91380ce5413895a5d2d7357560d22dad7b8fef0626c17941f0dbe05bafe8bc2f4252f1f2b6a75320f4f0cd0060ff1a4e2c1dd3454ee1a20dfaa2cf97d30a2deacd10a57c632be4d3da0ee86f92941536bab32744ff24043a6be330c434ca5ef5138a5f6f28c5139dea1654f540d70cb7e13787d081a51648162dc3e6401382609808eb787fd50749db141aa49903ff1cbb012f57f340c3ce838a67ba4809e3a2f7a3207952957d28f29caa725abf2186169d8bfee7ba4b3deca56968c9b662a17442d6063a238cf86a48bb04df28a1b33b47f42afc4d66a3de2ab559f7e7946140a8d2c991294deb0f2519f87bc76e24709fc2c9a16b8f37c96e57eff621ef2cb9b0619cd5db74a34aa24331ef222ba8a531f7e6b5fe5b0053c1c61b0c2807d57b08af7521c2abb6f1b8555bb4afa6e29f641f2c23ea5ce97b099f40669accbcb35138a65479b13d3c0eb0a41cd9ffb251b71b51e1c4600ac8ce64891e29b430c7583baa3ed0cda407e4bd4e711eee692ab8a1f048b71d4e8781763e732453a2b7a1d674e712ae137ceebac4f0ca2fca45e616ba8bcf2b8faa33d50fbd22b346bbdc12ee7155302816e10096bda682be4f24ce55d233b6eb0af43e9677a1e902d339c9dc7db0496178b3224701902afb9357262e2c8911bcfb381d9107e25d98ea31d04b0ace629d7a43c40f2641fc3c3ca8dba85fe6def206f21d0217f23dfeb2e5cf35333baa84ce93dd8fe4e61d2c40d25cc9fa634e811eabb251dcf059a0c7f57d71a351f9947d5f747d84de05b292f7ad998baf7537b2e307342563e4d252acb842c8c5b80bdf6afe2b4976db0442428d4aaaa2a9add6ba80762df80cdb0ce8c45d02870ff539ac4b5511e076be325923f36f38aa23fc4dafad2bc1fe93cf6d0b20485292b1db26e8459a7ad9908d90696c1c3bb59cd807bab26716d5395c233491fea3f4c1b67ad5cdc11fe94b86e4381842c1fcc718d8e3b93f2509475d479bd245b1eaa3a8925ccdeaa222739af27f78e29aef775ac9b7b9546c9cdb06544285c2a46f0ad05b806c78e68aad8f40687fe2eb7d0de8fbf9736756f96bbf7b82278b1c89ed5fb73b337a7d9793b0277165280b35f5ec75272ad67f60f709fff4e9ede1a0c2f1163b3425779d3f7b8ab9551fb21a9fe9fe1dce1f5e743a35cc901e2909d059d5886113057ece09b1858bd1b0b36e847fec4a010ba0579b5140ce78eccdf0401c253c0d06798ce6c76ff8a89ec220546d5def4a0ac2739a8f4502152acabf053aef56f208800a6cb6929d197c7fc803c403f0ed06b1a1e307848b28cd07d6a1a30a262e41814241ff4773ac0bb6cecddb596813e249640e99582126ea70dd0474f011053657104b00655980f4a33ee4bf587f3f3440329eae4c14473297d1f497022bb5105a6c9f2ab2adf581b9c73c8decc6d95daca12bf117210040008c06a7be4a66d737e7a010bac1d1f395529e2ddfceb1d9bbe810357708fc4efe29d50b20194874fb8bb678436656f909b659bda9a4e1f6ab182e25064a6e8e9d0af76c21dfee5bd0f8db82341f2bb8ee66021a8feaa565507e1124050dbc914e5d8600b5dea09618a32acb36bd2afec34c5bb03d69d65690784b3edb014082cc01cf43e8ee1758416a556387d7bb75707ce27f90115bbd5b9a1509b706b99c73c5abe36ff19cb08e3a54550fceb737c4bb13718ca09e6a7e6472de11d1f8b567e85f0359e3e25ddc27e1549345e1522882885c1f8da0ecbb284377795e271c3d386bf6f0cf7e845354dc29a86d15c235db5b9e97c6dc3f962ed4e1b0f101c85eb41484c1970ce7fa1e9012d7cd415ba8603d43f6a49330a37f88b297845c826bb1aa497af69fe17946d8a7b09ee6a583d951575c7bfee5dd8d0c5f2999c2b09548c09b476b54e24b591b3a1c669460418ce8ea6cb4e3d8820e7eaf28b685293b3bd8a50246cd87a45e22e03c3b540c3d70b26d75dcfcd345649e4e46d40b9a960110793a240749c0c0cf2f600a7a81754b35c0f400041d84132f2f3d269329db2b5c91ea4478f71163c7da816c0056dbb16cdefc592a7c90a9705218c0b33740774d70b4a10a7a87e4de52a0aaa7c12446a1710aec6a66e67d9737cac260224cc9c707520b61cf6a3c5a8f6db362e10b1d01d506ae0797adc1c3a975792acdcf4ef9a004e6d0133b6e1c7d6a4005ff6b91dd989d7a110f78bac0bb307697552ffe045e3dde440869a537801ed950e6155be5c6d1012df54bafea9b68e5357837ec259db89a99105b44ee84f5999696ce10dcf8ebdd91c9829d102dc889a119466551be16d01b5559281cc73464a6458de84e9002d7ac1506557d59fe4593834c134d599c7095926766e18047ae322d5921c3e83c6b9d30c2eaf8e9bdc9956169cb2d54058e1a47fb3efa44238deb8b9aaebcfe085201fac2b913e412182ee1cea6b0d8efb1c04872bcbbfff5511b03b2a68d40489778b77f9962b813b8cf5f0243a2f61d8185f2f4a57bd801da3b4949e30e227aec324c75fbf087d145f390c15389d2422ea6fe5c9b8fc7b4c7dac8c1bce59a0bb132f1982c8c5c9acb91bc6798351358432217555e2e53ff8e32afb0b1b4eeca6fe69938b9116de1d9e2cc5d34efefa44337d71a0e99446acafe528c013251746f28f0e1b14447dce1a1a6e590073751444bea725051c80adbb68945338cfbdab4b7c64cf9e9613a26ee0d8aca0e1ee2882a4ea6dfaf842ad173d64f2994c8ae8ae8b280a0c913016299cb2d5ce3891f436583aa1a14d32bf6191238048853ab58798fedff14822494ab6b261487de093a47567d3e2578511fb3e1ed12068c1b12efa098531b8df17d367b79cd848a811a99bb960643639ddd707bbffc8443363e53c4c1899b988450331d2a31188f224fde5183c7fbd0698587f29a6e7a4486f030800020319d2c31809dfc8aad71d9d3ad8c9254cb894f54bc3debbeefe88109d7bd19f566e7919e931497bacf4072748c9a253ac2b8b22c56aa0192548b89d0189f2f99691456d4390a181c9d0fdcf839ec03380502da5db0177e320a67034cd29f62caf60c7ecd0af3abea4fcf321272151f008c955b5f0795ca144c816d7bbc822a0ef5f41528532df0a6f1558db7fb9fef274aabae24038bf86d78d2e3096fb70e21d62d740a6d01ef23e851187a9caffd0c8c404618463a79b6d2c7f1843ac64f76a7014bee98e42ae2a8394e1e330b015342f47b4b7c4e3fba616ecbe64e9dc0eedb926b95528b4b4292bdf2b7da4703c5bc9bc3a1788c6d3728bc2276c8d6faa1881a16e8f0741becf14ccb4d47a144dca35af3cbefb5bf4d56e41de0214bb0b9083c06c9f4b4fd489eda086e5c8d1f00dbe2fa669567c85f0c7cb9f0d3fd239253c83774058dfd75e3399c097245ff5cdf332d0c352e7a2144a1af51570d5945b33070016d488db963973afcf65fa397d74a77413033d6ab2ac98c87bf3c6a4461f51ec19202a60892c9552757399c574d60f89f844ccb4525c9f741c58652366f263cd0c274c586e0ff946838388170550b1356167a427b307242cb458d58bd0f9709f76afcfba7f0e13e75bad5830765bc3852b248ef4f0849774f961325943ff6b955a57bd9d7f65a0991f57c22d68615fa4b28e39e5da73b7514580bef95716468d44a65e296190346b0544c67f2d3572eff4bb0c6200cd9560825cf6c46f5f9c53121da8f7092051d1221277c14fa8971ecc6565c47d520e2cb066753eb97f7f306111684411460cb2d0e2dbc7d69cbf7fe0ce6ea8152ae3d2c01b2856a1c4f0b103db9dd86e7685dc7e7e962b02c02c77e2dfc0b3dafe8c80647392215de8310f416731c29f295a43e171be827680635dca86195e070559e05931d0f0b219ddf879f3ebfea780b4dfa36fc6e1278e429c3216c307a16066c338a6eca272d27e2403c61ca3db645c5492239b76ee321534fc2d9fb45ee9ba4fe6a44fcb8bae90be2c4524e12e039ff60947393e443df12fd108ac50a3489c01568523ab9a6dfeabfd8f6607bf105a4bf60c9da538af0418e6a0023ff219a37452213769ce75d1eb895eb2646bc19cdf433aabd59dda585a092bbce817912db0505878d9a8eb443d464250cae967054052e0031ce83980e11b20c537c774d0588af254ca0f1eecdbb7b1b81d1a3206195b923325550f7c4ddadb4b64c908a76934ca7b490cceaeb6bee239abc3db0a2e556ee4b723260b658929f57c3cb19bc64331dd63cf2ec876a2e2e8a4c2add0b9a540140a9af8e8d86c2f42c99c89b841d0ef2f20c5ba21610bd2a1c19baad5d458d485a80678e4b780e7a5e2508beee71179f4854e4acd5d85ec5e8640b5724dccffef5bcc6f1538d3cebe3973066390bdf01c693c840b6c16233e2fd75246040ff72e07d2cb4e51d83c8b2b04ed1087f8eccd22dcfd6043a2c3910003685e1fd873f1e8fb41ec176f1b0590dc4619adb80f2e514deb7c98b394bad4f9058c610c7c2eb48ca7ccda17b482afa18412b810371021859207d32174fa1d607836e790a9856096793963b08b61bb5bb953544cf95e1b6ed3fba11e59ec66c84faddaacdc4a37f3eb75955ffe57db53b08f36579c8e2558b08f1dcbdfb236fb5e87e78a2dc241f59bda259dd59e7ae98adc9a56c9e37960083947e5e26d40bde6e942e3b0e2803d6bd74bfb1747f493468265c891f730f1913047a26a4a1230e2aa1637fc3f97661b808865694229a5a987756f2844cae6bfdb42725a358d8fd1161551126e388d45e1b0a80bd74672904122d52806fada43f427adc7a942f28475b6cc8971c6481aa6b8fe7fad8a6b93a299ebbb9f6a7c42750109ea369aa52645665e57d691b5b40ce6c9b10f35dff87fd6d1daffc44dd07925c025a99cf522b59798dcde31de1b598cd536be55716479a15b325102541f49eb0adb192b494c9f24e6150839482e9afab350fea69627b07bec0f004aec3a60a3f17880f9085d0e259bcc38049cecceeff2c48959480a3af4dea2c8647ba549951cd3acc85b4b344d3f6d489187a58aba1d48205d473e99be3254ae70e4b6c243d5f18b57a3627dc63b81aa5801df92ac51565b88040269c27b6df232bcf756410afa11b485b1635cec8e56621e4e8efcb619841404a54fc44f83ecd84799d94b7413aa99fcc46ca26b1a84d45e945acda3bf49a6d713d284b0702c892a750ac271e2709b167f61dbbe0828787ac1d825341a82d52139593a4457ad23160ac6fcef2d2c0c037c84acb64ace91e2d334b238708c0539fa13140df2c340e4d7984b4f07800724b5ee370615693b59a08d644ae3d6f6b7530965cc029532b1194cb6f05ecc82d60c6c5747c126d75b401a58fe0bde1f72f826771a5075ae8a5559f46baafadcd18ef1c45246a637ed5af81300771ed31fb416bc09bbc517ef18a4467efca4336899140d36c424b5fee95f6c51cb209d6dc6bfe6338991f67fb8502547802c05292465fb98d577c0fe65677b4e1b154e87f5934d33d7c024eaa428d04439cae45077ed007792f1b087dd837bf039248eb421b1f6e875323aefb45db9287a9656ef382063fd80924155f90a8caf53f0dd86fc39bb2485f5435b2adaf4e25025756bf5cf84341ead1c0dd220b3e6d74f58a73019bdce1b0946063e264b09fb014e7740c478af5c988808ae7357a1cfc9a3ea956bc344227241507c104988bd082c70aacc754aeb1cd221be46d867b17b8eac6df36d13bb6375ec8effc6600e18d539b002d63d3d895b1acd9c609106f1c2e7bd1acc00e4af1278ff12800e0b65130956b72ce281303f170a776c22504191879892509ed50ad461b809ea46e4b74f6d7ac5e09a2e851efea29e8e6240ac293943d2c302398d12f427ae7c1cdcaa7e49f7a972e7b2c48eed654a45953f4fe515237858c520fdae6471f2684e4e9b15fa84a13287d6b09adfc1692aacf8da385f235f267f3333170c3c0adbcca66aa6ffdd8ea0c882d8b9a7766a58adb4d867f0ac935252ca9fd465ad192ddc54e5a3be5320d1b290de3d724fe76d00aa40b6239be8bb2508454a221195a04d3c951b8d9026fc1a00cae19dd956835fa2612a5033431f08b6bdd6bacd14236a37a1357bba8a00effa4715b78aaf47e19bc6c1be110fd48e594560ab1a79b7ce944fc8ace031dbdd99dbc0fbacbef8a50cec87be0fc03798eb7ea461d226a392b5c8b446b182c8f001d5fb73f3586ab08650e5467b11aebc30fa2e1a476b588a2c5e9a1c02f6af40f9da0493b518974286c69a28968ca0831e5d26be3972cd5110a8eb1833d8ca0d17d6ab194d631fc396e72ba17e450f4aa5240ef48e28615505716e833c4ce7aaa012da7a6a3c0cc2d007eb16326f730d0f0bb4c00c6f074232853bcd1be77208f63ac4887a3256e65d397e570328bd2b9ecc2245340b9c24f2b62660d0c02552c8707a34830634ff8424ef00b0430c3a4f4bc17764933d802906914dd2f0c2e974caeb4457a0388bd54af1b8b6fdfe68248e74de0128734135f9e110e01e0c7a1a426147c1a7b427dc8c2add980bfcda42ce52954e026bfb1d12192897eb974193fd397c7a20036c5febf3fb0c48011bb3a62f8edd3323545cd60d1aff6a139521a7ec36061f4bab3ef03ae0e123d313a3e66bd26494102c345c42befb73c9ac1389532cc02aa4e3f9171f632d68ad62f3523c471fe69ad0bc121a7a1f004a6ecacfdd0602f8bd9fbc51e5659e8f7bd5476a5ae9cf3a86065790e10d67e259ac15207453c7a01d5150eabb4c225e39dd3d620c1a5581af250c07f7744bc30cbd9a0d7fca7b32a67bae1693d8d4167a268077c41b58b3aa6d4e5fc8a23f4cb68fb002028b2ed6024d181bc68881cc1a886c91452c04e18521d5804799e8cbb91d919482c6f8b63db2658888c28f6b982f8dd222a15c4948aa207af54231046673b4ac8ae62ef9f4c123e3c8383540e467e99722381e2d24f30abcc1ec81861753b40b03edbcdf6dd33898dd221b8ab810720ffd250a8b0d453e90084cfbe54526bc9a0324b996d9a0a9e7117673c8c513533d779c9cef7b365a6fc795c6773d17105fa0e74da11e6a697fff81b877c164bc010ddf92f6a4ffc14e88eb26ca0fca581c50ab4c9228cf16e2e490d690b50c9d55710c569a1e3b3277360c3c025585e77592c860f7fc57394299c714240f5a6170f96806e4c32bd4d491acb844bfd3cb60c1cbf544f63478e11ef84e188f17223fc38e777533c4d8074d398e7df0212f56becdf11d9e6e789789e9b525dc21442265bdc814263b86888a9f69381598b5da0e96c184a5e1a40d3c28a53b15b790a309cd9b339025be871244426d7adc235a4b6a0e1685e6ab8ea3ffebf6706584d229d1341bce001a1af29ba37086bba576f5d4ee72c956a0b69e4bd7468d00019e21a4cf53e683d1684a132e041428e1fd150622c7755990913c3a691af3a1c6f452f282c67947430a47fe36ee5fea728ff8a833a94c2b3d70cca7e7c28214220626a4427671507585a7a8c3c7ba26d4db979a8b902e0026e0af4df6da9b88b0758e7ae19394b7e88054bf32a6f14205552e3eaba4cebb2320deec7b9167777b2e9a9bf8974e052b2793559a68c9c6c2a76ff46bce8a92d8ee05816bebdd52bf1eb1c25e9af7bb06cd0f0468c895bbcc6ba6e250e0179ba0dcb7037db6820f735d34aa2734a2033d984b329d71c9a435be48ae9378201f1b5966998921a8e96420d329240d3828bab612ed8f080b937ea54c6a5442d18409a6563e0abb65c61aa81222476b44e70cf42d2c507dc7ab67752944f2d2e1bd9340dc42a2fa43d3b5fce8cdbe12b252ac20bf43a10a6507108914ad34f6068cf023dda2105458c857f93043bdd27d6e8d4945a286955a5084fefdd61a441998f9fd981c1a50ce631657bb58bef4c9defc912d51580cd27775f160adf77e0d8788a7fe2ea3d7a0c3944409c71b45d250900edfd12755d26ed15597629e2bcddea792b0c6a14415f2feb276465e1c762dff955a62a9cafbe5619bfd3bddb1769388932f1e8180dbf4c206bc0a1e1082f4971606c2d35c1bfe889a2b653e4ecd65aa11f321913bdf16d724c7f3bfe319d2b2b3d6d8cae75d3e1592fe4031e3374a844656c4021a82cf53652e6c24e1d0131acf94ff1e8af698a748afff04001478df1038d0f070c27638b1188e4314e3cc6ed5669a297adbe2308b1fa30fb9e47cf001fa04e668647d9591647956edd090f67533e59f6cea5b2846764e3a6a544f7149ca838b0ad380652f8fda5750585d19af29f0930888f24837e24650e2e9cbb61a63187fcd3f0aedd440fc00ac7bf4d6da06c3226d80ad1da6d8c32fba842f68831bf2cc10c793673b4da53a9d1f0a544e91849f1ff67b3819e77bf9746a50299ab511f8a0131fe1b6a4501027018d4dcc81cd02fa7e168f0200481fe6be6006f1f878e38ec0a8f3640f0c912dadb2d8cc9f32fda5dab9596475a20218d09ec8f38d6f51638fd35b2ea7cd1e8b17531449a1ad1012979c3b90985d0fb20d3de83accef1b5db1efa843932de50b845c53a8c581ad53d1795cb312da0eac78203059a40279352cfd70b1b1e24224dc430a89af05f94847d6a42ee86176c43c611f9c159ff8cf1fe4f7bc6e4874fc1cc0a18af393de6299caaca79bc9e0204b632061aa0e3edcb5d6c2c9c925ff2eb8c891caef23cb9df9b04eab5f96bb90348ab288035675421963db26798e323ee5e99c433fd8a6a8c4566733ac21f50aeea23a1375baac45cc7bc39919c99e37c879c4f1e616089bec30a372135031f8dc3cb60087b5a3a1186caa1aa544cb9c55f769a411dab527eadd8d1d77b2eb24187909d7029d053d119a9fc66e2d683e09b98d5151cce904f6ce2cea1d838974abf9dc2d5c5e128ca35bfd6424b3691fd9d31396604bf2acafbfee6397893d492533c2e6c89613c65752dc408dc9cb88f975583629cdb73405cda99f2a225a63672da4c5e5ac1f130d76194d50e0fa9dac13fd7630f375c32964f5811fa7452364e82f890e3196fb7972a3df14616df22ba530edd8a8f86379e6ccd5fb13a35d5886f94b3392f1313fb46f4bd73487d8c7b88626eb8fd6e6fb829a68295a482f7337a1d2fd30af57ef58cf2e3f9a76cc0b15a2ab6dff59512d35604fbabc04b6b61ef318cfeb21cfcd218ebedf61b3fa7e9226f97a70fa1ebfb03559c32309d3d8dbc4a09d10053977f957054018555f16677eb8c1fe9b9a962d88d070b1f8750377e551e45e4216184205f1ae3e7347717266cd5d77afbd037bbf6892fccca4e24577261db10049227b071a457e6a1a21ea97dd552c2ae5336fa5affed985867e8bfaede0577c8892b89534f4741e07eb55ed8550a49e0ceb215d59138ed01748eb7ffef6646745a1a16a988a05b2cbc0ae01707403154ed4fbc697ef4d4ca23bf17c3e8e0dfedec633a1101d469234b5499ec64292e4d8753a0397c90f4412abba40fcefaab4c243a17debcd503081dc22104aa6105e45a92f56aaaafdce4326730d741677446907225dd0e899b82299f92c0215fc922dc7d2520940270b77ea9bf53b27f47b8123dbf34945b1433ca2a35b3a044a70b12b31e359a1fa0b2f4e3fb43974c54efe653ae85b487845595259907d3882919cc2f578826aca3b03ee38f29890b9e22f473522693b38317309312e11126bb2df171f4a01ccda68a71bcc6d220521319a8af48fc71314054276a2751ba93a2c8edec3e7c6906d4f39ef87742b0fe5fdc5ae218ca0f10049798c4ca546b686269887c729430762bedeba899b48077dfc3f4018f84f5cca1d134f91795027104d50877e0e2b6b46ce5b9737d1260d754730bf61bded09e6d09393f14daa2b6f2f8f04b6cde24473263b4667003b797a08b2504f2df1bbfd9b5344aa79efca18f58422f1e2dbefc66d705c7b6ee4da7685c52a58eabbe9174495394a3d1a05e452fe32fe93ddbad04fc0f9387e5186e26dc966455f9e3eb901ff77aa10b2c98ee2a92321e856c90f2033142930573bf51c88e9e17e22264c9cc8e0fb41720acbf52b42a2797a69a629014313b897a0300c456684583757c656c9a73e9c33a718e20cc91d9f0a987e241a3ebc5e8a4ea16fe2a6d495df40fc8d7dcc269af881ee67dcdcfa4597d7988c914417f22e2b77180276ecf71a3e3cf68ff998062a8ec868f19bb3d64028a484b50182adb75525a2727c651a33bddf9b27c85260ece3adc6edc41b2ef1a49c795b7ad6350aac53507494774498d9775cad2f4ebdc316310dc338e78971abf11d9f38d6eda1757c6295599502edb0ceb94faf7a7e6efeb69485e83d2e1cb8756368c36dc76e1a398c48bf144241ef9ff7cb3d221b8aa81d0550d08ae6822704523a22b55f33c329d7291e9ebd671c7e2d8cdc2671cc5b1d22c80378012af1413c4fa3523e8a709a25ecc087aa34ccbcbee7774eec214396e366cafae71fdb8e1f85bebfef24b8fa4fd3c894dfc9dcf418bfd9e0b9491069189e8c970faa7673b2f8982524a68cee9227929a5ceec5f0ab76a8fdb1d8f4a2dba9dcf16a58afa6cf4af119dacb5d3e81af22fc385b348b207cf33b72b62df6120c80b07394cef568be985a6316b9cb03589b62dab124bc3b314316ed9f0e67698023af117548b8ab4f97809f7b92c74d00f42a9f422911c2237d2441bee4b8a1db2e75064b25b10408e513f2c0e961eb9b71cc725be89585a9aa49f1d7e69f4da4eb78b887bb484a091d80a9c537183f580312c5092696c49a24b579257629804b83528ec0c987b7138a3566083c8b68e1c61760d210dd1fed46a44bccf9d836350a1cc05e4689cf66f2a2fa7202707994305fe160ae2a0ff1f4dfbf3f1a9850f25077e3cbb481c3e641e0378cbd84340fcbee6958164d54daa5911007d935520aa49dd32e6d701298d2b840bcafb4e80fe28f86de562db14c28331c8524343fdc0a954c231d762790ab58da0db7eaf9ec128840beabe32da7e94e889fc2f40aad15b7ab74f9c21d112201425dbf72ebe2ddd3f9bd8ad8466eb1716007db2312dec11d36288d6d488b074c86bef19ebdec98400c702d1425dd84a0521ec8f400545dd7cc29c69186d3caf9a6f3b64ec51afa8b3b3178f84d95a5f770634acb69f5d6c2bd9ea071390a950476e29b4029403811e22db8a3fcb8f715476a536c9898ab6adda4a36f5c982fcf08c7e970ac1d1d748409b5e4c24445d604d4d777f7480f2d411b87728954e80a9ec5ca9bfdeff3a62c79e2deedbb1920c68cf9b6b4d36815a568760bccb8a5dbb4a1c76953aed2e8a4739c11b8d28c0099285669ff2bf2958c4d50b796a1c4e784801583f44edc0d07dbd283c797e66f460478fdaa9ff4ef1fb0151ac02066d4fd4e91e70b73ef0d08f651f3df744143e30ea7e60641ad7453f7e04422d3faad0ce8f0d927ec4c54b9d2afb1114747d0e81983cfe087383bdd7fee57b95e5e522d3f5d30d319255a3c1f5ebaee4e78331460cf4d6f130c463b1f76304e497142300cb26aaf120bf721e85533cff2dfadfbeeb1615ee06116897e78d15fe2321c4e21e1dbe2f1489f78ed3767886ada8721f0c43c27b7ef2ed1f2c4b6c58bf30c2e5c22e363855b90ff4a0b06e25551ef0146b721ee4db78b21e0d32b46278a9927a3f7da6f71baf67f6f5b99a20c4bd9ad9fdf4320dd82f5ab182cd0cea820270057c2536d13072074e9d6c8fb5c3ed7ba572e4432fbf4c55b98c5034ff49a8419f9e1c7d502ae1d96e469610ec7683e789ef386fc2b7f699f84731f6dded357e1722bfa242e5a09805121edf43d79b08d3b16caaa5aceec784fa6ffe5204ed66577616ae259777a0dfd9936a162208a286ce27e3939940b89b629b96562a6434132e9640a40b82ea8de51ec2c22d14fac09bd1b07038f3b06dacc97ccd9fe0c96f102b0676494e674b6d82f4010022b70279ac752069b3ef88cead4a9fa60fd5e03565147e7c1c1a0def5f9867b67295a3f60fe9315b323431a39bfdad21e2079f483976dd18205a160efd821a0faf34ce14aaf9879cd67920befc3dafe4ec929674691c41935871c286262ad28c69f14954a3a6b7ff9ed8dbd9cd3f901eedfb68cb9bc2a724914fd2670dda5b221d885f47a3ba59e158951cc17041e899c0a921bd35ed11f11efa31e5bca8cc74d5a369ea1cbbba11d5862d19888cd21830042fa86dab0d5bf22513c9632ac7e3e02f4702cb53fa8343106fea5878b3657258f7d58bb171101f93c0de2ad594e534ef31059345337b50d01d668f9b65d2701ccbc126202863aabbfe1cbea5e713901bc1236365e8990e09de1594a21f6d3e28b9f9c877e62927cab056cc53cd488e405a61922aa556dbf8ee6b0439b20beba2f3856fd61654cef07e325b9a35665f2c63d40222506cfeaad86121944a1e50d8899746cee32e16f3c55c3db9495b0badc6246f6afa9541b61044eee7e349ccb4aa895ac29de68c2070c4149dea130be9b608a3879e0fe7d43df45b15c311eee135e570470f245a6eebd751a522ea6ff9d13e446f567a012342491c4a8db89b9ae766c952047dc93a6fa92029472f6020ace930b08973d0caa7941d57fc9f28ac72a53c7673435446ff674b7c911430140b22def347e524ea7162ee8ec491782a8bc55f490d1a54fb469990d640a54d9e433cdb89381d2e11744ec546e6cd86512dc24f0f0bd497eda8001a8a89157b55bba60965cbff9ca8fc31ffe218f430729592215078f9d49c0c27fe55d72b58f413d2e48644f0c47392dfaa39861aefc9ec3b923c40e75868a95773ab8282d81102abb4ffa63401f148133c5d82622c8826f099ada2597d536e7d5a9a5095923a82cfea05fca55ee9a664069103fca61b7693a424258abd44f7fcae18a38c9acc52abc4360d705a0ee71df2bf35410b6e5b696bc139d73c593c850b2bf0b2f38fb0e69dc48d0a19a55488eda6c23d2367a0419521c9b62a5d9741c0509752ab0a72dc9d85bf7455f08756ef904a21f4f20e3e9b3861e3c8882979800540b3efd18520e84d28bacb33f37fc1105e4259afe6ed67fc0fe1008ec182c337a9916e63323d769908366672981c7af9b687105d9827e87b959bc9a1d48d1b81ee39ea96f6c31daa18103dc054832c15253ea60eafaddb2ae9b0ae44db8b32b4399aff2332fb183a7b3d0dfdc5c1f181770f444a9ec94c75ea2df3bf8b7d68421d9c6378e62306123cbe5cf8f0b7df98053961958495e4d8345a7116fbbd61911348308047b139207629db4740d48e37ba0a860ec6dae0d39e77242552a2e5f1c1ddcf07c28a527b585135041ad9a28c1917d1321a52543d1a5efc5840ee363911a50c29e22d8e0d6c51ef11f22e33427cd6e4848866cd8ae2a697da2347b442c51b0f5220181af85136de38e71bb0b347f16a2e79e6ba50ba37b28f978c4236be6f1a34a528746462aaf01d3ccb0d510d56e3650f8291a3d9d6c8accef6aa6a92ae5adadc28e80ca9a60fea6e7a610a629022fd7d0a73dbd4a045fbd598aa162786e3165e2b460bebf49d493a951eb0f055f5f62e000edfaf585ac8b33c02fd8d6386a7a56adeae00efd698e8ebafb5cb184da38ad8cac00c01d70721c6d7de527c2a123ab040e26fd2c8146b587f6251db85ae8a9a0d47297fd86bcc68de64a418d50a21dd187500181d31bb0600e46826b1874a3c9ca0078d31fbd073d6056b17a2bfb25e3aa5f2e7c885f6c7eda4ef591f73cbd244916237eac3a7581da04ee579418a8467a1906c5923759d485f91288ac4a6f183ead0c78d4c8ca8a2406433d7be91ef150db5341aeab3f996b263a7ccbec414d6be9c8c54adfb9a579ae9e456423787c2d617506a879bb54b63a1effb4da85cf803de5e0d1eb951e4915277e7587f6d31a85914bd9dcb799f1eb36b8adf0c82e56d65d8f144e3940d69760052d49950397336ae208508f947fcf090f3aecd4e768635746799dbeaff72ee9c9a592d06a4aca351ea84a1091eb2142b3af1a6702ff992595940426b988cc3f4528c4d78dde916a0b0afe478730669193d2396cc679892640943e06c90c882cb431fecddfb95868047a3c1e0d1c2f80aeedde0ea00fb7f5199d31470135ed666a0d600ccf059c62c8e9a2eba80e5e6517319de8a34ef64a18972c6d05277ad592ff1244d327436071d95abdaa6551523ef9be5a2ceaf8349d6e8755854ba6f6a2721c8b72b7f551992b0ad40e032238c0d3e6c9b48c96c0b15237e10c26ca29af7267f41822c89eca583d84e45e0da6f292c5be1e7460a7c82b8168de9eeadcdda52b84599c6124c1458fe66dfd90e7d5bcf21a39b7de197be60897ecd5a24ce11fc3b798cec02c570d6d8b276345ea83ca09f7a73148a1cc376a228933d7b2e8f920db77b297bc606c3b80f247accc4c803662ab4521a6afafd17225d065c3a36174290d6220094696fbcdec43dd6762395afb05409a49f560d0d5af010e63f14dae4d4439378d387d1f8f3b73e6874654c445974558cc9abe2220278b4ff11e0fa980969281ecff940b7b5bed97693ab3d611ee7ea6f02a299b510943647bc88e459c732160b2e17b356dff9ba8d1d9abe473c1355e2debe11376b3b74d6974070b08aa36987094663c6765c9ac30e8aacc06632dab0b254cf788d07a298e48c5e349a2e029224339426b0533c28fa3e936e94bdff566f928c8262854ed51634a5fcf057710666cf4c295aa0be66da4202721f81da017c8f45d1bede6affff45a4fdd747726a56289d4c83399005b9e6880203bc3f72ee4906c65a1added9fdff833d4f2e29cbb4b00b2d82ecc899719c15aa7e590c13352486050f52c1f7ffd3e2a53db6109804c187b16334ccb41928a5b7d73a17de46a0401149cbce7b76c278161c4854cd3e53b2dfbd425f7b24b4a2e7b14b2ce3e05650de3bd1afc389ea0846cf17bbe29b3f49aae1be2fe76e6bad5eb540c082303cc94413f443d2fb758a2b31518846dc0eb6dcf624a686810a7c8bceda996ceaf9a0a73bda7184a3d9778f29de49ea600e6db5e4d186d7a6f5ad23a64816b8939f98c0c51750a9ed6702fe6e1e984bd99a3749009ccc022a457ad7d6601775475ecdeb7842c48201e901fe2182cc7e99fba0a138feba438829145ecd33dff0636a854d28daab8e63733950be790baa0baf7f0c07f074e37c0ca746d3e7e85d7ba030fd8048a4b6077faedf831af7debfca69cf6e1b1435e15af02e97e402e80b10ed51f285c13130b25cd71a5edc96d65747082cf1e483581b646d648d6f9fdd52c07ab73ddb5b49861d0d69b0407f1d8336d0a667c3d9ba9f1d60a4a83b4332c0b4a93e793ae6469b0448248939c07c44410c6d600d8bb32d4ff95bd55f62b54ece0c4ed9b1d0dbd4ab3362dce6374ac4718625d4834d6727fb6b631cdbc4b92660e1841f5cb4f6a8a560a9efca31a8622d34979394095bd34218d098bd97c2682831b75cdf8b4e4a0bab6b6ee8a121e4b123599f787fdfb2d30af3397312752608a8c1a8e873430064c1de86c76fae391999a170d90206b54c8de3fc2da32ff89210965a1ccf7834d181dfd29db5b8937ed8c4310295ebef2a36fa1728d59e3327ceac8407038aea78a9923e755599828aab4b4b222be82ed86230cf73d9ff961b1db6cb8f5c7e59f4001ebb21e9998e39fa81c070e5545a50624e392d6b18a18bceb948c2fe3903ec8515896d5a03017dbcd8a24f98171ae4197f591b4f647d5891035775ecd222ef164aadbb2853119f0c9a6e7430e8c850db7aac678ba66a20e157614ca759773d9a78d109b7e22c01f2dfbf1b5eb1fbbaf4fc18708d6d5cb6c81ba10d347281e8c50876d78a3a7b1d66f948992e3c374d90649ca765a5184879572cbc94401af3be97264c6bbc57685546d11b8bb922aa047c00e90ff625be7209dec805b56a2dd03f4f1ab269b5c3162d8c7188252b20a5194fe5227621b03b82183c7c200a929d7e4b0d5fcd5ceefd1b2843704867afd04d935982244161b75e5f8c3fa8f81ec6cedb8bc255578347f31ad380fb53bfa2a64e43f3cf2ce9a434558af01b837b386230b8adba366ae96c4ae8021cf3d5d1fc2f822f1d21892adb6abe0ffa6687b57e38b57300d74e8f9af441f67ad4ac5fbd37699becbee2a12601727a65a5a4ca11e004c54cec2892deba9ac8e5385ef818a8a6bf72285f10892211cc6a82c731e98af1d301762033104cb7086b158334401cdcf4f3480d9ac8922a428914d2478f3541c252fffb09b1649d6f902cec9ae6df9455f5b7fe0eb93d34c525bb7a8dceb336562198d287a8308607901c714f658c410595c9a78b067aed89ee90cbe42913d5387eb225c3d716b05a8a8234304dd09df1115343b51b0cd24c2552f76e2d2a377d92063aa5beb75d9665a299cc84ef89407b3aca93938ef20df4a9d38afe99c46c857da18e55916266771003be069bdddf7c4f0ac00207a272da540113f74548e67cd15d4829918ed9e41415c7b059f41e1ff046e963628b9f4659c7a4ab13b58fde1770381600a51e597620a19a5f3d68c6495a2270b17a1283a418f2f0e333b1193cc7b31a9441a9354b929a2053db12c3c8c0e06a3dbd26c3a90bed22e68f7652f8106f08247a23b6cc766dfbda7543c34172bb3f83ac5d63ac40c623a639b2fb9bb574bac8a7526d2c476cccd32bc4118403e23fcfe4b973982be14caa5ba9cd04379822000f38597724aeffc11ad258c43a805a219a6388f2be8ba8e3d9d8d57bdfb1f8dcdb8e85fd72cd25bb5b5062e113a4f18736d51ca576e1d92b478e74cc174759df5bd742d1727d95741a55dd08e9a8083fc3d2995e8eeb3263bf27a44f8784dce8ec7c795dc52ea7626a9094852e463a131619dac42c3dd32546a28fefd82c63b0b941863f0707a7722ec7c7689fa19d9282ed6dca862c8030926c298d93d058904a1b33490002eda087ffe6e1fe69866beea11a64c847c221d9c578435b50a8bdcfb430dbaa31b42a2bdab607957ef6fac588df41a56c9d3e0bd897e77413fdbf25747220052554d239c4d44eebdb8c45ee1834e19f014502ee2f85fbb9a5c9bced2dde010f2cb88ba55dd3ef40c918af09e522230d0207613376848703ff9a8b6f7488206b673865783e5254f5e4b80ecb743c17d5ebeff6ac659a84755ee79cf65d5eb3fabc6970738e6e1a3be1f4062009895150b0af06b0de49b20a2dc5354f5f5fa2706dbb3c036d8b2a30bb93cf707f5faa8a2481319121385798b43f6cb4a3653d9023e6f27d68e4a93bbb4903a12a9ba0ba040e4e65480446a7d539f900e60b6e5e7d8603c133414e5435446b1586cf89e0796886aa1a61d327f3dd579957269ecdc6ef353fc273b5fdb4884af48bbf0b7ba039ede911fe763a44b27592a5a2d8ad8aa0dc9c0060f80488eed0e71dd19e9ee6f0419c162f0ce99768bee94a08f733691ab7b6c298f8ffe2bd8e163e1c4238eeb09aeb389f42c56c65f4649469092b097354d4649b6fda19708a7ffece71d14fb07f4ac02cac9f95e5820504a4e07bdbaaebbdb6b668c916e796acf0fffabb999f242c76e68967201d81a2144c93944fe6d83e8044ac83d702a25b592537c06863a135404f5c723c10434f51176d0dbb957171ff4cab728d4c8eeb6e5de52a69464b1052706c7052f9f1e1eeb6ab1c06fe555314b34c1de71968fc62048356646de95bf86119ddeb3bf6fdfdcbe887a3dada133bdf9598959177d93d10c3571ee2ace1a23973f0987d47d5d7e522386774c6f67d62acc8d797bb8d80ac2ce66d6ceecac16c20e5dd4fc0004ada3a687175754a1a6c91de58dcb9c418d0d14063528a046a82132a74893850c69deb4b1dc954f69d6bcb8c289281d9e4421f992849daa24e0503049987971c5f7c9bf3d72b7a774baa5d2fa01f03a718cd1905ce8834ef6ee49b9393b8ece39275d3dc18c82e97d29a59363666621130a13f7749fcd711c475f2f70544a1da2823780395424d21071812a16c99399b99bb393acf9d5c5dab2fa93c5fc404d54b97fc2b84032d9ad664e0602659fa28b407cccd1ea83ad2aed7e4292fb99eb6d3aa9650eb294a12c9231cbe34d1bab37fe7de1f37e22302db5acd6327f30fc1126bd1751204e0935ba5cf78af87aa0b01ae0367259b264c94d35303133cbb86fee1694ca956938588707ed60fa8fc5985b5c25b1726a89252232daea97883ccdfbfaf200f4bd50ca03d0af614b10b8eeb8bbae3beec9ba4169d09e483e23e9b5da1ab31fabb726d56ac1d70961ec28d1a480630792d3240ba9657e9321889b734e12847094896788cc4ae966725f0ef22efd6f364b9f2d4e94f3c2e0a586714179c5a46cc2f84086d0811c9a6fc3e78e3eea0c2f546b73336a776daece104142ad42147248b1dc8f333811ac53d871460d73b46cca68a291fbcee7addf791ff7f5ca3b724f55e09efbc9893ff552118af7396400b5cc3dfbd5523136996c2624a3087c59cb95c323b312ea2059149bc367404de44ea6ca20ea79e2b8c2ac3f2a90d2cfcfce6cb539237890d0a6eb93d296a2b4a79a8a8e2d2575dde5831d5b4c8b69321de5be19fa9dddcdeed9ddf41b26b8a3092694eab78ac7c8cf97cd6418cd98f3399e93721c27f6f8c1719cd84369721b3e8ad1dcdd9229e5eeeeeeeea692fbbb9b5f3609927e9452ea5038ae3ad56ca529a3bea59a8c99c866326620d5282109470e1ddc4cd889cd394ad7980927ca6a709edbd348f51f4e3c7135b13064b299900c18de6a25a2e0912103c3a7073bfe03d966199e22cd711cc7bd1c9a3488a4126a4b4c4db330463ac89811a6a8ab9e27a250c9bc2ee8d475b6e9e4cac1c5074cd48194cd97411d1f8132c6ac5236bf1b3570290be0ed01e4d21e4af507274d9e174a695d4a077663efbc6c7777777777e79e316d56a8a58fc9e6ecf1e3525984c7052a3a5090ed58c147530d4a6c2ca5846448c93e662f28aef051c95654328f4a56a9641d95eff0a020a8680eae1d788eb8d0752ebc8ad8f11fc8856983ad86081ccf72fc50aa2d313575e92203caea675eb4e2bef3a81c5de4a249c78c9282a568c9350588a729516ee7ddc92e22f8d768228e88c75ce7441d2df31c1ec4030399d5af6c4b3e136c9d42a00b06170ccd414f4b3efaae3fcfc045b2aea8d873476e620e3eba846525ab2596fea477ecc84dabf7e71b77a9debb8d35c53ae4cb31cdfb3217f27d2faad55af7987841de217de9dc24877cd5ff398dfeaf6577eb139580d03c5eaa377f2f44a272fd8fac92d8514e2d49972edd9f9b6c5cabb97069d3aa8a160c2cff275f5cf93079f4bd9421ac16b02484efd0a6d49fe2a35e3a634a0bb14bff139f63f4afc419c7e89f89355cd1568f8f24ea7eacb43038466bf59de441deb788e49ed8a28fcd72d823fc80f48094f54f200d0b17e020a94508852946039f86629207f53f1fe5e018fd2c1beb7582b23af0c1ce4fa16524eca8ac113220879a35028f9f2c127af0aa79ae562bb95af9aad542bd55ecc177866c96bb9047cb90f8a8878cd1941353a882060a2d272bef2803fc6699c02edcb9a4a341e829a6207575a440b9f22024246366347bb0231090cccd6d051e74c6d90f3ec2968a735719699131435679919cc9bed8e59a07f9b36c0563f6fbd84af6de6c9c5d4967d6893f3c0834c28e321842dd6c7ac47782d3be9740234f3559f97c0bc3516cf3a2f720f63f2ede98d7df45a479e493402ffbf299ece1289f524a29a594526ed9cbd874e61e6a77cfaeeb260a6ab8a395b29e9129d6999ccb1b21779451f38eed2b9fdeb870472bd4413da370a09094031c67555555736cecabc45c704a8e06ee8cf1610566ee1861a37519307084b0a0ce9322a240638128dab889410d921e986c809121891ba8266a8e48e105014b49cc6c916233640aad71f062a4cd901db4d4a0cf4031841062ae54d9e0a40d18da02788041c8161a9638b9693349229420df44e1411648aef04283133420420bc28223c0701102c5883550f4149d170ca0bff2690a245308b9a3d0170f6c5186872f6c8ad819e39a530324dcc040c3113f741452de198e06237052608593106b6c5ea49891d24413559429f3b7a5664e543b4b2cf6bcb1d65a1d3a9f102e01a94677c399b20fc78cbc5541c1898253c41d654d5043d208e164888d490828ee133b3508e172a6cd0b4982d0104316426400a516d52415440b922c539e94b962c31351ccfa099980305950e1f2e486db1377052369bee85015a7091bad67b75ec9ea279466c00113850644ca29e3c30c4a3062a0017911a1b948848e13369a64a20e1b25342559832de428a10169d581018b10275a873f6868409a39059687c960397344884bc7a0059d18bcc80d41dc30415fa2640626da0c85b8d03efad4c6ce13dac715d1640b17d0beeec9091376685f055f488304edaba04ce2ca9822342ad619fee0a0406768540c42eb2776b64cca551148a09aa0cd10e80cadbba7f0ffe6cfb9430ecd8fa3bce8fb99852c6a5bdf3c68b60c77760c77b60b74ced514bd6ffe71a8c679f3b6d14e6c9bcf09034b454acb3c8a1c72aec983dc84bf549c5638a7ca344e2b9c535ffe39ad4ca726c2d244954a95160ce62706a1b9d8c95e2df3d5f34b1eb33bb158fe1124213627f72c9b77ce5a63dc80e60bcde61bcd7871e78bc0e4ce4feadaf36d13f5983bf9a82587756ac2b1b071caa7aa2b52f25cf954e5e489bef1966ffe944ceeab65529c32e4e003564231d5641379f4a682251c033356503db9e972e57f573eb981e2c98d98fb8af3c16260f9c1967dc0f200508c91d283ccac9ac80e3ed4fc3a7f2c1afc4d51893e61a3adc4293fde4bc93749746ffefe1362477993bcc8521d3b927270b7c4dfd40f968e6319d24e4a2993afe6c6769b697abf8c2e6a519145eda3ff87d252f3f4d9e2239f258db3285babe9ab7d995948131353cedcdd4aa6bce80787521034ccd683f857cdd44b2de3a91a4ffd149369aa4d62b3531237795012bb828f1fcfde5feb07a135b912235636cbe696ac16855ac63c35d871d6c4e59fc93012a104a4b0ca1826536851e4c92d0ed5182a51e4445185e96e621b3f47e1e72656f2d305845a1b3497d9bba96be0a6232751a85871c272eb0255457e6eeaa66e6aea266e6a2a3d6c78f5b28a071ff10d6359ece955cf3b62801af86ae2fc58e155f98589cbf579d4f77eb26878dd081ce3e8882ab715988716dbff23f01177212b04c3169f0b632de3596247a019fc403221a326facb8fe42e83bf797c5536a11b9b282fd8d89c108d2e4aa055152160cac70f3ed2f4a2bacc2b173c6490575555cd89735b859246a5d564aa55bbb762fbb046f0fe13c7bfdfb7c21f1cade7c16205696ab4c9e33fa00f07c12e0abad528a18becbb7e073f0ffe1f603b9928314dc4639aa8c55c7ea9c48b6ab536c69e10962f7f0a3b62b1eefe1e168de6b1a38edbff4db163953e59dfa10fca222b6915011362ebafc251b271855e38faa09f0fd80a3d862ab51b4db2dcd6b21afe382b61d27ab233b07cb9abb4ae160b44f3ad5834daefdcf1baa673361fc99b2b49ca81548345befcf2e67c5b21ab3748e2ffffff9f864a4094baaf6f957e5c893ef7ef16f6c2c378d9aaa3be6240421df7305ef60707a7b402c7713a6a98c1edb7af1890d0b3075b4c31670727555f8cd0dc48ed055559dc90868739c5ffb353a37f0c76de7dc20f0ea51c1f8486e43494343b75fb75a4b0c387920c41aec0ee935e6bbb5d5b4c180c0683c16030180c0683c16030180c0683c16030180c0683c16030180c0683c16030180c0683c16030180c0683c16030184c6ca2ba11208aca067322b00bc1206420e7f6333ea2775a1741909100041c6016c3004342ae37052040906c001f7800240031fc00740000183f1c6c105b2dbd70010bccee73cee954565ef53eefb95ffdc7accf7b79572bbed5ab2bafaebcbaf2565eedbe53c1e713b4ee1cd8ddac3febc6eb729c17a994fb381ad62ee4fbb557af5ebd3a0b28e74ddb8d384eac4d29a59c08443da723cd9bbb873d3c540d8144e3a8034eb638faa03084b0fde38b84d702904c006f4f05c46273ac337aa4589fe2d887309ac9de7de6c4da396e72eea36b9c999a53cb483941a60a314bcc8942a28a29859b0d2c8922cb1818d030f58526458b162b599c6081146eca2499f26ee038efb282385840d56009284cb422497c21630507263929686327083b3a703506192a971c96dace13704b9725dc9b72296e19d53f6bbf8d018bdb8f4467ca46b959f2492fa2514a29a59482527eb2ca0aef475967c993b759e5c090a5809403120544ccc7d1c9791c9d94a3533669c7515a100f483727e4fb98d949d69b858a453d19b622995c27528a462925d1f4fc28ab78a4e4a5db9250ac9984bdac2f71acd6471c6dac471c632fb3e2289bb99e6f4677fcae89358ed96c36b1c66992c254804479e218bb4911f3b5cdc8683693c9fe08102bc21a52266dfd9e68f3da8932cca556aef7ad6f50fecc361be78085ecd32d23cd664e166157db070e104c2f68c2c97134e04f33c921f97c6197e9cc3c1cc1587e27e4382bd095f57dcec972a494f2fbe6a3c6b2642674a418153c26bf9d5c42f4578e2a0807294f328cb95d6902ab392d490d8103991b9a6a882dd854f121065156a4363045126dec5459630b62cd111d141d5022cc152470b45421e533c6f6044cd50f777e505373a5c0b2a154cc09c727193a9f38d38999328b1972b8e20311532c3db9b9c2063466aaea4ce93458e8b0c2a207206fba8573837471e5131c2117c4a285e663295f4ad95f249596df717ae6c3c6f2cba829665ee493722f6bb5b26f19528e245653ad95ee40d0766faa98f6c5fc6a2c77e5d39b3777943710bcbd61634119d0cb8231f00563aa05713ca6a3c5c704c8620847270b7eb6b17f71e5d39b374e527ccc2387e6b47248fe0b42d193b2bf314516e8b310c3df47ec7e72c89bbf596481be8f7a3d39e4f432093c5952b1ca217f168b93e78616a84bef0c7d8720593c8ecd8b0cf0f29bc98bac1c5b05573ea3e92200fcc855307e7ee43a1cc8e7303017cf5d9a28b6c1cbe72df288c7d08f4cc495cf3719c2ebe573942002c89e97cf4e9ac8e7e5330ef2888fc87e641d785ef2073ff211aee1ca57e21a09e4114bf1e047b9c595ff4386605fbe8e2e620100c9cf814204e41187e1182dcac72143f8fe47d925e402402557df0157d957510c7e8ff2e25df0e023ef02fb217174215b007164ddd1de3804907182649c237ce4476462470da0e98326297cd4551e48b140e26805208eb5c388e2d81d8aa37d918a8f5a4a00a8aaf8a88f708c0eb8ea3a5407f58b531c2d0cd98f8c03717c666666af72c7ad5cad8f055a9f1e9e8fbdbe6391c0dd0d621ea5cb0bd185e85160a277793994940ee553c6a7a7ddd1dc8ee3477858605455141855655dada61286d554402a61be8eeb26295256a147b9182f42c670342ee560e4501fb9cda243c92129364ccba23c4c07755d5882b71dca839a52fa4e7f8a3f36ee14a7a4c5116a189b4f027955bc2aac26aafce7a379f939e7ffd8f8973beed07cb2e98d5aab09712c44a0690111be857f7822c01620c0d5dd4f7ff6cb3bfb6df43bd7bafbceee66819bf3bbe7ec761974dcb1f472432a71dd47bd9db720065ca5196ce6d971c75e561ca5eecfce719cf8c274b13b17dc981dc7b1a48ce34c98dd94b3d50386a72a6a462e15e4fb4b29a59472f2e74d9de9e85d15bc025da3d1ef9e0b7fa638025391c9a8672e9b4fa3dfbdc7689463b22374d7c516fc42210165aa34fad3efdc6989d4b2650ca051f1959023c78b68d68bdca9b04cf3a1c2a6f079cf49e00412f0bc97b4ef579ff883c3f35872a85b853f27485afd42d683af0464f5dfb34011c84aac0d42f72700f289b5d5ea254dba0c5be01b1e5ad60992160b83d0567d65cbfaca5f85dfd7f7508a2d708f0e42932c087c5fe8a01cea44faeefdf88b016a625873c50826a2b0f02109ab09006a87424c89ea62875879a2420c5f1feef33d2e620ffbd7cf267af12f15be079ff55ee8e2ffa87072bf7f51c313154b505436789738f6f8db020797f5aee7582680ff7def85e35fcff33c2b3620c865b9fefb0dc2b1f5f21b107bfb85df4bd603f8c61ea93f90f5e07fe1a8e37ecfb11ce0bdabf5b5c49f0604b9ad77d9773d288220d78a2308c06d893aaeeb471d776c3df7c51e0c47f05962074f2c289a10fb4f5421f65654e1c57fae98285be6e2bd17df37cbc60b71b6cc8548ff1347d8ebe572f97c8fcff7f8f47c3e3d3d3de07fad1ed783fff9f4f4b81e6cf5b8787a441e9ef7421ef05d2e97cbe56abd1de27abe600b7c7e10743dc9697aa202cdf8f1d7a73856dcfadf7f137469615dcf7ad75771fcdef5491609cc6a4010974b1cf9babef56068df8a48ee0afb822ed68fef8372e1a8634e5d1ff305834a3e49e9d3d937286b09e9aa8c850a5da468d9a1872090788146432a8b95257ea001149b2b929e888282aa1da4183325ed2841840e5516496038628e171652a6071768f1030e34701285d66f99f0a28608d50d072b9e5c4d57a831820c0d455e40a3c236c7cb9ca62b394ca9c200509c249184056586f040eb2a2cce540155844a8a8896838028ee00516bd2c4852b25482383192754405449820a2256b029b366892465d64841a68a151f6a45a4e8385e90b011b3064c152b3c6489320415171b5240c41215f41426d894ec7066064d5cc921c89024e01c9165054bb22c6938cd51f8a9598badb19d2159a26c4ac09143c317196458d2c4126fa41c2f559070214e9336663c90428a11414071ba53a7aa9baf58e9b49b9be74cca3dac8f8a72656bd0dd2ebafbab897065b1ce4dee7d4ecbbd7f10cbfdd8f071ded1450dfce818bd1f573f7e3f823fb27e6cfde8eade47df1ad35a6b5d27b470b02400e6f82ab042c10b7f6cd8e00bf0ade1cfaa0b7fea77cf97863fd75a6b45b9f24aa8dc770f701bf2f66383933806ffbc7d2550b79a7b7ad1ae7a949d9dbbdb9f701cc7711c67917c5216759d73da5abba25abb2013083743e13347566746b1effeb3b3419187847277877223a6f777774f4ae77b0be156323387400e7114d49c5b95519ba6badd0d0239c46ad0343737373777e50d70b0fc54cbfce9ee002063a71d390ffdca395f2de76bbebabf4c7ed9e771d92546f2785d9e3336e7e4f1ba938ae724279d88adb37e7ffd6f1582b3ae7e9c2aac5ebee8ee73ce7a67b52e64569eee5212d559797a55ce39e774329f854ab208c62ef55857cd39e79cd683b05cff19be64e0d1dde0e521bb5c17eb0e9decc297cbef44fbb2fda2de6bac943d3737cfb1fbb1fe4867d775b25a2ba59439ce7a10f3e7eed583e6f47e7a220d40a217155f395e33d83106da1727bb2e36139d0dcef0a5c48ee09d53fa9877ce379f3bf5ae7a93723e67e7eeeeee93ba57b97081820b172e5ef52a17ea55e7d24dae07ee76ef9a3ef91268f4a9db52cadb4ccd1c6366e618895df00bdee0998367149861cf3a98d9e7f9f5fc8c833c5262ee79ae31b39830f33cdb98d9f56c9fb13083cf3766ee9eeb339361c9ecc4df334b79cf5c6480e7076508f35949ec5fa0c0476ec5c50f89b55a6d6a6a6a4a898fba4e9dbedd6ab71a133e6a29a9b6d96c8d050b96dbb5daad7623c347cd84094f4d711d77728a5918b19f58ec4a29a594bef266ed3eeb025b2c9e974fcf7f1cbc64d1d8e0391609dce5600357e25662e268c3b810dd0acc9d9c6a4e351f332f9fa93a626e4fd5e969b16e52ad1beb26c5635d6d6b2c2d1bcb8605ac5dd79a497733f9fce65d9aebf091c340c6e8773136ccd4105c678aee24871a4bcb6e2dc3c24e53acbffcd19db8a58d79a57c972ed42e8c4826d81096bbb1fbfa5f17d6c97ded7e6cf4f5db75d960819ad73073f70e2f6a0e70518b83fa2b1c7b45ab06addb920805778b07454648d4987def2b81c5c396cb3d972c5c586e497223a3d94c26fb8f9aef546e6975dc9c1534ea66c054082913db546224a16e61420cd0f91fc7b75519f90266dd90603a9995a884ad9924ad544335080000c3150000200c0c8603027140284f2461f31d14800b68904074523494c9634194c3208a81188a0100108200008618641042880c0df5ef3749509953e463d13e3bd4f5de13519aa4618845ae0ff4ab51dfebe01abe3d07bfdcb751881fd87282e81b3f18db24e23ee77249b3911a8bdf9d10471db42a521bd57b61fc063326bd5822163503b9aea499fd98636b2b198025ce1fc5f43997bbf9f8d3527bcf9a49c90f564efda96311e0745d275467e542962f956a3eb63a17fa0ff2483d9d4b92a7a63ad67a2d7672403a49427686df5ed657e36ebb218483082252bd007c1282fcc65a3b179d0b9a5f0698097cf06dc214407cbc19196aa93972e772eebd7c773906770dba6326127b9cc9eb3fbd72d1c6e9af7957115186f082e6241df0f69d72013197bced5e02d90832aec93bbedcb95cfc6440e597443bb1a445dccb1cba8c0efa27e842f7cecda3787675f5ff17b00f5bc7842e94aac8d14f4f6ae4e04a814e7e1cba90cfa53f2314d07f135d2e72c09ab20b0a17260926c697f972a8bbf5d150e1eb125d3ab514f638df5ac2579a73479371b5602b9c4caa4f447c38355f069aba990994677df3a01728b3efc5a6362ca7da26b356848a2017007cb0e6b0bfc968452b84643cb0bf2648060a5562f1ed5db5dbe2a90032992ca6377ec5cfcf110b78e349932224d37b65af71df9bb4d7f84f5f32685aa0fe90951c387ea9f1632219fdeddca225283c2b1bff379327540d249956dd446270ba28da913bd64719f198504f74cc07bab1e7ca7685ebf156325b8760d90f45cd26b52079f62fee36703e9931225974b47e11061b7b5f8e4cd123475020c642c9849a4d12ddaf733a873ed89b21e4ecc4c8be176bd57767944193fb50a43ecc3378f56b6bcbfbf24145c56f1638a7ef9559dab9b0c09f8f48ee3d67e6c2de6128e417f54032b0e3773b68c96be919019aed79ad140289cefb5ae4918d29c5bd101602489868948d122dd5ede5b1fbaba12184f4768dbfdc443ead104d4b47e4a3f1fc5a57d4647da8c2ef133cc6547c13071ac778a8fe4c05d66d9e49631e502fef8a7f50b3ff881d5db1e3087799b6202b9df78c553fbe8f43f2c30707aefdd715dce0b0fe5d9cca25f67208f8de2c125d6ac2df92728275fb556ecfbd89021384e21b85a80025b99f6652dbf518b0e01b3cd91ddb203a5816a9cc868582e0c8199f605ea3c5b9fd2ffcdfe6448f51494f54671d74c69c6597877118c61f959d1ac41e420b761d23749b25eab6e840ff7860fbd760875ca99e9098107db41d065858a30079365930eb7a25f900801ec076ec769f1b8fbb5cb75d567079207502c2a8a14c4e09aa1b44b4b1250e75a0441f27a1b97f26e2e82706887f1672efa26992ba6d0f22def11c9d81d83168b79623cd773c42cc018184502c14b6fed27a866186894256fc8da80153c911d135d2c092a2f5ef335c8c9b9df291d677504ac2b118fd6664ab8d6bdd837ef4430b87437d21eb54529a1c88d979158a0e00dd5691bf2ff5a14dbcf4e3254eec2a8b1af7f8fc9a43a933e78a6f5cf13106daae6b000a628a073b69870bfe40b0a964e94f83890881e4412edb7c3e37154a291860dc3c2bf40d8ffa9e593965c031abcc9875515af44a46cda562adb793f3e4670430c19b78d5c05a4a05160ed656aa0e7b8daee4b40ea1f04318e26e1a9ab6251b8d3e89903769c90d9f3a6d4f1ae19fae43e5281e6b1e6f1e5840080dc51ab4f46e1e8bbffed5c56ac73f5727194f3e0dd729d653784e8af6d4e961112b34a0423d25f4bf7673b99c137e43ca1ab63255263a7e160674e1b422bbc29021b53160fd4535397eac3f3556e6847c369595b88b211c499077f8532b0c8c62bcbefb79652539f00a33ee44592d70a55bb4e16dd36cea3ee0902bc2034985cfd4da4a8f8150467e382b474d0d499e2ec7c6bb28bf0f93d59443782022934e1c139c37c1a457098206a3ecdb93a195305373ee8b146a5391d054b9041b771c9798218c2ed489274f4b113cdb1166aa1565e7f4682ae1612eb9f36db33fed3ed967bad3f0a0b14b870cb6dbf3a2fbf8553eb568d4bb5966a6291689a56283ddb621acd19456288248697afca9711302c17b6bef34df7b3feaf53c250b1cfb01f4462d03359b68c556cc15761bc5b527c43a5263353a1db34385bac118e282a0b80af3b563ca039100d42ae4f6b8cd7ad51b1d29c2a1d1f48c8f5a2e9c85a2b377fcc67eb569f6458d02a3056098ad86969bef8f5fc3aae42927fb0b50a52114f3a9451393072c092f7b3917d2143ff24a28e06548a5002a2eb3741db1f42e87553f3b8f9ba90161316bb9ac1606cca885230b9e560343cd57d5e50271be5b23b167128eb6db4f71f9ee616cab9f295e2341dfc10cf4387c5cc8195c387c06721b29727acd195e4757559e10a0d22ded4e3f8b87aebc202345b280ceba84b4f86b8770fc18641e76a113f98804948d0ac53bdbf74bd9826483ebcbf0f4d0c6ed5672c96332821c4903b36c07c51f339d7f44138021ddf5e6143e1cd6962a0115bd0dab5331bacb34162999866462d84aa1c66f0c7428f5a5d1e2e04c8f2170a0b11f45e6f15429ef4189a1ac2bed8a065fd1c6c634565f50241b27cf6e788604a435d3e2269384029fc780c6a505886533af823bf1a861808e66589da5d7a8814c2e57440e43ea28db66738ff42fcae1eb6ed8f71eb34676fca4c37d57684f83300d1da5a6ec824a4cb5186b86896e52f3a6230a1ecc1d8990638fef630b64c66ce2e19cfe3d3659f623e1f4847824d81c1fa7aaf5a25434cc5face81c2ed865b77c01df12cac1b28aad39b6c7b94760c72ab98821230279fadef932fbf200dcdde1acb49abdd923ae84130a5ecb1ebf65334268d12bae4541f1c0c98c9b08b8b7c824f92a4b0d196de409f7b1c27474075acebb47e0393946bf59c8c96026ec5d6ab693ea80ec96bd3ec0a05d975e0bd298280277403de136905a33d04010419400e55a2e3faa30a6c414e17d936b762261830f36429b9b083f404a0ddb9f8d8d8c53198cfca2004f313e4bbad19178871330ee696d3e25653d4fec2b7a6d7a7082a5e06a34503ef819ae801b068349c9fe09696e4f114a318af4bb51ea4c2191c8a7b0d0541583727520228ae2267d9b5a3297adc5183501a0baa08cb27c61fe0c74aa4761f5a4b72150ba34c8567e706772102194a61c12910ae0f2a7de29c28a6d8b7d211f0f40d10225c051631ebcb48dfd0aa905c1fbc4ecace0a96142cb012f20c40c8ff922dcc8d41e8b13d18c77a0c29e887661e455e5c4bc1459d47b1df0ed05a341df9eac3a4d98f59d336d0ecbdfe19efa6c789b437861a5e7d1b696c6351661246ec57b83fb13f0ecd4a0f1db0e2f774ee4b1efc5219fae5b1e89aab639ed92a8c34794082421d99a14d8ed3cf5796c0420f23468ff47e6763d1d29be940e2253e698990128c8d8e6c6b2f7e6041b84661891a78673ee56fb7adffbe2c7e815e766bff3df9878903cd1184c700dd98973d56e1760d9c895782b31c7c4b9d558e0a8d4918e7956c4397e19a468a8388221a806f9c4391325bb1e76ac128e3539e0433b7715f23aee9b9df6c037762d12e73645b91051b9704dc4c13611f590f01d39d316350d43dc8e52e750b218639c9b0f2966608892da8e2c54f9a1034d4b3834eedcaa16661e564760e551304a68f242273fbb95ee73b439b0dd5969e6848981cef5f1192026a71c10e9db1bb0d173dead9ad293ca2e7cbd8878c113d61670f8e86d9d6d26d1b39740e79777e82e9a73ae9f1bc3dd17075932669cfa4931074e6e64f8b3353613b1b0858d38d48bec504c44dad69fa6cc032fa7122c54834ce5748f2969ecdc30ea32181ce8b646fd4ac4aca1d77b8dbaf8b97ba8ee2a4c82eecbc47ba9968eace9ac3fad974267daf698b5e94389420bed2ca837f66826ad4b6dac0d228c8792ecf1eeb5a5850c34ef363886035545667f47c58132066f5299a6b7d2d43c887a0b81fca90acd388993c26129427e37c3d6879acbbc5425aaa3075e5a04e216a337ae60443a65ff4a63abff842fea0ee9efaa71008bcaa539e3832261553f432f56fe0023fa4da83d9684a0bf123661bb7622ac08b845413611d49c49ca812a3a5e171528494ddbe63acefe6e9d0de9b4d90d7907daa705366ae8eb3e4fed6edc512c00ed478e2cf7c41dc5bd5fb0531836197fc0cf7886299d2c4b23efc614856062a97726a993f9cd0ef22480a9b13c22ab38e9aa394c61cbc5cbe5687da3bdeedaa89ba31dfebe738a269342b38ad34510a70899129c811db0e1a768298450c2d15a8fee7a718e63391c85e6ce3bbd52dcbb9ab9b91a63b97c2c5e1400d5915bb266015fe228cbab742c6e2059d46fe22e646b127aa147dc277ecf312cd90cc1b4c48ec3024e0b535f5b114d63c9d48d3f61a4baec9ef67fcc1c3d4b8169da2155e08f6ad9bbdf2a6e8a68c6542c86beb4c092116e8d8261dd96b30fad68d7c139ab822e4e5ed5da611d7a4d1eab7221cbb7436dfc749b40298b2fb46174a6763826855493333a0f430437177c9193905464da6220bc8bf5e2865a64ea4192d33fd04d962565922c76f7927a1f93337e4f5f0ed67289dabf8995dd12849a1dcf05f782ffae3670289a86d3f647b7273a941397b2c829119ae32305b6e9f4cbf20ed9325fa4b6258f02d3646e1b1134060640c5a01aa14b8bca9168ce1e2ad4fa4bd30fc59e83756da0402410cb490d5c941179a2537b21c85f313fcf6031194094973a228b064b233beb4fa004b22261b1f1c68a16c7ced9e9417104e51c0d6003805443287cd7d0dfbaecc99dc0041f906d47b2d104633790296b5dc2b6728c89ece37cdcb2749e2e10ceb898079cb4aa1c0228100ee47bb3a6ac121551d4aa871cf8bd7c29422838d92e4940374960191e1c947cd77c74a2b4a21c48929a77030341f422ef201cfef7641022f36183bb8df805f73b911c1ce762ab261be7c39bd7ac40ee1208fa1862dc40576f14d5e90c28f8da69022b0e8f8ec17a43f3843081d095011f047403a64c6ce743581522b09957dbc4bd012275fa59571e0ad68c65ca2362763300546d46877060aa35030f409073bc0aebd919c118939695cf47310d3c40ba3d535b4d2634063d996acc1e1badefb2358af6432182ce97180d12fb3cdbc43a19600d52336c4c6d68bb8da2e1641ba18cefb4244b86dc56e94b11141f7028a86529f7c6ebf409aa93f781e662466c9288c8973dd8396789e7daba45479db82c28d0b4e5f73210e72cd24e4898b85838cfe860a43cea0f509d9cc53cdb72759c6b8a00b85df7d8043e43568cafa0a5f008a9728cd1fb82f71e314b1c960633441c0a9b7ce6a17156acc8e6782055b9675e8c0b1318ef0a5350c09cf2174d8312040e4b2e64a7ae0cca744683efc54574304e93cb7c6e3a58e91b8c392a7622d9a8e845d4907f54bca3f00d9cfd2c2114f828f282e247c93e316937e82021864a56332132f7d9c35bd28be6543d9137ccc189bae79d403f536f93f33ad657900d15f5bb6586d872dc47db4772066a8bec573c60af9d44fd4e827ec1542cd1317ad66e709ea3bf0a39be5a41b05460d92ddad83c5e6c46f656376c5d9da46d81896d989db8fe999d882fccbf712ad35db60d27769af4740b84b617d8ae56c5afbcafe9186f5fa5a489f4540d85203e9946247488244439788504be81af5a943b23b2e36f8447efe3455fa859eabd13c58fe1ce50989f68da93f5e44bfc4fa5ee819f3ab392f1cbc1f19962ecdbb899c2419783f2425301c24662c60b6d2cd96f7a827023176ee5a00ecd334b251551ec42d7952c833b69a4719cfbcd1157c7d850516f54018fdc47f97cbb6187105cfde69415b07925a7d3fda26903b966f26762551e03596f269569f919ff2fc18b71468a0d0f89cd2537bd74018793db2d8cec9e22856a735f3131a10c5855665929f62b8192426f8b3986478ef20c8f880da3509a29ffd4b6d5318142870df78fbdd959f557b27190b8534833287427ac703863503111de158081cf096d23c43e38938c14bd4f4733fe34a7394ae6616bcaa8f5e2e24090de8c8a1fc42a9296ebaf0b283c3993382cfdc19d9f820c88f429cf3e3644966349e787c3a9910201718b7dd053f5a23906e3c6adbd65aa69885861dc1d256f79b94000bb243ee1ad219e228b397d47525ad4200a6d92c3e7cc20f1ad8e1c2c712d14245e5efb8a40b589918c1be3f92f80a70b2125e19f4afcbf6fb4b64959e59c48d491907a79ce0a1fdfe03a847d99d6b85d5ba95ddb34a7b7a05c03cd28422aefa7794c0d4c9945a1cb83ec79ecbf92abfcf0593de5411a2fa1402047a8cbdf1cdfc400ea12321e723473fcd98b8aa15d38718078b4d76f221bbcbb1eae47453870a4af2050811caa04646469a98c82fc289acc0ce3127b002d23bfc1e77edfd59a822a6fe48331beb7bcde01af4885b1d35736b5bb1531eb8197220fae902d0c289764950725d87faf9f35329174e735af8cc68a8e550ee57f22ea350d1b254ec42fc7628a715954005d280e4a69224fb3512988dbb66b5a0bdc9fb86c5adf8ff5368dbe34c2376f136a0d86f1265295d85ed193834998644904b9be23edf5deae6444dc6d1a1a8214d2857b719592cc3ca2587d54c1657802210876b5e64cd3a1bd2365c96446ca2cea29faa867d106a8d520e6c9fa42ce63ba704d15b07534291874bbfa9ced69490987cbc6503f447df7add8658ac860c038f0f9d480015a9255b0b3a687fa5cdb0a1422e678b0a8da161f1b2c5bc7113f342d4263ed91011815aba8d8ac7c5a50f545bfdf6011b0c5a0e70eff0cb0c97d20a9d66b033404623dc114ad7f2be92f2906db55c6c2607b0a1527e912c57025a6e2aec23b7fc14998d01373829bb2a7b7e0336193b9201f7482d3c411776b38af59b55ac8b55f901044c3061409391e6b45cc2138a6f2df1d24f1938ccc8f478b0bed1520b8894bddc801a25450050555122f70b2a0d33eb31a17e6545738d68ddd1decbd00b6409a5156044dd91a69c1a6514bfe587f634cd80ad714a1d1b6c342cfeb85e6675b8c28632caa49ca2e9d330b3474ab0e7dcdbad948bb711456bfcafa804cf3bd687407de94c997507745d4771824504329d348c490fabd602b0e60620944143447559d21630d4e4dd28d4f017a29cb8f368d0a0bb1780eed97ec81f4cf67f18b6e4b1cd403a8f3697f530587f3cc1a755f5ffbbcbb279fc539128bfcfc0be79c440aa9a5b15b28b283853fbb8b66b722aa8f135687c281344deed363230aba3129549a61ce006623b43cf0293772146b68c7ccdeeeaae796f5ba21cb37b6dbac7d1863261fb8df9dd3974ac4107e847a0eae935ccec68fe0a5b8004dca57a3de7be07b025a225eca3f32e1017295a29ee17220178fe033c140700db6aa47e30bab23ab0ad57bb4e9c418891dc33d2c21aaa9330057910c37ba7bda47f5eb97d8cfd31ef03eba159f4eafbe67678780b8345218bf8237dce1e20dd71be1a78cc6ee63c427fa714b514b90d1250ce0b9d52d625c01347b19df07df95d7c2384712cf220ff6b11a4659c767985c09d5d08b198f5c6156a1e205657bcbdcad0c0b5b888df51e6584b779d3ff87be2dae76ebe8008abcc48b7f1ccf599587043bf47676b0aaa55bccad8666e0ae2c543ab8b94aef55302ac911884fa947f7c3f5cb0a4995dc47fd23ed7b36aac4a079b0f12553605c06a157b54e2d0b6023e05cb11d55e27ac8b97fe7df8c5574290ea4b5cbfa189ad1e791784cd08f0849431ca1e6be655ec8b633cc4181deb6a02298c4decaa749024ea63ca1fbaf8f5489187a36f61b9cad528fb8d88fe1d5221c8a5f26f03b9f502e5d9612284859ae11a0ca4c42475e5964765569ef287f02ad2fab7b00babe6c8a413d5ed3eae31ad2c79f51defa8655f4a79220f0fa2705b9d444ef90dec6c6c2e6a8d72ef052c9f210f690713bb70c02dc78a181fa113887841980d164420f2f728487c917d002aaf5b8c14a949b4a5ff57a4ed686c238479b4c3c37a6389e0183d8b16a40a1f488c4ea57c39798f2a12b0b821597816a20192805d98823145c003d1ca050df521144af23c33c50fb7f5018c7e59fd037408cfb2f06ce74b8586561d0ef21cc0bbd8ef7043b7f049a86cea334c694cc7ce27adaf28d3294ac8710ac7c9caf83c8378fb4c4682c41a46dfe92b82f311852c45186ba56c1a00067c84ea80c78484718deeec548b48d81b1afe8c20650320833428f53e51590c8a9cf9e2533617eca15a187566208324b324f8369cf7fe8c2acaec0be90877bcac99a3fbe2e03395be71c2e021fe750f1687214bdd30fb2492d16d2539af204b889d52935668a78970a721c4be46b0c5d167d7145dc867d878d7752ecd4bc42be8f9d303f78766b8a3da00134103996bc58a36093a5833d5e36c22168b72cf2671b9162535fd829fdc10ebc27ede344aaca1e93cbb4e319fa5e2679e8eda35b49160a0905215b0dbde4a226d27d4a70a5929d00dde5eed82c40df2a563a174881487c45c5842cad2c34fd85dbd654f391caeb4f958bedc792861450941880507ac329a9d8d9b0ca0e171207999d810667e5e739cc4c08898e313d19615a931b0654c01f1fca88d1a90fd9b50d048215b51cb2fe7781fae99000ed2a93576a9259eca465f61340010681f8c90d063b62154e9f1f63aacdfc07544a82f294f1751cd058ab553b775bf53cc3f79457bb4d66fe722fab803ba8a79816f0b30374d0927c97900e008e37b99d6947f0336d265f1a7704f6ec755cbd99d40d907f92e254b63b9e392d112301ec769e6d0bc1d25ed992e6c7c406c5417a36316cc93a9312939f700687e79a3193b6562f24414e7d990d3888547b0d2d1044adc0de82539bc21cd46d7a9b6eeabdb397771e23abb71310738a7982a79fa4a47537863fcd857e2966113a5d6142b76181592731252c9c5e0305acfdb269618865ffb0846b591ebb79b687da1a8a672a111295a50957871d675e200cdac536c1179ddc4ddf3483e42aac881fd19c82e2018fc75b3c350c39a240e92c6dd5cc86980b3141dc139c7c07fba59cbd7ae33a1332cd03473371148abd90bc394cee8def9e7bce9e44a49004aad499328cb489e4b8797cbe6982e4755d215a113d301e474af00e4bd62deb52892f66e882843ce05961c97052ae09df3f01365d8c669678090213db740bc77372ee79b962aae5d4cc7cf6b04f4bd79db47b166becf02c0bb800063dde5a7ccc03a36d459b30f27366c9bfe013b8471a6a31c8c82a408288b468236afad88a17b4d02262e5ccdaa6c2928b235949d1b82da9be61bf6fa06ad37ff75adc5ce46e94da699c4d73267a0636ba1623256dbb9172d6133f9bf7a0e25a61dfb10d07f1b212e3d0e7ae191455ce8bf2e62d050203ce815a1f08dc741c7b94b5ea6224e0122a659f591d4104feb32a5774c00e5318dcd14a007c62242be4036959b2928849d4cab3aa374b142be4a564d91227ecb48747085b48ff2a75e7a99a0c1250ea07bdc0213574a73244487953bdd9e3572f6d25b7eea5708560d489e0682a1c6af605925381de0523fae2123c56fd5503c626e4ba726824acbb473ecb2a0aade012eb26dee2014b55e38f0326ba0c2fd1e007cb45ffc9862e071ac82c5cc0717d6d61516b2ae9b3bbbd6565b9e753a8a75a7cfac1f1ba1194650844acca39fc79513d1a906d96503f6a59e59f2f723ee070d1a766a81fbdb8accdf008723fe734b4b88df18758583e146bfec34d5a4d017ff7ea95b6f39c120f2c5226c1780231b93883c462a0ff7f05fe59017fc0c8153627f3509c1bb55e56417d4dadd3cc3a354f95e9ba285ac40a9cf7070fc9f93a8d9669af8d4709dbce18c49fd2260b725bf88094beea61da73d741f7e457ddce5be40885d261841234dce488102b47c17f5025f0ec763305f6b2a261cc80bba9d2a8e033e673e756d81f6893727349e235c1f847f962148eb8f73bfb5aecbd5bd879641e07984285513bc5e773cf1a9c3117e8f229c5fcb84e749e7b0856b32aa349c46fe995619f9b05d6aa74ee9c8e6c470a381c1f92afd9f4d6e333ab7e332ecd857afdf7f874fa769f199adb26ca590abc8f307e91675ac80e0f6c4890f5b28476ac875e4dcbbc3b58765f8cd0623a2250d3208a42a4745ce857672c970020c5e8eda6aabde2163231007910539efd72922eeb950c7e8d3ed10d228a6cc6e7f1585e7abe07a9099a355a433922a035030b17521b37a94f225891ac47660b2b538e856b0d0ccd8a02f2e32796aab61676e26db55d38d7d0ab6e9066022abbaa8e216337647616778ec8f18a1204b8aeab7841006542b3bffb4fe611bd27dd733a6601ae2f4e8b21598dd9dd6d822c928917e719f9a124c9cc9d65fe9fcb48f951809991549181779a6f6b614608ef1cdb00c842ea257bc0e1af3b266f8da38e7b76489ccb5c6dbb3de59432d31cf53ef48e929a7bf612cb5d7b6dda6e5fa2c04a04f11bc2dbc4d47175d6a5be56bcb5cc036d910bc8593c95665e286bc8d061a3a33bea5f7e996e91eca5fc42e85306448446f6a6913ed9279d456fac0034236feee68c3bd051a91cc527931450fff6bf8a8f9e0fdc290cf2c653214ebef56408908de8fe9590ff2bd83c4f9109709abd23f4be0c31a08c63bff9e59a420038ad1f3a45eb158e9b7c2c4509a60a50aa37527dfc69b1b7c11a6bffa4d19ab51df0c904137420c5c74a2c1a4d39f8802e7706549110afbf95520460bf736a6c0d8bd588f48d531ed0fa15acfb9a809ce45f6a648d275648fd6c94e78490d997a660e7c96fe1b23dcd907245ec3b2b551615c9983c279f558fb4a44ab7ff362770a4dff2916127d63d1162dc5e302647ff249943cd2f9fcd3276ee2f74831768a38f58532eece64b7b0618417d7ed25a2c0c16df27735a287ccdb5f020478c07405f0a3425fbcd0ab4f74c630111205834f462ab6be4b0d03c9883205165cb288bf579f79cc6265c3cc567b32fb06bd03a493b0e4710e4060a0fd13298fdaf1a248af704784017872d6bb7734208123b5aaf928b60a7f4fc5f490d9e167022d006ef42f240642da0b2fa4dd77f9d93151ff89a743b104d53d5788302810885747790f6c4a65b8767e24d58e8df1cfac8ea2c14547bfd03d88fdc12e307717d7866b45e1254b92706f03bf190eca92623a97e7ca5d22faefc74db1dd34529e636e48faecb0d2063202408e310479636ac246665cd678ba69d82c1284eb68671a14c80824a8c22b086174d36293b8592e3c8b1d881aa914c5b645269cb5a3786599b92a0c44f2f8e0fdbaf345488d204eae4c11188dd478c9a8c74e4db6a3a4fb6908830e1cd4e92d06f3e5eb8c43c9b726dce8e05091c6a078389941c1502a4cc2c0d5198792a67874c5104afcdb0c35aab6e4a38dcbde4121af9daa682a110c2a0c4ff79c7c8be036a67ad46e6bdf7c815dddedcb837103614e771fd02c76e6f023c0231ac40748b33ac12b0599d6d3e0220d69d12f66c883188872c97835502ef1b3a5304b2c11ec39a3730199bb347cab273e5333c942b39071d077c4b5ed2ca0ad80dd3f4c4bc696f30a4b3a878cc9d28806fab876c1f9c4a09931222b141f29889a48a5668a09338072e648fd94d89b9fd64f14c749d4203831f1acaf36081a4685dca0a9f724139818648dd8b0047b6518010610718b9e02f4ba245f6c27c1495608e122d62a4028daeaa6b61a152cdf385d9fcabcd942eaa1a2e65c005196ccaec1bc5de11d02012fac3489397e5ccfa0130366cc8e3ceb14e16b431ad5f09a1e03b3d4609116b1f2bd805fe150b92eb520b7c61c42eb42231a5b0eca1e63f3de3ce9f5d90ed19b1cbe3d79b7e2619458246f05224f90d5e55ec834a29ad559eefa90c4df9f2ee5652ec3a2ef9e5ee6689ecf417e0d8b90bff798eacfbce838d6821192675e982f37509437bd47644e3d0356e90949d65eff1dbea872bde1feeb95eed84a99f2b534b42e7073ac19f53a43fd18f2e1e1495856de6d8cd816c771c3772477f768710d55817405a015bd0b20b48238a4167e2072a31624f8c2d5dbc2c742b1a84136b70a600f77c8635c2f7b3594bd5ea82ce12fa1dc4d51a4fcf2d57a4dda06f46554a07d43cc302752e21f708812b8d64fbaa732915b2cee58531c45882d8850c83fe3d6454a6f43051b9914c65427ab843396051fabbb8e5fac9806840565190108b70d616d2b34052ef8a6a08738c389d27a041d9e2fb8ae9d049903c8fdd79788749988e606b145369b4381155b3629a27805d0cb5d6e88c92051425778162bd8990c2760b2d43ff6edf68f150c24b7bfd8bfb8a081a8a4c86539941d3dfc9d0d686fb6340a1e0bf4e91f250abc6f10d6c8e96e2db0bf42198778216965f1714da753299e3c805856866a3dd4d5c3c78a06c25006fb5aed0c68e6eab4d5f8b34c4844e7c05791a7e9b48d2f5d7592c253d07c1b71d54738c8bf3b9dc14e9c4d1b4e2781404a23989bfeeb8f86b24e3af456369b355bbb4d1711162e0de4588b085679c8811c1520607070487fe7015a03f41fb9b1a9cdf1204ce0291cbc590fbe3b253b46e80091a41a7396dd72c3b2b90df029247d004590610f69d504184c387a35127ecbfb62cb619d103a831dbfb29d8a1f05a564df15c67e2c1800619d5b9b0e83e5e94f54139e0b09d041e9d051d5b471f286adc43e9c519b0d8a560472e6ae0f1fa4739db593bfeda436616a4d7837a2e3e4503ea7737cc1b8fc2272e7cc01bc0082b8bdefe370b2d8936f1f2219661c6bd1e3cb9eded69a91955025fac90a044193e2236aeb9f57e1ea5b9496e410f1112de890a990c2a369c7a994e02f364bd7b9b822b249c1b4ba70aa118b3b29fbc6fc13580b332fa7d5028eb12bbd9b399881ac64f3aa40fa43114dc85ddec807268978fcabd16f47220bdd23c05781e9a9678867e89adc565931431fa1b8c9e4970f44e06c65cd9b655731bbae9c51487ea93de40dc90b0affc89cb4474274984fdadb2b5132cdd54355b0338843f9dddb43228a64999074d799e12a49ce56b120930f059f24a97e84ba82ee018754c2212bacabdb24af19ae34ac4180a202b38b69cbd7b4d5b1594c32090c54a5691427b880b691139f4c728d0736073defe0c6fbbe33523499f1077803184611b02ea8cf84521bb48a1e0185544139163f059536001476716c4bebc008a81135b5da3dadd39ee40e8e447b1802b11fa87dbb2d6565d507c5341bc4287d748b2fec15af76c8903eaf688a2dfb718277d343bffff6a46741ed0a6078a1393ed9ddc9af33d77d92ea7143b492c7ec320cd390b65a2c139be57851666bb0ec9d511135d47161cbc6a24473f659a7d5b40a455ddf98edf04c6c021b8c25128121861b4c7327f395af80db0d2818cd8c8000ab946060657dbd45f741286658d2be160fe7a21b831db389f7242ed955bd38e4e57aa646d2f18d0cfb16873a212912c940a77b2d9ce6aec460d26c4ef3939a4b4da4e2e420ec553c93b11ebf8f1623af25ca26b6aeeaf789191c5d8b5ef3fbaef3b7f7399e09fc0e1b8dfb7846d313142199e95109b4979ac1f6e909f79e721504f11e4c05f27b7c7b6abd68eecaeb39cdb4fc4003351cbea3604c608792bdebe55f5a19404cd93837228524d04c4dd3afae7e1956b9421eba8ec85e1854a7069f8de92c9fc67586cf01d2b864dc4eda66a334537a19845282e2510158af8e4fc5e327c73a65a721adce365fdea1e2e85c19bd9256c30a07f15fa887bf49524083c28d43d109de175350285e3435c3a3474991104b5074466582771f57e428c24fb054cc8d50b3eec108ef0efd0e78691b2e3fbf99e7de5f2303dd19c1dcd81853fcfc51aa53396a48d7a2646333345fba3a1b11f60ce94cffbe3dc9887c20701f9bba309cbc9a1631b915a99eb7168eaeffa96e6a901ff7236c2914a16a4974768eac2492535c58d9edd0250a657d5de4afe3d9dcdbc95b9b1c897b60a73274ea8bbe4998739daea9a67d7a55e2eb21b904f352c6978a89d574724c4976fcdb3c13ae6b1a7f9e4338f466d09c27f39f1779bb9141c4c9d58eb21535be99ac10965a17405ad9f2c8f4c98c9890ab1750e86637abf293dcd732faca105adb0c1218712c7846e2ca19bf103b61a339493b81c1313d645f232fc41fd5b1e74afe82cacf9326191c4c8e45c7e5263cc77081ccc4f1ffbc54022eb799b8f940375f572963dcc6c33495587a5221c334915836dbe14aadcb446457014bcf2c21ae6f51a0a6b48685532bf4e23b9ce67c635b8f9aa0b3424362947f871af1166006d03450ac2bdd9f5d5f651237e73359909ef9154b72c22e6ebcf1cf8be8a9acd8a85f28ddd8ed877836f8bc403a04bb01fc6b684516ff96c034657cab64ebc1f356524439a24270a0931237331ae3787994bc5788f33438cc5d2cd7c2f74df911aa4bdcb66f594f8295e994d7afc8a265eef36fd86158cca1102028121454dd3343f6ca79a26e1e2f1a284a9093dc810d28592ae24487876a31d86f7719e1c764da8276d0462e6a501f0d7a97ba73f5e843620af0708db8cfa946ccadf3a75bb27fed7f079e978163cea191a6d7c2b43470454d77d72fb6ca2b95786441a0218e19ff9950f04989700328ad064d6d87123ea27104cba9010a5aece7ea260efdf08b81922227bdd4ec4aaaba79390048c0936c4555fbf88d8e9ae720a9562225d43e4f5f51671f0af2410ff00a170fc5aa192ce55ec56625b6970f6d036ca61e0e05a992efe627536f1d5b0f88b8a2cdc8125244eeef3130757bce2d243222f22f812dd4f3c8cb274a9507f0f91fc92c95496e22f956a5459f84a29b43a5a42a9c5e85a1d47f3a368fde2b4c54337d1d456ff29f305afbe5fcd0f07794b3b4b1da4b5dd83b237c058d40806cb3e7be74e7255aafce2d3c2e8dbda6667557f54520a437d53b57bcf43a3be9d3aa6f3e77984a002cea5d08319f67c21a957ad19b362239457934012566224be8a1861e244ba0d85598d80930713669b2724b6bc75806f60d1954b33de1443932dea0cbb68905d72cd12a2258ce629679970cb8a45ad8cc880679ad89a524afd4dd4d76c6ac7911c9eae84a7897e220e278faf1d59c5360cfc769a3b2d4b81446356d53fc0fc7fa740218a158dd6e3c6f0e52617fd114fad609708d9f55d1a4cc1f23eda8e4e7618fa0186bbd2339c32c05c9fb267183aa6d666d60b5bf3140cc5df84a4aae9850eac6f76164b253374ceb50f96f5b13a965b9314435bb16330c403b4a550b38f5512b3cb8b8da868ab13c20af244a213a2c66ed7b68ec8d394b17edbf048c0306724a06482be52bf58002b8405881a164020063b273b48cb62d0903c29991710ec99306c86446b72d480f7a8db418ce79b5fc8dc51c06ebb54d032aabf2fbb41c4143d294cb87165fac11153f4a234e1f2cad407a326d1416582db6bd31f8c9a420fb52997ae4c3f316a820e14a65cbe36fda4a8097aa94d717b6df2936813e8a598e6eab5a94fa24cd189d2b632d30ccb785f4e3005da1b8a98a097d214975741fb9942e489b595681f7483c8a497f873fde3c5bee3d07a1a9df318ff3b7fcd5d5bdd5ac88b8d6ad4aa5cb4974ece4b618e3aab22ea659a6e2d6d2ba7f5e50c860dc0285bd872e56a632c5b08fab717af042c19888c50fa8f9078e017461013bf098d13888450f21f43f608228c40ac7ca4ab465c11af09e4f04086a0f4af214d16328c480c7e104608031242693f80cc48e2308298f84d60c045248492ff18b26b0f610462e53501671bc91095fa07a4a601842288890702bb094c4228ed371a2b082bf23461fd792404a5fd02c2a800420862c403010c7fc8104bff17122c3f0ef1fe7ca8b13f0ca1c11e878c61af78227824243d3f19a1e4ff42041a7043f679c8364902b24dccbc5a0577ed0ecfa049aed93a34ac7ba61d93ea4e066e69cc9a49b9f2bd2bf4ea3c3aa9fc3c1099ce7370ad02576d9b51ebde4ff31cc6b0f340a079ccdf98ddd51a573f399b96bc5370eb7effe9ce3d1091b597e437290fb1c67f81c05d0dde893f65ee2ac1f1b081b71c493665565bfce1f3839d86a64091d72dd1e6577022651de0dc00aacba2deb77fd8e872596431c6df254bf8135b45a3b1824fdf0aa9bd6bb35188e2ee66760e168523682450ff6cd5631f76c6cf9fb7a5f550b95040154aed94ac4e4a1c92ca8479b00b568a843df41a2cf7e820a3313b9a88e11032ad8f5e9c2d4d72a76b877865ca058fe88650a78790c9fe7422e63a5957d20baf863d7ad3d8c8d98ecdd218874fc62f65168d801d419174e42c196eaa881f982ccf02ed2bdc1e88e9ad10b5b3e9567e88f5188def37b7e6b7370ff9fd1cd1d959eeadf92b8ed4168774dadb6be25c5d1a8309cbc6d517d3b61bafd3f2d1cc5df53319d8da5fe8c5535e1df0fbc5d44c6408b3cf0c21b5db3e06089ab1db365b1034cb48e8d7f1f45835e056a7cdf189364c8082a023cc57c94ddb1fff5503bcf5896a930978a529501eaad784330a906554a42767a1947e28536bbbf6175db060d315ea87487f41587bfa0a3977a996fe89becd8e3249b3d12d8eb572f2b6933b984307398ae84debb4179187574a2ff6b0eae61395fcd2227acdcb44b08a541d5f094093f8aa989ad187a10160b3f98f3a072635a9ca97de8cb553669958c861f127255af6233c887e8687061a1dfe9de0d66fdc5cbf8ad5fcc2235adb0d81b4852e58063523637040926e46ba98fae5e6ff4faac6b76968bdd5d83c133221a076235aa82ae0f882f8ebc6441c778a4120fab6ec7262c1a09b537238b7edf17b6f4654b2541423acfa90e82a1328082514cdb1c98ed130fcd48a320d61ee4ae7371cf8453f0df83c0970e44b5a1e499a9e37fa625701cb8c70235ec98ed68bdb9149ba0fc4a647f019eb88e34226a2cd2cad279499d626ca2a6f2b035f7c391281fe67a8b933a19ea1b65af6a180d96e808359098349c1e4c327c96b3a5453f6c3120b45820c480f48c31fa61caa2a324d53cc54b295c373d596932f987c2aec77ae20ed349732fe7c44305acf1de18f83dc7614bbbb773cb7a1c8fc03a26847a77d1af1288ce5e40c67aa30f46029d12ad467b4243837373b5d3773d0d61ffcea4d36f3d8a8b5b121630abd2902ee9f8d547fbe3dee7e9490b9cb674c2d58bbc05f18e1d2d95ec3430ebce3250d5f29fdff2caad786b5f9630cd42a8cb86479784fb444972d21fb8406e3e9efc71f239658a3e984d8536da6084ce1f9166b396a9023ad73cdd74b35f735c97dc8ca1422d22a02d02328647fc888af30902cc314ff726fbefe56c41904b8df55d62cc9ec0386b7832704dc43c5065546940aa625fbcbc74c262ddf426d2cd290e408e081c92bce0b21814e3ee9e0272bb63c561bcf285e6d5ad115ea0f6c792791f028f742870beef24a016df4c7dd2329d311c9fd2518d257d1d19a65f2277a4109c4732dbccf7a2937d4e59266a4901e4cc18b2b41ab5d543e4e3d4fb04f0b1eb2b463af887badb13f9362aa5e8242633e22e613a2e58550edcef0c564fcc5b129603549d5f2c7795104aacf47467f2feaa9b95c6b74b1d9a23abd47a233e47fda0308fa97aa9ec7cd6017de39841c393fa5a5d638d15263495de4dc5f4c1d3f21757af8d74e7e38e0dc1f8afcc563151a213da8006a422ca98104bd12f84797bc24d27e8cafc5aebc7c41e30173a2b8790a27612fb346c1612b91348fc104830ad31fa9c2352538e54a24ca4547725d595e19f45f57351089b4a55799b58a22d30f2565fe6290438d2cc3dbada54d192f4e3878308bf42778e0dd7ef8e6fee87a92dcce532e3ebcb5819c03adb8d5cbad7797638b7f180ea3896e61b57831aa748b99dfec9e5bcece32aa3b4a1e5389807ef78fcde305fcf9293370b8fb5bf9ea56442ac0e4ac5ae4dd810081f42b93df84181d008fbb626fb18132ee2df0d2095776dfeae844220ca5dd9d31e198de137dab97c0ea9483661345612561f0d2785fd24c7a15412fb2aad63f2e86a92f908858ed608f683009e0f2a1738b654eebcc9c21ed4acbc3360cad320e4f31d1f79ef9a6f8d7405702ab16bef6fd7a5447a40872f8855a7fd98e2cbeb11d2b7fd2e65690519acd116b9badf19dcc0b985529054e357c12baa598141eaf48ba6dd36209b92a095bb99a0fdb004ba71a0b338223d4f8659b3315aae11f222f9ae06a0bb98495a6793c8f4d2d7a1b9ae1fccb7b98d2e00bd7046597d349f97ea646968432799ad8404d439096f53aa013d5c5113190301a827a8fb7e42263fcc4a1e2ba22266f7054d33601296114135c6638d24a3c73aaa10712c87ac1997859ef9ab4a2269676f1895cd68a6e41a1c47e37f6b0f09820eb0a4bfb918504af337a9083fe5dee52ddcbeadfcb192d906e5a8b90ee06f6129f7d41bcae33742ac241109b19a142707ef4a97f276c9b76377c7025389d3aa81e3f35b1545228a41b8295cc6ae474e327fc19113d79b2655dd06926411f222c619642ad351fcb467b4c12946cae1947dc8ff0072ebf7169cbeb259ddb00408d87efcd62cf6912217fd7e7dff1aa67627416ed5378d05ca8453ea2500c3666b69b84dcbe80ff29c0d361fc363b4c44f08c00ed7a0b68aefb7a98ce1b1a54c01024a6018e2e6d6fc64335e0b1062d364793f18d7b540405786705047cd652a53a067210b74f5f57b4f69b0a7051ae667b7666c2c0decd2249dbf377e91d92deae87881dfc625ac096f0dc1133eb09911c420e30d034bdb558abdaf04f04aca0b1baa6b2efb569aefcadcfb794a098d6470d82cfddfdcd8a41ced4a8d0b46b0ea1da5d18b7398765e6789630969aa6f2202c1058ccd9cbb100a02bf07c7e5e13b6ce7de8290994cd17d6aa1e5dee3cab48e054317545f3afc853887e7dd3fba01537543ee635b514da4ed51165c14eec6989d22b13c7dcb8b0f7b21d53b7a9d0096ff3810670222085d047ad868450c5d6ca72e25a4ba6e241f08a9bb8ad45381e346e870cee7ac46765d81ac8bb17e4eab044328055bae0c73c7e2f042d9858d5f6ac8f720e424e53d1c7e90a28c9755054551168804dedd34f3d1ca498649d1c850741cfd899e5ca44f8c6cc1395f8e20be7be20d9ca2f178a07a5c701bc964737220967f7cf515ba6d9926953fdc6e9888dff2a3e0f836351926619e73c90875a7b20cfd17145b6d6a8e4febeab53c3945e0828f2677343f9d0365b607b7939acb5f195879f4d423df22aadf0f92223c3d52d8cc7c67dc24812049ed70f8d3609e4e3091760d0388c685ef6eb55e3cc36dc5683ef2982d7ab718031d380528ba0b1e44158630ea60b1f435640daa9d851dbf4fe725ec774e5fe617b0b50be8c65e9dcad61d30a6cd6fa18408c3d91c278004c6d760031f616c5e25f46c763c09b08bb90d94268ce7918d5f80349bdf413289460a448707b7d612e12b3e6602f33e835d3cade16f6fbd5952c1229d4d6cf3b16e39b56c5971e30eaacca65a500b22e0d21b6e1c2ff81d30ad9d28dfb84f063fcd333d33367c25855f97cc942d76de0fa1d2c0ad6b79146f4c0da723aba0f4d40438254156f2cc2bc2871a088995e20acada784f07fb273b0d9036a8d3cfaaecb52570b232b11e3906514a825efefc6a0252475cc29b20146d6fcc80045f2001373a9ebca8e08d3431a60a8aa9997ef75300dbb612cb28e9b00163168a0fc61f14e1e013ba2e2b48b3a2d1d6241ba42e74e1d39be268cc00897e452c6c0ba2dced96fed80c816fcf7cd4e21744104063b262ec586d272381cab1d2d74d8b25845307997da81da0df760f896b5b931188ad3423185c912922e8160a58abcd2ff141faa8f94717fdc8e672228cef1ebbff40c76bbbc22107d59068cedea40b49d7a584f1b05bd5ef9b9e5b869f3ece375043b846df736cd67a9b0eae179a70eb20c523874a25d85875d8b9290ff9204d34c70b56ee4c7304207d1b792a0748188b2e52e0293636e88cdf1c24566f592036a0c677bd559022c24cdf344326e367e74c87fb7a840e568accf22dafcddf358c3c5301e1dfbd8769bcf6bbb30dda69a559826a06f0977d0ae8006caccd5ba16d29989e0b6047edb922f598f59b73d180f5a2b6bb7158b9d7f338b2eaa5a9ffa890d27fd8b22cca5a1053ead8ecef333ecc6b165da3921f4641bbbc5ba3fc705f5134b264471d643ac6413b2bfa9e965170e6392bb039928344478f9bdec14a5ccd9c44938f1c48ee6483a10e07b6bbb3e75201f1b189450445a9d72e38667b679fea4b264cf84c95f29602f51c43c78382764835cfad5a109aca3fe971eacd7cb279b3f28656c5bf41812e4e612726aa32c710dff5fc28bf29c10e61934915e7ebafa42bb6702f6de8daca2b86caebf8480c4846892c067b26e821aca4d14e712222ed1ef894672edd86831a8f9bc9426b333dfb747b955556bea70e8b94e29e3e33c7d0251094558a1143a419df040cde0789704a1a8bae296f1552a7481ca364687e1b3b8edc7625e3fd18b58a26091647a6d5a2cb0a0b0c058a65712f071d236f04619f731a644a8c14c73a102d210cc1c5ce9287b9d42eaf99a4f50fb1ce57a49d963730cf03d4a86a8eb96b2cba68255c4ee37941dfbb03722057795a864f8af70f385ede3eb2513b237fd32cc0ad0304baf82596186d96a61d0a19f63772b44d90cb6e67efbe8f24e6867c942572d4b18aaa1361407b15ed08f6b0e95c30c6d79c4a4a27623715fb183c8621e75c40c037454d8b1ae62468dbdf5a6022d5a872cfbf20961d914f8490f1fa3cca8115c0302ac5633dad4561e34e5f82fa3ccf06ac04ed0216ae08cea7c8a2422639e3d2350b0990545618cee51f7f8ab05c3323bfec5f2035099f1371271c46d43c883d0bba3ec2edcfa379a15048ef3ce71dacd1de776ea69e8d3cf4bc609710b3da6f66f45e77a66170faea5ebb195a0392600cc01730856a61d15aa5f1f374ed00c886a91494071b10b149db0f4bfaacc9695cb4d917344645de20bb8ebc3346ac0a416beaeebae532516467577db430a8dda078cdee3a360a289d98de5ee4261f2b8d7f7d20b4e343a97b14dcfe79d7452aaf87fe9b8a0d23eb87393af336598ddfed2653b3ad83b5d4e9e0d87b1edb2b2757b6b5b07aa0c726d574be22e024f0f402bf5f95d7e6bc9d32c25c842d41130e6590e8899bc282eeb0470438209415f7ae5c45db8ca3ec3813e5b506930efba78031cfdb8e0adc2e36abbda80f9a31cfe5e177b04801d9117d62d03090b4422d7e51a60a04b32a706f91689d7fb207cf33a4708c8cad3117936caa295ff3334683085c2dd8dfbc1b0546dc9418eb8f5f655b63339f8c80f948c1fdb3d25e8f42da796a4adcfc86fc9d5435a2c2025c127fff0990062c4fd4cfd1acda5c01e43c4d1585d204e7d0ca918e052d0a6f6d5317efe194ce5fd342fc75d36c7c88f7ae553f4ea7819b7946f527b93a66472288889f23979338352a803c7f5b9ba9f6c23093879ce2f011ea8712d6b3f2b5f645184df36817e8f633324b01a81535344cd183bc35d93e914044080ed3ddcd047bc8a5c47274a52051e6379153841d729620fe5041fec5a59823882ee14bedac42a896885ba5c9159f1b6034b50a2f8ed10deb8b9040ef0040022bb2c4c3c0f9d8106a5691b59d7b29011fc8645a0479ade02e6f6cdac2ad44ec37ef0b6a364a84b1d73947fee2300e393fc0b9d72ec80cac20a4f9b1f10f92c3a33ce3d09a45a5f1c823cd22967b6c3e38c28894db7affa5b80d6b804abe2ae0d71ac0083ffcc2d5798983b38c151489407d28ece43862c696cd3f677b3f6061459296d3254985395540727d386b66ffa2a971f1defdeefb148c838b0e3d0046456d80e0b8730ef30f6164f214acba364e7b0f6fdb225a77f52cd4159df2a0ee82c7fe0aa8082811f44bc3faf3af7c9352568020210bb20461572f065c5dc037cfbf81a34eadec2d4c74628e578ce074bcc80665e6bce73d7234f7f31e99d9c9f31e33fc489f3e69938592d4517b2a0dd977af3d76df4d04e77ede41f42ba5d4f61701eb879c4167495baa47ba98d1d81c56994cbeed70f27eed3a2ebcf4bf531b06c46d5947db932ba700d202c6b278cb6f98ac051875c668a0f4746b6f3fc0b8605d771b98b181b2954bdb6e4627f2dd3dd5060ea41cb3769e9f3a1476a3006b263fcf9f73dcc23dcda03731f5ab1837ad8994b1fb14b8794f67d2d0d055cd103faf25a9054201adaa40d9a04e04104e9d747840891ef84fba5ad1f792026d526d401b2fc0814180b2709d35f5e117c8b45a78eea02ad929b8111bfaaa7080c5189b3c7cefd6e0533ac7fdaecb7df4d768bdc448456f64e2905d6081609c308cf9cf5d44f2c5a956459adb5d69c6b8eb5f07b14f5a8d71863cc6cd90b53d898b2861a9359fe20a4f4bdc52cf9ccf082d2beafd87b90e3713752548adbb24f2efcd7deb98714e3f1eb891371190aec8642948ac9bc2567e85b9156d1836ae86776da75a2c37a2a7ada4ca28f0ffa196bfc987acde717fd8d474a1f44eb9b4a40d12d21a0dc693dc0e3461b7aebad9fd1aa97f522cbf2f88dd1e6ccbce5d7a296c74133d64c0e2965474a5a553e48be057a91168d3224ddaa322018b2e8d328158882be1f244155a88a2ee784027a0a9a2fe3b497dff9a407d50b5e445c1ad32ee845227bf1f8bd8460f347fff2a0a72f927434fac9e377649df40dfd25435555e704551103bdc8de30fad4fc50f5cb20dba6cd89dfcfe337da8a297cc2d3a59e5ad4f72c4a75418a88db96bc634fb503b487f58a7b9e4b782ef5ecd5ce32fbb88060d78b7028ce3b0c463018d27cf9293ff451d6d1872aadaa7f9114f4f4df5c52bd941f921f1bfd50fc51bd4452e641b20a8dbe7af96f2a0999405fd9cbb444f4b17a6a2f13c82211d18f96d9c7f5e456cf97884b5ffe0d93f5125dd58f2acbc36e94f96873641e64735ebee261b77a2a13aa5e48d59c31cf5349e963be14132959d5981015233f14f3eea918196360622c8cc37c5561424f29a594caa746846c4e7c197aebc69f39f1214ce22fbff110d0cb67b709bda83669afd0836a631fa19fefd46505d50b880bfa50c85ef2b28f91bdda1dc9c8d80bde16fdcb933ef4cc4364bec47e1ad98b883b2ad9abdd908d7999caec23c65e4feec85ea0e70b53775e1e5479d885fff2a21c277de95f3c2c3e49e9df3884f68a2051bde09291e847224a299b48441fb2a2bad371dc10f50e7a8a647ec83212116d5c1e074df97f661f6ef517bd96357b329931552853b2ac5149a69a3833c68eec0561ec456f55bad54c0e28e442787a81d0074847f39f88961e731fa2669e3133f8200b998d16fe4ce5d924c7f3ccdf384d35d513ebc1defa8bbb5420ac07fb1c0e2405fa83cd80bb71372cc6a3163dd15f609e54fad2cccb7c4c8e8f11fdaca67fcbfa1c55a0b052a5892a5058a9d2c448f244627a6a2f1e379a4b443ffb867ebeacd75f29a50c85e6d3977f4354078fd0c409e9601010214042a1190a85422f274e88521aad37d52bf4fc3bccfc68566be66f5c64c9d154627ad187ea682a91a19035592fb2970ff712fd7c6a73a6dd8980693efdd0ac0c79441d3c2c1dd557ea07b0a60e6b64593baa58f62afd5b55b8077bebe1c4b168e668eab057e9ce399fc65ef05af341f6a2d79a96b54222eb45332f32cdbc6573667e647372849ece58f653e9650eeb7d22c9619b9f4af66562626094c03ce961e44709635592244918d2bb7fa410e985645ffae5adfa329f524a290e0d3deda1df77da1cf9216b42d2133469c5970cd1077d652ff934d4b349df1cf161d2640ba5f6ea59451fdbf481f5985de608082246b69b987ea7d31901d31333fcf36472c40cb57b6c6d293db14aadfdb5a940416d3701624e0716dcc7afabf8a907d5ab880b7aee1b406f49f88cf42fd6347a26f2f2375e995461554d9c187a58e94b2d89ec056fa431c608dfdffe01025527ed05e552f16119b47aab0c1abfa703660f246b6da1d5bf586b0b8d96fb87457deb1f90b2fefc84a79f30ea8f06213858f56b54b9f365f532bed25b339f43c7ebe0f1346fdaf1a6f9a39f2ffa38ebbfa85abf230929ddd33746f24402f396bd62e692d14f215a542fbfa298177d8ca9a618f9476efce42361644c65d264cbcb68e2c4c0983a9ff660ade9851453ada7b5af0f3f748901c98468e8633e34716248150822588d18904ccccf89131392f461ea259f7f071e1f9a95f2f81ba7f3453153c9ffe863ea55c48df998a944f4d6c77c94a926fa237b1571afd1cfb76c8edd89802964df08dff996adb3b29fa6044d9c494b5446981f5598e7d900fbf5659ea704acfd6a4d2fcf44eadb7a7a59bdd42a84f56094642f0829fde71be6d31eeec19e3e3571284e08f6f40f187b15714732372ca65ef21f7d9879a42f8f7fbbc3093a2d8fa73687c7876cce0e5979fad2b77858f6938e17edd8a16386c664caf13c95cc7c8e9fc9112d69d51c73f4568eb7e64c8e776fe5786b8e72585629872db9d25bb56449cb7af7a28f95a7aff56ce288ac9f1f82839a8ac8af5e247f3ee8db5ce2e4ca9f55caaf441512f9d5fcd1080ab5178fe823cc8c7919197b794ce5fe11b2174fdf4b088af42fcf7d43e8e9d39f1faadc3fe6df305a413faa7c67f5ef61ac93be22be2f3567a7882b123de8b967928944f495f52901e71be71b1755bf970c89ecd557f4a37af91dfda4f3ebacdc3f467e47f59a4f855e54fd46367bb0caa0f4ad32a8e8793ac07eedc15a6b0ba55fadb5858a2cf70fd0d3eafd0314b239f2fbaf6979fa4a5b3dd36b55be54bd5a11971d1c3b5c47972eb786cb5ad6c07223e95d945fe7528f7af0225dcac58aa2b132e95eed9fd569722f7e1d5293cbeffdee46c80d9998e3738cbe34414f1f04aa3094fe8cf990131e17863e08f455bd48b7aaaa17bb03940b03027d25fa987abd3cffe861405534fa1ba7f502bd0804f3540412893ef4f23a2491bd746ee82f1dd0df3050bd5e44a3a7f5a20f43ad0ee98a462fb239a387b139f3a90ee95290d521dd510e1dd29df47d2299b6f929877d173fca483f521963043d15451923481465a29591f9aaca84dca075f4a27a91aee841f5d281f9d073c8d287a9ec276a2f7a29fd502826c65ea4073dcccf54f61e3056f283ea7b52bd74487734fa3691f81d7da8f61d8d46a3d0537b916ec86f6844abe8197d91bd48975248d22191747448d749cbf88c4164ffecc5c3b5bd78ecd8a143070d8dc93433932347a92423131303034322bdbc8c462211a5a1100834a794315a5655414bdd27dfddaea4bddeb5ecf56e3f45ddaeecd560e5f79e3db5bddae5c3f5eaa46353658891a69f6b2e20fe27121b6108535cf71b38f1e1ab382d5fd8a2e50b3e5abe1004125b3542978dd0334553bffe44fc8ff070a229c216a45c7f9233a1858d1e2d6c54b9243f6dc1baac850b63f0a14274026cc1ad317f10c5ab7c74e0e1e6c8bb800ca00b627831035a91f979a1a240513eb0ea02973320a32aa7a890518528bc000a53a0c2441902edf66cae2393b0183b1063078c0c37d0b081fc111a7103d0f639ece1bf6757c3afae05bfb2ad1b5a6621d738bff2c6bd5a199a16ef18638c31c6bc0d26dd99bdefbdf75e9cb99cdff7f3b339feeee6343305a572cb0136234787c39812c694b65711b79fdd6194e5009bf1ccb89e84c360c175db3cc46ffbd8a26d7e621ff25b93ecbdf7de7befe90079eeeeee0eff55873befe173b08566c044ab80f20f09bab8fc13c5e706b9fc1345ca7d5c7bf240f9e70835eed56cda9f68701b7682db9ec6833491f6851b516e7b526b2f5b195e7c6096db9ebbbf27dd1cf79afbeb55cdd9272a341c64ff1c7b95ed81ae551542af4318481346669060b22575a1edafbecc0c048a0c31b8cde655218a2c70e15eadc1e880b6678cb927dd1c0604ca7548accb22b31c6033ec13d45f6caf222e2be12a5cf6461bcf9e5c2ee2b2bf58cb18687039c0667018538850b6a7ff7a7299bdf82f5849dda4db3400693d704861c7efd8b967f6bdf71c63ecbdf7de7ba7ab7322833137ca853e643b9282f65c863f9f638cb9477df313e4f2a8f79ca3ace0ca973d33e6989bbb634b57401b7bd760141863cc5de301f482b6676fa011a24ba0ecdb0f6166c73c437f40bdfdfb36b9b80e233619f76acfadf970190df7727767b32da90be5f6576b51b8930b1a4d78114712777e830edadbf50272fb44bf9fbb67ba07addc3d42d6832ab31e57b33c4c496b53499b56d60a075220499c183b102389db1cbccfde6673986d563a28d2990e22eb94ae73a07473d8b3b357a95690e436243fcd063c163178028e24c6a0c41a0e30c0126494610413de380117442a7be3eead6cccb27713dcb3d69afbd65ecd69cfda3377797b6d854b07ca155645f1a5d36a0e7b77f6937b53922a875bd55e85f8ecb92c20426fe75c4e7bb7de318ed545a2117f66e35b35c759d311befaeec0d2567f5dee9df4b59e8af5fd7b483973d6c5e951d4a3a8778ca2f89f6d7e7a1e3a27af81bd6a6e94ac3dc369ddac4581f7bd778c9999dff133da5b88d19d07aa85b566df8d75777777777777777777777777370db2083f45a0ee10569515236cccf487feb0d6ddac779c52121291cae587a389cb96c7af01ac0e91c403dafff7d94f01f0f10208baa581410434811a3c0c0c0b581374b13c72cac59c80d65a6b24ea1a768921ea41a25433571c73ef55dc21f61e4551b239e728244dcd23dc3788fe24f82afcf7b19d31e78d72ed0992265d631036d71ceca78e7c6c676f3e35e6ef8111a2dee57741a2d086d683defb677cd0b37aa5fdb48d31dadd21cbe7c710ec20421daff456f1a97f0a71d97b0b75286421fb6890757b0d712bb30fab3afb68fd54bbcad0498921e841a2c8e7f656fbeadbaa57beb28d35d95afb7e20b8a1d682880d12717d49ab86b8bea4dd16a36deca3bdbd4270fd5bfb57bd3277cb5b16cfdf7b95970d81afc5b7fcddfd7dfcf8aa136f3d3d41fc78947cf159c7a76a0837ffc6dbedb9a45dd7e6f3c0ebd8c7fb0782e8c4ef9cb6b18ff71dd9c7fbe7e3596eb7b94db3ad5d28b2db14916485f6b3cf35f1fb3313db073011b7fc84941c88b865d6a308ef1c781c149c38276e3241889039464dcd6d7e6388e4fe17aba524d0beed7e5d859637c96dda6ddfb47f7407f911fbf0ef67c2187af8ab36badcd3652d6260c28d335a35c6ea9779caf569c4c2e046a7722393c18d6d89fb2eb30d1bc1165918e3c66f3c447e7c67df75eee6b877d2aefcaa2e717742577e7c32891bb94740594b1b6a5cf691726635cbb29c653dcbb2dab22ccb8233a00b4a13377e5559cb185c7023bc57f50ee2cf01f15fd5bf79513f4120d94b40f68272a7bdf8abafa2fd620d2b575a661f3186f8e35fce359b533dfba95ed5e4018a164aaa67d5337eebfa5721a040b90e6de3d25a7b5860e62e1560669e007305b8a53087008e30b250a10b152e3fb0818d29500ce107681cb10593c25c816e013305780d666606837901332041195e3031a50b54582982119478c112a8e0858f09a0d4200c2ff08213bc38420aceb0610453b250c20a2b9a885202224d788218ac48e3073f6590a10739880112a8eca008616024a8003fed013305f8e90a2cc04f3b07156016431b4e5441230c6258498110a05071842a6869411a3b50630b16c502cc6f1081992b109905b155b4c009345290841f1310b9fef611f73adde63e1c11650a26c018c316de20d2cffdb09f76731183b05fa1d7cb65ffc243fa861912177ad9608310f6cefe24aa01bd68ae1814de22a4dcf63d1de04488e81b7ccce06e2e6019030c35ba19fb6fdf3c089751051356a6347bf1b42b671028dfab35a3845c8a3a51d433fbe0504174e01efe25aac5638304665ce1367bfd0f3acd512d033e52fc94822264a10ceafbf67c14d51a14aac6cd3ebab897fc2b86292e77e1083138d6ccb1665538d6ccb1665538d6ccb1665538c79811ed9ba3d20ca4dd996c71e66cfa43f7861d422a6837e98d290ed2debf85ee939a6b768d31b3b3678744739bd113f4e29f19e8c54c388d214813118395eb5fd34304fa86c874c45cd0e57f1d440ea99c7de62e73bd8808ee05e5892b6e7fecb9c35bf48ce0f2504fba94bd3ac084b9437b7a487079a8ef2b8625aef56c1a096d717b16e133aee029d4e0f68f61e50952b8fd53a0411855f0119070fb190c24b0176adc3e42184f2083b34851040153b8fd9129d085c406947cd3c88f308a9cd6b05428c22307272fd84881bde882115118b7ff71a08cdbaf24c7a5ec05840e4434b89405ba3cb0e5f6531e704352d3086cc2ed871389dfcb89153b5847849ab0030f276e9b46a82a14792fb8aeb21b9b7a14f5dea3dea3a8f71e4551d4a3fc0cd0756fbfcf1da01813c9904b5156553dac8c7f54dca37aa7b9d55f416ef5171056d9ab7aeae70e1ed01cf7f02d257d2dcb64e6873a1bc4dfeaa9bf3c8dd47077380e38ee3472d95b3dfc58b50e62a7e3b8413879d77a1edfc9e15ab6d907f555f5dbae074a97a7749b59263c385feea2e788db031af42f1e830238bc9f6aa2a0fed30a60d872dfbbb7ac3351284f1cfa034aba6f94027a01b90e862ed7f9e267d573f84ba7a9a4efb3333f949ffd7fb3cf2ccd0b827dae13bf3bed46f390209cc0eb9ee75dbfaffa6d11fbbeaff6757687e388e3369b248b31fa075f24627ff7a809a749b02f9ca0b931bba0858d2e0dd996d2652d6c04e192fce4f04a259b8d262ec94ffd5f60270844c87785cdfbbd47d9f8aaeb70bb2ba1b5c656ec5595c51819ce587bac35fee720e5efb5f69a0909fbc68c3d975516188f61adb9b7d6dcbdb91128b7ef1bb735f66a40d710b759d8f3ba9b438a51cf3187105a13120f859ad933ebd60d9d0952cf756b8c3566621fdd36c6cc05005d437c2f612eab764a68d89c7bcdbd67bd5541aab5d75c63e6f0992d115d5312f5af618e81d800c46d9ab40a44e5f11eec67fbfaa4af4b407eb44faeb8a77e470e2813b1883091f88c893cd185a4b6e48b95843309bdf0a39c45fa421e3f5913075a229e1a40b80d75b459947b4f3df81ed57fb9c9aaba3508df83cffd7b671f7f1cf110e1363aa359c46f067e4082f2532f39deb8d1e1080b129fdd587ff01eec5b8d301cd337788f0c558aad8a8240f9675040fddb9a99edd98d95081c6a5d1d3fb1ffc14fa22bf4e20cb80dbd8cd99884e020c40acffd63c382368d1c6594684e349cac600283698d191db2b5074d9c066b89faab348b701aad9992bc87561ad5b7673a6691ea1f182ec969e692f7f04951321925e8b2c09b3e7bb2e92ae882e244fbe79aa88c1efe86e2df2667cebd4d15a45e63cc19638c91bc2d61ad8b28ea01fc089f84854d23af480df73de79e255128ae7b8a12eb214980c510e2fb95560431368e7785801223007b9114b43e715f844524520ee0d943fcf8b050f161cf226c85229ca5480db7fa1b6ff66272ab2517935b7db46483d041aaa9665445217c09a90a63854592dc9a38b4073e21840fdf83f582d46b97f557e526cbd4e09b1c5294a39c7bd83f65ac267f283d3d3d3d91c167b30867a9e1c26f1389452d3102e456b0c910455828c96d9c03413c7245931047dabfdf816ffcf74210e1011ef7d99cf8ede114d43d1323d6c3d7b16efc589d21851260dcf83c79e033a450c208375a4bac5b596c2e813f9945ddc6faca149fd5d15e4f6efc57afd6aab7aaa9d92296c999a0897ad6ce934b7d5f8ba2fedd6a26814fb11d76ad67138975a37d5676f5d493dc86ba20e020453d2854534e44c81060f29781245156af3651adfdc98d7f59a6688b5826abb546bdf7fc7d7baf596a491880a28612d2de60be749bdb5e3e1ccc97dfb33223c0c55f2c818acbc3eef329a6c0019432c06083045af8a9a2837c9f3b40b900eb201d08f7d99cf7423ceb011eb77dfb213c5163b6ec96f2c6bb5f4a59f9f695525ad64beb65bddc4baba75565bdde5ff1e5b3de144d95f5266849d93b2d25f58f7a2b864451d01ceb5bce553dab4f8ee838885c915f844584257177be4f072841843dcf2639c038430a25c038430a2a4498088b0fa8f52cfe8d5b35c7facb7a37adbd98dc681ffed5b05e8f44f2426c1a4a6a01bd646ccd2a949774ecb9c6e092cbaa6807b4915092112097d91cecc3bfc43efc3f4b7b96c53a63ccedb4cf4e6b719b868bbd248558bb6f936b7f02d9bb099a5efbce93cbbc355fc62cb38d096fdfe06582de1072bdaabf2853657afea6e6bdf3e476f7fb27f1d6ceb9ee9e4b9ea57389554d2bd49fbbdb08932e085c675f2e81df60160adfdf2f7418c4cd75f28280d2737772b8fdba180025b117f180f643b6c20de22737ea025a39d7acb5b9c47d7bea99c985f0dfd770498a544396cb56b87289b34d8b68c5b7acf85f8021894b5532c6df61377e7cd6fcf8aa69f295d35e4feebc401fff5593db22d635b12d625dcbde04b2ecd9bd376cb6ac3becf68cef6612eaa3bd42df987dcc8f3564afbee23bf9a42b7e7bfe59aff857fcea2b59dfdf30be560eb4a624d4b7a72cbdba59923c23b26ef1c676ef1b38014faa80b216387c7a683d3d445ef31914502ec209acdc8b07650870ec3202b43f69288cf914483e803f88ec65a341a025ea0329643c418a3ff4a7fea536b8fa8b99b955b5baf81d12ea5aaeb6190d36e8f87f4e80c6e5ef099f8a91bffa56f9abf6907aaead55becc54553145b987b5e134232e8a265647b6196d46114eb04453a1bbf40fb64d9a0a66b41949b4194d2245815e247f1a803415fa06bead9951067a95ee6d4b50f76928924535a0221a3c331e9204faa99b3b638ca901790b90be1723f1dcf64fe8377b555b685f46afc0a7dff2a3ab5cafb8b7adca8713473e05257cf80ee14bf96d567c9a425cf96d82e0b72040f0d96de037f9cd093b6b9085ec03c221420c6d93f5af5573d8b7aa7af8d5965b13a9ef69e48740dbcb674ad27efa5b8344024243cd17711458fd0305ff0d8efa87ffd3fe8182244477e6aca473f27a7595cb7ab88d2e3d684851a3a7b48106972e42840061eeee5f0eed0371c411873b074e97d99c7ec7c27da64879aaa1290959e2724f9092271321acc712426437cb98fb085982f65f42a634a1b51b1c6c00229dc5b71e54679595598fea9959f62283f66d0eb79458e39fcb04082040800079ac95e2bf4719ed1e1a3831d0eb927af8de37f08841fbba66670fdd37bdfda335ebfda37da45c07318183edf7a4606fd74b0138f40fff52c90b18c675c64db00a68298f43ff6082f65f387469cd5dd67b553d4daca6aaaf554d95fdca922e880a94c2ea0d7a3dcff1ef6fd694c4fff1bdad32b7a2e754435322bdf79420e5df2b879b03fbf0bf4ad74ba512c9ff260715d0fe2b87ebdf258ad07b2fbdfac643e053330ab4af731f601fef5fe321ecbbff03ec837af661372e7b5824092db4d0228b2cb2e0820b2eb468d192254b16221081084000021020433684f6eece3d7f240c40e263851556400105143ce0010faaa8a28a28a288020b2cb06833de0c8b533354bdf2be5df3810f7c20042108010b162c575c71c514aef9379bc2dddd14ce357f820a2aa8f0e6efeeacdd5988f2823af1eb56dee01272ec7a6e8402da3ee77d3b31ea6ffcea2155bd28585dd443ea3dca5efeef8dd8cdcc1b88ccecacdb0e17e61f22331c589835e09843c8fef93fe7cdbda3d0eeddddacdb8efb76916e43d8fca3156585375679ad4aa1aced46792dcbc5272919e22111242f791d7ee8e784731ee10b2dbb8f59fbca0a2de6edba39c61a03f57b23ea3cb7d7f7cded9a4ae805edbf484ea612f7f67eef6eedcc1ecd3730986badb9bf73ec278eebd694bb6b4f2e7b678dbd2f69140506ebf1e1abb806b134c823a7e8c806dddf4356197c5565f592336ce2c0eade30b653843fb41714d7ae2bd2260edfee5eb020449a96baff07d95c60ad9140a75001758526484cf7e820ef1d1016e4d91aefe1de3db70dabf193fbabe6baef1f15b82d98e632f7ff60536083b42a3d3d3d3720c24fed0d8d311f838f0d44fe74ea1f8a83902f6c68ef20b0bec19f1bf3eacdbfaf237cd14ad833bcfa59b3ddce9c31c6581377f64c7a68e28c89a5a1ee477880b4c4cfb630e9a1090598535298d2c299873077337777736bccccae0d4b7dab37366c6fb3377e628a7a1445bd7e59220f80f2b87d790bf35fef79873f3f0d94cce3bd77738499bbbbd9dec73830ff7f6b4fb73050dfd0e0112cc04a2c88535216790176ecafe777560766666666666666e6e66666662e22d734890b2a455c60c039ca08146ed136e04683b0efe60ab5bcc07673e6026a6f6bf20bda58d4b88b92685173f9dbf30dedb9e6b9730c0710525a2a3d680cda0f25859036a43754422829a496115244d313ed9908fbc6b2907c885b5c07c618638c3128501e8e88b8a0fe593e3206faa1cc2143d818fadcc0c60d32c441880dec7fd07937888da6d12edea3b57bbb53c9e2bb534b502a5da648ef61de549ecae9b2d69a13f4006d346f2fb1a04dc56d9668020ab789dfbcfad65d588ff66dfcdcd69a658fc0b7ace88cc297b2dbaf5fea61ed2eac546256073fd91081d03f01fd7c9e1108d92b266ef609e8456004e8e7cf9716d027424fa1111bac94f5e82ab697f053b3aa50ee1f94bdf1136bdf840501c25d5a63c27a3403dcabbb9cfcd4b6a0cfd6bc9f9a280c1aaf6283d8ce16feb40664a1c180bab2c5bee7adcabf577bfdd94b511445b9a728fbde5ff7d38e72ee4160942bfddab5a5f1937bca96fce44448a0fd350e0af3c6820fdbf2b1b5f73ea75fc8cd430821c584dc3c4bbaa4fc39d237f4b39f23a6b8a52d2a6830004d618b1719b81618a165a1dd1cd181bad1e1c8cd1109dbe7e70818dcebbbe8fbffa2e7ad4b7b0dc86d8cb1672f793758e3850bc36df1eefe7d757777b773ddee4d1c77730442d7fd2aa05ef02129a471f013f31373e68c5ddd9d44c8cd2b954a2da45f080e37540bb969b72427e43208f9fdc78830dceb146570afd216ffae0e7eba3972dbdf1c693e374720a494d123ae83cf8d0e47281cbf39626f3bb741080e3f466cb94c4bfbe7bc8726ee33efafd6fadb3369e2368d6adf84c76dcfa48726b031f120b449b396864a9f9b2d477868cdc7a0ed5b6badfd18b1857bd1bf5ba879efdd9acb6ff906fff76afc9db7ff1c71a541e13d3e97b5c461e5feb8ac050e376e57711b374244956ea28a5341afb6d26ed33d0d85df38b30f053c033a0e44080bc2442091fe236caa71a50943b0624a4f0f91c6f246fc2103cccc8373cc39e7dc4e11eecccccc5c88ef23554541a0250e7df5a121384853c17abcbf388ecbfd6382dec2821afefa4b006a00a11d231ea297d7f1a4e7d7c16decf31f719bfa315ff3fc3db8cd0c2f13001b003c3fff0f6e2380e7d7711b1a9e1f081e027afe1dbea1c7f30bc136a7fff1fc3ea365354e15b970e1c22556115b4ebeb1ce5af3b1aa6a00be0ae02b159d0a4825975b5d90f52738152c8877f11ecfdbb8efa5bd4a5ca818dd800601404a054003000480929109409519fa5d9e31b6a609daae09056aea7c8f5650ee46071f263df096233cfcfca851bc8b1fe0c7d750a34879223fac9be13dde932ea4640d4cffa0838611d76e7c14101b80381f32d045080e422a45c4136ea39235d592ac16937dcd03c1c36a9c6838e9a8a9a97997a20229225953ffe5b38091357ee3abf946493442d713a587aabe6f55b19a7713a78606529494949c1fe7fb12aff2789f4678f090b38e94a0fc33022e977f909842ddf90c4a276b4f79d6fb382194159cd37a5955935541cb0abdfcaa9a4222d0ac2acbaa2ccb9af36fbc9a9339764e4e4ba71d5d111f196e52b0ee301184b39a56ac20082402c1592b2767ad9e27fd1ba7646e3cc61b77b2aaaa27a90ad36db01eef21a45454cfb388888a120fb97ad6ea79fc8ba5f91b8f3c71609eb2970e0d17fe00e45314455194a4ac58137b521f5d063171e0c7cab7aa702a5945cb64b0a48ad264cd9937d5be7154f9c628797c4f9cd1bfbc8d51077746fac48191d2fa01802cebe74b29a5943f432f0700aa89098000aa3a82419c9286ea5d409200d5c71840753342d5d1d8513d0d3fbd9f41761b2c8853e11eef21a4dca517210c78ce5828032bdff805658d48f94ff8f8089234d6889c89d648e8a34956750403fa2eff2041e5b2094682aa3f817dbcef511d0afde3fdc9a994fe95fea21704624b8f7de0a01469da1740d2444355013c9c46a8006aa0635efe41e20a54878c8c0c40ad1e003236d831124366474c49d6d4ea6788718247bcfc83c417317fe391873455b6a61118eb5d66752e567cc80a988f33d2476d223faa77613dded75079def8c847476916e9fb848f8f956492b6565f495a5878f9c7082c24fb4223bf56afe3258b19a81bc419a4a972d42179d4ea45d58eb0e0aa8e6440dbe51f246870470098951d5d412f0ddf99dab76656562404da6faa7c7feef49df9c89505f22ad8c7a3817158a6d0f1a8601fefbd0aea5ddecf70711f0309da6ffde55c2e8c3b440f0a2b50dcc76f14b1177e8cd554f95655f5d4c4a976e8f8ea75eca85e87fceafb19cdf7653450ca9755529e385557a9dd849fde9b2adf191754d9a1e0472b63ec8fde18630cc6a7fcce54be39ea457d542652aa54260686f4329a482a52687e9cb1ce39619b22252fd1cb6a1281a64541539250f5555f49bfba30bebc843e147aa7e2361dfa7e9889132a954a7256111028ffb4a08b7b791c5c861ba370e333a4288a82d5cba7a88aaa9eaab25ea0bf26887ad33459a648552624f0ab87d5572da5bd86b8d152975c5241d623008f00655b1a4ec50e2768739f3703b5b95a1a9771711b8682ebcfc6f02d6ec35ae0f8c2f5674c48a3a553a009131e28a6a87f222d684c6b0d56937b30cebfa49bb272af5996654d48dabb6f38cdb144a79e7a1d6e84d8c0ef56a83b5253a17c89eef9f1aafa157ef2f12e1c0c2ceecfa1f093bf5bb154eec5b65c2e7eca82fabf2fe14df8143ca47b6c9863694d0dd9d108293e85a7b8fd6cd9db5efc3ec5a7f06066a97136871280b6c818638fc5f62c947dbb246bac35d75c6bcdb5d69c73ce39c8ecfca22c64ef0bef98f71ef3637ecc7c7185edc8b8f0775a4f0f126c2691b994bd86b8b03d7b52cc7bcdd476188ef59e3339483516a380a8c4cc38943d2b15d188000800005315000018100e078442a170344d0441f21d1400107d94486848178be35994e3400c21638c31841002008088c0cc4cad03311dd2056ec91f72bc01527b65990312e7ffa178c28e446956b5c3236818153a3e8d403583009931b462ca6764f38d899c0b93eac8d66fa04e7a92b30717e38f81f395c6e3fab24cdd31d2aac41746f004e76cd2b18a2673e21a5c9d5a7a357151b38fdc92ebe98c2cd0cf34c975aa01f2b0b96f57ee8eef7c3f3ee7ee2e5a7a691d38726c224046bba494aa56d2cea8e70894b5222a5c209b6ea2196504781bdafd2c71ebbb306b040d8c8e6f22efad33cfa383d48729b93346c8616e1155eb0a66475219008032728c46bea7b3ec8c0b44e09bfaf87ea340de6c06901f6920b05cbda383cd62e772a94474343d035a0c3c5a067d0c1643b7eca6b46a61ae9afb2ed3950b956362ff5678a2a2f9cdb0c7583eba411bb1d5816c5d4f9fb90e6292263f971725a8601d1323d393433ff967078577ffbbadf85cfa2eba312cdd4e56efbca6c28de681254a8b490456afd5d63900718d3ff1f150db85851333f7cb984a1e313a4be674e812fc756a5fdabc457266cd86ec57d0865220661471cb740be1a02e8eafc96cb44597b9935cd1432ca18fd4a03a4d694a86d7b460b9f325de0405265468a6074570b8c1107ffca92542ccca9c8637ac7da5221de9ba7b20782b88bbe5ec288051753b25e61875aa6912dd0c8fd355bf0c04329988728c1232fde2fa8640e6388c02541dfd92bc5aa143d2aaec053f982ca69ba178ec5723f5900f97dc47e751b66ee0c3ad3c8c1da3fe90eb32db78f5cef8f934849eb7784708cb6331bcbb8c4376efc56797e35949a41ca7250f2e75e76c341c2e40b11ac53a2f3a46201d62f8a137c786537e46a437e3b239fb8fd339cacbb75900a38bb6ccf75946aaf9aef2688fe0b95f7ae2b662739a9d5378b36f8909aa29a2823b4f99a4da65ecf8f88ca1f145fd9eb34d159b78fd4aeb0968583b3cce5f0bc2c5b4a45f6c39ff9cec30f1e7145229cd0dcb81bfed376c36f8e528d122ef2537d3715828df5c7ea37e51fd580d8de0aa8eaad95679ff394ed3eed72baa2ca85434b226f11ac673e47c4faa387128f8f8468cb8e3935a9517f6c05919a6bf4fa97d0e925f1d06968c93a7019922a0dd778ca6610cb89fb58c2dbc50d543b5dc409154620cb89207a7ebfa7bac3c51dddfb14398c1622a09be8a81a716bbeb8c1694606abfeb095e30aa0628e7053e8c044b3cbdf8670c9e8399a2f3e59712ff7285a23a80796456b31abfd339dfec477efebefded2de93cc2b2d81161d6c43bf8b333c62cc48ad77b0e7b2e1902a062cbb58cc415970f2964504564826e4aff8bccf3fa9a22a2678c0a026c705f8f943013b8fcab52421e6351d05a062f143f269272438b196373569851a3d2a5678bdde598f649bf2e9f07a24274eba89644d690ff9675a61b8053d7d2e26154fb2d65d85c3f8eb9eb5720466664ad572c2c59f7dc31a645d716db9772fe16cffe87ade472810f789b64074e8d51b36d8d64148c8852416ad3f69860e93d0cd965e9af5924a06bcb5fbf44df9a9829c7cb749fc3020755ba42d0ec205d423fab1fce5dd866f9234c2f7588562a9df3e1b138ca9971abf67662ea1659651ff481150a63b6d09cada8ca9dc63d15f6892cafafd8d82e80cf34c99110648e1324a761e43985ed4a605e9cd7272f655112840e4b592d92dabe7a15a077340a490b8ea3d4e4cabe66b8a318ccc5f0558a8037df21d8ef19babd3220384571f15f449199c77d39164d5d2af4c281a9c1721d4b52b31b6d419da897fe2f3de02d4200e74f028ebf40c6926a004ab76f8e99bc1f70a97382f90cc9ee60198b2da4730a3b47ac2f0b229f4f84b01218a6dcbedb8badbfd19a15eecc1ed820fc4066de0243dc4ac158df9aa45c07b5d12cba6dae52c1d195696f9f937570e06104585ed8015192315e1272733dd44a26dd89ca2db699ce4ae18f7fb93cc8240b68582013d6d01415dc67bfa052200de20d11b4e75cdc13be91158a84d9e27a0b0ccbd22db65745d5f8f377b130d86f5b198aaeca7511367cba3148603f07384011c2ae3da9f273731a4016e7c470f7c714d6f36d901ec24434763eda0da203cdc8d9bd99ab17e8c8db09530830d277a23c07faecf2cfda225b2fba9471cc1b7ad1289a99d456cb8dcf93631f1dcf0febe5802231916fff980b8799cb058e3bd17263455c735be7adc51c37419c6b3231d848835cab26df82209993b050cabb67f9ac45a1a3e396f9ade794ebe3937dc2d4fe11d8900d147b41b17b8fc03ecad5eb63846c290d1418b0fbfcf638ad5b2e0d5c02af49da0fbb947c4c3fa36093b2b066d4313c1790dbb729cff040e5b72bf639fba1850e4afdc32d55b0c2095dce4a0642a9663df4c1e7900471afede37fe4372ce631f85bd066b54b554ad09eada8f060a505ed4b698615b0ebacd6eda698604813a496671797ab5677f3f8372764c57b07eb6ca266fa98d486724f280a7883d1da0905e8e1219e5c30f56ceba60a60843a591d6a7ebfe78047b9a143f17822331c501c1068832817d6221d5ab58f82b112557aceab4e04dbf730c5c2a2b817fb13a5979d808c225cc65a470c3a05de827d91d15b5c72199d9c1fb893fcb9c9dc07a943bd11612929222ef45e77eca0bc1997702a80b482e0aa1ce1647b199c4f6fd4229c6271e78376ba5b8c71cc89b5df0278a88fce82989e918b208401083dacee25d25070a566cb05bffbcca605200887311339f6594231bcc3023ba6b6fdc922ced4927fe24eb450edd5c445b7b37ee65372c072eee5a0fc7f3129d551a7910257b55d872a42760f9b49e48bbb1a70d279e5420f08b37aeed770e54dfd248f756ee07623df9a6ba5f9ca2762b984f2c87ea48464dcdef3bcef752325187fe7bf87aa4314e8bdfd22f1b78ffc2c9161a7db967be6d361237b6aaed9f5d78c98956a008004e9804afa00ecb537aed93b9be4c1f4fb8e83119510fe949a455e6d1bcc356b324d3183149b39c7918887626a210460f7130b842d8f190ed384af3db8c89802b3df217c257a7257da7b296768e06b4197303ca1db0134ef29992b9f1b246f1088807ae839acecd2ee8098afe4948a8e5d75ec016a8cf1198a64789ca366080fdb8aac07c8eee08df6e98598d659603ae180d8676f9da80fcce8a5c6e3461e0de01d52bab2b3cda24710af405fca8c1fb3105fceb0280293bfff63dc5b3962affa1160f5f605a4b5b04f6d8c231780f38150c247b39111ca681fb58a23520ba327e825c0d25a01cb1731532cfcf7bb750efc6368368c10c0743a5d7bc5d4124c1d6ba5ffc72007c23ec7304a8016f99973615a3853d8b8c08d06912955465acde28c8ee706ec7bd7562ee766194d0ae020bbc9b43bff35a509ee35a2d825acd99cec9feb0f717b74b8ecb6bdc061b3b7e4f4272b77ce72ac6afa75643383075026f904805f3fe0d14c0240244c48cfd79d339ff89314d373e12d317b2ae1d7bf9faf0a16576c812fdf4b7349a7a22c013a8646d1e8dad959eb96de8f2a2db1f33ae045b0a6684905d48faa93d516261974a3a0fcb6f8cd9f9a22f4952579930beda0f146aca163cff28dce92f58e51142280958fb20110dcfbeea6c9dbba1ed828b194212a150880d51fd9334e3f44173ad260b57de7ff3f53ea14b02d42f434c7f89c013db41266e82e29059c051678acc5425cbcc66fc0b8d977a166773a2690b3ceb4902f1cae3fa0962623e11056b9e5652c0f989e41369a6c3b550f88660e1be2bc60db6018c1b17af7f4ad08ddaa9b29f3d67df47d86bde493bf97ce0a2e08683e15dbd39eceab727d591c845f1e1dd9785269a31d36a634192b84a14216ba48d47aa03b311546c456b5bf23ddec8206d50861879b7b8c823f1cfb5f908f2355b03782557954f8ab643190513f901f7109209014758c7f48555d33a82a282de2c239140b6f0a70c07fcc3ce9fa1b3b10e015d388ae32dc33eb56d5aefd2bf40ce3a12ab234bb98abfbd4f86351a6c6923a2382de298fecc6d96ee27c70dfdbc6d3cce9c9695388afe0fe138611b8f841864046c134976f4501f00729fd7dd0d3bc3331c58a1a36a0a0677ecbe6ad320a1fab4d93010d19f9ddd9d59ec4be8b81ce02e09130892e917e1edcd56a279992702f97db18ba62332d9513d295e2155577b2b68953e8f58abc19c831f42c167e2c3bd800fdf0b7562458278506e8562a95362d32c393e503fe295e7afc65999acc0cd8b815b11d4f944b2686fb20d565994ccdce9dec053bdc70c35e67465d30a65ccb3996955d9003baba260a025769e0af0506927a26f6ee87b5dfdfadf682d898fa0d7f5b03a6e36bacd38cab2136cd3132786dc30342b83a8b5e6b0c65385af6dd9cb0c75426401757ccb4de1e24ea3e785cb46e72f9f7b126abd267a40d1ff94dd3cda86e62ee08af5438d52f1e38560cab3d88629c655bbd884f7a73c7dcf5caa1ac36febe13a4e15134f443257ff46d17b23848f961d92595eff252ec04e049d97f81b63afd6c1d8f9c177afcdc767adc4833032fbf0adc92c997f86b60cfb7b7c9aef8b1cf2a4276d29a0dc89aa9d25d5b8d2b8eb51346be0e1873f60bf8d897606e40ecfceb572c87ccd5f4d44e215670d0bd1148aa5967a6d3eea40b1268f242d912cb153a0fb0523b7db6a603602f261c7f79d6f86efcc0096f948dd9b36809f7babe553fe6f9bc03f7cc8a6ecc59e29637e0d7325ac6841af77ca54cc946b4ed4cc02a84b6f57810bb998f1f42a23299c0e7f1334d4350ee7a54568568e6823ba5b08aaec9695b355111cc12014caf3f508502ea5429e65a4232d02dfb28506f1a3aaf99ff03c2fb55d51f3d5b5a7d98ed1ce975ab22bbf5fbc9c8b6843a436c7a550b526e5b705402ee69eb501334f4d7772d37ae0d7ab5f03ef6b8105484684766153fc3726421b49ef0669286a3648298e1ea16f7ccf8905061c842714a54ed5ab1a77457cb839f61bef6d1c248b5fa8a1d90503251d9b0876ec0f1f409254a2c2130a394c66fe038c2a499b21bad3b5f996ab765e2266c29d7e9edaeeb993b0121110ced8e32f9415beca92555124171d80a0e11736ee66ba55f019a1ea4e906638efdf07912428f9e091bd4c14666106b782b309c1cb5610fbca2082113b53445e9f8e228527416173cabf72dd5a6ded79e339acf15b9aa7a40b740375ee9391b8c01b92721082cdd1b719d5d407b9392c73257c52870149ae5d5237eef9a4c9382c30020231ed9c3d491e83a6b95ec4647d10d93aed14fa95e58a48452bd6f8abd23069e69ae750c90cbfebb346a7c9d0d979d678e7145877ba32b555c42ea11f8ab9f140d7236e7410de369c0d49a8c199bb98810bd1c10102a3ca27a9b002d8224dad2ac41cc350c55db7d616fcb09c2425f8829335f98247d9cc8e61476fa09b708218bd246ae06a8f03a236fa0af20066a4eaa3965564652e0c0dc71c0b5e89c0d0b060a874b503199aca9188ac493420393274f169d4ad93bb1974c0aa34177034bc99aa4545db42b7cd611e4699f0d6d4a5b9c6cadcf78a54cfaeeee19beb1f4bdcc81e8c20152b65280c32ca05a8b50b8ce70c5d21da98b16f970ab6eb78ea8b3938274de0afb6f25a0131e0a317d804049b898b63454d5f37140af29a5013544ae15e7ef3a3fdc82166e02d3fb5183017ec5e5eac66f36e1d9f1e6d6fda4ba5e0e7844a001758814a9afed16989bd795997d81d88d43ef98fbed2a545c8455408515963721af58f52f4d5b97099c96452b116110dc7aa9f9f374453c41640c65d80dcc64b6985b0491ecff68c1f65ccd546be6c101fa696a27f41a9bb7a6cc5be3e1b622eed5985118c208afdf5cbe0488e8ab2d7c8cd85b02d7335472622c0ae4aa6e936fc514cc7c4cbcecf9569ff1064d5868611b9fe4d3f001eceb0d498045421ade32310eb359d1f971435fd87edeee19619ce21d39876d56c1b92bc6a416bc1bd4588f13d7fa45c908816168f5c6ada9e00780b018dbe6e78c0d10871b88764c1c3dffe41716eb7fe0f2323d7a2ae1a3d3c4574952bb789a8889920b51c8221d3d4c358c960f136e6c9c209e13bf8bbd74cb8d780f44bb59b9c799174c0ea541e236168a40e85135244da43c98aae55a092b3b621f6dcf2f3c5972a2702d303a2b86a13fef1345976c3eb6ae59f94af116b024d134133d75ab09e6b331c24d01cd18a3aa4190bbf97556aa844caf25afb77553ea172a1591cefe181a58e75823c77905077bc73d7d3c3e87d6260e21748b738465eb7bd25d8447e2cb556382446bba96af7e4b27f1eeaa87e4d67269158d16dfc0f38f8e1a6fd6ca32efcc0b4eeff3cd74aa739eb95f72b5de4cae91460babaf3801498aaef3a7e5b215f63dd708c33c72272ca512c59ca9bed46c08937dffc13d192d4000962da4ae9dc86f89e1235b6d1ac711f432af9f677a0776b97853df3245bdcef70f3dc98e79ab97fd05c9530c56aa1c86c9ecaa0a59772a6a0d82101311d41224c0494928c0744a86c5f46a7f90d7e7b94d5879ea9b74175547944f217be95eb0f65a43400ae189f9f2d8600fa2de92b46764b96e3c625e4b253cee9b41605105d5b1588691318410d2a48762dc48c0a5ca52939206e862463e1d653e415e2a9a2758af5a30e46c8da3ca1a83366cd139d352de92fed10312e9a0db2ea5b669cc4711676474ec68a2be7403c1dca9a7427a340bd8f1b648825b9cc8d67f5306a50a8a8df1e942ca77829f9c86868fd264ba9d6373fd42751e507173d170c60e4a4833e37db513230722be4b61a3fcc2ee6da17b040326ba1b08ce6c9f87be6ff41147043740c85f04386a45e67fccb516590d82e617376dd6cef7d4326981290750ac84ecef46f93fe3cf35581afb903ba040df69c86e996e25cdc35533d560ede05e7411ea38ac75a8a45e41eced44b21c5805d4d3fe3061cdbe3888c5b6219930c07eccd66e140b1aa45989626eca501176c0f1158ee69c5f9457dfbb163010affd69bcfade654b81802c4de8aef543bd4ad2cef5c3f99fb76e11300e1910fe85fda5e3c37e9ce820c82480e4d672be3aeea61f44fef4933c75de7d8b5618dfc22dc01f6a60e3cc8c0c1bd7748d9f4864a8b8a45d8dfc9c87a5e343798ea670ee545cff25201055a8021bee08025ec4db7b883da103dc631c4a07d846a9953b38a14e859de1a8d1668313742b61467ba1ee94085133d081a93d399cad328285318c00520ecdab522021a9a2b4ee485b47cdf2fbb63774b39ddd1622c4d1d7b951ffe15e7f7161a28191811460e2c5baab2511320659bcd0cd10cd6b19404b39abfe744fa0dc96d9b5e4350f75fbc0aa6f97018c206ae2fb814285e7c1c20cb7051ba85bacdfc755adc77c2a5eba5e2dfbb11a7cb8c41e21e5a4b14ff2e2acb4c3c0969652a0f025e17ddc92a4467357ec6fa7438aca4831e7e4f2902f82d49e287953d5879a9a5f1377166806e8ed65531a3a4d2bf4efaad79b2815af366b31e5e863745dec69a01f645deb4621382fc238d1c85d127044fdbe8128a63562d5dad319d6d2957f95b2c6f64139a4e4368bf7ccea878ce9b1dca8e163393144d73893bcd1525a99bdacaec35750516e650ac39decaaf3b7463b29e8aa2279d8e04cf9d89bdc97f7e8641ffba0f3e09a5918e32575616ff04eaf5f5c5b2bd208f9c2fd6d574725712d0e88e020ea449d4de5c787ba68157e808ee74e0d67b8f0f8f9d95096677136d93e0a44e677b3858066990ec33fde2427210d26014ce83bece0b6c3f2f9111c22e0716accba6c0788b9f77f5490b62bc69bcb966ee63b3f52182109db101076877c898698368781cc36314398d470e149d73db3072dfff05e0c9c5c894986c12dcff7e766cc274561f2014596fb10ca6f2a744c6994e202bcefcbf3b7141c63bc6be6aaa34d83f1fa5a75fb00430871fbb36ab82408e058940a970724a01914db0fa1995097c47a32e06ed6661b1aa9fb2cbd132ba8560272bf6e63e285797ef88e03565288c95834d6b435cbc90b715f67817c9da783088d9c52458baf5848c0d0b10ae79803ef9be2306732227a7dd21bc04d0ac4b3a368bc720da71ae3b5b13829bdbed91803b63f6ddc67cae34d9db296b4b7a5d6eb36b64df2114f60d7d7170d840593bc919b4e76aa26fb7341ef59daf835de07dd820bd7edbbf1880b0a1649fea34a40ffa6d1abe1c6110fe3551bcc38c0938591385308ef4d4341537b43ca7ad9a8ba85b4b1b01753e9f637508f97344d074c8820abee335023e5455487447e0a0d9e11b081611041694ced5a78f025a266f55459d4d1023f258d6503788236bfc5db6474328c9af9351a0f1a3272a1f61822913a7f89c31c08d200708a4b32a00d0d9946e34b7c24282a3154ab6f0b281504fc461f219a80bb348ab4844ae45edc2efa2116d8fb9a28e8648fa9a3f946779221106a8c50e80dc89497314d4f7412e85beeb4a45db85bc755721b15aa1a84e979c77eb49ec886b1a20c639cc754792554bd02c33b684fc40f364eb7b217e0d79ce6b0db68e927a5efcb0fc5c6c35a4bb6d16595e8bad07bc1d2ae81d9979f4ecdd71a343434d085bf3ba3b8e95c1b2a52ce052dd828d02c1d357739766fa529c2467ced05c550c50365c7974a7fc41dae180871cb406a4bfb7ddb188975e284d3141a9610d0eecb8f36ebefa11528b271bd7639e39250e8974c1b5ca5deb0c0747907f0b849c59bc6ac789b802722c1a0891f0fc48b7dc90c13c6c0086fa7c502d5b1768293af080d123050c717607d15f3cbe0bdaed2e415063917b641f4039f3c49ed93a66d15fa2ce86ce5df31b6ecd04ea83b3164a19c1dbd23677d2b9d0ea87c5323904f9d9e96a066348d895f7e465d6427b6c96d1da901d6ef834ac1a7b56b7d4b0a236c96cb6374297d6356f6cda0018d3af736910fc970dacf80e94efa0923f55a14a51b419c48061d9866677bf8e8be93586bad35ed7c2da7244b2c48350e8e3cd1bae3cf2f705c2cd65c29f4bf5cc6e56d68fcc2ef061aa2894aab0da4b94b42826522dd70610839acbd3eee8ff80da7194f9e01580d21478e22f890cff8176f9bc41d04c704e41962597a7ec46e26b15cff6fede5a58e518dd0944f311730959a64850dfdd33cf624936f22371497cbdafeb1eb9c0c0e6bca34fdefe750d5ac26425f7348cc0a575f648542b4a33b5a09ed7c3bfb74a30195d7b8d5fc6dc36a804da096409b3341e3e89bc20247d07e6d3901cb0302b9754e96d44b8149c4ca0bbd9823c7524fe5f04e5209938dfe0053311b2dda620f3a7d2ad7486860d696ef732488faf8b43e4d241d228a7c8b7c1b5cf3197cb0dde996ae214261258864deed841dc68c078b5684bb9dbec8608901ea3e2558fa49c9a40cc3e8c7fb0153353af760564f250ae671c9187aab960ce6be379556ea5049085605402fca08bc733dcedd464b0d7c1720011e70da42f12914c2771210c5bbf9d7320e3733b9b4520001347c3f24fe9dcafc9635616f4944f34d26adb3fb4511ccae5bd2ee69c8764a129399ffde659debd84b287f55b49676469c070eeb11a4d6821c9d9048cf1acd5341272979b56c2b56a8e30295b44dc567cd106afb35f6c5a3db944b0b82a4760a8cb858d1150e5fe5500f0733c53de82ae4be54d2854210f58e18dc98f4061e09944d9c6d1114b3dcfb265da822187d87c85d2c60520962de3423e6452dcc7a4d86a7f884d5469af4d85b2287da2eb977ee869645d01e61d2c5eb9bf7e7df71ba20b422787a67a794de85861d58f60731cda9786f97b9ad4f348691a0f25b28560eefdbde3a9151930d124e27ffeb08e90c908d23651508806cfb1930502268863d7de89fa7fcac47a20e01e7e46d3a0b66972a7b305d176afb3ba66e5d54572d2c81f1c7bda643ba5e223ed4ca5903407ab2fbce04e9b9108f6eb64e8246b3bba4a9744d49753674167a0bc4655f7f8448fee68e1e320fb2e540a9960e720056b9c838e1d7be60c87ca3fde21827b4501e47bb061073390c8e949cf1ba706d545f93f82d33c488f1d90e6b20bdead77016dc7cfd6cecd1622da0a75162cf938f37a40f5a741f1704f43e0dbf1c62081d2fb24844f48947f09362265ba5d50bc17ffe4cd00840655015a8f9cf853099654ee2693a7b4efc22b87d89a89baf126bd1e1bd1a47e0df88f19afb533ff4527d53bfff7032cdf4a9eebba9b8ba44a67b717f97937f2da61090e9af5efcd49c4ebb13b2e69f3897c6189231294d90a829bfe5e0646f842ac2114ec59553921b30c28342503718d7de785db8f489621d6dccb2bebdd2f6d334fd8e1464a8d715554b5674f8b6b8c2c6f64c3223bb8ccaa6eb2bbdde85e92fdd3de4920eb0a046277556554bccb9fd8ab18334f0aa51f0ad5d67f1048c3d5152a378c07a92a02aebaef6e7f801b2ba20351353e29442fdf7c5091e92b4e8dc5e14b80c6dfab2239de15dda2b021b86d4aef2757d0aff0915ea6ad966b2d5081d6dc3345592b948092229e0dd0b847d48422414145eb743c24e17b182006a5325efa286eb179350cfe76754538a8c1abf521234c5c1e66ffb530f9fa1401a5d0d5e34dd2117be7a5add0c40eec2cdd9c6fa750327ef01a9c2db44cba01b38aa5079f69a87cc884f71f48a11a5d1d152f3e9cca4204825fa096006a69347a42ea79bd2cbc9c540673423b94826da5b90bd703a943ccd82a74ca35b3d1987caa2a992de4670fe7c8f40a9367029fda16c73a1435702b48f381d793ec838f14dd2d2fe5d7f455ec373af2c29fa1750e6539b9ba90ac80db9ce984e7d80a67bf8b796b394cc04eb430adacf5385c28e8c61ad9999326d8b51cc3456e65ba14e61bf1d5b38ae9886f2a305fb077485b1274ef4bd74bb74d5577164ef67994c6bc9de7250785d9ae6e9d14ee00274e564eef42597e84eb184180bf96d5cc89d616566dfdf32263624bb4a9c32f6aebc6c0ce1a60a7797dd147b3da172c57e6bf79f365bb4a5735a64a0b16addfac7930e83a6109c3ec25bfd571d6baf9ce4e882de1b6834e0a250ea54ed71ab8997c9b0ff7de5200e6f9a95aa186d0320a8908804b5128850d364a51e0f43660abd1067b3d88fb21e19ae859be2a593cd2aba4304c12a6874bcff317980d8ace3ef452c261c32aec561d2c5446771c3a124e2e513128c2055d34ecd70fdc2aa12f5900ef76036996b6adbec5df3085d3031952b2e71bed8b8099ab5e5a2f8c9d82aca276b42e3f170ea204be64ed424858b38170be276b51cc94f110136a2e9b8c0c025b64b88a959629297e9edd3a607fc891db1200b71cf7d070b164474b467a467efb4692525e4b83e913b38fb71a1d9c238be55522b03b90d807e5516b9517c1dbb3f3c7ff0d1f4cedd10c793eb8f9d58d761751d991d73ad1452db406b20a498e40452fd6e3e628eef65cd8956b1082d7f52bc22ab6d154b801ac622ae64e83b6ccf1a48f0cb0309a3c177e7170ea2197aa6793cbb61f68216b2ee54d2138e96081cbb2d70a1d5705ab1858180dc5686a949edc8758369b9e1938c03dd61e847549e891dad3b5150396103aa0306c8fc40e85882070524b21ec45a1b92e34260f165014cdc27d3838c0dbd686c8b9abacb7fe2fa11bc9297f23645629b2745c947d150bb90e953c27116f1e5f25ab69f8d3a8a01790f094c9023eb285ca3650c7fb2543f572a0187d93426095a1fd4568e7eb283569a8e9908deb29d4faf0c049e33c10947ff48dcd82a1d013daf4df802f644415c51578a3c6c85890cf2e304fac8a3e500ed526ac6f93748e4cf8e684116a34bcdfccd71dcacfa6230a3ec84b5eda2eef3439065716715692ffe41ccadeb7dae434048cbeef839ac20819c974c1f7b6518ff02640fe5ef59ce170cd814ffaeb013edf212f13549a8fefd12ccc7b3077c7fe34a365d29a7f3a5b5024c0769a2c17c45ecb6a4db0a0b2303db6e2cf5e12a384efd62a6a56f61c42a1cd5b44ddc0a321e34242bb969f718da17615dd82fce20d953a3fe7b462aa2d9f37367c0c857f55ba63e18da19b072df8ae22c3c5a75c1b177b5b5b70c4655ff16254bee8fb086194ccc6ad45192cee8988275a553cfb7e11b3f34164c488494797ece918108af92eeea00e5e49c2729c0e62baf0aef8e256cdc36be6308d9d257b3aa072525de74456b36f51533e808392b388665d55359c4f1092b7664fa3178d874e16a5d1db7e2a955d893d98a74130791f1125566ce2411235d35312271efc0859beb707acea4cc00f61cdf44afd6f5123c64c74174cea8db4c3e331122ead50be7a760ebc45e159c9ff47a604812b964463eeeeb1b5d547e927d09823341cea1a1c326afc979d1d8df3caff4828c7081857b2494ec8fd736b5ef8f392086e59d0d308acdcbf40bf66d2b8a15cc65b98c95641225817464a7b5c9826d6d914faded8492d5063390ca4ddb7546da924a49392de94583fdaa8e63e5e40786e79f5983ea115c760a2f206f33cfa090a2ed4be48c5287d7440cda31698f37fbbdf5cd0cbc7760d937582c7fbab00cb779ed343b7117d180393b42b18d60dd67e3a0d8d22044055175d08a6720a31600de996e65523f87ba338c7d0ce9c6e33cd2b039c5ea1bc0cb2655afc14961e9c487e80dd430c249d8004780b24f8c298b4a569998accaddc273a71be397a76b67e0085d47d4fc93fdcd723bbf16302c126d9a9d613d56d24058cccba434354ce583b8a703a68e94de0c519868245cb38916f2f223947c8558deb6ef4a22b5b5d4c0c9ec435625107de16e33202072388552a983048c7024868aafb29a9f72f5a33dee7870bcb530ea0899b088fb1ea1e4234a7e4aa9d39bafe2dc0d597391bf599025502dd2179f1aa0e0c1ba016161d3ac00d8a9db6c558e46a7c52c50b29f676e0f82f6f0c7a251ba563501cad7eccc85f16e103e1de41751fe9894add0277b95a8c686cdedbeff5bd1764c1a201560b3cd7eea42a5cd5220d29f5b098a3707433af149a8774c486a9546d80a00a936ef6abcadb9635f449a40fd918e28318ca0d4aef5e6b43363d5293a2b4bf8f2e801d5cd92ba70012bbc5dd4f49ea08e95aa20a42195985d1a03fa0a1d3a59fe0d603ed68108f4888e5aa60493e03bc9241a9919bc6b6ee2db59513ca3fb2cdaa7aa3460f6a6fb2b1b20818332c37fff9fced7a7158b4b58e444e2868a061e3164bb12df08b512bb29532f08d127712a697c41d81048de6b14ed50de69d3ade22dc6ed7ca08f067789ce009adb8800910062d17a7906decebca02e92b3bacd8331c5699df3b207dcb461c2e6dc6a911e650b383aeff3c3e46434af8b58da7b11dd722d1321f5857eb0323f9470bd5241e1036856b7ef8d64c7b00364113ec924486141f941aeb01819063707361d44810cb06c429f470fd460388dc5841a932901f703fe42dbd7585b791ea667285961203c1674b5481333694b3aed8442713ceea1306fa3166a3883cab6391c450fc971a9989d9262cfdcb9272d4fc76d812eab96c2a0f103db3c38ccaf08b7324c7962ea66a6a42dfdb138267684dfa15b2f111d4959a0dbd19cb4294696356e83dbd7c7923852dc3241e3108d3052b3997db1f27e18da771713782e52548eb825cf114918a515247309c45a1873d982f856e738fde46e45176500fda53f2a0da9b42c26d3ae03a012fd4cfb71b5d8198d46f65667e5d943cb59f4a4a651aee1e0335eef72f3ecb900937d488969c71b25cacf759f50172c8bb31ef815aaeb02cc32e2ff99a6017de40b708b67cf757d2491d296ca24967392e5a6148ccc5f273a0b19cf9e3ee51b6afaebb6f473105a59e0851be0daa5b83cb514ca96a263e877d85ad46c249851905efc1ca1293dc48c3b98ee8ec32171c429a3bf3bdfd5b1669dc315dca1e3837e841dad95aa9eaa7df8435f442b03586b6ba4bcfd2ae8c71c789857d5f6d1635ec0df8065c4335236ea1de9743f3c690a9482289a3140be95a9d6cbfa859c4c54e6910d86e69aa549b469a7a04145f4e5b5f6b52dd533406caa05ed1fad00a4fc3ed9cca03d75ca139f242be908090acef539c73b9c37c8f501f3d5707056bc2228d6b0025414770c3517a1bb96d6170355b7c72db92881b8f832f0554c9ce944e653d82ccf033643a23f62ac614bace8adb1ab7801c9ff3004f1ddc14dfb4e0f2e44297cef77359a11dc439bd1bffc8df0dc43114732a09b83eaf410aecd803ecb7104ee4c9060f8f0acd43497121531f0feeea4612b07d243904fab1712f600c7619129425e964540e20abf04aea8d5178f804928bc9dea17ccfab45cfa264d2e5774fbb06d39c1527fb9113cc6379eb5cf77e9ec82b429d86d55133a279ab750559120b8daf620e4c5818c90fc6d7a40344943afffc0b21e64321a701cb26bf8d949087b0ae64b8c66b40b7480493fb9cd50ce6f459e7a2b0b5b8092d7c9ebe799b01b5e5354637caf989286c319e4f3406419e7e860bd26d381c3b58bd7b0b91fb470b22b04d847038a0f998fa2d3b1c8481b56029a285fa3608dcbe67d97ac44eb9aec6ea3312840722fcc8e0283cedfb516a0e961b5f55d6833e86c0e3d481b58e2e285acdd853acb1361df6599cd823c7e5268a08be1d31a21e065125ee53e136799580285d0e0b644dfac21e7dfeb1c74dabf9a44270f7c7643906f03b756c8296d7a1f13f0af1d60411a8765ca2d5aab4908afddfbfb6fb6a44c916290bd8650b598eccdf8300ce6a326e53dcac5055d855c37b527df06fa0b66019d27a0bdcb0de90c8ab078b01d1da8233267a43a82689b18d2017ea9728bdd71a8ae1992660eadd470dd259449af9556bbdb088deb9f12a0f5a16095cbbf2d3c743f984b064ebf61d57aeef5614bccbe8d0d24461c20717755b9cab282245bf9e91550fd37d351c8ad5dda24e079f64cfeaafe7047e72b01273cdbd5e3348b996b06675b771933133e7932e3a7f9d4e963963659e9d3a03b127a593821d3095ff59cdf9286ab0dc290a43a8e6d9f70398b96e3883c9dc42ad353536ae057527e0da51194ef003305ebf79cce7a880129261ff7820dfeaf040bbb58cc6125eaf5a6a1d117a60641d92802f78111bc76fcdd38bf177fa06f0227b6987de01880d426d9f3c300e5754d10f83695239ca9800a05f826998575ca13e6b66fcc33a5909c9421fe53b449a8b5565f3551812c829f756f4e4f0b862cf5e4f331d8adc70cefd5a68394d9ceee7c32b3bd79124256e97c1b568b81c5ca7c4f2c756b10f8d93a1858c682aaca83cdd02884494986f29df4a9c19431b291e9fe9720ae07f361dc2cb9d952e0b6fb71146140c851593583e3830079f699e529a17486f0efeeaf614f620142ac761eb1bea9d7b5559796f0c49d4490669230c9e54d1c0ebd07070fc8d5b66dd900f1834ca759eec96001a519f6ac1bb93f7c546acd830b0c3ed80dc396b86f06175f254ed06f34ba91e33e45e3734806ea9f6904e19695d44d7bc7e19b195a1522b820fcfbdf8d2f2fcb29187363acf94e9e044fe3c5763ebeb8091a827beb9eb35742a333560b42e82c6a33de5218453430d9f63a50830e4a199e1c4ce9a7b3d7cf08d62a8e67f438833a83caf06aba484b88ed9dc9691e81d60d3760eee52ed36ce0e3b7aae00629f9050b43cb49ea9a76d748474a30121096b978a3628ae99117b34657cc89140b56ab1410a6390ef1a418647d270b997c2c07d68add38ab1f63b41c796390e3027494235b77d55397d2ff9fcd24381a09bc8783017a2d66c29d38e9e7b8de49a0ee3394d622614fa31254be82959dc180c42c6a7fead83954d10c29f25ab1b6d8e66269b4c4a5312ab7f4daa3f4064eb4b2712dc1ee1ecc0a54c8566205b97d74b66e56be280a55f21572c7eb5feb1322e87a8770b5d8955da799bcd19c3d9a37cc00155408b6a34eff03b6f4c753907a178ed079b5a2d102406c6a39b646bd3d5956fe1dd2e20fbf3d880664e34e747ac7ecdea8b6394fb983a678abbe4445a75b528c629e03d58ba29a7a29c03083a1f2522b54fa3afcf9ffdbaff2d30520f6d1efad40ee1fdcfce03eae80986fe9930aacce06947c6e782b90fb07ee9ee5a70b10f72bfd778552fd7ba0ade0eff3e249d78c193badd6124e7065f997582a45a8c78a1787602fc4065a3c4b25e9ec4450c43837f885f8d7d23de614dcc6cb82209194fbc551875b86408043b13798d7dab07af5bbc7ec0a200a4afe718310bb9a0596f8bb8f37818fff86b702727fe786e2f9aa6ca0f45bf7cfd2df3528fe3f3d88cb68091fa9c500e717f2a2fbc9edd89d3d778c3d4b34cd238375d7781596c7d7df902ad3081e697c5c408ac60ffa69ea8d5fc58337dcc196fa6158462dad3e4416a8f84341ad9a4f0df161e99c0658de7d74761d7e7c6ef6ab10d7df7d780b7efe6fba2b90cbc76d704325f53e3b751482d4d2d2984cf95dd24fd24dc98011e2fb455176b435975a0da7d542207ee0fcddde3408c2093fbe7b43c55c55382ed728c5f14e64e3b854e94387b901b0f826e440d7bcf3f95fb67493f8834ef8f22edbed705de81823782cd3cd1ba6108fc33f7b7ffae3d494d22133323b88fef12486918e24d6876118457aa07ade4b2ebb4ca7f657921ae8cedd99c558fbea822942fcd6f12c1c62a5ec2595bf952ed042d60899904a24cd761268b684f661c54d66204a57be035267ae90346753897595da9f99a9892ce38cfe0b00735738b68dcfc001eb0eec0ecf9b5e306d65aea85f7c8a0ce9e2f7e52b4eedace68f6475545c61414e6048b5c269d195395d60ebbab6b9dae3feac8ff2ee6c474aed23dab0fa1caf63be2c72efd41ca9ada4866fd61b9f8a69acf243e0e934cfa85f1c5a686ab69ee4ac42ef8ca8d6ead0cd36f1f7a990277007fa75876c5eda20e4378bd531b637a64ab181668e284fbbc5968a7fbf9b338eb09e04870e0de18b47556cd5e0fc686be731691623c16c0a799bd0e7e80cea2f1ebcf98547a59dae7b0c17c0b153050683874c28b9c41cf9a1e0ee0c2f12508ee25b326db42782989c7c4a152721adf66a5b657c415b24f75c4241e94a0c5410692a1c6dcb405b0003a82145d9a019dfa833ef933a30ea5e186ea731eaba18874ca4f3ae797cacb1a80f3e299a7e60018ee3ac5f648e601ebe779c45e782e57a7dd7285b36da72e349a702888ccd735886c562c67812255f30857dbea9c2a5f22d33427ffc614c4b9069a59e1fc304dca7e61109d097028c2250e18cdd3eb60a66f0f13e276e06597086a85e65d435d83554f164fc206f64c474eb553e8aa2ea3c4d00d475833a6c4cc27172bb6371c66ce542d3f401337b246f6163ae121a123340d6f48c33d62494a9f0521580fc58254bc0954c8f65aa2e5fa1b8f73b8080d5c56e0da1bca737f92f49d548afecfa762131e9a53e5b4c4e9a7617658eff51ec82a5d735fae5cbd4acc43f99d158080cc0199cc9ec0f55a1887c4227aa50661755991c2622374ab9cb064b864e01f47df9cb5aa8900480a46a188658e1d8c707733061eb866ddb32d54fb6d8107e7539f4f5891dfb57cdd6115518ed536700c77637813344f46a1744668eac839dbaeac33b9d1d2fa5910e7eb5d955d9835008f0b890b27a205158d1f5a7f40dd1a3fb82b95d455861b1a5fb1a6e6212a0c7ba23f7d6b411e1558f6ecb68858d6cdd06a5719d9c6012e62f4d58c4a621ce84eb584f990a46c374887c5562f8f09c006f6d099cd3539fc429bc9df40aca78c47d78fc28f1b599b1011dd508f108494f25daad317986a83717e30a644c1f32763ed822a6d2614cadb9c281bc0c8b9a7bd3db81eeff487b9eb3d604486a447b962fa20fe7fc315bbde280d0d36df8e79b67414bc4a3c37706484dd1a26e42708f58a6d4002dc474e8c35a4e3240bf8052219f1871a16fd41296c15d1a9bdb704c0b57ad4f44e3893846bb907653ca7e6d77ba685802b3bcacaca30dedd91c5726b2174ca3b4bb144eaa2f3a71975a826ea7cb349ecb0e4a3d9f64ca3de5d5cbafd33fd3431ee966c742830716cc31a53313d3d4a58ac2380ebafd83996a524c8085316ba3f98239e6c17ee690768bac2946754ff2baa875c34ce6999428dc937283151fb219602d592e2ad6f2a81e4c17e1bd7d5022d376b8a55318e6f783ee9f13872f254c812cf9382ae2702f4ff8c1d853b9e9d7511adb0214aded7184c3b98b2675427d28783cb66228b396f162f0c52f36a961dc4906755273efcc2806939cb6851ce893369a766bac57517c4906fa149c9a926f52f12e2a532cae92e8df99c9bb37aebe9add9474c4dfdc759c02a505eb91bd43a9e96eb0f8305c8a774a501a0ecbca1340160790982b75a8c77052b0ae63d34380e466296ac8bfebef40cd3126382fa634a34d0158c5f6ac52427128aec5e0c03520ccd15d753d91510cc9ea84719321a4db2fb422f3dc9b0b2e1ff409c99ab3fbc2e98007146aa4a75df3547e89aaf2eec18746abee48bce4f33faaa4af8813ac462d654a6cffe07e9b29d944aa338048e7fbdf5caabc9c1e3ee337b3e7764a88a7e15a764bb34d1551aa4903304e19c59df132195a5961ef18f702a2e1612748691e608cf5c9f7740745f5ef68947a64c42a6dbf01d7b61012cab4076f3623cfd7559d7538c5cc45d832d342bf2a50709fbf2fe3b3706793b4748c2871b2fb3a6ece3bae0cb6d92e74031ef75efddc740f4f5d0e5d7aaf4da28886c32a7097efa47456d4b29fbe3f8b37cba70f606e846767f1b7523a57e3fe4f763c741686753064df58e1fe4f7c3aa9d46601df28cfafa5789701d0095c9bcc5918078287b954eb711643c26c2d0de7c427bad7f26598073304d6f2a8dd7b6eaa5ecd9e53c07bf109e814cae3f3df92f7869d2480abad02d017bcbe666bef96badc544fc537672e7bf1c3320b9caab03d6514c095b4dab9e7bbd96df1b254287374ab10b6c7bc1e551938e6f1356ce36bc4c553b6e6daf81bde04067006942733204800988c5c04902d1fff3199e3a6c945aada6413a4f803bc975c398148361c8a222b8a5f0e671e95b4de7ebad098915dcad58719dd2fa4dce4395fc76d909c886decdf649b51f4561046211c33e30e57d07afb39d4dd197b15de9c613864bfdb1d2f20448b7c5eb67eba78e1f88cc4e05fe5d7eb8d08fb72ccd446a933a76f86bf9faa442d2a257d4ad834f6d1d9698e2c012ab63a2e70eaabca808d281771ae44a387d69f827801bea3d5ccaad38bfb09516b459cb7eb3934d14b02ac108ea52e09482f9eacd9a5e5a415652e7b8fe4e551b11507a0f7d7e4dc3e7ddd1e7571ec5083a26a0c33de48d4b8249e8d68449a9354741f76a00ba996d15aa09f8167243c502b1da7e024dd5682de0e49519ebe97471990f2a7717a28de966dbf57c96e4c463fd500dbc1e711ea605fa80afdf7215598d7b2050a90db25b57829357857dd42a449c20860fd8fdbf3159e828ce0f769356806a5a7adc6d169c69dd8ea6be7cc8103d080b4bc94953346dc804fc38438d65b45626fb4d825decdb5a9b232c5cdac23f957c37d524a4d3d616d8f2db6ad553f9e260c46acbc44b3a9ead65688da22e5261d54b5cf12412a4e0f52b7afb34d2c62618c9166227b88138fd06cf158e5a8002067cf1242a87acd9b1642c09981d3113abab179f7d6e76eb2adafe7cacc0ae544a4146b69a3c16836de598586d1eb4c56f95b930a459fbc6ce8272ef9aa8e3d9715506cf6cc6a809f0d532a34fc464f3a4310c30d5f33e6c74e5b2521a5f8599126037ed614380e7196c2cff2103c611342cf2b3d0bbfe644c8375793be0c0136732a34a784d096bdabe41ea8ce441b677c58913f8f8abe32977c826a95a58b90785bfcee7c241d3ff2cf4e7f1474a0638e5b8bab92c7022672622d76c9e01acc3a6762404e4175dc1fa873c7fb36312d48cee3118320614d1a9e5353a27cfcd889aa7f2a09d7e6f6d4fcb98bad99029f16ae006aa275c9a299a3322f9783ebf82512efb2f4f3d5e1d554537a641649e8e36e54be21c808f503c12822c6357ebc72a952119f6bd44cf798a61e223892c2a04ef2490a7e255d4b1c5ff1aa0d9ea4b43d4415367b5c3330b7a85aca9b29c0c79aea6668530d84ee5b6592e51572fed38c0a4eaf639687ed8ef55064ae4f781c5d459209ac7bdfca1d8b6cb6d448f751afa50d2452f9ea2710e9561d30ce9b3fa50053d015c77a6161bcd6750474890aa5b45d0c5b7cc53a2b50729c52e5be8e061c9d007ceeaace74757b4348d7a294089fa3fd11b4cd4f5d6882056375e46de3fd1b49ca295f5249566e26c5516861f2cf5e8307be7edfd7a00fa08a357b3b3833f8c72a415d39a4f313eb294cf2915aabe000e16bd0c25639239bfb2d8794d67994c3ae04466b48f8414d4b5d628949876497e5f07136109c4341f4e96c851672636df644895063acb001121eb4a0508cb4cc41cd6b7ea7d5cf261ba3fbbc701d046e0986e31326ea4c2aa270ef96f4e5ae20c79ce13b40bd5ee3a299777dfab31ff12144511e2ee1a88ce9acf00e3f8f4b8accbbc100c703f5fd2ee8f48deefeae8df3510aea9367d89395ab0040104c2d8c03246ee6c00e3533d7b158a07be9f67c7853e178ec381aff59127cb6c2d9363a96360d871ac0223616c3cc32ed32bfb21c35039081da9576c0b6b2b2cba26ff752edc3cee6797d756b5124224e839781883f2be515be043c2b9b55cf48bccd6aab43444e63ed796e483052ef422bdc323294ab88903d28894dc649e688d6ab7ca423ded7cdc98f2f87c4cea7593b9dfd2a858be029f13a537b16ec8878769aa191816f443a73f23b9cd7d616615ba68ba721764643a4f9c312a98d1140c8bbb80713a4ddc6e26e27bb8b87b3cfb59ad912aaad926a7408f54ae258bcb52fb3bd1282c003fb31057504015ead56c3a3f12217bcb68372d1a9e8a6094ba3d5692062f218f50a4da72ca470371b350ef9ec0e4ad51300e4a31b2137f015f23cf92270943fa12376fa03698088b5057b13fff74a3acfa8140529187a70ee0022a36b862b7dbf67632c150eab57a7752a61c1ef959bbf34677daf34b29407e2a0e5e7924d448a2bf7e6380c4de4c385484f630008c692556554ad6384e855bdd2c19b5f21cac66344c2a9a0979010df2358429cd3e0a996c7d752b79fc307f26028268ce1c69b41dd60fc546861393dd6e5244d462fb947e62f8d97f33c45ac9be40aae37bad84558339f330da5658a097df3a0d224afdf2809b0d959bbebba2e416f09635dfe908eff981a07eb460ea0899c16ca5c548cecb691d0729e6de47d4b0c4da9d2e2b63e5912c2dba8a032b76b8bdd39cef815927d7f8b4f9877d3efbf0445b21848b0775229d3fc23d4dda5cb07d9b25d6c23f371731088e324a8e650bb1301ff776b61fe1673ca991b6bb67906fcb7109bbe3cb56dc9bfb62f51177d6d904f7bb50bc5658c938f6115ec998e7108dcacb70622854ab700da5dfcaa71c4cdd6013bcfaa26919b2cb15f17d2132f0694865f1e5603225227ab7d5c6e1d4dd57a4167d541f176a296aa3b7a903e7575326a7e0467e776b7923aa9f434f7d0e176f5f93c89424da2735d3c83e578773a99db76956cbdf75c48bc99315b326f4e23a1fea8cbbcfbb20d6391909b937a0a6451d01027c4b9b46b37df7a24338260b70fb9a191b92799af25eb3c219338efe0304e6c4aa1015c42f6ab4baeb91ba96a0c5504a3386c857e823423c0d80b62eaa53354ab0ed02e4e6c0953125f98828c2f99fa551267ffb08d99c23294981af9f3cea57ee2a21a9eba5daa68b67b3f441b66f92e3b999e8c043ddbe1089982059a20bdf57ea8211644e8b79bf10753fbdbe252a8ed0f3373903a59b6131fed83f85cd7ea8866b68b6e46426fd98446c5d1039075b3cddebcdd967364a07c2d5d21c5f563b72020a94871b73360f567214d648106984eb3a711e387d9fceabae4809664fb5434f90a3db7501d5ef2605e0b0d19b06a9939eba90dcd4ca7066e1cad597205a3d4f057148d7a0245d18319d8a0fdc423417ae09ea682668010c6aaddfc6a6df0ae09e695929eab477716a87a1a51b3b1617c205884c21f0c5a87383f942c9a81db348b080bb831703384a9128a4be3a9bbe839135b7f1d86159e3548b029abed23c68c0730389d80647eb8b2a6dac5f4ad08bd4f6cf2384265d72d7dfaa68331a3abb244a771b2b0cf7e282e6bfc9223ebb5eb13ca0a288e4f6dae1a7782e42a9ec70d1db9429a7f95ba8a71240deb0ed9a82bfdde25a1251b8b267d482f86d1b6961fb07e310b187e01ace000756cbb51816e786a86521adf045cae247379396d9dd2c1fd31be4ced6fb0913cdc554b386daad1e740226c69cf789ae73e0d221351d8b401ede0895590bd3195f06f17af5b7dc428e6203b19775b65b6e230c5f19db4a2d9e4d62de00ca3399b5db6d883958ecd94a63d14295feeac378e5a3b6829ce3832fd8e51f852ed903ea8d34e779d57b22e4088344cef5c6e4f9ddc643c92488c1c1339394e5c27a29025175dc77a85b6f6dda4e54f7f6431c290844225112ba13e2742160f35e8c9c388486b533e9c82a41e5f9feaaf2ac222d85e7767dadaaec45b1082d50ea122675c4842d3fe96d01d2c7391cc9f98f96ea64fcf6c86b99721893b565a324e546cbad1742fc9cc502a5e187df815733ab74a9843ef264060dcaff0ac72bd610a4662b9f5b0024ac38f9deab2e703e59f1464a7dbe22bd94d0c0eca455aff34e93e884f2d4f78bebf8ea4523b808747448f4ac72b5126d3d4bd1678e0453fe0e8750b1751074cc150e212529c9156b7549738fb103510da79185910615e2194a39ac57323d772479d42bd82654c28a1a037f80038b07f4b207138bb52df434399333503d3d660479652aa9377126653048a2424a818cf709d12b7b577ee716a9d5077b0a88e144166eeafb6de200a9a6d14429ac54cd66c0d95fa9dda4d5563f09cce451e10180f963df0090fb449edf04c2c54c506cefeff8ccbb55eea60b39f5705d1de2c8f2f25f0b44cedef018f13de46e5cba96bd5e93a8824ca1144c64fe991eee156b36260954833ae90dee8df92fd27fb10b67a580ff7069b4f650095055585846ef4083e6c7fe001e290f5ba7970bba973824c3cb75d7834a7cb5021b1b03d75088adeb8cc1a42a3c19edcea0f7dec6ccf81a534f5be7f0e2860ea79e86c0267393fa56a5668d4e4ae89cdc59d5bf8a8650e3a70b970e83ddec1eb8e8d8d9bb4cdbd432e8d0e8104c4a28bd10a69b7e3d7ad273e4de71b0a24ac1a0a6004fad086e5009a41636e6e3ef740b0360a3f297b2bc9307eae71effdbfcde1d4ccedfd02e355e5904f0dac0a23bfb6efe4f90d3ae508538e7d4e4b687ed220413e6c3afa755353cec4639d65a106d291dbf40a9b986193f7278e0f15c644afc76307250ab5c4820c8c5ea290b9795fde5a5e5580651405e8b9238410dbfc28125634910c17b591c9a436f40e682a61be6520740bf423d6dccc5cf68ef84dde2cea9b9c6877eb14cc48587f23f747e160bdc7c49f512ae47a19232c35e168e4585d1217337f75c806f4c4f931151bdbfbf1e1950360fc3b2de747fbd758f0f2db79b94fe138b8bfbc053c4a35612a1f06527029b270c07d316fc5a510fcf8c750bf42450ed6f2ea7f406daca62910bed45547d3630838a2151e51f8d3a0e6837723a9f8931b7b48fec8c95b250e69074d0e31f0e0f36ccc34d2bb0170a67ecc699c266846917411cfc87f559fd3b574888c11465c607113e5206c69c9e8e8a68045b5af40f853405853a73a0d4da887d4561ece9284c56fe2d49fbc87d616692afb3b5201d881aa4f80945e57e416ac7a7ab537454b0454630beda85964b31757e8dacaf9d206562d63f4b12b30235648c00d0901d1b4be8d1224afd8ae4fd3a4eaea786d94b4914e5471e5b8ab838a6a770b12b4cf244ef85cee97c4235452db39acf1316473eb0581e9c55b94e2c511cd7c8d34d3a42fab648832bd7aff5b2bd423748a6c3485e8c3d0c461711d129dd9931046d1b57e78738012b3b0dc1bb8089654df7c079be7b4463efc076e32fc77adc93076da93958eebb49bb29f05730b1154d0be60eb52c8c095e6a9ea4209f542f5227cc2dd3fa96da26302dcdc634a9849fe51722f9f770455847fc8262834713aa6ce320f5c292ea441f1993a8aa5bfeff0f3c955592a2f5fe2bf8aa4009645706c21e12a249148f795ab20c97da0bc06b7c6266db9661506fd39d7ee27e7fac93f412195b71fe5545de081767b029ac1a3187ebbdb0c8a8574591b509d5f296b95ffaf902b3f95eb9c30ffae48cacfaa7198007fa7a4745692f3e13a3156a26dfe16d196baf3952f80623a794e7d34ef7bc8542687841163c347de87ff90e318b15dd944c079c1a8b0809030880f948947a7d66159a3b742f1b7309afaf0538d3c530090e7d10a609bcb543325ef35b201b97aee324a30bec1c527b5c0cda2ee9543d85fb97b543999254ee4b6348e007865b07a32a0ae13bf51f6793df88d5709fe6ded47d300d108bc9bd9ec234a40e37f31c7dc7f9fa76ef365ebd1bc8591af39cd7dc0cf5bd85d36557b97c6a8c15065fe6d0c307e41a2dd6555271410f1cc308706e60727e59c5c7595b2622780dfc02c2e950807e23e0fdfb632bf5e495958ec548bb106e9ed2d3831fc125c31e47ea3b534773ce4a472f7692399bb137aeb78215853841ca21a488796786c63e470e8666bb80cd53a42dd5fee8828c0cbebdeb8da5013ad8bc8cd0269ec2ec1a090786f7da5dec994d70096cb4d1c5997294a38cc8e83f987e17ff37bb138dacd1894fbfa7a54a4ec7f509a52d657e23f968675dfd71c9aac861828e604a9ae1e45c83a59f3384adf9dfefbfdf87813f8f1937fae1c9f7febe6f90ca9634b544e95300d7870270f0d69c31f3a19c5f4d156d99f4a8d5a5aa8867c2ebe80a6469932e16f55a83d94b4e12233c49a4a5d720d3a8fd6556bbc2d7da11143bd212c5ce5c8572b23d48fe21c7cfdcfe185f7213341ac27d29ce87edd81782f4bb20e847d0b53e7c5f98d060b1b3314ac81fbc90cda111d2cdfa80fc5510ca8df371718c73fb7fdcb2bb31f41faed36553b8f044188582031feed1713a831c1c3eaf89e3fa6cd941a7ecc69e8700d3aa48d48071efd360708adbed885784e6780a70ec418ecef7fae785b246fea3f0eafe144de3ca43c233f9004e1b1487920467caba4ce8f91dba0c5c325e12fa86ea31ce480c3e20f6eaabc18ec106b4e9d245398a9bf2676fa34f9374acb41430e4ea55e9311d49feee4c2ee01c4e598320aebb4a2eed5ee097da94bc8a2bdf3755d5d45ef5e23bef5e645d2833b2ca12f510193d0831e4654863809601a1ab65fda51cdaba697f34297ba57d6f816727e4862d4346e4de4a6d9ffff7bb34d293fd9a30b376d6e432e892b03a6797f1fcb5ce057d794795e1e344728342fd33350a191fb02fb475cca7a3008328de3c87fa09bd3826b8b03c334a50dd97ebd72b6e0674663f68a09ab742dba002ddeab618aaade4c602cd2d01a6e62d55c844939ff2e699031e2c7853eced91f507abf9cb589668532e8f2f92869043ba047f7cb6bff7e4e06207307b3c8ca200775ea7fe2b2af42f8b5728361fa972eb1329f549932108e2dc4ba138cadea9ee6994b35bf1ea63fa94cd40f8d0f5e5c2c700f0ac3f86f3b061b8a24654ba92f250ef1a1190a1d7c10cc2751a9aac1803bbfc4597c5c378ac9c8f688e6de00ae8462cf1ac8624ea0b3b30cb9ed0a9692e1ec6a02d8bb8ac0a83d6edfc2c08f50fb781354bd6435e71765fd517683ef0cecdfb674fb8ae2498056f288753e23baf3e3e2ae255699e25dc188dfd7809d198bf08e81ab200b9bb1c5b4bde3cae396eccf6180daf62d37c0a99d0e729859c31c0ad22999c9b5abc9b86a930dc446ccfd02d26c78db61249aad76126d3256723ebf601538464568f7f8150d4d202e75ce4afea0001f236a48ad77414d2bf368544277d1abf877a4f50ddc834d1813f41f2c98a15be14ed60f3863979b57553d4d6314fba928b4882a62735900d55664d36f09e9d5104ad8c30925a0547eeb76980797d1377d171a7a9d29bc4806c42678f1ccf7bb1c9beea2ecd06902efeab589da3a259dbab538b0757236e8568f212759c7429bbabdd58f5411ca74ede10ad1c999072fbdf0aa27d474fc314f1670d71c4f4bc0d51e29d3d233ee5428ae3a18fdf5da333d6440f1084c21430190f40aa2f9d6ff07e7787f5e1c154355c7ad09e3ca82f402bd97d871a3f525bfaba292cc9c5c434b0c4079c28d9d40ff0c43638a3b0348696a2ee33f5c91f66acb9a5600547a5ecea75f28d0710d384554b10706a0fce92ef6fa3907bd69e2875c9678084e800acfdbb5bb2e0a14edb59034ef6c89e7566a3e59e747c60b86a706400dafd733bfb852ee4857bcb1357f55fe4ed4d828717c6f79515f80e2a8619fa89b2d8f6e2a8c779628b2e13b2e281e014d6380254dcb518f799db0680ce46aef97debf4c8532a30147986204b9d57e79beda18999cce0628f35b0c551051c18b61d732566b3f848137b84bf24ae06b5501e2405f8bb9d9d243c87b64d991772dcb6b91db00dedf75d4708648301b11a4c55b3aec383b1f8abe6382017e84fb5665e65ea05de97d8ca19dbe5bac32ff30aa5f2e56430123ecdd3d7590f5e27518dc99b8e160d47479a27e8aea957132e2b097a68c3b207bc867afc193994f5933eb9cc86b4a1aff9999db753f8dd4c1639e7b05f7870fbc799999640bbbe1efda65447b9d7e19cc3f45950f43c8bbce261540f9489fa519e087930bf1359980e4d49f04f0331dbd720e3952dad72193f960d2fe4c8f1fc12f4f3ca55a92ef8694013deba59e98e2f7426e69108b9fecef7ec9d020c9c7ace89319eedbb40c20e6f59d99f0d84202e1bdddacec508cb1c82706e87557448d0762b16c4cda0b078428d0c92f5064aac81ef39d19ffa647310934b140996f396396219b28b60be4ab696123c5988a899e1f0b53ccfbe5ff3200f454d0fbb54994c800f245258bc6c2996abe5d118c271509aebd47f0655ea6477867bcbbd90148ac4d9ae55c0af1ef116fa135aa237c0f3d963ed723ac5dfc5efa2dab53484db4f470bcbeab14158cb484ce97fb2b4104558e56f8ecc0d6ddcbca1eb5ccb50c94a58524f90149f456608c617a4206be4ba05806ce364859adc1e6ca00e9ed7714660e92c4bbb92dcefa23ecafba752182d948322ce3bd522defa33a9eb742acd99fe824eccf30eb377a9d29584dbce68a520d73346208889489b94aac50b84b6862868ea05b0f89f9aca8e6690f6cc823789fa998b50cc1e6f9161659cfc7ead4b382ad3c9888158ff42562a586cef5ea58379795cde259ab5802f98c08660f51737308342c4de5f66b7a5650585d9cc2678124b92506f65a3c7221bba902214c1e449c494d7a8408df06cf1a00cb6e8a0c139947f595c41366eb08041cb43f8a048ad092229d46fc7f47bc3e02afc72f8e7cdeddecc21bd012e248c9753c427f6f8d8f585d2dea8f5f82a381f2159f3f74ae4e8b150d5f0d02084f1230d9613d606a1b9ad308ea42d1e3fef015956532a1280cbcf17c664651df81932d92018e7a5b48fd29f9e9502363d6ae2dc4d2949ac3a22192c266aeaf782e3cfe338713398b2fc4c31376c25637de2a4326e275724202021e2851c6240433d2e4818350ee4527d10e951127b811b06406f3635a0dd2beacc80a746b60fb41758f04a37ac0db7960d389d7e7817dae949ad03621339f0cc5819cd222d3c8cdff30746d4c1a3db5d095127f4eafe6ac633b06acf91ea76c0d3c46fdba23aa987a1fe03d8891fe9df4a0957f205bd63fc34373e60f23105c9a4f39651685368ee3ef89310bddcd1d18b687eded84e88514d2a0f3570ae949e688a304529695bfd5a7cbe6c8097e854edf8d72825064b4b169d76f2fcce2d312ce77a1da4f50ae3d43f98d01d944f9bc50a4cb1a18e869f51ec4e8ef20da27ebc11c279efab2a9c86467f4b6729b77ba69f0de92fe45bd721b7bd3de2f9a208cbacc46c26222144c68c2dbf5dcfd28b709ea89f9310957e96ec9c4f1ccb36f9649723035d602d3f09d0597073e2cbe1ef6f95c0383441b5996f3ef560d0e00a1c816c881de97b816fa6332f50bf3e757020c986f7e3bedea3776c19191e4c4aa5b5432fc96e0bb22c4d984a71ebf32999e139a1118238400b4b81f43fe583c03f763f8fb625b48d156d1f3a470353de907144d1120fff634c7ba6351dcbddf8b3a2c999736e43a4b1d92590462aa3509f306edca70b31eb6da0923fc7e3eb821978491361b9ae99b7fcafac48ab6aa0f833d5510cef8b07f1a3bac68af1b8f94ba5024ae578acea3ce92a957d376268bc48b89c54b9d3450e3a2fba5bc3ee6c649048c2a763ab4fbb1f08414e400e4bd149a09486d3b2d79dae31b3afc85b5d7381dd27de3ab89f2f3473d8e858bf42b79136c57d295d8113d8817ee92907e60ba051024f3e5c3da31fbad772861c8e83b8ae13787c40bc4678ab80f4d67b523adc9e8918786d2e3c0e190e52bc889c4682cc0531cfc9234b904317dd79a7fcc508dca66fdb0fa5df079c33c9efd3c33a17f9ae5d7f9f2f2cba9d72276276b7fc1920b9f79f322b692cf337a23667619c5c09ebf2c2189cd8d7560c5503a3d9b80c6f077d551e3604d4604bfd0c353511e66741c8770f30a43f16cf1a2f502aa94f7f9b837008d1b30d48b4d9cac1919b304447ca1124ac1066add7f2183ea208e628a84e265d3a90ed37e13689c7185514cfc6b1579c4bda6374273c66c913e5011b9a323ab54f681940fbe293bfb6aec812b496f49fe522f45480863e08c11fa9e507119c3531250aa0265d919b6c5fc4d6f49a3778a9802b2d0c1d8cf38a7d28a2c1bce81086ab0745829a5f2777617fae710644c5261f09705623b750036ba5de4f0faab002d66aade928276293c0ccc68989a41ef6d08bf994e8c1b88441ad8fee3810a0432de02936753830536ee655f135c9a878e0ca28f34e7136e1078f83580354e84e8f0054819290d249f06026549682045ee87e79f0e1d2e53edcb3b076b1ac0e65cde9604edb0b7aa49860145f16958059ea65354391bff2ecbfdb783b153409702172ad01124fe923b17da6bc0440b608cc2f2bbf62d1c05516b4b299ea2ce8b4366f0c76defda08b34381474dff0e3a5567059c7a770c238481d3bd90b382371149b9b333f4525d3a224dbd6cf2214cd036f3515b036a9a986c622088dafdda14fbc8b3b24fec80d95f3761c82fb520d281850b240a83ab478b140dd3c71832a10546fbd41c7f1b6a8581189a69d52f907c684cf3a8bc19757f2c3b02805ba2a46798931dd6a12f6e066dc258a9537fa90afa17bdf80ca34b9b48569dd007b0682001fd15d4db96a988bc869ae34fa45cb91d357a3ad71dfd00a3651f7274d4c22ab5830ce04513e74d60c32759233e165ffeefd56bbcc110414a973321d965f6124fea1551562366722b7b60c04106f73a6f886aa05dec5896db07ab03b4b724f06f1b0a137df6159e39169ab2d9888642b11aae07d7b7520a56e7773494cb3c2ed3c87a11216aeb71970176f40098b37b1689165e444664600b0e542ed26566804180d69bcb2916829bf3de4344f50c323d9dd7a6e33d685648c22e837b123e2e4cc63495292d078582e8a9e2db016087cbe5c304beedd177d17d74006e66bcd70301709225dd7ef8870547536609ee7be1e3055ee0f5144f1780028b0f7ac4fe7759f3d3bdcf5c0d7f90084e7bc0a713a5054d00ff3af45f947c8a29cf13861a752c0de8d8862ba49e63b91919a756a4e891c40f625d6970ea86a0e6d9539cfd6e2e490defd3660090e40a43039c31e6baab786bccde4fb1e87e6c4c32bd6203b3665242ad5fb3592b97eec15dd67cf0bb86acb9c352fe2a4f250afd36cba6d69ac55366739e92ea9fba4438856028165e412b3f7e2ea981dfff803947ffb053db628b90715473f6d2cb571f6753c29c3d39fabfd051da9cc7eda8594c1eee844781bd209c7873ec476c644206ac747b1cc9a765ab8a60f452629039e76d02bf2fc4ebe51d54489bd2d9050956ef57d908185d2908d20846513a7340da14cbad11434cd495ca0286c6ff348269ce3f109a60d9b04e451cf0581c6259c494269e17f1f45de7fca1c38251a6b85a2e62dcfb658bfb2486f48630dd9b5de6c98265800f8ccfb9da0b99be952c8a5b24949c535c6071c1c407932358ae6039c0c1038f1f3c4e3079c1e504cf010c0e98f8e0e282cb132c27d81ce0e080c50916178c9c0d8b9c0b4405b2686f3d42481db52f78d5201b701844613a8a7d32931fcb5151534eef630209c6d87b871a7004e325c9ce49729b31826d6c40fe7ff9e4725ee2a7ee5b7776978ae3f40779584c476dc8866043595d0a52a4e2206ade0f368e34cb285761200cfdb6d6072b9a5642405ce094637cde53a9e66cd0865b4506f3f3e547a2b959376c95433e469b01620dedda35c24c21d7ba5ea508a3f71cc7215571ee096ecf0c35ada114ad5283c3a248215ffdc9a461de9d346d4e446bbea633057976cf34ef251c0acd8dfa66d9a6c6914484b306a5caa145868a46ffc11d7850ed61af55c1644e65d96daa2fb1d1416fa2c69829dd324cf60ec479789f6508106cc054e2dc10c262c67923154487312c8a29a094fa14204c4eaddd1f1f7e1c83a667696346b6f07ae7769ba26f79b4357c1f80516eb880e87433aa29bc3f74aee50bbf6b59cde0ccdc34d14623dd2f4ffea8e25df8bfb38f52df0d0037c7c3ef0a0a27e7703dd1b8145c3b2259300f82a9f7d7512bef1d418efe877da86475f08876f45f56a7d76ad976e9502c8895b1aa17baf611bdb924946a2852cee316a237d7eb8996177d1cd042b47387e6753da35a2ce8f14ee2d8fa0ac092011cb702baf3b5625a30122b4a0723971be9d5d0240a5b780cd932c2ac6bf92b4da6cc95935bf080cf7e9112a554ec5977bd0b183db018168000d00108423169fc3879662efd382dd5cdb6e0337048977d0851843d1a21b19b902de5de524a29534a323906ec0546061d2371fbbdbe6342726eec261897d9a3c70829c7e9d3298decd1e77445656ee6665ef1b0b35252b4520284a195922e564aae582991b25242c49295929d222c5703d95bed3074df0e3858ed4003fb03f7f67e08dda13f6e52f9779420eb7ffdb01a1678c4f48f1e3ffa677c00c97eacbdaab57662d34e6bdfb559ff60abd28798103ae7912797fdc109ad6a59754ecbaad5b2bed65a2deba2564edb98664b41603fb5ecad46fa5a89a8d64ea0cb180d7c2d96424ca699206512f13021a41136b7920bb2f9f3efa8311af8b67c25b950ac665a3ab5524fd6f7c9400a964b6520858c3b9f6e33cd6142fac658dfe34f97a9f4d6974ca593a515ab9996529716ed5d12695aecb2b6565b6ba9dada62e5761078415a0f2ae0a12b6dcb14486528b558adb5561415ee897219b6e2a5247f11b3c595df719cc5950c5433b9ab06e85b12a06ffdabb5462bb1fa53ab6f69f3a946b90acfc847cd30955782fc4c632a1e271fc75159d6bd223e910114b1b9b52cc103342e3f2908b7be7da6cf97a9c5a62c117103d19d5af6a4e71e97997929f994fa4ccf0ca9569769a9b5d35ed8fc3a573e40d73ef5fb563e515c6a370e6a0e88ab3010d6622966e7cc48a3519651d942622bae7cc758b0bebeb498f6e69cb35e97b5b38cdbf1183c24809d18b7b6b3b765b0976afb6092b0f3413e01eadc47c33153c029e0144bb2a0a0477d2950ca0da9d0af3cb5eb6b3f4c05ecd60dd55cd69ca492593708dd77a77659b5525aed55eb9ccdd18fd8a3935a9afdaa5d6f69a7aa5d1f4495b686bec5980ad8bd365473f2232624eb13958c4abad1e6a4fda9e1e8e8c423565ca66e2dedd49c7c3027c8b2cb2faf7c7eb77f556b59f52deb7ab9ea75d1afb6d6ab5ed79cf5226157bdaca53f5c713b015cd77fadb55e5fed556bb5ba3edfae97252db7f8a03612197c082b93dace975ba4802d5332a1db9570bbfb2b90a3aa5f21f42ab72b21838f1dc2d1f59628d9bbfc1d85eef21dc2e812f265d1e9524619e3652d7e8d0418751ff008bda90f279511993fcbe994c618298d91da47fb32a3d2b0b70b2cf5647c1f165684ae7f0af3fac6e3b4c30499ff842d16532ae9cb289cdfd118bb931f25744aa3437f59a1befcfaf2a5dbed4505f9324e7ebe135b8184cb5bf7815a6bac96616335f0c1f057be2c7477777e9fecfeaecbaf3ebf32f6c60e55fa5b2b0991c5ccbc093d503bf45c7f1e4ec4ed805c3fe554ffd7a3cef47ba731c4ed4cb8252132ae7f402874e19fa87d4136786d4709b20eb63fd8dc1b40f6be83fd609484c8388ebf58e9d0733be6d6d4773d06180f653a97df7631f262b523044d8840c61e7968e2be150f45dc8ef3c199d049a0dcb74ae2731170df2a872c97b11a095d9bdf4ee8476d721c989bd30c8e2c7ee701cf365854af942b2ecdad5fe1d79a83bd6bb58686ad6b4ceb4670b1ae0323b8f519c20dfb2ee7520df0e601bef4210b34d8d65def0fe35bada3ab1cac5cf8d7d78ed2bf84d00fd297b5ad7228e3c2a718a6a94073afa775db004d478550ae5bd758573bfaae011968eeb56d80e65e7f6d45aeaf81faa50f5b013eb5349e5d44e3db074868a67a3b46c624e748d01234f0a2872b6e24c969c11b4608a3891b48c1828d1e2cba499669e182087413c714518cb16365082f5e0ebaf0c167c5041b33382284141ef8c2a1d99358e9418828528a306309307eb0050e8460060f76e8c20d0fe2676a01041f95840813e4c04b8240520123acb028428d2f76c288e18da138beb8628d2f7000628915943b678a1b425e406103266ee0840c463882834f1223c860e24c94e04055b483b85f03a1c10a4cb005142c68e3ca93a0238048a24a193a51dc042b121cd1c139870eea98477dc83182071c84aa10f2a28b24c830e30992369a70e1460f3fb861a7c83a546bd1cfd9a802872da41842117a70040653dc604191143758a2c3920bdb70028e28dc1842173688f2d8c092640d2a3a597091c579806049c9ba2c48e370ddb378af0666e420082b48c1aa8d23de0bbea00284358aae008216eec3183d700e5d45f3674240838d31ac948103142af8289731400e35108309d00ea808c27b804cc347ba0aae9b9fa25a06ae3d89949a67a89899f7e23663a150747b2ff5527193728b7929b681234b725f501842976f7c1a55416148099a39dc1e84f320e4f1bfe5fbeca5cb20ce31c61863646e6ec76a38061912bd7b0688b7bbbb07dded5f0cc1848dcb649de2df84943865ed23421e4205fd195771fb574320713b2e3e31d4444d744697d1437d4613355119b5d687bd07df8bcf1cb93b135a05057009ef63b884a700139ae37e139ae3081f6a8ff6833020bd785dd7459734b91de9ba05af6b5e8f52f9f46b7c698ce05a42aeed6505f9d76cc3866b3d6541fef5a7fe716d317b945ed7a3924a2bc2eb9af3a2c15f54a01ddd3a3ed17fd7b5751fb85146e8d64fc94429a5949a34243ff5f4a5d3e7f0aa92f554d6497b2a27a62f693baf2afda9b4edbccab4719eb2140af928056a7930086bdf5a6aa975999686e241eb534cc8112c6e345131a98e6bbf926c36a9d5ac8e6b2ba554bec97332632c4ccd6ab56a25253204dc378338945c93860055497baa92265f48c651287abed55ebd2cafae8401affb56576c705dbb71fc1896828e1574582c6b69399dec6c723b0840cfb1ada307404032f8a1c10454f881c14bbdfb5e8a2eb1c20216acb2c8b2caa207484896442291acc63537d95e175643a21629c348d6c4386b49b6629624bfc79459e70d3eb65a1ae9d95a4b237d6335585071a5de8705155ad46b37ee7b7c369a265309c346d6d649c2b8ed9c734a497f6072bb1262762821513c1d45835fac83965aeba213c35e54e83ab517f9756b01cade4bc955a331be22dcebe5db4c4a292be9bab2cf306bc9397afaa3a74fe7244d3aaf524ff6ee5b3121ba7db35373d19a8ea5a043c7e8471fa4477f7a417a345ba864a8bf2c9494f84fca97927e7da1f24d4aebbbe47bf44dfa73a31afd57af69d129e3a8497d33bb8f3e6e2ad785d99fd6c65cf62d2dc604cbc565e33c25ff4aabc53457dbd6ab5e3d1ecd8b188661580d56e7b47f594a29a5965eb606fb4b73e2f2d3053b5d9790ea588d55ea51a273e75bef41d43ab25523bda539c9f134c7bb68487e4ed9d7911d6135a7ec9465d97dab1b84701fe6c44508662dcd47732e1aab7268319e92921f6397afd4665a4c73b27227cd8714197fc71171c30fb000ac20b3be9230dbd97d58ec307aa3aea32e04776e319ca5f9e05a32cb642a61d8e9c26a2c4ba12559d6b22c0bc39e642d914249dd43c9122450b2582154c6edde16a7cc9eb21315d69e32fba815641d449d2015f2c115a420293f353691eeef4e2d7777771a4660cdee28a3131610cfa4ddddfd6d73eda7271c92b1ea01c8079fc0d88894dde08cb62bf4a113ec27f6384e29fb14455aab946bbc22ce82d5b43cc1022f0769f65ba21445c95ed18cdf2245fbc04260ae0b733ea2c79830ada011e97b64415008a2d49acc69a431bf9a6680cc44c6345e794a325173fd50e3556683611b073111a7d17203cf45358a07ead144fa74be8c0ce18b8c1c297db9e2bf58f15f6664969429a492ca8790a70b67a722e4a496466843e40959d68cb2868bf0ac06d2ea91a34525a5fc024ef5cfe00917507270fb0a76c18309e29e20a755e876edc36c9eda0558633a64cbe476a4db98101d3a1c1e2108722e33ea0c7005701fe9cdff213f3ed462841a0c30e03819fd68bbc1d98aae1449abe424ebb8c97d451d43e11e3fc16dd55bf150e572143e217ef59b2b33464a235df120b935c618638c31c618638c31c618638c91c618638c31c618bfce18638c5f2f6ec29ad4fc71f3715c66bed4e4218174e7d6e96cfc643ead1b3731b9c98c52e31aebc60f86bed43a5edeb8097e4d9ae326cdf5331406ea1f1d37e126efae7a58b1cec331e24fa43484181d297f8414638e2ff5b226a54cb1c8cc94eddbb7f3d219b22fdff25b76f61e43a8f379acdc5803318fa8138ffe01e17c54733caa64f3c43d6c02acb2db47e94ca29c218454ba33f3a4f2dde7649e52b2c3c161a3efec256d33c60761842e8ee2512917e1d35c91c645c48d7be01359146366272b72ed0ebf8607d30f3b6adf23c23a82580a4f0cc83132f718b56dce3211cc75dc705c868fe0293c4edc56e2f210dcf360fab1cc50431ddda0733bb6e29dd2f7bc8387ac8718430000f009ad739f9fc870f618e35329f6a2e55c8694b56c319eea98162a99d74a3523cde9c4b8cc4d4cc7c6b00dc75345dcb84c0838d57fe4b60e3f9486789782e0c134ce83e9ef138a52ea7e55684d9631faeb60b901d6e485c98bb6d1ca89d5c09f3d847e850a72c325346b50ce2037f40aba59469ad3c17945416ea8d0ea4ab551d29ff73d00b870b7dfe1e7e8b60610c19379819b04b7df5ff8ff87d19be175ab654b6764fed9a5a13cd5ae0969b957c589f6d5c8416264ef7bb4174c2c71bb179406125af800f14616ef5bf9f05c9f9d2134ac30e28d2b2b24a8fcec80c4135c64f3c9946ca2204691b9dcb74242091748ec5cfe2148e848aaf1e85473533214221064483f9a09b13a420a8e49680163e4e108373e0af12360e3f15f8814750493abddeec88d03238ab86f7504122dee5b19d1c48d41866849f7fd08bbfe5646bc71ed7d6f5f66971f6a1ef0f60bfbfabf77026fcc84878b81d2ac51431ef3f8300ff7d0a6fe84c03750de6238f1309418ac70e07375dcb7c201941b7970e5773eeefbd4fbd1438f93ff725e28f054f452612fff659e927f59dbcf069cd47762ffa95e6c58657d8eaacb6cea57fa3a2f44ae9f7ffddc5e5a60d57c56cdbf7ae8d1047930f2339a192e41c2ef7ac899f48f6e063a4fffe82b05c0d34469b40c1287d2c395df59fac76b1924a395194b5cf9aed33f90c47165e9ca7725fde3ad7890c695ef3d1de15b9591e5ca2fae8431fde3adae1841008ed5e8bc10d95e5a50d11fd95c4fb51cd5686b21ed253eab5e88d8af6fb7339edc1ab69ff897d65726d0aa19a2ac8b747684ae0cb94c0e1116f95e448425eec887453a573ebc32047bdca1cf95df433c2ec32af9fe44473edc81e23d2ef3544fa00005ada01016a22ba594d281ae945fffceb8cc4b0bd66e2ff09fcafe53719e92b28786784ace784acab733778666c6652e99aab1ca6a4dd443d635746daee329a915794a36164fc9bfb626f2945455deaced3ddde4cfc8c36d5fc0d1377e227be20c25cbedec7da97702bf12de33bf08f1fb68e4738780cb5f85e75fd9c110bad0e20d37a0e82054c40a8adc2001144e4c21a3066976fa2266863f66e6b920376a91eed1f58dcbccb7b61c8e631dfaf1f9862773f358e7d1f88dec831a225b52821b1f03f1291a991a376ef1ebcbfb47a1fedeb8cccb8bffa2cb91ccda5e88bc10a1fff3a505ebb716ea5b6f83f5f56da8db8b8b0fd9fcb9d97075333a1460d57c1fad87793c15ffda7827c786753c15f95378b708eac1585a8ca79ea75e88bc8dcef87bf1bdf85eecd6e99e3d91e7d1349607337ffe0cbaf3df0fbfe4a85e6c787c8e2a00ffbcb1dcf9530edd2989ee9458ee9c3a3e3d77f2dcb973e79cad0d612c77f6dce93ea2818f203fc77439994a2d196984d97a7900b4e8e3a9f900d0228fa7e6f340bd683b96c89eeae5519e9aff43a47fc7efd88cfc10d9f12f9b11eaa9f93bb68e3c733bd26fe4670393e83ae96dc7f78fc0014882543b7a7b21b2e3fb77e8d8b8e6e6c7786a8eb0c8fe469f27f323cffcd8337f8716753c359b8828eb22cf9d1f9f4001d2d9e171991cd57cd9237de6cb273f7b7c26d07c82dabab933e56a3e095b47736c9d14baf3234f90cbb06a7ebc0265be041a72d93a79e5b47572c8b47592a8b475124bcbd6c9a26ceba60e69ebdc67b475de836d9df3d8adfbba75a8ab89acad934177d2ad8b4477fef32874e7dc3430834c9da580fbc1c8fff773a3d6b5b4563d3ea11fcdbb32bb925596f618aa39f92e4bb2775f6cf85b2edff9339fa38ae13c2525ca53f28374098cace5c1c0e79f1fb9fb0d4a451cf7ada848e37610b8fccfca7d2b2a84b8ab2a40b7cb6e152897ffc45f291359975dfe812c68b7bf36f6465470dc773fdf9c2fbe47d84c1ed6f4159d61051a65406902860e46d4206308546861058c14a8f8337e1484ffde0fc8d580082c51601005119c34000e121cf941892639e082ad48c30452a2007164e706191861e880890aaa6823057c0ab2ef999f63a7590c52608327569800428718a84e3d644f2a518695c6751d2fbc94ff10d6e994bf6f3a0fc6bff486ce0e8f35fd2dbf4ab79bd7a7051e8c7f18fe61d0b9bdc0b9cc0574c8ad83c00b23bbee480ba75580b8028c2360c1c5132a97c016514820b4451c53de50f9b30eeffc60bbdf56846f67efdfaee9d217d985a3b90549ac0d0a11d871dfea4a19ab219cd8a9efd160efd97abdf7ac6e2c85fe27e46dfc60defbb7fbe329237ccf36f7badfbb9b2d19fcc053a6e822380dfab397c50919450d9e18a33f63a0272414dc44fc49f213d44ab41950382175fa332b3f7ea479782292d19f71e1447bf1f30413d963230c66c2096b5e31cefcddcbe2f6a381cf8f6a7930ccf70d9954cacf5131e471a099eeeeeeeeeeeeee1ef29eeeeeeeeeeeeeeeeeeeeeeee6ed6d54fe940fe6785b301ea58ce2cc53ef99732edf7fff5e0c1697b72e8bb9ef87bcf7de07793fe47dccfb99172411c61943675479af36df2ef3eb6bf373c111605cbeb408fce9b7cbbe3e8fe79af33fadc054ae90d145b9bc129c84eb72cb6c94ccff65d6839ec09884ff9020fe439efcd7dcdb7a6b521719f5f7d13f8698ee5bf95cb9a42d329fa0eb1e634510ff21fe31332ed778909bc9548ca593549f99b1b971196afd3569111a8ad4406bc82e6fef400c54679c815a0368b804203e1304487333b186d8f3a79d61c653fe6f65b0f998f633a24fd2481a66431ffadb6ffb238d55d8fc200d350f500f6497becf00e9546ade6ee6eea851da7edbf4bc5befdc87b930e765d1f96fe329183c882667b81e331f74e5785b4004b98f4aa6f98f46f2e3b8cce95dbefab0ce8e8e91e63cda48894e4a6f538282e3297f5235955c70d14a3c7aecb8fe39665113443d847c9a40993fba2714830c596c5c060810204240804c970703b7d383f153e9d5bf34d671dea975c3f114ce9c917e07726ef6f56b49bb5e6a380f0604fe3cf5d2c2f5a6376d363c551d694f1521abb24cb3980d4f8f8fe340170ac29e906d31c9d452c23293c9a5c5f4279bd2bbb005ff6193213364683d9892dca8bb6826530b7462e236bda5ed642ad376e3a99b2bf3e57c295f4ecd0609f6a54f8036c35a10ebc7f5570033c0e516f360a4b469913c5ab41b9d1e72fbd71c6dcea6e54d9a0d2ddff49636232dd6975c68f94ad29e8a7e562f92f65417ab46368a48aaa4d36572a9246b492e1ae94d1aab4e2eda75d27e4cb392dc1d420821740923162bc93d929e6ada8c648bdb9f31b6688ce5c4bea4805e4f2d271737c11c0f4978a8537a984108a164229d9cde3527f5fde495a455975325413b7d757b82104619a194104208218410c2971142081f4208218451c293cbf48d3e18787a3eb99cde6d307d7572fd09c2ebeb05e15f5332189fc6a7b2bf5b703654a7ef40cef5b719fddc6e485fbf9e4e7fc5096f5ae605860cc0976106f83846205c9de173e1f34effe0993106be092e5c7fda8c98b61722a4ff4b25ad2fb98a55598455c3f1147c8b6930780a4208635b336450743a41a226ae3f1a715cdf6ae8f77246ffe9fe4cb527dde3c7ad83db66e9e5dff9b171ce55ce47cb54994bfb6b83cb5fdb4bbf4af387c5e548e6e2323948787fe6e11e9cca828c27d7c40c3173f38185e34c4f1e60ea50f649d0aecfa13dd549fba140c9051234d357b75cea00ecac808ee64e2b594dcd83f167ad48dfc66c2a0aef0a1234d3730e8d55271a5e733d0396191e16085f11229e45657a591223839a0d92d1d7679d9d191e4de33c1ada53431b6935b2beddc37263fad33366e3426f5cb4194e30bc006d4ab439cfa2bad85099361b4a7fbd1a99bb3037f85451abda5359dfa2613fd29eeaa9e4a5aa8fa461aff2e71d1ec6341c4f79eaa96688f1918423e5c8b66a20818f2407aae2cf215395fe65d897def4ef51ddbb72e332a7f79fc1655cde1fc765489fbd3f0c2ed3f28fe80686172293e8a4f45073727d6b456a98a78e34fa2d9a7d17cd7a527d93f64381a72afd89f459a31e2fa01b5dff8b19e05f2b50d6ff30f91265f710f252946d1381fec15fdc70635c8647370f1e97475b0f066eb44ad6dfa53f69ac32cd8d886751951e56a08c6bce89f5576b3138d9a12aeb4bda4ea6b2181332bad7948cbb5244d2207f6e29bc1b7f478d92cd9f1b77e36ca84aff3024d9f61bca53ad8a1a05b4a7825a0bce86cac2214787beadd75b2a9f0147631d1834a21c9d9b99514eeceb494541e60e24a250a4c626c2911757924c8deaeeeeeeeeeeefbdf3df76efee76d6f8ddddddddddbba5107a34f7982d67dd9d41871bf514aa75b26eefe641adbda4bb286f74db1fa473c00761d6cf7049c68f5a02e1f67220771c34d04942b8bbbba98d8cdba017d51c7477e61940ab47fff038af199f76d4e2b3a4940da594705e301eb9a1efad363ae7a4314618638cd0fd488cf127b56cb56bd4359ca995c211e4c52ff011993da824cd1894390915d1080000005315000020100a86032271583016cb92aa3b14000e76944a68489d4be45990e3380842c6184308210010008c3164866466e80416ba773cca8a910a123aed8099d7a6a1a1f5e9a2caefd10547f0c53326bd9669d177abd12e58a1805aee16baee6834cd8899a9867547602566b7cbba77610a4aad3b35739f25ef1d6e1704d4d8bc3bf25b630f935aa8ace3d97270193b97aea051b3f15b68ca0443558f0d372d04d98b5b792cd8d0c2a4ee7e8d040029dce87fbd8e25be6a149c76cf1ad0337708caf22065f8ec83d5aa0d0bc3191cbb220c180057d7f14f4442cc3ca0d25afb469a23d1585a2a87997dc0734985563960cfeb3fe591aa931ab640487d1d73644b0d5fa52e18ca18308275b91afdf9a7761b4bbdd389008ca78b30a2cd4f0cf159b85392365012bb9a42a023c7273a2cf1b54c37b365e0f2e05698c40cb188ebe93eb1ecf689e44a05b0850a85082ff0829900b89b3acf18a51a44679470d7cd2e43568c9e04e2f48f33fc81398105e9b45ceaa384e5a6091b4c03ace77f8a60fc0b00cdcdd0eebdf000c9e6f7c152c8c799bd3b925e1d9ebec947f1874511fa5d894b0951546bef1b03b00a6db722a8828221bf0dbed43aec3630c0b1a081d60e4419f7e4d28197a936b9d1757fb3f65bb2100b02e410f9674e2ea13c378c8afbd2095d6f4ce583e8697b93c6967eac24a5ec1cc328406df7c4be6598ca762db3c408279430a1001b9793bc4f9ce80903c01cd15de3d0772248866c2a63237b1479445a27c52137436e345d332d9ae4087c5fe558acfec97b2281c2d184dd4a23e642a2ff80538cd9bc5f747b338cd264070461ffe26d2bc7f2fa37dab58f82d6a440efd48be09881eec2a30fe701d1bc5518195051bb9ce5782db825b06704717d80cf690a43b28f9c96d74fe11046abb34734684da6d49035af9f23a86c5c57b14b39a10cc48c22110ae8cbafaecc5dc7612a27a801d847373f54618d582a59426b4914db3ff51b8e110ffa63e766be5522b8bad35a0e1f5635c700175742884aa1203ac54474c2bc5625b055a8130affc319670a68f1d456640fcaeceeda9641322002a88dc38808f147f860170485e11cd7d7b82a89d5a14f3835dbc9e24eeecfd7f530513a62d2a885287488b2b0924af2d4b6e747a87dade6af888b79adb54e790864dcc2cd486d645760d4091f9836188b94fd5caeb7749fcf0c59fcd3b8e5dbae1435b3f7ebdb5b96804c61faa53e7955d706f3dc6c689d704ba3b715c81919b0b70d68b1651a2a3b2a6f933dc28efee651c11825ea34e0821b70d8aaa2aeee67891d8004598ce64db92a119bdc60b2e8d8d6214c9c926af243af52fb89d951bbcb7dc547bc455c5b6f22165d28f9ad07e0682b4de4a623f7202c0a60cc78135d49e911c65bec8b3fddf9074c9247eec07b4cc2eb23081bce0d0750ffbad10e8eb370d4dc35c7c384e8402c9200dc09f6d83e08914551140f99f0ed8cbf9343bcf40e57008c8cd102d4d2f1df465c784a93b8b45ee6ca4302400da97f8f17a1bdb18508ef4e101e1ca3eb40def398a710d4b32747104d4bde8669c5a93296f0b6ad6c9c6760b500981426154b22a35aec97da1f547631a0af68071e4d89809de46b767a367785fbfcf5df51702131a19b6652585b7a53284381c0131a948b1e6e0414bd61b1d2c908991f40c39f6018092510e8630e1be59075c5bc28490a083c34b20f9889bc0201b471188c20d1ec169d00d402c4cd2fb32d00fb576b398e130d2f7dad567ae110a03a3f61cede3d410b3a7a6d202a389f5f761045d07ec075b3dc74e4051ecf5f7b054d5e1decb2e500febb842fa14d387f6392dc671c8ef332e526cc188cb3491cf5ffbede9900b9f0dd6be0c14fc86a377786c077836748dcc4b2108aaa6fee64420bd760b02dc1e0dfbf0bd95ba1c8ed241035b82a1915d7e384fa8244a541e5ed537c2858af95fe28dcc2f49c69179d33bc7548338957d174c8753f99486b88974691aa06843a620df8fa6e2d1ac993fe9c9c4f4b701b0eb391f1ca74d64207c3c0cdc69febd03e2c7e9fd6a9dba2227eacb838a3624a36e9c073f7aa04166fb2d1449ff2333a53fcb975ea967dbda06576db8bd0c9e067c9cb398f04e88618a61bcf4e45e7f88d8e731a6decca7878d79fc7f40bbaac4ba785becd7d370d42d8633e8e65c1bab505bf591f7a1960fb2f5370e763467858e788c76a98cf19b51e7a76a176a0e54d7690a310bfd5851c200a31ea1da53bff9171aa2700f6a3a3d045d83609746e7543eee30e4577a6f0b7520c556d6b4f447bab83c5fd33442e8e36b54878cc37b2b33852ca7acccaf2bba73952da46d6e1fc32b0f1be9be680fc2b8d919893115d9c3e19dc286c995a252142311cd489d33aa29e218f7fe9b372467d4ee0c56695d2e28d113b690a62277253ca9a14980c735e1f55c0a4f8093549bffd04007dd5c50649b3482f78aff29de3337ca21a42e58ea632084a38ef05c5e325b9fc44455bb4934dc8ecf337b441f3e798cdafc447cd2b4887943013e51a2ef35ee42fc40ab86820b1605b1526234856d6172c7751cccbd1e0886094cb0e6458c69ba23900c02b955fd924eb6bbd4c7d035d6e61bef29434e2521f592de80c5d6c2fbb598a65819a0e63e3f0f8257d8e833250140ac84c70d7970f1ba5180e407352eec9102077d182fabee432462242217fef2ff3cc16b1667d0bd7b6fe51994641b367ab7b8bb0b2e7dd385866b473cadd2f0f60ae3d173a86c92767aeea75f2014bd9171893fbeb25c8c8ffad805b73153cf4a8e3ff17d5d9935d7a670c51e9a65b274c85cb5bd31ccde6a0c2de1cb5f839401e423a3a28cae88cf0928ae365d699d4a5f10611733a68adb7dd968ba559e1474b0c1fdabeb8d294fb491e6f7f9101ec8570f85a20de01b88e0da93443e40a2f68e95ab42e5e031805926eceed0f02e6ceb9e3df9afa2113bde87dd3db04c567ab26fe5b3351ba4e79a59f684fd4da3c860e93b73b2efff395ec3539ac6b9fd9f51040490a5cba7bb2bd04f800f29ee6f702867842bc46cd4f7529a4c684eb3504bcfe149f049dbcda0794d72142d624d1d9b57b7b7d840e3e0c537e58791dd73dc4211aaf193e7d8f6f2fde4ce0bc6ecb952704fac66a8837aea4482a6f069fc27007cebd6e5de09d6b8e949b96a6301616fee161ca53d353b0fbeab6c7cdcd3eb167edf4c3904a5376bd16acee134661afb20f1c08f9d99f69d61ebf68d0b005684106a867b903839a4b75b856118ab3e2feede2b6f3f8acd4d502f17a834db098533890739d05d027251486f88cf8b0f106a890a0b14f7f20809f28b9c289eea8f454071498cb5aaa959fd62b7fed2cab5a22b8cd39a11a3ce88b582168c21b0776db6f5f6ebe45a2397480870964b29e9050c470825f7f81c35644ed889a85338454e492d039adc08ce2ecacf2edee9d05c4bd20ee7a0f3b4c4a888bd1b2b7c48edcd6f3d98fb23fc545aa90169dad8b6ce74556faca603a9755e15413aac561ccd5cdc1f577dcc0fe5938a3eb209593e0e4349c7d19187fa21962c785daa1c3b0b946be88f3444e6ab8e55669e1671753e09616ce70f82ced180471984458b05a1762932fd4af3a0a56dc56acdab32e8f7358a518e71861ef9133535fa1e1ce7815975bd204e42803be09c4aaaeb919e45552a92977d79b7a816102c3c822c8aaa8419ebe4760d52f1c6a997240b9a14950155386cb16456c586b0503f12891bec6b59f8a61782dfbde988f1cbe88a1dd4e01adddd82e31d49ea8a28be65b0783c55c246eaf2cb5247e5ffa0fdbfb490fb0803980283dc5e8201cad3ca27a0de494533541297430d527ab74ba9625e21e6b2040bb092e45685ae2d4d927df6410b1009b520c475e8621d3c19e9213a1521f87f7dfa056821a4d653e9087de1816f98a124addadd36dc4987c32d31f9d7efd4557bce65616f9d8e8c11e16b4f02887c4616c558afc957d93d0449d967787aefa8319b42976e4fa9bd94b510a8e700ef7d726add29bce5e2b28ada272b511f69bb32b64912bf486ce756fd7a4d22ccd4ad90a45a26642e5da40049ad6ae0e174de3ea187be6187e74e7a69d1479cdd09509e8e077a3d6edd4115bfb045419535945c3ff311cad603ed5e4979e0ad41e7b56a34de42c86721033a49ab41e8940b9f7f58a0d9e4c90409421b4e77168dcffbd4c0d7fca8ff62813268e290e3ed4e152f715d12ce042c3c4153ab8f99f942df27d918ada63ddd549411caf3479dde8f5411f283bf2e4efa267d6cf05e7a0380cd169d2dc6ca49511760a8d53c91d760ee7b708dc29a3196986538e9316475efa3824339d9756a244e205c95715550b04d40e60abae32392d7f94c5ac45f753b2ff99ccc63c1a36fce4a456202d127aa2fdc87789689b3cb65f6fff05f16ffe3b80d2e458f5ef4c1f11d686bedeed5ec0d9003f1c1179fe835e157ffad96856d5d563fb7cf1a3f6dedb260ade6d42abba0bc30d7086dbfbc1639e7f376f222e0b260278992566ffeb3a3492f231b7474423db39e021a3f684f86397e8ee429232c7fdbded536b713e335eeb7e1ce57ca32710c7e11014e3aaf6cd952d728fbdfd4e938cf2fa40a84c18816602b81376e512e8421c4b83dd0a3d0a62440fcc302a99a0ca25e9f3c34236a6c73e7e15118f89382aaf2cd5e90dcc0d1d03307c44fa1e108fa1356845104facf7418a1b71f0d98101674afb4c03a19bf2fd985f454c74b8190c849c6ce005669f8a28626543007df6c40408aaae8e1cbd13c8d46d7dd5ae9ba0181b94b2556631fa1797ca27d5815948be636a1d25fe137f55b1ba48fcd4fcdef797c4006634c4d2cef77e7fe1f27e1456472808e91b751901982d76c9f227a7cb400c6b0d773c52a8bac428d0e087bb72129f2053b7dca0f83b9e2c0f01066a3d8c5fb903ffbebff46f99921601afc9c411c7447fa4d3192fb034e04ae379c667002ba062dbe75d97731e227fa75ab2299d0616ee5c5bffcbcb040452d5f398496d2de2e5f1f9a1cf7c91701d80ab1bc8e5c48b1e6dc102e0959c0d099b135fd3b036ceb1c4227bff04a575c86099b9983f31bb80ef619cdec4b901771511452d94028b2b7f3e9378506a66aa4662394fd73e00cc2124e4ec954620bde04a009642c9846a88a5eb7b94b290569e499216c14700503523768dc43446ac64ff50b6879b34e08198e3705411713846e21755b8377a38b939f0a9965f2b3434ecb73502d14ad527c35c5f4b32a595a31ccdf2e2e53ac5667984b26e8cd60e6543d9409ef3f3b304d2fdc8e432e8538464efdb9cf1a4556e957f3129afdb9f5628b7ec804cb2176936aba9c29f0d6c7b6ea426fdc852263c6ce5ed613e910b457f1a0725c048968c698a1e4a2d76a3e9594daadaa7ba0111644983c33c21bca64049ba37df4e4f1b26d3f33161ab256257daefd3464dff0f8674d359e4f83404e1fe6e1e77c9798bfd4122e6bda0ac44a72cee254419d5ec6707f80fc1b17e5d0d68c62a9935fcb925792766ff279505a00e3d09f21415fa8c341a9b90682353cd33ce8b0d0d2654ea58bdb5ae59a7601800d801c026835f515908ee7513d2ef272fdf914f42df2ebba5392a6ed079891475cfe7e0b02db858e666fca97d4267fe3b45ba3902f69685f6b510e8a25f188d992f1c7f0b0ac7a333950f8655d6ed70207caa2dd67b94d8b313426beb96554fe3e90ae30cb02670270b5b0915bed1ab295b9cf4a98e08638c8ceb877db8fe1cde210879330664c5f2d21bdb8d4da547e6768134e353bbd73fa5114af3a5915cc184bc00aee354035a6ff66c17920845527251515837d3944640643f3fae48a482f5e3d01aa65366ac3fc367f7974364f609906ef52bbc2d4352e8185f46ab9a255d08915df2e740ed025b70252907f1d00adc10adf0a32e1976292578baa7bd49e58a422e7db7e22160417f06b651756fe9da4e77b18013fb6d44c20e9a5517793b889d877769cc0ee21e23a593ba8d9b49ff532e9fd751d718726123204f0e04b3b44d3ed80d941d7f353d389d69ecf2ddf495891cc8610231b91f0e686f60193c3eb1127bba823b35713a47536e825e79eb3d7a4b76f40ed3f5280aa1e8ba6008d91403ff3f42288a7d0997d58f004438a3a330650251dc902ed82125143af707860c19318345062cc4b55e4bea11210e78116a0b99a5da151e75d63e2ed0122727191f38b8424e3aa093d5570fced718948b264144f8d4f34a287f8c38e6bad850dcc9d999ca45cf73a9904d54905cc5610cf0533952f6145ff1c28f54a01842e4669219f68e374ee20d8754db1a45bb910dd3d24a00cbf570b9337223a2a0525ef2037c0831056a658036afdcd4ddc907925a0d0637805f4b490c26debf633a2198897463872422a6e18ef9d8823eec2302b4ae766042ddb416d2eff4b297368ef80642d516919a3e727dc30bb25feae7b672c7b5650dceee878a8a5b29499fde05e4fc22442182fba691b7c868256f0edbd3ee6fa8bc86cff3c69d74bc566cf6c9ff55e33597f150b6a3cf5a71c6577d0d9d5f476ac7da78b00575b97292c193f640278e070ad47c3d55276b55204988085ccd00505ce6bd55158e300ffc6116e6b58078ece7b02807a1c1d5324ce410baf4be38892f5d45817a39ceeebeef65e5c22f5154b90aff61a8110dfb52530ba8ee9b35a6e2a7f9ad6e50995ce43d2b478036d6da3c10690da0cda60aa08d6b0168932721a15aac7c0f0ac0a30e29c31488eceb15cd35965bf18ef7f97c1bf63e9a137c488aad72f0c9dc7dbf23ba1f16da5d7ccba1daec8a5114577a1aaa4650fb42066a2d4305e81c3e0e1c3ae2d28f993c4e719b1d4cdc71064914057f25abb1892a9d320aa1ec8a2ff3508d925e8f74e2caf32a6565b05ee4c1492f8d58e4a286495b3aa1201a18e715eb372652cc06db225d03b35c9c33a1777c1bbbe8d6017db6312079135233288232730cec5e343f2833d69b5e40d26451e37f40207499ef4a3f66fd0fcaf2434cf88796f2dcb43427e1f8d5c5d4bff9af3064ecc69f1cacde4876786516a48969200f243d5bd6a4f26935ae28d747ee2a1a154c0a53be03d6e2c76f5d451df67f038eba901dd0eeb726cc29c6535eb456ed0e4d12b99631659caa4c612a626c1401a52a511838601123a904fafaef6581e6597ea7e0e91af14bc7f50052e752718d712fd0f9c4d5ce3e1cc65701ec4e2aa3cf9e489113e0b20f556b8ab6689b6097d924d7a8538cc2d5d977b838ed22a4f3f649611a94ca2912432863adaaa6742a8025250f369fec9c61a582d1ee00607941416ba35c1e262f9e2e0e2e92427fe8d79c1f8f9d1250b2a61f8abeb5fc93541d8da8ce5c302bdfc560f23d4f6a6b5de4bb160d6895492649fd591212abe2d20058d998257097a819dfd66a9f0f3f5e0dbe3fe69e68a27bafd10ad1880187238f109b4e91ada0609f9212ce8a0ef76378dee9c47e1adf81372affa1c09d8a6d2f131b5f4647a3b2a6e2c57a1af0401ebfcaadad24aca2f283461261a57eefb86d37e9e565970d476d8411905bbfd8828735882eed310935143a8b3f19c6bdbdd22571f15d3916893a9f044f3b0b01121755393ea3bb243e622d7edd0424966fc4697deb231e370045b914c92b081a86cbd41f039afa0f129aee9742e732ce35b67ffae17b87cc9bc2c2335c25e56bc23af8078307908945ca065b2005e59bde92cbc183bfa2b8ad2214bef7556140dfb80a1efecb7a0ab2d6e164db71b57017df482419ff93635e46c93df165eaa90ddcab8c2d18dd56f92cbdc716b8320b4b4f46756940b6cc3d831026fd8550af547fcff8d5253a40c45aec37af169e9c67fa80371b47dc8766b80c210f08c85325cfd373a7de4136f639f072f020cf4ecae3e0c2aa0f717b5a056a4a2ad3b654cc7a84457191f836087751cdd7f1177829bdae057bd723f6022500fc3b6fd7ce3c82f6982a528e516e7224e94cca24d078b650d166f18be6e6b2bb91330ff2652a58182ee23976014972dd1009f4c52b259ecfa1de875a80ca7a6b0f23441d936f7f3b02569ecf1aaf53097ca2d8c213a9d4559c2fc394339410d4277035ef65ea0954964430f5b37f19302f1092853ee676a3259740021a309b6c022acaceb797644004e8673a102d33818aa1391293104c670a5e9b4acd963ff39179d41d68dae2aa5afcc8c58e8b2e8c2f0b59cb5d6cb3b5fa4fd0ae7f4765200d13c4a9085b41631880051e8219168994f7b24019ecc7d980f81ce8737da9eea67141803cb6655b6b8ce3362b924ec96c7c8f67138a0d329cadc298703c8be74c16970d6dd560bdf0a591f8965caec59acad4d7771767f25179285cca26b5f00beb9d54f458900f4689b639811cc25d8fc422f60a41ed9f5e3d2c70b73d2c16f41a8068dce13c2e154c2cf254881703932e511747e9697489bacde54d945eba7813d5a4084289e1475ea333ba027236c27466af665c8d42cdb6d7e67800c410edcd7bd8f8e1d054eab1f16cf10796d80359e71a06336ac769719ae0d2f30c67a56e42ac895bab5b42e8ece1a4b74a0dd6fc9a8a3f7bc1ef7df493cffbe837e6c3171fd63ea38dec3c5162cece81ff8febd1db558a4188ca64fa930ccc2aaffa402625024b5daca0a081112faeef89dbbc0d58c6190cf2e98f2daaf95d432b3ac0cb7bfcaa07e292a1b0a9cf724d51066c64b2f0bcb14adfc18fc4b6acebf705d79936fb67c00f1f9102df8b0abfe226595e8fa0789040cd535eb26344e5c0512186ff3f850ee6c85b732bf99fa4d1432a68d9d6675efbb36028438e020fbf58d3ec6259e42a5ffb264d73ecc107a3113b89919b6a83c5de243c9216979badb81a238da36b553f181045c1854df11a2914d991a802ea22775b585097c9c84d15efa2a8b0d15403d0289eeeba203fe987804256aac9c697cf01c8ddc9ac22b8d3773011f1b8641f273c03df980361d2b39a038ac2a6d7e3d7744de26bbaa3254ae9bb914a222363cb80d3f50e203ef87158f9c26f80b753222b016ca90305dd78baf95885b096cde572d143173c9080403de7037d5584a09e8fbc7e48d450cfa39bf327db8960a95b197f60de3ab6ca8bd9bdf0239af6da5b0116c4c210cc070a517c340c999a0ac66d30c45cafd206ccf7f7ae66be5f3f599e3edb7e34a26d9fcff563e095ed48b2a3bb68d26a3489612f8856656295c4a59e1293ce556a1b8719bd7936357951fb7a8addce5fe276f4613d1b58eb0b5f68daa2d01d75f55c5f8a89119395d38e75dbbf042fd0c28e78bf9de0249351798007a154c213d7065d5cae7bc815da2c3e898ba1ff70391e65455d339df8d96411918494e258b254e1d8caa00642f4cc8905c07ec2a6e8b8c0559f21b6a969174a26fa8dd8d0da1ce00b4aa0b6b88ce61657df320c7aeb590ceb30cb10fe5919f9496e530aef05c4f0e9178e42d1f70091d40cf295e7c242b3888b6577bb8a3e0399709c6734e7724e1208d63149e498ed45fc51da6dfc3f721413cf47f3ce702550a0ef039da74d90a6ea66049241a1f72ae768b76f4f16a15f40d0b34ba3553d753447d102c4f558ce2b9d668811e0a64c1f43ee048305622bcc1191734cb1236f05aee78a628a73fec30b75c23e4d717c31a67ef8e7370294f23d9d18e4e6ce96d2d25fa03e7e2f74d946be05015d59ba7bfba60ea2dc0a0b775a309c34821b96dfa33bdfc8d3b83257c08a981e872739ed6c50a0d42b75735c7d68099b23d371a247054141af8da56e3ed25131f94fd5bfb9df839dacccad9dfb716d79387b4f615d50a5ca7ab56f97ad69edab58cfb7d47061b8dab184d0c0e7f080802667e6c41a9de4113f9d566d58ae6a0e79837fcfbbf0e216ea5d00f5132ea0e0f7b2a17205d8789ed0151f88e44b1910791369b1c75e75252e1fb1bf344c143f4b91e78af60cec976648e15730663daaf234b5a74d2d12fae8d68a85b7f4b5bd1bd7b98daec098f5b522adf647aa15ac0c4fe8c2b86ad4c42561a2458b5b4606057463887525abc76212d85b36333f51ae86186cd178374e6365583fb156306479376792d0299d6919168aab16ddedf4754e34e2b6ba02635617c99a7b8684dad8ccf84475c590f58262834588c98996751376c58256b736c77b53b4d2cadc447661ccbab2dafbd748781486d5136f1583d657d9583dfd275caf614df15630c6caed9fd01edc4a886aee96621a66ed2204dba0fbdf88d1dacc5e43db2f61747081de647e35cded52ffb84a6d18efee8550548c4eba058439c3c9d9d2261d6c97e4e1b5b7fa7cb6ff9f14352538ea669e0db193225850d3337da62deec72754063a73a9fbccbcabdb465c40a9cb0810f0df49932301c2d714d5165ce72a543103b178749b7c596e73090fc8e367ce3c07e3460301173330124b733ce7b6ba264413226a0766fb59baabfad2666e90fceb954061b17294aad282ceeaaffe9ba9b8bfde08887a296dd328db1afb5f234ba2280982245340cae5a3aeabaacfb14d975c30d91b630fb25e52e0410cc86b79900c510fb1f2cc448feb6317e7c1a61973ab6969f38910948022eebf28b6eb156bdcc1e17ffda2a85f5f4cc25f5b475a25c852e08a371272dffb23affd99dedfb509813544da46453dd0826630e15f5f6920ffad307a51ce97f54805e7413ff8411dbbd56790b26bf5b8b92e32bdde4e924081367ad17ee5693d2db0e2464add6f3842402a204c5371ece985eae7a5822323934868cf9105b017d6f4731cfd0d36b88f1bc5d4738a4157e42ad09903060382b752fb67d31691ae67854127f37c857ba0252f76b77281bf0c7f942d7aadec63a0314f2d3e6bdd25f246ff0aca5544be68500606a2a1b804733d13d07d2edf6660db88de9f244c70d1713b025bcc10cedfefb7faf09cb8eed3ed38c129c352d192f500a5d925903294c5865bc1a4e6ba7c6f790c001c4108d848f3eb06f2e897d7c213f3f598553657707abc79044592239108cb46d3c19bf2e2b805981877733f07bbc6b809d339c3a6d29b59ee9f45e0fa923c15a558504ff470eaa1ca71ea3408b2f39c43b82b6fce09a8045d1f16fc04cce411116d4901fca6a4302d3d9812c5fe779207dea078572e02bb4f5d1c98a816bef1ecc787c3d418d1786bfa7e1afd82dddb0ce1618bf91df4833457b9369beda28315c3ec775753c858a08c9cfa51701c515cc81367860999cf05208246a35398eb71c15f2fb10deac4da8e8ee7eb96d3aac863b8947c36e72c298b2ff870d2e34f647f66242483386f9b4852cf7a1ba66b2bd531a079cdb71d0b6efae68861668736a4f397d905287bd67f02b1412db43b3aa26a5dbe1a31ec36ffcb7682c366923b24f0e962e4e66dc4b9de3540accb05320d1a98a54e8efda3cb78237c752872e14b6f292453e3b3c17c0626d2361a5620102418ebc03bba1c7c21a40aa63908d574014aea9ae602e66f19d2e04d58e378974e38c2c47f793012e0c5c6c282c7955642d95b60021a4967460c2593be881e3584cd1ecfb9cf4ebe862d0acb8ac93b924461ae4e6f9cffae1bb105d590a6ac744e181738c166fe77aa48404056f80aeca60a7b6dc82eb86a037d005ed6ae40f6ea839aedd844eecf80fb3fa56720a00b071f357bb2573ad90227c5d0cfde030fdadcf86073a77d2cb52dc76b5566e945416498e956cfc9b1b7d5e1df3b55565769b55c3977b1b4ffde311daee958138b3bb90c8bd7de2a3e6ab82990e126900268dbb200e772323e63f5e4b7dec0603909d81c59412e9ed9b4032161e1bd530188c6f08042a4d599b5824957a9cf8df6a9c922a7f09c46b2358956c7c1a5926f7df348f5754f69473e2feeb89b0181371b9a37bbebd08ca7c688e2bc2e98eb3378a0ac65b3144337bb6d9c2d82d9ca1c111476ed496206e7dadaf8d4f9f84af1a911b4f25083dc0c495de58449655991fc2e291390584e4e419aa767b5af7d7e798cf8193270b42b3fc6d6023619ebd9ae9d7ad2607ff9262f741fd66452e968b21c6e1ea28e192a619789f0188405d98c570a5c50d8330964839763d90e918d09bf4be5b3bedba12fded01d186593a7668dbff4c98e01c558a4d75bc284ca33ea052030167ed702ab14fe3f784b4216098868a932ef926f2abe774be5d452890b678720cafc7ae7427ddc9ddff9987372298d1c1e48f7ce91a418912959628905acee158a2880209210dae059fee0467d04cac5c4950778e045131af19852597d57faca5d29ad26bd5fb00a0e8318225d4a8e4c33346f01766c4c368152590507e06cd9120a35d7c5e671837681ab6ae22643b217fa3f39a911c98a94a2e845d8fa2176cb83ae618183554269d24965b903b02b4336f94e1736391f40bd14230201acda428168c175e93826c65932804c48cbdc604c99f8d8d001b61d1a76b72408083ef22b8e248c996c793e2f87cae457ecdec234721a209bf8b6e564d537f4ef06915947b1f2bec44c9e1d729394e2feb9c3d443e9401354a6ae9662e006e4a1ff5c26fb08c24d975651d70e98c917a021058ca168c6302af24911abd663b27cc110b319ff3d024d9f576ec58ae25d98e6e46ad105a339902a65fed864585ba5ea90d74f4667d081cab83dae43477df179a85f2b4a8965f9b6704f1b91a56dc8dcea3bce4a4a774f51384fe36ca17506525a61176882e4f5ab5a03a487a896ad12a38f6d135cd18561ed184e77687728d42a25cb58c7981f40a40967d39706972a63344ea2e8cdc2510094e8b9f63045734cdd715e383a89cd28f3a826a7dfa1c20a498c57f2a99a377b53349dd2eff8095cae34cb3d8794d06be70a20a49ca9ced21ee28889efcdd9601ea599131489027d9b6181830a2de5b493fd3e8e419ac61ad50ef56f9daad3a89d2fc5d238e3e7a3f2f38ee22861d7f9abd598c9c344c2cf4c27a4def07e82cc1c6b278e340eccbeeab1bb152feb7a0e7aa3a8e3c3f2525e6ef251d12460816a7042e3b64757eb358ed73700955c28003ce37b09afb93a0a43c1c32e130a5706acd52d18e6637279a9751f8fd35fd48e764f13ba2c65503b9c2aea7f79640a5832a9fb39fe5d3485c1ba4cc1f566416844302d5e3fa4040cfada5ad8767e04f6d47cf763e0ec00ef86515a9129cc5e3f8a3b0d4974d5d99bc5c44a11197c8347faa7fb728eeb63e8d6c8973b610c7711c9692900627c11a25ab1c66b31f6fd9106f8b63c8544373dccc92850cb7283ad3da68c9e7fd2a0fc49706261cb4b9769bf4dcea62500c7a73079cd880281af21336882065a5147fbb15e35e27fdf10b7f4a2f79f793d43a90996e25f1fee351a9d9bfe07516a22e6968e37c4ddcb221448658a35c97e690e6788b01ba372f465582ce6a14a708372d7111787ef4eaa2b62d6a6d836ebf4b44cc20f8ee91db5c412458601365fcfb26931fdccefb2f1f10ddc788d397c0aaac00f29447e4e856aaa57290950e7adadb6a5ba8d8a116e93a0e6d79f8399ec4d9d8a1df7a7236ea113586fc46dfeecef69e4a6a251c7ccae7cb923bb7e5f4bdeef48fe5ebbdc065f584940653660899d6b76a5d6afad00311b0823e7bc659011e2c32f1e4f0bf3688d8769ce302d84512ffe2dda04de31b1033fa8b8773a03f2a6d182c95a0a071d82175ca286cd269c2033cd60617a8244b2708ccd31a1928a0581e9f88aa7db7eeefb38b0f08dd5709241edb967b3944060f826ab9ae02f72025797c6c6b429026d5a793d850bb71932f747cdd26a4622b167979bc335180aacb8f200d43f8d64fcdb918877ed6d3598691ce5c80598cee92554d4e76af5aa45dec98036a99ee7db86f8ba6dde473416a37e98229f89df2ca28b665a2316dde7d7813d536313cff9618b386aa2891a719e80754e4a681195ba94faf0acc64dfc5d8512cdf1111c81f1dea670880a9157417b9248fa2009af795ee15803627ca0922f19638fddad1868c6a63d97653ebd86c34794d796b3cdc9f7f8e59a21f2493eb6c8976fd0b6f5fda0460ddf45a2f60e4919b3a7c0d1ed268b919cac1cbc3bd4b40b666f1228e195756389d724c86c2340e648d84526977f827eb632d956c70334e7b5a428251317a4140a9c9f60ff73c67b5dd5888675245a7ac48316f781daccd766513651fba385b9a970b6f1c4c15ede4fa4f2306205e911dec8e1b48266033b122d770a38c1abc7a46265ab3654ac858154ff0ef58b607ab4fdef6160748b75f24fcb5bdfb64f50c20892af090a5e12b1a2c352a1087e5b0af49e8eb813a3fb83413ec825a53a359c2aca53cca5a4fbfe408e17bf0399fd4999d7dc03ef0e560cfbe96413f31e2f4596f3ab81c72dd35c28b6591f81a951b3beb7646ac91e068bc91391a5e364ee4b819e1635a034640ab2ec7ac50238cfbcb42f8b4c9dc78a63eda5389d34ceb0542f4aac895ad81b584d9a2305bac88ed735983b46b91e23baa36b57d10f02e074830f8ecc3360b94607abb68d58030fb9a62e399bd1e974d72c9712b704a4906f22587fd213c15e73dc058674d06dd4239e3ec5d27563a46a688eb45188c54dff34a6e80ff917cbbaa5f3ab82d9eec8afb5cad1cb5358d0c68570f9ce016075278c18cff7cdef587ac4180624a15c10af295e2db8dcea2d9350683f0f92caa8729c32ee19fa480bf66731637711e9f965bc59c7025c121447cea9c81099c28c9e77188b44097d97c67376bcbb9b09e91b4b19d0b56f184dd640bdb4f2e1f7eb0b0ec8c7eb36fae82024c18f4e7ec5edf70d8915f7dc3514d47e45e9b57cf1e7747b2aa168e195af21aa6facd7b6e6ab75ec0fb1fabc0ca179e271cd2353cc4ab8cffe57b4b8ed6398e09323ffc1a776ee9f32c29d053fd8474f3ec0eaad6fa03e3ceb97fb21b11a18abc43bcb9c2efd456346cdc409f0589d5642b41af9517b212cd65444675bfeabad00567619d9e370cb12a2d3f65f51f69dd99184f1ceb5becb81a30027d10416961fbf8fcdef94c9701e04ee49a117321f454f8655b67552201c8d33e004d1504d372b34e8346250480baa3dfc68183a5de5bb284adcb23c5aee77250e3a54ed4714e58bf26038243f1c2b03449ae9b7ea7accbf49a0dc0daf45023d33d6f303202493b040512afb56727b0bff44d923263fab297ebba14f145215d95201e1772704eb53945f736b569fa2c4e59390dbc4d23be56f4459559f1901273c3951c0e1e92453a2b94b0677d2b95e8aa29308d3248a622344b91842047b7ad028d1f1e5f8a4aa851d0875f785fc53e1c521e0189f85703e537c9cbdc340668315505178b80294449143f09e25bc021a24c48747e5bdf335ad63e9cddb47bbfe029b5e4998c24559bbc07ee629f5a21622bdf32b3ca2fb95faf610473a872300222d98c26b6e705af91584312f522a82fdef33379a2a01e2597e851764ea447475c23a572292702df2c5fab8803c3bdee8267d5f6e011e7b692647f0f3ceb2a74547202dafa2127cf7e48390741307190bcd3b10af12d6d4785d6ed76350ebca35945092ab7b4093f70bdf6557a0392d56c00b340e28624ea90f9032f04bdf34d3dc600f3d1ca77c600615c437b0b4b84edfd342a62edbb1225d7ef8ba39576b11627153b3d7162bf45e82720ffcec2bcd57db6de693fc896a0897e3f50861e784c2dbbb4bc20fb8d088589d42d6f6d4a5902d59f006398d8b80ad4d75d1df72b5217c44e90f83b7fa228cf47133a8b6c968c4e7f3abecb3f335cc179d997f8a21315bea7701933906c3ba34ef2466ee37159dd6cb08cc1decfba9d1206df676cd24e90fa1c68d8f014fb7eac2bddf066fc6ae502aee213a11543f95734bd203c9ee687b0063f6034cd0d7403f398f784a53a1236db51646c026b5f4cfc9599a2b0a6a287f3ad3983a1bbfb522078fd83126e5e941440843baef23a3cd2da639bcbfe5cdc1249d9090f7adfe92a4a1e6bbd73de30e7a412ce5228b03886d516250390a4f8a46d844fac842cb4324b45a460d3f65cd44b3b0d578d64489272c05f5d25288981edd326f57550b3fed941f5b9c45221484204b1d38b991518598fab952e311f97592e55b64fd93ddae40e5d3a1e52ac94557e8c14f6814f786ce6735be0aa5c2fad4d7bade5d27249c14f633f2128a87a5034a4e94cb42f3aa280f61a936b7a7a284163c462749519029c4e10773a3250f590b5dccc1e8aa6d8aa415b9e04bae43c8555819e355ab2ee1e4a4d1ed157304b8da0e3ad0ed362d6b42361d26e1fe3136e6c32dd51361fec25eeed4aa7caafdc98c0b8b070163d907f609698c28b2950abc3083817d7fbb834913d1cfebb00a9651f7a483d3ba6fcbbd96ec7330cf92883e591cb8075c69595d1e64c9fb53da89f3dc9a8b5163ae07a34baee74bf6a519d712fa1735ba1832fa1bbbdf02f4c2253fc69968aef5a2606ce89e3137aed7b0fe3c3c2d44b3716a21802f1a0f5c969e788e691498d4cb6f8517810ecdd00fcc65047aaba1c8af7a7355ddac2b40aeff72588af02295aa34337a33f4b29be99c32c8d170a0593dedc547501d1e8359d3ddf316135c40ae7ef0747e27e9f330d2f30336f2b402d37f0cc7093f72573ca49dde17eb6b6b55b309a2f4dc5b1ac92864022eedfe0cfad6fd1985b4e13624915d95046f15e942a5edf13686671147047e90bdbd53f13e0da5d3e1355159a9dafe3b8d08ac0374d0c3ca7c97b44f64c125aae2b62e9b62c39bb27447f2794fbf957eca1a426efe31f061c6f6dad48f92764789eaa70c96c90052f13f71c86835d088088aa503fb3560a9f6420951838ebfb53301b30bb8d87105b6d766c1ce20ebd576a2ce8e5a35af6ef1076a780be101cc41884ad515104a99f3a6d00a65a83a4ceff06382ae7da0fb0b485adbec2453844a0454a62911be2819f909ce5e97a2c06f9ec1b092c8b813883bc72bd7d83e007d3a0dd06c2069d35b6331795e3b9b55b5fc5c405600b84e8fe2d010911e52a01ef6577f64c8ccc4046d0fa3f0a07cea69de22df78e467737f5827f179bb03afc19361c34f138c920c8997b47603e2879a1fb4eb1fdd72bfac2567ba117ba4b02c619e5cf2149aad4d710986e46283ffc36f16fa3d5d82854d10934471f513362d4f857a3b545af4d984946d4cda931422d6829b162d01dd4510b9b595569ed0b1e34c2ed243d5af0178a7526599afb2eef84c3efdc1c60cacafc9cbdc6bf141ed20fa6ce1399551fea8cdb9e1ec81705e32b20e263a8434e6367b853591acdc158611e9cf771bad81ed87b5eae0541ec148c494b3e58d7d8b9d8f61a9b62181ee39566f19e30b1cd528dc4d41637086cf9ed3157d77895b19a35fc924d7e6cf37308014e1704c5a32aab94381328c98afd7b34dec35b40c49b9d74d957070b9e83c4c66243deef25c07bb6c3da9fdbb114625fa079bd97ac85edca586408ab78d403b99e51efff583951a5f474f8aa01cdbacdccba169cf636d00bfaf84a3dc261ccb785cd0137dad4bb03579264b15cc7b77927fedccfc2494432e7ad2d2e8c6fb96d14c5fbdeea64703ab6f5612c4522f774671b9b8d20c6067853f6c6f69f24100c2be4e73332e8c3495919f34580011b7bdb520d5245fb667197791b0b3fb07fc0c7f32dc67748f758e21532a4d248889008ab0baf228787bbb1746d7725c0380c9cfdb456eb202c61af886462612fcc81617243e161608ef8a6b5e094916dfa40219e66a005fc67256c59067536fc583be4a8a05d8dd14bb1816e0918474f5576fd83cb1e8ef300671adde300b2d72a5fbc425115c2455f4020d12fba9d2e239bc5bfb1e15df054a7edb2be7f83828fe21a124bd9da134a4ef1132ef04d7bc9f1db4bb739c0a55ec30be6031115c0bb0fb505760fd84a72a7754d844902cca46622ca66a78a86298fd3d8f51813747120f085f6830a7b8005177edacb9d4d452672ed1910f02601f97ecc438f53af591cf52409ebc64cb1652fdf6914a3d0c22bfeff8f038421edb049435e849345c87d3472b95f13840012a1632b199bea8d2e952e052067a64094d068dff11a48e14b7f771ebe2159ada3a443d1a321ec9e596191d812ec964d60b2f515faa63d44e0070f31cefb2fdda7246a7c0a750e08aae2521900bfc15b7f8ce1103f10b45d187ed2f8b0c5410a0bc211b03ff3aad1a3837e03d1b848a0d714fb76c12cd76de4de423dbede9c1f8d6bab66b7f984c20ec203bdab674dd5dc89c5c19abcac960b251ed0d517d2a6c208c559b3fd2c970ecf5bcea7373b02ff6eff46257a0e61cff53dc362262c4e3d2d9316e3bfa311637d07aa697bf586572eab7d39b9655c2b0bd376f76272a2d39075797c73a1cb24fa35802d97bd2dc14587d3091aa1b6c8927e443241fefeef640c4c4f4920ff5519fa5256e22d1564fb4cf30663e4c39dfd6ba5e1b1f94e24f9a59f47ff1549e2f21a026f90eb701a94af264087473efb1375a82ab099f323035d7f6d0b8c2647367e7cb4dae485eadbfdcf69ad0518c1cea17210a281b9e4d0444454dc9c79220ae34edd8d796b18ba5f70a40a00e9f4bbd75897d2e25d64eb20ee7f2e26ef3a0e90e84840ed1686faa12a74ed88fdda33a86e6cddd65c57ef5dae8c4f959e2b92dd276a4f0419989c958b1037a99656469d43555368af1eb5afc2fb127f227ce4f10a4e08eab3086f48a4ddaae848279df7807fc7018a3fc05d4279906422a5dcdc5351d86b17a3a1450ba92d10ac5d864fa597c34f001e7beebb75633638fbda52b192b0d302a6dbc8058ad479bef16f200a7b0edb8cb552e6020472a601928db1cd2a87c1d93c95f7431b5ddaa2c8a10ae9363e95d124c53c210ca93cf9b5e8d8d12b82cd4abb5be6c02f4d38bff4c6aeb1a1f83d0bbf61d60af81de4f7b45e2f652a342c730fc58f3b1465d68c86397a2763440a4105761f295ac29cb7948cda094a8b8543f7223378c605e3b22917f4217cd8515ea2d098567b690e236e0951599f228a5da1b917bda799e9492b16bb8d91024906f6d7cd90f167c4bf9f7149918ac33835138588c996c48191fe3c120f0f6a4da9a6c2bda0f9c0082f1fc6081a53b5128a24a6d6d1f80ac25d2f2103b6ee5864d816e75b7724b412ebba1b4dd081d7909e81b02d4f9631c04de74f1950c265d3bc89bad3b198df4f3e97e5ed2019daa31df1169259e4138dc74a06a43f318be7385e2a6cfa1543094456b4e1dc8cb843cd03e9e7ad23b1b4558bacc39c0cd332aa56bb4431ca12d657f7dd0d71582bf20f17d7465f6b6bd45917cb1ad9675e9bf1c469da3ef59459b5afea2953ac72a2f003b5091649b243fc645a55558f8871af60678b6c5f7425e249d17dbd03fda4e5652a9f05edcf9087cf17e7c3f324cac8b594ce2f80f7ecd0bbb5c8f52db0350a9924108a46d06f10246585b899a9931c0169866bbcb74e5556e85640661c37300570a631adab3c4433437970ebabc01cbbfd8e483dc595eed43d8c7443411a200e8304813a12df01ecc1ac20a00fe65f107e38616ec5eb6c72a1b321b2c070d75c76247acd3293a9d463b31820f6f68f005b2f61397b4333d56a876ba2bf4c3628e4b5f6dfc70d94d1b135695ccec1d66aacffbb6f4c64ab5a85866e056a09cd3528f3f6138198a1d1e7443d0eafe4b859392153881303b86396e577bae4faff863b2c935e102b9eb3c29cffe38748be85ad358b11c82b739847412eca04dea31889a04e3da3cfbc784b04d25c0957d9a10f8378825d694a0dbd6d91f4cf765c43f2b8fb123f9e2bdad1b043701496306cf5cd0ca2486f82c7119cf7fadd50835441fb4631753a93b656d83c793f1da48d34f95bce3c3bf60191ac93341d412aca8c2e30e41d74ed5854f7365fecdc5901dbfe4795d7cedb7d654a6040737975961936586605e977b0910083cc8b542f634e904ebdb4646961dc39feb43efa48223c27712c50751bbf9f9b6a1945b75875e57a51af47c4d965379ab5f438f9f5eaeff6a8b9062cea2b337dfccfcc6638fa86ffe4cf0159c524c527880b6121a2883616a96e6a69a128cce1d31a1f21879c658e6762387035766433a010132aa012ec03696ba4a7b5ea987ae0a02cbb666c6e0746fd9a7e423dbe2830e67bbee8377d2268c9f32584ba84fa97fb152df399bffb2fa8b8d39b5da5064ef9bfcb5b630b4de90d8386de66a85a1541f362135c8f20c69a5f25a93213d12c0162bb65b16bbe5e043b13f44c0d09fdb738649c1778c68dbd5b20ba616f5e4a68d2325bdcd70a387689679c72cd69aeb6f8baaa1a18aa153ead868c118dc544904a18614925b67fd26d4893df031f636e9cd225c22cb823962438734ee5515adc9ba585126c6bb5f5bacf7ab9cf0e98120905e66da838676c747cc2a20edd260b0c73381abe460ec1659f14e200abb8dac8302df000113a7f233727520d65c7c2e856d9496c4b4fb954f2c10ed85b8edcd2bbe06020448d3a1e97df5745ca67c135d9bcbee85d3221402ad42b61f3bf3713a67f30b5ae7e04cb9cd373b76b1ae9fdbf240b4de80218024882c710e1255ebfcd2d584af8fd5f3396455facaa2c19bafeb4e7e8787a81b72ee962963a67ad2b55d086136106b12d7842c05bde5aa6409fb10b975d92f4d5cd2b5141f560c6d272d19cc86903ac8246f487f53fd8f6cabc049c7415a7cf4a7237b2021e8acfd11238439ee0a671808966b7622eae6e3a1f827f0735b79a25cdefe901f3cb5e42640427dc92f3672e787a55e2049df9342860815624c0599a4df5797c3ff7d48cda32756a24d0336cd456f9a149733ae3b7de8f7d5d190c252cc3ed6d247eb7db5f18ebf7cf70ea4057c19b97c5b9af0e111cad3b1aea6dec7c61536688926148f7f0c6affd60caef8de219a7afc36866b6fd6e93cdb16063898a8583044b69fb3edcf95077436c7dc555a0ec82717c15ab28ef58f353caa413c86be914f7e64974ae779afe6dd0514a4c103856708104ac8bf172fd2938c38814a77e80bf8c9009f7002bf6017571e509ef9aae85c56be504bf948c80f22c3021b9321ed8c406e0cdf45cfbe709d05b440f4aad8064f12de22b18623de896a372e31c1a136737a0645f39b6fb827ddb5845e9f5bec7015fd8c56111d9cd88acbdb9353d1039c2ac98ebe44658dad5f60e1d77121c92508f1716ac05b52f56dd7ec9a8cfa75433436555daff5578f63ccabe764321b08223cc62fe6f6f1c692a446806576bfd962f47b28996744511ba9cbed3abd25752810ab5c945d57829c86c618ae94860ecddcbda19783610c737f31d11cd9b391f22c95e464ef5f0c9a58c12719d9c8e3efbf9f178eefedeb19bb50a8743f4634e7908cb1c30638ab52caa194dc51e831be9440d3688fc5b8237559a68981e7e7ecfaba68f07385b5f4b2fa86667947c34e83e468fb07af0aaf6fcdaddca69bca2fe3f22c1741bff99070c4eaab0a1c92cd228e46b78fb2ef2ec9723f5f60781c852632b747f5c8c970166318f280a45b46bc6ced8d7c9cf9450fa73b9b6de50715bfcfcd7ecc189b35e1cfacad2081bae54f9805c20da709c06e0b91278b07935c25f9a831211a7ba4fcf852c456a338c873c0e59641cd642aa6c7b670f84376438209b3c79049d3a4ccf0f5f42a5308b94a985c8e936f1a33d120633dd1ccf1092edd108f85757d807f48ab9b1b52bb2ceada1126e1f61e881ca060543ce9c4b2b5acaa8d600ad8604b90575471afc6be3089b94a832386144aa721b5d11a0289838521561d72a8d9028cb22734cfb8c8f6930a7bc9b6874f5f43213dc3d4557590534594f11af324b57ee9df8a56fd1ef4a3eaabfa5858326a76bc1e0dc691c428fdd418930789b254ac2825bab1d0fcc392984835710cb0d92a5fe0cdeffe4420ff61d058584cf11f7f885d4fe8f41da4d4f0a4ac93d490d0dd2687e6e2957a90da1fbd4730c7602a513fdcb878d715d361ec4a4a215050c15d0ea736da88d8429d3a701db3bd1256811a831958d6343046492426e58bc24acd405cd703afafe30a70f056662fa63396f27eb60c80b2a519449b5a0615a819c4b58b361d169466a8f3b328d0fcd8cc5a1cfdfd580846f088b007bdaaad8250a0e0b0b4492d2781f0eaf5216f77956d5f4b06dc4190c9e5f48515d648e2789e4ade91a6a99e6f77a4c2d31d4c0780b54af0a0c94a7232cfee6679119f517a72d604647fe9ffc82d3715e4a9f71f8b059a73f6a7b64e1a8d3f9f39836676a328976fe26fac527ccfaf40725fa139a3901c022a3a7b50f381d80725e4b7b23f5981b9ef3c5424cd81757e52ae966536a3dd7329b4e48e517279818f821941fa028f4504376598a090573548bb9d1736a7b1015d0ea0e00c7496c49310720dc27fe1ce46ea8e241c055d4cfe48d551052e6eb2b77b8df09a06812001a2c34a6483c5895e1a0cd3bbe492a2ea6509bea6a75be43076c1b85411584b1d4470038a63427c5b300eca9a0ebb9e8fa07723e04231693500c25bdf0073172ee4eb7de6998737c1abe1444af97d0da55d0b96d2e1255532a702800260a00ac0208c7cfc127ecd2d7cfc841425c26802e6a26e9ac111ee3c82c2b6ddd6e4de52a69464c507e107ae075dbee312e43b2e68beeba2446846b54c6180f4965a52f8a6cec5c027a8d450d63035949c87927a7fd2674c4a2adbe84736f86374437e7f755f0c9d2e7c9ce0b714cb6e16abef76966b46d3226af8b55abf01f8f07b017d47a9304618b724a071b8fa36f37d4587efbe52f56da3f28dc5c737961fbeb334f9ee2c59be9dba66b418167c27754715c056ac9e19072faf57770f51c20c23e57c77d768b9372b2d3cb373dcc18628446e4d482924c5960451eb6163f3a38d171d907075f789213504825571a300fa7ac1fa8d97362918b28399383b66fd80304d515fe884117365d65dbea5befd012f966d16d7530d817eabdca2cd95a6f2705c90ba1e284697ae199199ab04a4e3d88fcecb73f62f58a303a2470d609dcbb8dd2965c75754aa86a882a6f290f4e03b9e3c717cf8b22117f6d1e3e606675396c9e87e9e2fb9fbc0f70c86385e8236beaf3d56d63767eb9bacc949f9ed7c7279b86de1d0d2db16b37a00c0ea6e284ad9713687434a29639c1e542bb08f1e5b7694e9768c31767777b758b4e3a6572b11bb3ce2ba8cb1e759ffbb3c78ecf628ed36b1cb63978794bdbbbb3ce44b16963dc92d00f4b058cfd1f6287b4ed7065276946382b266a5c36ac95637277bb2e3717d2d9647bb4fc873aa02450418a8204a802a33b3407d613850579e40d5ba0b5413d4125511185dae25a59c1c33d790f8904a9c98b839514d146e4e6538a7caf3f1e6c4a5847ae2e3cd094a14eabf390d1180a48ce4430807c597ae19540613cf9ec21fc0810c0ebac4e932a789e2f21f71c3c302978a8398e86f7406b5c1aaeb5adc94cc3223a7c23ede86d4e19854ff781b9246aaf6e83081d41e2bbd068a44a27e1f6f4364681a62e4aa62f0f136048948a51f6f42e6b495baf3f126e44d6ba9dcebe36d498e947fb80ee358186f43243d0e7e195978316e63923633cb8ddd0e19e796b2bb27b8cc31c61863036231283afb327337f7ec1863f429c3cccc3c4eea7253762d19642f69fdd846fb24255ee2f2cc4ccffc143254c83b9804efc3181a9ce0e6cbd2911f2f8ce1133431840b91365547a07073e18f7d80b08267da26c9df26a727296888ac704310138c68c12cdcda0f1612d6f048fa92c29959b8505b3e5cdb8609576a970a88e7186e1859f0ecdf9722c58740ffb9375114319f0628a0e0030e4a4ee2cc2142410b44a044f93295a4e5d9a5ace0bfef9b02e4bf293ffc678392ffdc73cdf86407789b142bdffa2535641bdb6c1c14ff262535354545c541f19b6a80f32c224f8e956d469d46a21667b2d066b506a5ef867ca89ef3e99ac1c9283e1c800e4d1aed8b62c4c5d328bb5be734b7bc5c4727eb69b71b8376c674fed9809f08ad74a58a68d72fdc47afa0fcd8002e728c9490c4cc933147567268e26acb982857c0749631757a4ee888508c08c0519125363748f962244c950dc091a3060574d42431692c6382a0503702000a181815d363c91983effb899aef33df50a87cfb0555aa8821cccc285c33e4ed0990d71a24684c2bb061921267c668b87449810b4cfc5082c4a61444477c71626b29f856c1b7fb782b68b50810cb8c69400c323626243c4731d141481513384dbc38597a76a12227639e5d4692bfd1b0c40c26d3e504a41daa7286333cd4d675bfdf872f1711cc872b34f8d0c5b3922555c90ecf0e2bf2f1b62487e719969e7da7a8564e810e6e380198a9f5cd77bbcb35a36996a71d3e257a20c927a5ef2cdfdefa7e24c1f22ca64c1223056031616207867be7a0af8234410225aac8113317624c48a21203123360fa4a0e759efd013ce485a961ad2b8392c97ca5b452065ad0b737fde19999999919c90e9f80ef1f6a28eb0b8664e9c5b3fc5c058e165ff454988fb723553ea4577e7dc5c7db11a5f77816565563246aa518b4fec3913fc622faaa29b699aad6cdea5a5330ac5dd77ea7b824904362d97a0b851a7ae0856f37f251635bef19527f3a8f6123fdba177baacbb49495eaaf44d5449c095529fc7a11aa5d8e1659bcd05422f150c8d188f60734ebcd8687aad6db8a87e22c0f0fc55b0c4fbfae5f97494cf4cdd6653347734a7a5262b2f4a409ca53945a0d503c146e1b1b0f85ebe6c643211ff9f50dd9e9a77828e4349f8643e2a1aee28313c2e4c4a4862a5bc2e0f02157e6d7ca871c9aafd5abcfa5d9d44f1db4eec443fcc44ffcc44ffc5483b2f193141f11922164933679e325373c6475656565656575c5b4b5e2a536914d921f1ab1831e034cdbaf83d6239b599c65e0f316f843c3f3168d0ffce9aa595b713429ae897be2acb8ab8ed625754add124da24af4892ed1264aeba0d67bcaf61bb7a97b926a0eaa89e2ec263545f5bbbb57bbbb318e06d5445c5207ad5758dd90a379ed77a1766fbf2bf5bb4bf54bdb69a95f6faaaeeaa92820e0b082125fb07f60d226ed6704399ec4171fb011d9bca4a2d168486c9e6391cdd39824f9487a5212f2b34bcbc4d138256e89a37149d4b6c2855a2dbea8918873181107720d215761dec2fbd4414d2e0bf0ac466f2cc5534d4f3528db0dca26a76e4f55717625d5534d1467711667ccccf49d6dec7cab41f5d6a06ab58621ca6f2cb2ac76a6ca906b928a8be345a0d715eaffc31e7f8f742c11a2843524b44087159fa73a2650198182540a3cdedb9a29ab184cc5430bfe50c51771fb09d69446e9392c32e159aa75b012cc826766e70ac04873e6d9a396672130b19f96dd91770929e6b5c190e44a85abe7f90cc3d233cf330c49cfde4b2d23eca7feabcadfb073c48aafd88506014bb3115ad451222ac722512dcd46103ac12ac98cbd0069c302a8598ed5b1646a3642f7987dcc8065456f273cfa68c46d8dd5ac635e0e338eedc3c04d0d88486235f3d684126c402c6b1817eb49a1c755ec07035c0ecf8819175229a3ad86274db319f38c98b194ae9123478e6c60edb4995ba8776d5172433cca435b5f2716891823eff0280f35d75c732c0604d189f763d402636cbd47ef8fe4e268e2fd3cb31783d8bd13afd777feface43ef3983c8823d830c68f01a45e46966096e146f779f5ecc80f5ee25992548bb62a426d2a7d7d88b3d567609bebef04bb1b29b6326f8d746c9cc342b1ec9800d5bf2f05043f9cb31d6bffca1213df6acaf6e90be1d2a4b8ebb94a6f111a2c22a50f9e32d882a5ee47a3e96bd6e6ae27ce806cd87b4ccc79b9a2d1f7e6a7078efe34d4d945fffeaf7ddff4430ded6387dbcada925200a11627573b3c4dddded8a2cd885b444065ee136656577bad40ed63d58a751c3d3213f4ac5173be51088ee31b3144f49efc8532cdb95daa18a65988e20397395450a1c26179a403242820c67a2bce8f343b540248af1abe5d73588749d2ea90c8614cd54d8b59c9a99f335ccc4d99e3534d0c1273d2e2eefd0a04e6a18e31789281f603e942f2d1ae88087a8835bb5a14cf632f45a63de41d25b2e59b145d3a2ce947e745170a938e61d98a40c1339e7bb013f07ae14cbb6cc2e9b17fa5d70e74bf595fa0d9c80c49422270ce18686a31ae8cc80822a226494dcccd669d460904cf50ed63d58a7b15ec3aafe887b5b735b63c3bfb60801fc00000314277a785c1ecbdd8f66a01fcd80fc6856003f9ac9fc6876003f9a2140458a00c02e78f9d49dafe547b30cfc6816f3a3d900fc6846003f9a19c08f66418e80189552d70f108305c5aa09b298ac83d60d10733835f45f2f40ac88003121a50a34802f0a188bd150a18651ca830e5acf20d6c1ab841a462a15025021001f2509c2085e6f6a18ad960680d826f1a8212c86416c97e88e1aae52d3d32b4e0db7a906c551a9e1d67c7a7c7a7c900c4043f2b9bd90a8e1da765c3baef9cc5e184a65c48d1017ba9b91392dd5b1a9add8527550951cabd85e75d03a9d52c3b5fa655a18dc44cc1483d6998999826c8b7566622a227fe21a0fd5c05578a8b7c41b0b687e9dc3f0503311b3905f5f0ef242d8f4970fd90d0769a726962d33d55d671a27ad018e24a7d8e14520576ab15593d59056cd8a86232c78ada485e6840d12da64fa68f2b1048515c68bd4961b2aed76041d239c1c517504d5112d3e4ab51592b02d990046b26827283589e9ccb866ad4b942d4d34e87064cdab95866835014182e18a17a3b13aa51a80269b8cd0e1a9313521f96060651515446a8716858290385140dc10a1948aaa880956445670a1634971ad091124d28756eb614729891b25ac2e4d685d985c4181ed0a2672251745eb321e4083eaf782dfdb0a53bf9b0288fb75b71a80122d258f058a24ce269205e586a55a2498d8897199915cf4415a4a64762e48242c2593a3fbc2881fa37b0f162f562f46228ed2a51d1636357a739332f3ecbaee05aa33e0c79b113a548be257caef2ed59565a92ed364224f8d65d044365b3ece59a4eff5f1ed315c214e3c44f5f0420f4bbedd7ba0f3ed321f6ef8762114bebd480610dfce8111df37344d7c7b8d0e9abedd831fa47cffa0c4b78f604912104e94767cc75b1a1ebea99e7caf0c9e49b622f9fc0bd4c0150c6d5a50c1882496987506544d4cba582981052b9875d477d3f77677a7e0a1144757802035114397ab21408a9030f22608282198b4dc60f84ea1a66019d1ac7695b7bbb5a51709c9ba25d81359f4f459d79463b3b88ca4ae73118fdde3e83ce454c312264e6a509c64789a623c293bc61c9a4695da11023684965c48c20a446bd389233f61b8b0592def730efc31e25c2ec11f2330943e3befc0703af51fa3f5edf18bf4cb83090efe85f2ba5ba9835c2e70b3fc18ed961fa3dd2e3f467b63f98fd17ed92adb62bd8bdd90cff22977769cdb0137c986ecb7a95b1c6c9c0e9e29948876fc7d547e9fa474bb4b78196917df208e29d4c43abe8e7dddc3b4bacca3bebe6982ffea7c3871e9d99707871a7efb8a329a63553ecc39a77f3ee5bee69cf3357bd60ff67ad5eff59a5f7dddf89c04d93e3b78ea9c5796bdbef78f652f1c93beaa94f2bb580a09935272137c8137be29a532543e66aadc4eb454e0a68d539b1a8b4c9822ae8a084323fb7629625f0b94aca53f3a4efe903d65b70aa067b03c33c61e84684f6a47cd0ed8b1a0bcb9258a16976c21211cc85069f1c0cc755d2787cc930fab106466f8304ac91b1927290c6880468d25c3028bcc910af39e8f37322690a1ed60050424e3e9a6773a6a88813777eeeef40563b096e05c3004fdd2279882f78375f91facc316164bc13286a16220244374b6014acd0993254f55b62932387165bc858aaf1bf8279327319145f4137294bedcba7c74de92e5a3db4ec89973ca6d5a2614ea7641ea5c1d228b88c309385be5a3b3cbee6a8c9413148f9453113e8a58ea11430b43849b9d30351021a4ca7573b37d9bf3792c820892253718f6f74ab0eeb7bcdce64c8ddecddf31b6ef34ee8fc70f2b0f524a8e99dba95ef0f1e685cc921b7cf0720449ed3edebc3045f102c40b8f6f69d6a3a9cb95276476025397ee8d9c5a41cabcd5141f6f2b1419537b5cf0f156c4843834bb5bbe945336ef986edf96f39951e040c59bac50045126178cbb556af3f65133df8424dddb05b455a2a2d16849bbdc76afef52e4f021d077e18aef3c3eed146969f3eb204cd172f59dcbaedb12b10548bfbe2bb43070ce9d4f077f2210bff3196b662eba175d1b7c51ca18e5a987401f637168d6a28c7af41f0c700c3032e3403f9a751c98a349b8262461a486b741d38c81336bb29344263103ea9c3973e6e4c0a482e9f4c39c81cd4e4f202bc4179ece24dd01311147d4f97a7cd16a270ea2cec59a8983a8bf16c6825d24b6a04ec1361259500f2f60aeebc0ee7b11a99d6b839eaf11a64813d5dbe85660430f3c72225111f72392f0d4c3d9c4ab20e600336205f407572fb5da06d5441c150f2d1b7f3555eab36aae20c210817ebb08b0219e823d238a2095037338e06a07da6c041e189468331e5da7ceacc9d27e72ce8fe9d7b1fa4ad4a79b2a1e7239e59e9efabc4d2b187cc279f530a13935a59e4a25a1a46d914d910595b40ea2ce32d450cea13d758ea186120a2abed8a72ea9448ac5070c6bd4c3e498bdea20ea3d45d470d6b867760cf69ef7bd885497ab46e713aa33c0f9ac7510ed251e7f11a92dd7063d9fa34918b9b4b0430c6f8343437b968fe0819935d9710618e19638261eaa4e7d4a8944928718449d5aa95c9e7a8c92871c9ecaab324f7d5ecd5a7cd17aeab386f8a23ea55cd2539f53d4299d95529768a28c23dd3c956c9e7a4f1095070ca90f0faf550751a7b45618cc6a82a1508361d1e421a29ef050e8c3b59aafede979eade8b480d67ad023d1e4a671fe7016bb08c7eb1102010dfa8070ca15f2fd475092641e13c1ed2cf8965d4f3681c96c9a8d0c7596bf15313a170eadcc4e3d4d78a3aa5b5c260eea18c7a74796514b159d541d47962930dcba86c94d60a8339a5bed343e50a720d2ca3de93a552efa5262aa2d57d622a90d4c8e66fc8afc1432ea75ed4444c6b05c3ca03d2e75a13c91834fd837ad9662fcdda4eacb9d644bdc441d429ad94775410023dff62aaeced047613cba8c79a8965b405f65264417dd6c25e7aeab3d694c69a273f9cb5f8b36614d95096b54f3aa19ece5ac7fd70d69e86d014fc80ab156089b8137703cea5943bc4a531d672dffd42ed9e02fb1454314375a7e1b216c77c299b98dfcb8f5b700533e8422e2f732eb4e2e50a9649172c932b5e7a18e365517de92be49c18149f8324e2c4a0f8dc058f633e73a7f1388ee338aec8398ee3b8b07e9c33b62e5b3a37e38c5209d7dd8d84f3384f88d5667ae9a4dc80181ba464e841464d0fb336a2c410689c90004409f6b18595c3001a0616abeb28dd265996c82c4e2e48faf1b5e02925912609a91bab866ee70fed79155cfd7e85f150f882ed070bc2a2acef723f1e5af652d929d2b7ecab292bbed799d7190bf0ec73ef4544aa897ad656553be51de9b4f9f60e441839b6057bbb0d103cf01f097cf01bf43c2bd57d72da16dc2ef9aa83965a2c66e2259609611947169c426415409e2e753daefb56ea734da0438875bec1c84d1ee1069532c79cf3a5097e7a287fd24929083675482cef32fbf26e8cae1096b9999b631369e314c72647855f5243d9af2783c9d663c898c03a0d0cacdb7e1d683dc5be304853c3cfaa89e82f80228b088351da9e418f6e96c1b2e892e33830e429a3424530970b8335e819740b1ec7c85152edb653272a70a9915d2704eb888e5b38540f85b95b0bd74e7b0531b3ccb6532c5470583840ac9086cc53b77b0404892438465c116288a459fb00c587314e36b0404390eec1cb0cd332c3755054466534d2d6dde80e1b333f91c284c422a58ef782d52aa38578b46b744a12d69417e894132696294066e7f113385a9ee1dce0d800878919595932ca3927afd2fa605974ae52d779ce39e776e47a8c8e2f887d233765f7721c578f484195e206478857001fbafc608b12a5e3cbeca884208864d9e2c3132f50683ea276b089fa01b5548b0f2df4860453f3f0c31b245494a849a12a4e6ca28a882e63ae30d17cc4b8012ec6c8c58bfb23a6c05e5258e2bb0509d74e69296069915324ad089cab37dddddd9ec283f2d2ca610cab1b4b0e692896198e60c96e16541ca538363cbb8c382d507d1f6f7190e23c75489ce9d16343cf198f0996f80f989d946166ad2f989452260463d9ce2029a55218b784514ac887716a877c18afe404c15e59856777395572dc3c7b0772e4aca9322aeff3f12627c98c23156ddd6e85b1ecc8e98b54122fdc88706912e73cd57962824a52123da6a8ba213a4a81b0c00410573d78799a35193060aae600a192e44c0b563b5df456e08468a76638522989aa12041147c090e6052b2d48499a618d0d6654e098ab94e95d7b76777727e3a0bb9db6d776d81b9e5dea8a98ac5b288925ac4313575a80450a9014489913068732404c997a93a5559084528a3735394b3cfd784b22860f6543bca2dd8fbe106c9dfe38408db75b1c9a446749686459e7323a767f80835f8222f4272141e7277e48ca6618ed618c31ded8ef70f027e93a974164831d63c7eee1c518e30d7e1cfcd1b745649915112f365113b9df847319bb612437caa6d17cc6c0821b83582260d5486a1242d17f80e38f66d40b61eb3c831c12f51e4d42287a1cad00ce654c3a0d4708a5044e6c8c91e74e8322f077dd49d9cdd94404feaefb952940d91581b96dc1eeed42607fb9e7b885119f86a07f7d727fe77d637f1ac9fd703bb99dff349ab1e5943b33b2e029e7ec25bc68348d248dc6734ec92c39eed9062f36916c9e712c7e538921491bdbac63de1b0d6c500235eb4fc672f49b2255b3113c1a72309298da6c84183118093293deb11c4b9b8d10bbcc24d8844d181315477fcb61b1c8419ed3586419f50b50bc4ec47c623d553a8f748f158bee71b1d895603ee7f45f6c322db14af0ab665becc4bada7f31eec9492824c173ee9120d6be139bef8aedd2d3988cb95c15f8bed50243137c8ce0f7d4431b5f68e3fbce2348c1d81161e0d1b9e69dd004cff9ae1ad78cd8c52acbbc97e0aad91618c42407c5a48c6ca277bb66349b47c13f415e440210b5be8b22d68db13821ec6347515f7c422ba11fbf907121ea4797fef8858c0c3d426e759048d513914846efe4e2cf4f29a53453591fa376f0f061b43510b5fb18b563876729a3767461e243878d84247eec70439a1b535398d41031456748fb60fbc2f800c145099bb98569513bb8bc3e46eda8fd0b4a23243df74dfa4976f95aa1ee6763afaaa4df5e4d991505402cdb9e3e272827b736563c93f1382459d6400d04d432787bc8f9aac99eddcdc1d17b734e191db412f4d086ec6be0d816eb400f7eec8f9e03fb20289d9013fd55c3d1794f89a37be6666666e6a2a28f5e54821781e68cdc94dd41ddafcab2fdb8ed8fe3e6765ca572fa8b52184c760d7e2f8e6b9e3b92997ef3e7ae8cccfa1e1dd779ec0583510ad6d7d70d7321d4715e6924a271ba90605196ddd88a9105ab0700bb92e970f2ab924a90b2ac05a083f449bf3959cd8c18ca97dbd1199265dddc273be79c7633c6ed1d6eb240e35545484a6943e87783889d2f483b191dc4711c7b005e5d0ce6208c650cebbce561d7759dd7a26dd1751dac76d459b1d8750bf8900371ac9014a51d114581376784c1fc6246de167148ca86c12f9d97a594b2999b8dfc525b1fa3760ce939270db5e763d40ea41ef5fb18a5e38ad754d7c7281d6daaf49cb3d3d49d8f513a7e00b21ac282476977c3605edf16b18e06e48c73ce094a8eeb6d119dcb70bb32ec4e094a221646279da7a97627e88ea26b16a1944a2a297768d2c78242430bc292fa75109494f9f5281d5232905134237dab731b924bf5aced5cf02250486db5488852995213edd506b553ba5736107889f6d19d916ab857539a16465b6d8ba5ee2a1d54668d4464d1bec4e5c3a974e49b675c5b2d0c0eecab4622be58b097882cda2fc0b31628ab949a48c28941edad9756dba21dc9e4f13d952413df53e95bd29a0c8944dc540bdf1c926faec93727c5ca735cbeb91cbe3ba80e6a87d1d8297d7749b3b9a96fef25fa6a61c434dc517d7b57a786b2eabb25a826eaa862507b15b5faf6eeeadb690d3ba82e4d64d15d53c7c4b2f6b04bf3edddd2b7cbaa26a2b456186cc170a5aabe5df288443862d0d5c2e8406cc1441caa1387b6e39c5f0f1905df4b7cafcf98e5c3f531c583c80204966d15cf685f16239619041b2c8b23bc9ed4751cfbcd810e4297fd9c73ced9dd2ddba71c92cd0c63ce9eed0de2a01406631d4c987c2fa69499999999b95f10a815067bbdfcc57cab0cba60593ba96dab51ca5a3bcbda35a317268096c19c22854f931aa620aaf1057be7d3bb988a13aa741529d4199cb77fee792a80d496bb58df812e154aa61f7d651905919c764021dfc0155b8f31c6096478d8812145928146b4fd6c8551ea67c87aba2e096c120f753e17e9a7535f241ea23e777c48c116f801cbe524605fda77eb23d646df07497e7244dbac049f97c0f3a53d8db32fc6eec5b683a6bb622074d0f42fa662490d21d6f90fa6ab58aa3ed7bf559a4f3c761527d476154a75864797af02480de54bd687a17c30556aeffa08e6862d3b3eec400a7e9084042d8fb6e75c06eff8f8e197836704598585052db326fc63f47d90a4042c8fb6a73d9a84a0c17fd08a253509418375d606d1b64a4c43cf397fd4e1f1a456380d4567cd0d74e8d0998189a8ae8f373a2e7c280474021d203cea893926d49d373baab7462e55eac3914ac94ca77ac206a7a29841ea68a2085413495a6acfc7db9c16483273aa2696395352739e96b04d406e7bbfce3de7a452793ededea0f950e8f6260c5fbdd9f2ebfca5be84e63475500a0c3ede8ea0f3f24398adbbbb239a97b248ce29a57c49067af68065cd1c60593f77777777472c1d2985c1b8bbf91b0c4390dbc382176eecc7e8c6cec7047c04d7a59452b6bbbe37b82fc03378e36771cc971ccaa3e92c39db8fa4117b57ee6fe0989f8265f1c788bf1bf219dc7de37931323348c3d807fdbae775b794ed452c8b2ee9773f63f863b43fbf9f9d7987dda5b2398e4a17db22767777cbbabb2b7211c6f8c801d33a440a18afd816b1bbdb394ed228dbfbc3a36f3006cba2bbd6781128dcc8cd75b4e57d3b3c3c95524a25ab250b6b3c27a3acf3bacdc1922b3e6fa7877e2eae737d45266bd2094adaea58b4fa7c2ecef515a1563a345c34ea6ff77c7c4e7cdcdc95ed9c27e42a795c94e66c6eaea3adcf73edecb866b4f37c2b5e2e62b03a584a5dd6510946564ca8035778b3e532eaba2572e0353bacca581d7c67e4cf8151c641eccca2741af58b48ed7a602b62b8479675100b1d88e24a95c938596c31a7f47abe39244fb866b443a0e7652b84a2accef17cbe183c2495865009a34274e9ae108d464bdadddddd5d25d0fcee2ee5982081891c7efdc6441018918d5462889f73892a301ab385f10f57b480ca15906faf6f60b5ef2bab6f9729518596f1a6c79701a052a8d46d37453974886a0000080093150020200c0c06040271402c1c4982b47714000d6b8a3c745a3817c963618c8230886120c6180080018410830c4086a11bea00b7b6d100ecb5d41b9e69773df172174da068e6612b42dca2455097869603fe2bce9987a4d962c34dd8a98cc20013ea3163bccd48bc08978aef066ca02f5b558ddae90b7f8efb19e57d01b66df5a393d9430fbaabc25f040562a93a3a47d0ce9784276040b34328a845d478fd0e316149862f26aadc9f4e3e52f10eb64f6e64a3896985b6ca42df145a8be8ab4a9c2453ff6e48b8782da7597c7581d45bfee54f4fbdc8103ca3ec6bab8679db029646aa6ed2521e6312f4fcc5b1624e3b834c125e60b4c43160483fff9edba71b597097917152bd05127243f5972a2d0244262935f49fca9b1d84359c4e4bad80eabf0ba8cfbc6f6136cf7b7f3db9a73426702196784bff1443e4377bb42db5f2acf3a411cc32eef8ce5383ec39d226d61e0cd406760dd5486c82128cd6d0621ad4cd41ba33d542cbb0d2084c0962a1e6ac174d18f115bbb60fc94865668e6b7ba63fc519ac973d1daaed035ce000c918c02a5ba04f3347bfa7d9792daf5dc5d402077e3e3c2f9ccde1cfb894567fee2a9a422cdb88de3150b6fe1c8e79949ddb3b63ca39d6caf54f8302c291152314f96dc985892020fa98ae290ed1b8c4010abe645028609ffb12aca734175d9c801b5f4c4859944846244de48336a91193631e792959f2d7350f6c12d28911f187a78e9eb7d7aa66a01883043c6a25bc60421d3bc1f907f93730784a3fe9dc9a97b1db24fd7f8e455d58ef603804f7933c4b2290090cb8359db3aec3656b62f1493425845532f730ea88c250d76388c060a8b50425661428e8592ebb2541bfa963419b8791bb150a6e0443a4a379f234a90ae8416ccc5c24d00881d8cebb22f0094ac1836af7a532138083eae37e7971a1e12beba799f7b731921ac19ef3f5327b0040d01f19c7df84cfb05d33b9c45080d3fe6ef8c5d6265e4aac1e709ad1ced81642045264895884c5f242502b706bf2e85df22a2a7f74f06286460efe66b0244db37e60c043d6a80f705963fdd22a53bfddea0b0003a1ef6c59a2ac14c52a523a771a80b16fe3da904bb04dc89f676d120a9711c56e02cbea80f669360603ee6e5add3c71c010424eac04a990e000da1bd4aec0aa9a333ee33f558fd2ce87c6b26bce074b70bf0138431b69e53e8ef15f04a6c18d3544981e84428710ecdcb7e00ec7946708d1c0bdf52a4e551c39838aaaa29164690f3408a5df4a8a84ac74977b93bc7e5897526b35808664691a44c81ba42111d2f9dbc07d9266e7ac7af9451461a540c98f50346c6f33db9edd9a27057dfcfb3dd4a821cbee1d1245e48b0e6d87b019bb3bc7d65a0ef8a81cc80b85626698188f62bd586c8b41aa3acbca6b25b46870a8c12c081e72de711d1f34626609aa095ee75995fca063828b3a9aefa0dd96bcc1764e51f30b9e40addc69bfc4e9519c08f7720cb582e6b2383b8fab5885e7fe482520edb15bf8c2d88b368437c3c64cc2f4995c55b06010d3d00fea67170cd9916c5bd7ea935c1aa754854235e8786e7f3eb99389f8f1ff051ea03f7db2ad0066060fe0a0748ce7915d83e25512874901b6e975783cedf31cba0fd731d957fe1c4f40ef766ca10ec143bde0623deccc2b870d998ddeda5ab6b6dc7bd176e9c62948d38e09c01cbf5caacc0ee79b0c1615f2cef981ee77bb5a81d939d30aacb59ece0e6b1ae9c4d256d38839d7deead2d7a4cf735dd00e07a25f21300366fe28bad09633ce5ecb234494c3f85ceca223afdb8350b12720a6e841b25f59bf04b34e0947b7aef475c924583428fe6fcd60e48c5d71f0e32951ae2a66d487443a5dc9e3d366f3740995351968cc7c06bf8a6c917f7fa17655c3004d321bcbe240fd1ec4e7c5a995a4a2b2b276821c0949d48e30b57c150b47e3c0802388d91bd2d799cdc689270f99b59f88cc8329fc811a4780810896a050ae3a61b74502aa9ae6f7268a3237353788423c9f6ab6a5526649f60df0d183c192f04c3dceb78494a4f4ff1012e71e89d7816c18b7d42bcfb91ed32e287ae1c8b7221c0680521c40b4e9c6e9a4840d007a8cb90a177b9d347801e2431fe1b2314bfe009f4b7bb159437a65c0263cbbfdce5b1997a93cded6b2996305d3d7b1f0c396200aa74d48200cf4656d0f2c202f409bf1397faa0ef4ab448f86cafa48ecc4e4783580aca8ce992382a6e1831829a556517f8e7da9514c0c5136c870de812204590b27a792b2a84582fb0f1a76dae1226df4caf91e50e6d37e01ad5b4e8837c05fab88462044a603b10bc9e7d467cc641c89284e253c08eb7e3e307cf993811f971810e058557baf773bc74a3c20e9ec282d6514aef1ae2490d008926b691c111a5160ab9d5ab87a050d2d424d0bcad7eb3d2a9286c17f06692dc41e6e4206bfb15fd123067fda0c9d95949e80327c4dfe34b52245e1a9c3a8fef79c4bd04f89b4881b16c18304e9fba90d48b3f91c23119340bb793731d25d2cb4b9d9f24e03a8ff913c0dda860f1b84777207720acfed0a21b18bf244d77d50cd5fac921440afaef39403328acc9b0ced0a3f3afbd69608e7728c885898217e1ef20c4573e99f2882bd2a1a32143c37c4bc065331cca0bcabd490e06cc5ffaf0eec9f335810cbfd2f994623f1841d00d89b1161cdfff582741543e6b5948ce980bfd346af7cf525254b653020284032a8ea584bba7878d5292311b0d47aba3fd9ca8dda52acc323f3cba39a25b871e2ab1953eec143712e59f5a1158809ec7717b4952b27b76773e63a93589be13d74bbd82adae4722efdfa3f4ec3023336201ea2daeaace3143d4387b597456350f6fd56b1ad25512394481b6e9e1a85da688753e4dfc0fbb25ac3583d15e0409d4aea270886e1cdc870f88cad20a987b8b4428b9039f365ba8060e36526936aed8d1576082e8e10ca7a7b619ca093af61c110136f482ade894f2b8f6dfa9c15117b5d7871a68801000862e71cd0029a8a87fad7a9a146dcaade1efe4f7e689daefc6cdbd7c639fd9808d77909f03b10b47a936bd0bce7c2378559dfe97e736fd7a73036d22dba7ee0c72d0db17f4d9a12d56d4eb711cd81153ccf7979e300332b111d206eb85ffbb6e31131d60940de27e4cb6c88a3b0bdc79036e9a7f145fb19e30dc1ee02dcda6ab3074d97a89061f0e56347c703f5a92dedaee295687e78b4a771c47a9037e22b14d3fd09deaf7342f220990111fc8621461c7078f8e3852919461765b95549da3dbdc66ba644c42458b4c2f4d9ea53349f2d9adff38a6473c557633f160b30332c3fe8ecb362a60d8052439603f5a57bc1a08d87a5f430856b2a7d7673b1e1338fb66b3dc00a06572a19fc9ba9c90fd276bf4f12905781f118d0e4cfcd5a0266791849e99f919e7f91f5219c03098d23e0fcc78875b49756bdc49f357b6bf355fcda9903f040885b2015a248a498ada103009f3ebdde221badd73b6ce7c482a74619fac0786a2c481e835ab171b9cc6fd3eef8b5704bf0dbd41102810592b3a6c0c81ba30579d411f3736402bb6d2c75479bb240a959d55fe67eef343b50dc35ab21e0188f4f006b937b63ea647cdb126f200e29e10382c300c4a7cca776a5fd124d23ff7513a5d62e407918e4f4ada425f0f9ef38b09f77b496d5bd815311397436dec4d888c6591618123fa20e9a41e0ddf592a06992e5334e56de36cd38acd24ed14d7019a4847848302e769aec4a749f70e11a9b95f6546d37550e986ee5a9017f3c2e7ade1a33ad27258c0472af7dc620ccc238ca958eca257800bd2dbb8e898c2749c9d63ff88cd37ccf50b8f867e092173b02937cb6e14e247d1f839e2a9fc875a212c1188f266c98e4515ba860a6a29f57a98f675dc3df7d84294ddfc767c78df660a1a2a2e0824ef0a3004001e2011fda0d7c53c8dbabee53fa971715e48351892b98c4db9b4571bb28965801402a29f6621de8ba316aafbab37a16103fb7e9b29defc3d4c2981f3121a0b0a208aa09567ca5806c435fd52b9f491f8b397f8f0cbe0177e476917440ee40495d2f9ad22ba9f173f178b88b92f340d845cac75a23797c2ce0b6fdaab3f8f4d64612e51584d3960f09dc4f71bfff48b00740dd3ab9cb90b4764fb2bda6e0f3aa5b282374272608a136749d09c18f232cb61fb07ddd68f6f60bb5bc449cbe1832c2eefa3d67e26a5453aeddddd65eb48863409e5af0924e1b7854ba35e418d1eb32753a44d4dded7db6784918ead81ae514a208237d67124dd393136ee8bdaf0e0ec7020729b272914af4ed2a1f6801d46a61c922619b63ee3d1a77d39b08c4907ca98a42497a300d3bdd85eb4971901df2e5a4c75bd05a638da928e0a5f7b7c559f37245bfed60ee2cbc971201b1eb5fd702c656713d7b0d2f3cb6575dcd7c5eeeb1242d635307eadb8153dcc038787a348a66355e3558dafa340739d2ad26f636f406b9e073ec87148976f04716c2fe39166d91085139685aa4ab8122f84d8ea3fa415a1a631696017f35b5df023a621b11fe09f2e078126094b9df7059271b88319f84ea5a95f94f05b8cddb8e84e0e26aafcddf22ee22d3137afa9abef9265a1e4642846d1b6b1ff3f7eac250c1e8e2a89923e66997f385d76063afbadf13fa505190d2d22c6bf62617c5685ccc136271a9ebcb739e6026805372cd8a38ac7f5aa37b037650a508867b1ca8e1db18603649603d5096554eac5efca5955fdaff67ca81855aad13d84fb4dbe4f5b5a279b18dbdbe70463f830bc916b3d3cb0cfa664b2386a7697b47eb4e9e2bb1c24d48004e8494fbcc44912ac3d4940dac86730b429402e6562b1a12ec192c9a13d041acfbc79644519ca676ff8cfe6dec13a2c59cca1c171b8606bdd730db32fabbb592a63dbc0a2527c784fbb3adf60dac6f567b7e563c2382d87ab533afda78393ffc00a4fb155bb6f806c3b3294e0edf8ebbad00911a28c4f95a6ba894c57f4128b5494dc8cf38693fb48d1771a419c910b0471659a94223e6a62079f821a4fbd7b0046628ce9cc0e5c4f3eb7d355d6af1d465d41921289239ca063cfe18ca6ae1ca99c02a5a323b173510a12d98adce580697755f4f33051d8aad6122528de8c67b72d7c9d4e30372a7e441c28614afc753cacfa2dccb2c7dfccf1974aa7ad71cac631c137c49023873debf7349b11577039c05fb4574f1604426103d14c4d3d23539581096e17fd740f5d149b09ed83877894790f038c6a16629a25af25ad30c85cd98955b01f9833780cb73a7b972f301185be42e59cc3ce3a7feca9be87f2e6c5e1d8296a5a75ed1a280811efde7969023dd82358e7b31e5cb3d73f2272793e665bfb3fa89eba63912204824c4108544c2b0b6ae4034706efc843cdbf2cf65f8eec45b323664380259671a4287d956041c328e938e73d9ec9c93f0dba02463b761a5d425d2691db71947e761f4a688fd18f063a128ed6f61e04d679fbb764c4f3dc37c5adf71cc824df203468639bb24eed79030e48374f46807f29b126907b824f9ff6f3ee8bce4ac7d65d7f58afcf982708a662188d7e8392a945877d29e1df7d1b3a8e69046f8a36035600bc3a5931c74bb70c4982650b4c09f514eecc0cc04ee81a5d77993d5bb4555f976644020a86d951bd9d74eb94baf442a74dbb77474fbd1f1d3994ae2db7b37cafdcbb2b9c0367a13a271c9b006bc69c1d4f55d220cee00ee20fa4602e38ce89f16644e13e10b2457e990ffbb5511f754302dea986c0b95f85223217657ada106987fc86b24bc0495f6d32043b5c0479d0a2f128b077f0ecabe77172e6aa537a92d52b38366df46a90d9ebe1dbf49431473d9351ea6bf844f730c73b4b1abe4a61348da5cc92f344f6593691b186ec02252256dd785da5a1d79978f597a8c015772df8b3cc71f23aab97f554e71df96f0bb9acf58d39275fb94bd2b6da73a167c3d988a4005562992e180f8c8805e9e84efe1d990721b41517991cc221b4183fd2ae0ada483032df48f1a63c0fdc426ff590001510c74a709628aa2f23564e6a8e3f707f7448c0806c230ec8043c43d8710291cac2a853c81ab7a89443c85c0fa2b9ac2a3655950831918acb40d224d6cae3c664692d61c191dd02dbc7612ebaae17897349c86a44a80f1d6002c404c907c3a4d6908cbefbab3f4ba77dd39d8a35f28efc93a051d9863e4f6b5956c9e22829fad2665af18b728fc4ac52b97042b18f350a0fcc10a58a7a3011dce423e25937c5701cbb2251e8d3480e4ef075438880214307983ab156aa4b1e9624471b5f73b15d58521e7942f1616c915f029f1f531c50f3e2a49348888f484817a00d65c88e6f6cc7d31d951830c214bda4ae32253c02bbb1ccb090f20cdf1a8c38d23b2fc4e5404df37d8c64d6e2ebe485f9df0e28177ea949ba3db15760a1aeb753199413a9451eb83d1142ab71fb44730979245ff5a5dfa4bd218fc322a8b3b83f831e7a06cc6103a903517446253cc2b7a116d8c5fd19faf90bb12550ee79286e0efeb27030fb325feedfaf6865a70b6d5da974bffbc3a57e93575b512d627a51fb421902d2438be76358ce90abed653027bc062dc9a2c65320ba76ed8ef3de17f642b849d76fd70867fbf802ceac927e8df84517d457f2ad011d281b348e419ae00fae3505e08587ad20b6c3347e8e16e3bb8bde49213797db16d60eb1ee4de338a7bcc8f686a13327ce9e2160cb9d912f772ca8141c238f2ec2bcf707ee19da33c0dc95a428cfe82186b75028cd71b522adef0dda1d4388d111de125fe63ab9bf44c32134cc062307b4ba6aeccf1ba8a02da1fa57706f860b68377482ec807c1c0093f5c41357488741556491dad9fa4f56b215190f268402fa6a932ba452cf253cd2c7d242f5c487d6ed7ef059e7b0733bdb35b7df17b43d930be507366e068e853a73e086b2b44c14922fc9051670a8822c4b331f877f6a55ae7be5478d92f159a8f5f3022a885c3212c13e226f2b19810bdae779a1f3df78279c5e7dc6fef723b886132a9cacb2e90eb43b18f9dc17dd74942f53bc1276bbcec8829972a700c12fe3706ca4274389f1c001e11f1c7c00ea880c2f401b31831ad45cf9a5c8844353296fe6d6a86472525ecca01dbf122b76431b08734b59010d5d3962b4d008800ea29950cda4902cc248c6c162b8011500f885135996f20e8a8c7c9b8082044585606517147179c27bd9ddbe9fb09428ff2f65e098e78c949f717151a40dc548d893eb806b8b068c5325a15fc3595cd0b9500e92a10be064f6067daf51382704ed964b7735064c01e02b3f018bf33327d984cfae63c71fecd3309b848b55e46ef4fc172927e86f094c88cc71c94e98f430cebf05a0803926f49bd0b74152b784768dad1972e97198547555b5baa118d982cb53252ed013cb8a584b96fc43f88fef9cfc38bd7726f095945f9d6c86ff267bd494ece14a84001c8ce0801ec321907b421d362d55b6f9a8dac00c402837db542a702613e6cad4ae948d05815d7017c4838300bc4cb24aca8f3612425322bb298c6424860abb768f3a9a5acd061170a3c53c952981f61742181b5d87980d6b2e253832e144077b0936457dd6b2fb1b5e8f53877699700f684cc31742915aaf7d7d7a3cab488ee8c70daad90b0ce64516be338a3dfd5bfae4f74b84c6c475c84cb93548c4a32c540f703adbd4666720970127b8398eebe44fe3f7b5fc20315b2d7734704f92a4a9f8d814e4505d291fe74e527ee665b5b72719d324af3f01c9f1408c28f917e94cec4aecb2189f3bd3ddea6a93a8bcd77d20511877989d08ab5ae7c7665d51e050629904b737b9e9421576e58ff81cef5b32e30ded9dce163a029a7682972e6b5e1dee7246f666986ce8a550e98948626f5803bfdc3757760e01b4bc9b85fe2cf4783fbef29e32c2f98cce1668438b265971ceee6249695782e6d632b9533eb266cae4bf53692b6c5f15caf52d17ca3af6793f5f0373d885893e6197c80852a5d0c47d43d3d4b80340336660bdd3a40e4410e776322ec026adb7261947907e80b487892b505a3a2dbc60325ad3f346bbad0188b73dd5273ceafa08506ffeb9348a6f14dcd46affb0f0c9232cdfea254a3a4f6a9031fb2a8654c907435d4d7195190701b5a4c292940b189e18cde725a918d415e0c5108ec442f62e31fe23154d95b8b91aca61f6efdf2fc38bee56b525098284646019c0e388269c7113a4d4d62ae6506f3cec603db46d047937368e8a16a9a5ba33ce9d3ddf4e0c59ed944aa36666b4896a94af7926ab91e149ea93105a9b926222acdd43994c37615bf28c83226d46f858956941ccd3ec0811a1b5aed85970319e04318c079ab5dbfd9d64892f5f33a8e273af47984627d6059d15364119a78c58afcfc9b526ab79e0ada22e35082cada9c9e2b7fdc2cc013a2e9d12a9c6b5713b671f0223c1c995fb6000206194e50fcb1e319c91253742f5aacb5904057b303e97477db190923e9dd62afbacd0626d8dd80bc16934b2eb04e5e257e596b81c98ceea74d37f1687e6d49d64aacd0eb725fbc1eacc0ea578b4a911d882e6705a7589f3e5ab8c5e679b65691b8e9f2d40bb06a9ba155c8c7b0b92b37cdc23343ce38dd15fa71c459faef5f8106b21669e834d8fd1c4b93207b5df4eeee17583e4e5d9c9f587b2e10953944bc48aaed5db025d7f875511433d169e4d8c98d5adbc290b96c2dc5bac86da1fa9d9d061431282b8584c07102940d4d696af573ab353df5a7048af52497564558558443dbb9a22afcb78ccc5340ab677ef105df495bd590dbac04e912d75997132fa0c2347dab45757cddbd4a63ab5e68613ceab69a5014bdf04aaa10cedaed1a1b1a1c5b9215d917135461a2b53202f6db874f58d61ba9a445a49daf8e734509c428eaada329a78961823d961eb2bf3caae7e6d82ea4444bc7095383ed589fd218a0bb01e6f80e4ba3ff4ec0b2f277ed20474aae6f2a8e1bfe726575613eb06a5bd6c3daf96a3a11617fcf0330328b9f1134e4f90956e5a7d2bd9a81b10f29554071e134d5c536d3aa82077c4c2059efc278d1fe1d89daf0957db9016dcc30683f2aa4a316df944d8c250d18d0e6f2ce99aed1dd3a13beb09af91b6c44d02aba8ec3745caaa51c00489ed1eae142014f8c31f72370a5d84b72d7a36d4b7d2c29e5a0d21a6f108d6dc8a32243b1cc6646ee0733afa2c25321de4e6bc5bb09638f0243d69b40dac99a84a07d774392e803a1cf65284e74a1c559cee7ba64ce7dc47a54bcb68030da9e80b4eb0dff206a6800aaf24db1144e7839fdc127aa33fda3aa5b88f83c01f120bf6fa13f868b0ed5ee8b53b2304f75732e69388804c12936cfc74eca0bef49d01fd7573ee73c75530d2648544313ce44a0b1d3af490f93422b16366913aad05acd163ea1db84ac1fde8554ab8bde8a413166d5bd8503300a25576c0339a35401c90d55b51eb25c38895c519312125b8399faef9ac61d6c881c3f718a013df768916294e6767ffab4d1953406a9a4347f0e91c185bda44ac08fe1cf2dd07f6ed64b44240f26bab65089a1e89a0c34247594c8a645981ee0e03c9e4b4254cee4e10d9051de4630befb5ae2cf3c08ec334f1c2beb5a52a8e92ecb8337b032b387fbc854e47f1866720f19a378399511d304e9d4247b18bff8d13413dccd55bd8083cd05d900828df1c9d39b46575e68650844ff834675a557fed5f7ed7ddfe2f0f1a69a46cac0e1d4603ba1da7eec2f253ab6aaf65cacb664889125c76074d5930a400d9f07696ff408c2c018b8d10431581b12c4440bfffcbb2279d3b3f081f780081dc01d409d633fa6dbb706640cf335706e5684572c702b78cb8efc5c84c270190759a1325d117c8aa33e3af6e07a08f17cee4174d5911102e6383bf59b8cce2ce2cf18faf81aa655e80a812d1ab119bc099a9a88fbbbae577bbbdcb8443c2c9168f8d823c58827dbd2b2c84090e1d3e10b3dc260ca84b5890c443c93b954914d67dbc72a818157594085b7a08f324f3cdc94152124a25435afc37039d33b7d3fa7c3672232249d806d1a9e62709117a0a892967e38036f3be574296d60bc60131b123666adcfe9e98bffa33e57e238e0b76cffc8f136c1e1b2648a68c42ba40a76ddbc1f0bca24f2c594cdfa8500dab47fa842018847eae7d2300fce6d66fed3e5288df9ffddce8e2a9b33c292e4d0323a78a448a4b209f64c266593063e0583a35bac448a85db5a0f6ab1cf512971b4238794801829a2ffbc8804b8c08f6b0dbcd50bb38b2a250577d66fed9d622095b4ad7b2efb2f280d7272de12631a31c3d51b37f65b72d393517b73b1809094653b58d3d1b296e01584b608376982416833c87148da2bcd4e9da01504ad2ba1538b90de518333dedf7db23bf5f6d20230483a58e53a34bc30cf691b4a542caf817bfc8dc0338fff675a38509c5a85056b1bfabfd67b4787d35f9901a756dd2c5eb51a02ef36577f0e2ec83bf08c7ead5a6b5ef9c05feb030a3ecf6b3e938e06b565da15be7bf8f1cba981f1c1ea559de963e93b1d8c67009f122b01c6739e16022008a8d6c3ca5d0c3367e4acf216a20af83af46cc4cc54afd54c358155d00fa3b9959bce398a3f2c41b94a4ae6efab088c410e6573d2317d2525f419ba908639bdea01554102961f38296014067703fc3ab36d24d2500e2f53f4a849f60ddcd41f21acff4b6acb2471dbe4016acccd74342e5f783a04db2d6bbeb07b8d7914853cbfbbc2de7a3e40693a476717b2410344f12d68c3eee6a3ec22adfab7b85ce6c58948c46858c4c1769747fe545d574e39f676e064249c2b2d20574c3cbca07b8ed8e5240f7c1e11cf1cfd3813a3dd02f907018b2adb91b967c2e01cb0192b4148aa290acf5b9b5fdf16d3029231149ecb82d92c2a3ca32b737885915a52135280f42a768ff5478dd79a3102958567265f1e3ba211906a44d737cba81b814b35f855caddfb0fa7f8231ef307c406331bfecc15c9d333de281820bed1c950d520e190462150192415c97de40bf0891c2ea8dc80604466e4c630d34175c20753e782be100a086329c989ed255ae614a2deefc77a2cb1ced9a7d6581f75d7fe0e2a8cd8f50169a422fc000fb97e1aa3670b6b56bad5b079ba85e82afd4a40d460468d60d01624ca03be44e19e7ed911d3f56d9bcba1ee3ad852bd185025422b0546b726d9cc68e6e45ad05bbba4d3e00d5195a80df7608b42680c9ccac83636f607f992533f4b9f349830db347cd297fce0c4b23acc2144657061904ce5166827430c4682c37f3207a8143aa696e4ac3e8144ec7d5942d3a53b69fb9d231b49b8f794233e8c32da97b160c33718b781bcca4689d49e3291da2bc82d5eba2963cb7cf17688ecf4c987801805b63e279789eafb3aebdf52269850bc9b01aad2de30f07ad5bdd984836fc7abb947466efc639828a1f4375a898ce57f338e1302bf6d25dd54680b81e60de9e675c7485bdf7cc379c23de21402c908b149d4e6058c996116faf5e2820d553f0af630bb8493616cfb983dab62264c34b3099c5ca407a62c908c6dd43eb76d12ef951792842bfa622d24f64eefe15fb31959d15a788721dc05c7cfd28cbd8f1c204eec3c41a8e63096b51c8c347f0761d538e1302329fdecdc2441b831c8a93618460d6b5389d2d630cb84918ef83172823f2bcadced0b2b240e8b65f5b1c98670294f021c03669a4945220146a622a348344ed89fd3dafde104701162812a8c357f1d9376ba67b6964fa6a46b61e45e096aa17bf01d08fec5ce48491580431091be1aa536e385028d4cdd012ad3451ccd93f8569232f82a89b1d35ff3e492c316273ba8d5ed96cd8ae83c02e2b4c6c94b96e7ce5c7725b8d8ae8e152cf50530530f0e4c1c10fbf85afc3a8e130c8788f33e99ecc3884866ce700f923964db41e470fcafa72f09713055235997fdd77eb6d19a8dee22ef2424e0e329b8f6f3a6f6d40d35033a3170d8b429b4e26cc3d78e099c065d025f37d023ffa23697f9b7ed886cec9828141bab4527ad70f38fcb3b468b6ab4c8d0edce5a4dba53f390733e9c2906943fd8235fe44aa5c5c8899f857a6d05f36f2b97b27cfe47ec8fcf249507cb40c59d2cde847d537f67db7f452f0cdb2e1f929cf816317eaf85f45ca4dcf5edfb4b09267d3d696144f7e90d1db43f4f5e56b7ffb6ebf5c7275852540d4c64870d1c7137bc5447b6287a1ddbb909e0ada98ffeacf55f6e88e199ac13a5eba92ded4b95d928d9a24903c0bef1e7fda9deb076324d4777ef3ffd0f121e6982d98f4a71dad83bb350ca18401f15c08a621b942481e03b92f999eeeec97f2313d722695de093393339210e9513436812679ad910d2640ba4c7d9f0f9970f6b2f6d6266dea1dff043c1306c60e9ceef9f0311ebfeabfffb467153a0efceb6febc1a1c09255d80c2fee8235df634f3951664e0c394f78ddc2b35eab08b8b420c84977294b0776e7bd39c71e152fcdd48478fa4cb31f918c50401db8bca79c356535964205c4e51046d23c8e30122ebf06ce7ab99dc6fa8d04531065e04e12e7f6e72d5b28272a9e52b3a87769c0b44d4c768b4d02885640fd2243dac89d37a63c4cbcd8874819dfbbf99ec5074128c902866ad06e8cfe6055923a18e97737f1a5fc6793be5e5efc324a099a25c784955ec32b1c5129726ada71702b56763deb0d1ec2ce14095fa16318e13e2e35345b1610275cfa1e2bf9f5bf08adb74c31e5bb318e492304fa4d02c8da5ae759e78300a59f04340289746cfa52f58b8456c5ec97178250eb1759507c0b6ae0faeeb874d27ea4a57a287edc6082424e57614e1816c4df1d7cc54a40d8a514ebcbd0b403a9fcf3f0fcc8b053276092caccdf109634a9ebfa2c37a4061ae364c8ed47e0a8cab6b3f2157c21ef46ef7cb3a99c57e3527762534337a4dc077fb7ad2a495e19ec40fa39ac167dede0f8186c6a1adabeac1e945fa7c2db814af654dc2b43055832c13a8667035578d88719fffed1fb374ca8cef7d7d7acf351dfc28a41156704168b9bec116a027ebeb00e651dcd6c8aa1840eb9f7df6b8277e33943ca8c5ed00ca1c2064edc01339248dccec4539aaa6ca535bb00d3e99d399121df1d15eefdec8d93778b04ce82d0aeb42d516fd59fbe27010ca3fd96c6629292680deb7202416fbd67bc3f91cfd8ceaafff5318f3526ec247461a2b804be66bdac01febeca0e76d9edd24191ab046ef602912674d35618a1069c808eefa6fba02a868d5a0b46abdeaf000843df733fd31f9da42141c2140e669186163882871efc45085bea4dc336a06a412c89145c44939e4543c6fd35841097bb15e46abd05d89c45c33fefded74abb866033da5ad0e6c32f518034509c22552630161f977a7e26f6567d9cf933e6c0b4993782fe92b4723fc0d5d89612e63a424f23994a35ac55f0375b187801d335567577ad5ac4d7b052829ffb4474d9e33f3afe0872803936668115e08eda17d196481ba9f46d9ada0bea82c8e49153990f421998513bf8254f18f931f7d46f62441429b262a731eac3e0464a0ed8471b90d01737ff494ce4dae2cfc59d96c4563142bcc14f9f792ad788b974b0d1bfa7930ce2e9fb87d832dbdbc6458751a74ad5e16f0fdce45886ba72d7f8844567290e64812821fa8d3e6a82c2375ba4c9bb0a5ad7c70325b93685add93bf669941bb74d70c0efd70e341ed50d7359e9ea41da8a701ff60a29702c307874531a0c220e565f7ae720d6377d063e081b9a7dcb80a5ee2baf18e55646ec264c10b4d817afa2d4000d118402c642ef89d283c666a536c6f7cd446b509b1fde31b0398cf7e95578824af780f0ad5ca5b7f920ac9cc59c7991db651519d66516b46b7812004529b8855ca65e5d28362acf5725a1255eb2f9f91d61fe7b310c695ceedd02d06464d20b4265723be553d79d6cdbd04d8a61eb60b30ce53b06af42495c816c5e4a13c6b32ad9e7236843eeefd65edfd1dcc2704fa87035c0ffc195259fdfb5340971b7c049945f4bd51d91e631510321f1b93f51a45412f9502a97554ec419a32ed7825ff771d198205744339a8844b87fe2d91a396cae0ddeea754e2ddb85579a2bad52641534fcdaa154b26f3b88262905ccaa06733a3a154b6ce06f2c7fe0f3ef2326711493ad5b647b587e30f1b6640e90a0c6dd4b1995d9cd80af94d6a68ed4e022d443d68417c3045fcfec7aa512708a790f3e4f5435e9fae92b9fba32bb8ae9339bdba4e52bc26180f649ec25b006d7b1ee6d6e1c7ec7e15ff73442771673bd9f706428869990e1f0e2c2b80b92f75ce9a0346fc0bd2e85bf248529ea4e88d334c07be7580980e3f7eabd7f5c3b7e184207c0ae831095dabcf7e6a075018f003fcfadbf88f061372c5368e6efa1c535ffb665ffa5d0ee59485631eeb1a61ef3d470ced31e305ffc53977cad5e75a370f92c8eb03011bede303f871c5fc801eeb7e76308b9ee444b4f3f47942a22ba5ceb55a81aff14f9ba259ca4cbe83f186f1999643b29e454f28a20fefd655f1b2d03444c8e30e6558556400e9252318dcc1b31d300d7bc9b8eed0f2800f7465442dab4243f543e103c4758289d6b9a889d00dc2416af208be683b044c4097dfa32c5ece9ef6b618c7842b63dc0a1c44efb36617edac203adaf9114490d899081bbfde5f3bb3f03cb81cb4b5d95755e0f91ab2e018657f0829c50a8f966070137e5b4dbb8c605277afe68f04010a9e3fc2fffeb0c594e9334798ad69f85deef933eb8080930279f9633915184fd16c7dba8296159eff621e7d91e170d2261784db16dbf307a6a1ef1a41be9d64b0e04ec203dbf4db222c0bceb4ab4945e21344ee824ff06f0145daccee3e0bb83989152e4aa93786e25b30c3ba889cfe16cc9ca2768f36817694c0344040f4f68dfe62b736c60a2deb5f42b4390c1d31cf071c8cc66e62a30f17cb08d16603e1a243dfbea514a16d4f4e688cdca2171bf71a02fa88b28ee420a9fc3e05841d5f1045e2db1bab77daff2173717fc5c4da310304bf02cabd873f6a0504944fca1ae4e72e63c8023571aa5ca0759a1108ebdeb0fc36c2bb0138953a1414e7694d9ea5486de780a08f2a13fe463a34a83ab687d3de4eda46fa1e995995061305d6f9c8d4481b6a748a697f077edf0c020a4bb94cd316b2135fa2012c7463f12e64417202877674ec6cae93324e37785ce8d6d73724510f1332a22441411c1baabda6148d9fd7d9a241e55c48727625347caf7e279ab8e6dfc1b0a8424a5592d58802833f0a9c40fc0924440ae9a857fd1e26c05e16168f7a355fc29a564cb671360cce5f370746b0127315c9cfd0b301180323e53741cee8750b1abc2a3d445e4d31bf6ed30b433821cd77e6e7ca5b43b1b9ef9419bd9ecad13e1edfc819f8a74d80f8a34db057bc0ceec7ff00dbc7836e31d690b78e4d1b26a39f56f9f723177f40fa795c3c3cf949a573b1c40c107ddd074a1c14198a70c9b5e28e24e2caf56de376bc69b3202ec9af24eae71417adb89bb0022945b06690fa8948a4f151a133522c1f112ac76f57165571368829b9b01a1988bcc6a6e883ca99c03299be26c12f30cdc59628b8e95f2cd0978b048fc2790df5269d77a4faaeeba74f64c4442a1494ed09d7d7540452e98509e9188dec833d463c3df5f3a192c082167aa73d0e924f9d1a5171a1cd46e718324ee9213c0a2f650a0ab25eb6513115a16136d9d177c5e3520b9f0a2e37a2f48d0c463a131e856bf2962de546046b648baa2b7bf0995584b0716fadf6c35b36c31ea3cf2e4db6cca31adcc95e83b3db61482fc440aa13c144f463d35b5f277cd007d9d70d2074d604623638826eabbfaeeb54b62a342395ba4eef65c619f6879def59154c401646f2ae4cdf0ed46069c4870e67e038ccf654ccac3f28f2a7ecc7c41353b3f261f940c33ce20fad610a81a2a049b4cae1a3bfca0118f4186249918263b9ecaff355ffbf833297145b35a96c71ee012fcc44e9095f39fedf29c9c0534e582c7e99ba011dbe4c83f8dbef0b6d79d38f5265620b187f9ece3c6321cb8867e698fbf39b993a764bf571e56226c4052c825173b0c8f35244c85f23bd517b9e034c47ced67b0778145aa0aeb680624514c029c673fad48a1089d0e3dac6c4533e12c02a1d169d52e8944c6d5337045c35b2f4301393a0ce3bcdc16d37f3ba4a8a445b1ab1496766c9391b4f960b3fc6b2ee79f42944c63598d6272e2d64f6283d199713dc9f8bbcf0c9abc34616d6bb8e3cb478f074d69dd4326f11c709385f6006fe62facd8a2a0d8012c80410dbbb8346f53e307737de928e5a93164f7855711d2e5bba0b76e6b279694816d94216911233faac0c492bc451d336fc4e315f0bdf4437701fb1eeb9e527734caa47cdc945f4fa6ef9863b27f3fd96cfbb466855a84cb37f29aecca415bfbabecea08e95b25473877bb3ff022d2411264e2d7e665348c2919d084dfc381d68001a7e42cd057d1a549528828986352220041c2000031255847bacaf0238a3816a74cf1aae2b89a160760af1fcff23c2db249046f580cd4140a29a7483b1621bb0dee840852b4d4db465b37d70c2acb12e56e507f38068b527a7a78a409350880b19a6743433356745587df9fc73b05e7de22ade02715dd58ff14ce35cf5614fcef141b0a5e2388017847370203649f509696d189e85b0525caac6fe7d2ac304ee7402fd7ea25471ff6045c74cfc6f1ca2d251bd096d5d5c85aafe5905017c45868332ad4b52ac5f181c57057e5ec22e0e5e2f6f1a6e59d64e1a76cdcd64f8a63d3e754e5f638b78f0f71c3c70705cc6513aedb0a2fbf96d34e2f134d9883d4e6d3eb271038403387e7ff852df5ef6e1cf0e766c2a8acac1da8780af5cb2efbe774a5b57ac094339d347631ccbcda4a9349fbd9813e237413f433457b3842a67b07cb87b0bff8dcb547116f1f1d03df4d0ae513f8ef24c74299399a3ff9935d59f8fd5fe48dff07c3426135c7d1365386298befd4599aca58c6bdd6cb4514b3a81552d2dc9260e4b8468619d186e5ffb121f2c03cef2a6edff91a7d16f1f9e69bef8158e284b6fbc847dfac18fd7d34872e1ededdaff3ebea8e12431b4749ab8f5bdeb08d36d794e9e9df9903ee06a590056beb70fc1d5feddabf3a2ed85094b325764943289e459d871dbe0e4a5d499cc24a8c82b78a122b5875ddccf1601f1ef1d47d605d74c35147e0e20f3d9151c0a64d75c327909a82b1d43353ce981eecd61605d3d8bea68386762f135e5700e9974a819d4a3e95cbc6c6196e34d25beab67111f8e73760b777c943241b3719285730bff856daca897632970c0e1cb2b8d84c74854da21d0f2bbb24c7ddd6e703634225f681c26a60399e5189709720ac9dcdcd86ee12820367ce553b92916e35e0723e15e54b7049bffb3f6e7b2e1b9157ab2ed750402adc80706b8c5b4f0b20cdfa0bad939df4ffd68ea9038c52ddbee1d979b7f7390988e59a6248e5d347a69216e2dcddcba930b0b7e9669acc0fef1759b7f1f5a512e7e419eb48fcebc749627ed6974e40ced179563d8c7527ebecf415a6cdc233ff54fa35cf1b60f2602337526db7e259119986f80505023dab2fe5d907dbed66528488fd15a1145855b9b153a72d5f515d89f8dc007b55bc8eaad64f996826abbe002aabdc0b4d4c5751c3e59dfa2406d2f48aeb7be8b6704e6a0450044ff816552918218e433d628a8e7700ba8f6020bd4f602e4f2567259b6008f4bb3d0abb7f053df43f3a895a87ba14e8e8af0eb405e00d7fb7b95362417bec6419974a74b121992ce8e6787e098cebee1cf082d45ba10f645f8161892e017c00b04e7d75254e415d690e3f3c54e7b418ed6c26ed91a7206e43c40dbb90f388450fae78de8983630ce13ca1ff4f353cc479c280ccc68220d12f27e414c8a515052180872264a8ade011c8da1115c841db51c71c626bfc79607e172064923c4fa03a1bc7183c3fecff88a31c155b62918a8746a6a3c3edca783bd82eaa00659e0fbc04f268e19bc1a6245c6bc19204236bff9175394581f290edc3937ad52c63684061a777dc48816ce327c4d9821f7d9443d33887396cada2b54dca3d2a817e5b9f9c01496412ea918a5f0d06f7aa62cf333a4185de8aec889b8868c101294d890c0772012f21554984eb000963bf979665d621f9d76f2cdd9c55a587e0e62de21433594a9f73ae2fb5dc867f8623bf6e6e69293a5ae96efa503bcfce2b59c71912b4837a80ef5754ebf06f21ae100c5cc6b812cb82d18acb4d7ca9313e67208e56e2131f1e987c576525c3370367f5f297b77c0591e53d72d90c7014a545c76a178101028ddffe30b5cfe06b27d0acf50aaf5c546d6258973ea1621002bc623a9533c62002020c4ec2eacd728ac72d4889ba9acb4cf4858bd7548991a45ef6790ceb035ae28cd95be68a883dcb1a99b6c5bd8bd30e2742c525f20f9728db0b9875fb28c242156f8d298c9f8610e302cac6f850f74c03eee7bc267b1f78edee18b1b1a94930409e4d99e78690274a1b256f43e334598c8bd46e3eaa32af6784978f7bea1121d32b5cad0b5aa4263981685d06dcacbedd4b1d8c10cc97fefba049c425826b7ffef68bbcf7e0bb79b06f4c1fee77fffef2ba4be72e1b7110a093971154a47bc1b2a343f2579830c52254954037715d77e06dcadf61c5fe119c0f11dcef5df1b08e0ff8ae621ff4b7d76ceb7bb8edb0d36c2d97fca62576c2237bdbd2df67ffe2d3581e56221d1945aa30526c54640d8c412d7cd7705e236193656fc6973f7edc1c9b95e6d316a13f7478b82cc6c4ca18815d36b5343714894d1e4dd569a02901bac26ed84cdc613a40dffc66fa41d60582d1c7150e1a064851cf3a5352cbaa8fa5f2363d906bcbfb8c4903001b7383cbaa7ddb31320ac0ddfa1610a194767c6606d868b8e523494aaed3eb0364446e3114f15e0bbc6af369dcc10a521f3d546108cabcdbad923f026991fbcc7b563b351e250ea69f081d858b5d128636d3c3c482449b13693dc734c4041b72b254bdab20aa37fca4d924119276a8dc05b3ded28e7a5d0ba1b2228fa74ba7ed69ba5b91017080bae131cc18c5247c963b1bbde378d92e046428e120e7c7a8802681f7661138265423b4ca79cc2fe30f788aa95f001629f430da00564ba13b312105478f8ca2a2390af9a3e01a187e401cbf176191ebba62bc91e5d7e35ee0df5d8eb5e91882118dc5afc57c47b853aa5000b759ab42e8b8ccaffcd528c7b19fb6ae81c21ebef29f5d74b1fa699fe2561252c6cf0d438e4b5e2b41905b076bf55724646dc6241614c28a5cecf72b9154c5d96c2f06d8647472f258f47a95b3619756d92815a9bdee326d40680eaa4d9841bddda1865a2e21ffe70e3a8b6ba02a2cf8c299956206138c622d0599f25f692e6fd808e8b32d92a8aa609ca917c950cbd92d907f2ae9daf2a506b9c0439758bee6cf8e4a3d154abae46765a06bf0edf5af7ae4f87c699b06fe3971fc7610b1dd0f01a6d8c3743bd591c8271d5c78509ebf54d2ee4b8fdebbdf2d7818c5c04a9d80faedec044d3e7e6795568d6507aaf867b6cc7d3eb0b88ab6aa3576c31b327d3fda0d43e9a7c533189d68ce19324ead593ab092c13ced126e51b844949f6ff5bc241cef7009d4b51e5d6f23703676afa3311d78eb022e056fbd9c6513f2b57f9e6e1643458727afd1235b4f48787216158e72fb1040c1286c8e2bcd16be2949c7b55d61f3d5923a5dd1257e9fd3f7d8f5938c29e6306bf9c1f25283807efa6cb6ee5ea3e48f905cce0972861c6c183370d83e22eba50bb4efa0cd8bdd641b6cc6ad53af9d86a86c7b3db0740bd43e1542d2ea746fabd6e00f4f0fad151f70b406fd7bf8efafd7183ac8d9a99bc0cd7a3418278e5d0c93dd0b2a6c9c04804250c1dd2bf22e3d04f082432bbf3a19dbecce734b5f373f9dd0f527341d1fd2d55612f525020e2a892bd684763b0355b70ad0e302bd83e486674899043dc1a9e604198e27e9ddb9db5f51450d9ac291a2f80ea78d93473bb981e060ff5bbcd5b90e6350f3de084b51e5b03548787093013e4c058e9b8bbb52b09dfbd22750e3e94ecad6539507142fa80926c8e0f5036818fe909d6c59840f484567a9610d4882fcad8f3ca8bfbe467dea4da541d5b120c157dba79fa20d4a81347add511284f19267977164846806d9b930139c86475afd3d8a54c8f47159dde2f118fc0363af7366c0f55d9c6e48ed8322c70b18be520a9065766bce838a9e607ae226c15618b7e93322382ba96967de951fd5d0cad38392a47e1690e8a39ab23fd9b692ef7f8120a4b388a7f9ed6a5989c5d1b014a6b4c209fd8d256ea9b215c38129a1560a9f8ca1b67f6c1fb932d52af7350148047e31383e861c6ee3569d53640ca0a4f0888854d776beb77324850c73dca032f173245cb0b12eb06891d440ade5352c1788968103670474c6217052fe48ebc8b5211470b06561fb81b2a58824e80e4dc5af76b4c40d924296fe46aaa521159de7dec36574a7d46aea43bf1a0eaeed0dc60aa6db471a688d274cafdf2604fda0accf069952533db8b3443daacd6a229e0977709978b03bee438aee3b0b49214b1621fd6184e4a8499946e80fe5c40ace419cf1f4e47692ac0571c1891b605dec8c8b78b1f65764f2fcce27568db1e1f523ed1822f40da80e5b715ff75f46d8d448ea48b1ce352f9e0b3017a147395bb71c399e5e0baa27c23d9765dad41123b4ed48ec6fabf0d7c1c41d3ff3d2e3ce6d6658dae45af454daaf69b204a75ed01d7211cd186ecb0511eaf3209ce25fe028c06c8f7c57f2c76176f9f7d2c1c06fae1b29377be1b8851bef3cfe3d861f81b06acd432a5d4eb6664179a138384c1d0f8b76050f6bf2207510c874706fb37e7d5d6c63c78170822762000acdfd79e4def13e01ea87cf02dbef1c6b786f06bb23beec7039f5b1d20b159b5eb17a6286fe615c99b2a59ad9ab4541c5139fc6c4d178d57cd850dcd3d18d63afef0f3235fde3b5720502b24fac311596c28d067073fc7f7cc4a6441aabe3c8be9e32615cce774cf8262dc0ad819ae593debe46422ba88be908d09c00ce2141c9ad556bfba88b151d0882e1947314dc028763168c04ad0452c5ea0c9496fde05b0c83ed13b693a0155d7ea09d02687302b6b4b2fbde85847673b4b57a4e0690f85c75c9b54dbcfd4010d1cf22c6ba3b482d43353b701854dde261b0a67103f7c165f55dffa450b1b2d7797c88812994184da33a2f9a4efe8b113a93e12d05a0cafebf25653d8a3f1cb805c5989b63d03f4858ee3878cc55a69fb52faeaaf805eadbe30195cbcbfa0929e3684332f4f0c27e8e5c9a3e69998da72a3aa21b227ee0b103590ff5a4a33eac61896716f08b5749480338170373f2736e140de1c103cb0e4e64df3734b6472fe1ad7fd5b447dbc985db45877ccbb528b11c98c64ee4d0c9d4b7f46954849c73e12242b10003bc7280c271846acc9ef102d173f1744a5c5f3fd447b14893465c4883bc3b481b2cb5d0f206da47117ef87cb696166c996c1d0b349c2b12012ebc300384188f6ec9c89811c7641292a4e31fbf7bcd383931821550f2588a26645d6fab100afe69418153690f6656aa10162448c9a0d17a951b7a2c8bc3b870e1142390c445d6125c73842373ae6169cf6fc2bdba7148c329d48e89fc4b0c404eab3202bcd9e5f8a93cdcb6536addd26737628d54b07881e99ab017dd4185cd08b49603ee8ec8b58cef8f374235cf4b3af034f7afbdfc50383d31d1dd3788707c947b36143d872399f170e846567821b2813df206298c637e30136e328cf1153e654cf6e15996e828d20ba9a99dacf7807bb21656bf5fbb36ceab804210873427b57fb6ae295b051a5d210a0964bd4240f0eda2e5c5f072eb32a059a14f3db29c68a9ea8f59d63c0845774663310a4e069d4bc2cf826c6460526832da917f2c0613f91e7586ab02697e84076665f0149fe01e03bc31f6981e3dc3bdfefc8191cbf9083d8606510b314654e8e2c04be371de2dc91f6d0a41f1fc35117ed2660d2ab4c217a0b612d5f1dc092abff119d8017e0570bec812284c393ee1b7479f3afa17084a4e4358cb25053ed9c8a0496d769e551d46dc1add76f8c17db5869bc19c326b8f6508be55b71f0424651c83e0fce1f626e2cd02d44118a830f25918919213a4b075a361a40dd85b8cbc2db8bd8786412f6b696fc28bbd725c78aee0f3010040d655c78188e897b7a713c22c9f54a83e1047c42dc7385d092b91d7735bed6dd9dd0063719dddeaf3d49ce77d46fdaf9e3551c1292f81df0b0926c666ced5111529c87a46fe788de62544d5c1c51655afd9affc2e7a03031d2c0d366ac412e4e198aea8ad06d7fd6838d7f7ea403816c7ab8d4184591a3247b7f2a5d9225238ec8c69122770cee269e92cab5520c094fcb77ebe47b232c501abc5be01405a701c9a2db9b0e902d13c9dce38b12423546bd49649fcf59fce3638b380f077b77f37ecf5da57c42bef3e5da1e30d6e22e325373beed43b9cf3ac25ddf583a4d92cb8756e387935758aa72b4dc6222146c4505b8cc36c4bfcdcee48a253b3b7784ae188a049cb09835c02015f13655859d6747048f7d508a6637206187037e2174d3333f0fed443267fd246a4f5db5e13a522b6e464760063b8235e7fb8e00678788064dd53c4126d3360b68ec74138e856b72a91330ee4387f96053e2c7f1d8b915cbe1e337931e9c0a0bdfccc91de10877081d06d733cb4bf84807aee8dcbbb04d3ad5ef823409de8d94ab8a0fed8e5615488299726270f8593e5ff06c04cb69e31d2088d0606e6095c1c45c06390b75cad1bc6569ebae18400966d58b4e66d0335c0bedf9388b5d67f0fc0ba6f0aa727e7bc5c4118bb944bca75990b3ff5a7b857ec4e0809b5bec39b7cb32f47229fd785f916c4ff6e92263eee8d0740d88d5652ab2c3856b12d71547a38ebda49279d3444e392018557356ac5d7f7fc3d8f1c7e081767c809dda03611b4a457b5b560e183f0544a14707709ee3f1497e4b77d596cfb584bd841026d049e970a57218697b095ba07419d1d6a7d4736a84e5465f23a14b4c9543048da15999606aaf4e32142b8d968be2bff3a083e0734ec3dc502036a6720b31c964f7b1a2300174984cc8491dd3ad85ee19c0da1c9b6e2c5712f73c602d0201262442c0b4f72293769170bcf1b7f2515a530dee7771dd2b7a100bc4b5b5f75f5659d8d543ceb52d8e201bd8779a3be437485ad47d4194725def1ec3b12608956c1311697bed58a587e8981a7354df28ee0d657f32e553522de33188f7ba1e896f8accc6b023dac1992231aba9cc27e029380c55c7e92b494614f3c7cd4b1a667d3d94930f16ad07883afe18087b50bbcfbcae46061f99a39a43596a69f5e51eed70c33fbf45dc5471273219edffc9c122b3e8eca0216bf74015ccef9c630263ca5e6f9f2db5423233caa8739e8357797ddd9d3c6da4c6cb71edb1f61e5daaac3cb23ab8a091e63522674aebaeae90c0680b6d6a28f9f5afe72ffef52ce99bebb777e0bf156debbcb0850df5ff7733f77b7745586bfd0a883813fd0a245698a0c38d02a2ed66ae4c8f24da018b863327662f64e31ef1707fc9df803758d3849aa79545469eb9ab82561abebe77fc4807a01995c525a2a249ae712b055d0896f02df00cb8b51218f71ed5caab3580af543cc859ca07acf72212294efc290699ae059071364c303133f1fd05902845d1e0f41dc177effab3d3999c914fe4e57f6ba815f60d5338d18702618f1caa7b049f6c9fc21a0edb2b120c61a89b4e00f689bb8975fafd0738d196b64cd50bdca6245e69ee12df69b553bf61837faf018d4802626f1b71b0ef21f99243d7a4a1028501dc96f5067ccd015174c025103e33799f55a863c525b905bb368fa05f589299c962fa9f85a95d99c2c1cd9a36e9a93e3a5677b39ac64d17aa7cdf8941a7266294fbc68809ff70359ebe46923d879063fcc9e6e21cedf0794edbbc8749dc99898886a4799d59256129a7fa025bac38ec1ecc046c2e720fcdeec833d4f27673f0c1857241d943a5b7492f4655e1643193255bb6f55012a73caebc3801a0601c637a7b792094ac4afc1b0438f9973f2e99a58f2e5f7977dc2e0a3b91f1b0528a57278c8c0b284dc330596ba731be88c385308ca6af79761b09a3e6187b202d8c4c356b5530c6896c58f4dea711dd3f4df60a492040ce6afba5f3e9ba752178c2f1e87ae596b528f9ba7e4fa275398ab9fde8684febd088375ffe045ba1fe52ff498307733cfa703e10a242f1b305c707b0920723dfe9d275841800feab0aa6205523623553c505ab80a1c4fb2d05b1ad9006c353e5f0881e1d08b83cb7b407ee1b725ff9f791744c7219490bd379c7f07de2b24d31d4e89492b1e53ed80bc741dbc8e093929bdf3ceb8437c2594b0b8c46a0ee255002eb111945c09a7f086c2a00a78250d88b948db7c54a404e000cb2cfc4cae76e7888b44a0a43731de966a9765b1131ea529e9e60899535dd6616ba173dfd9deef1429d659acf1ae4bd29e5498e3b58f3fe38dfc9b8c3ad9d9f41eebe438721ca38c2b3bf5e60eb26786b5d1e171a1058587bcc62c24d14cc8708c87554402e458d3ba99bcce740438aa0163c9d16bf3441502be95e238799c3daca312df6b77d318a42b94b874ef780a8b179786f55e6ad18d3ce33a0b4d2d9e549a56d13fc81246adb3c57ee995bf4d40c7d9a453ef6e5d463c10e2fe7c46e806a607a64b09c0420a59e90183d08efc53b7717ab9fe6a7cb21c8cacf19c70083767cdb0fa13229a7df599809832f18b159199a6f2f0804509bf60e52263d64b24b8ef7734bfca89cb025885d895e46b3b7660fb4e7c02ac67d59ce436f601be39a7f7cabdf5df4e72966bd03061df5004f8d49d4dbce945cbd46b2a43178dc2119035b53c1aa396b751030a5b8cdb65010b0937316be96b438ce9237dd4521fc6fe7f94b776af4ba8af167890dc5404bc6f6a03bfe383a2b8c72f257eb3eee43a8e3f5062bab990c74873fd0350675181ce0e92c069e32fb7a3334339d6175829a531a8e48051db4c41f4d8a905586d9cc90a3f4cf7b5cff1d67854c19ad8fa80450c70169745113f2f5807cbe31b24daf04fd250e13664541066317b6504735e4660a382e184e48a9c6d3f1e51013ed262b94eab1b8e0710b836f2aa03af24b007e107d09b25a5f970294578f4aea78cbfe5dfd7262996446be514b721f2bd992cce3e9d7ed9e6949261a873af1210a12300655f5148cb88c9a041615924b8cdc35d7e5dad4c5f2c8fd7a3919bbba0011140c57fbc069180daaa35bcc2d52fc74acfb87c19cde973268c8e58db1d50b466ba81eadfe6aad3716bc4a9b26eb7ab13bf63d9ad770a549467091123b574d80c1dda09e93b2494750cb2240e8d4e4b77530c087e59bdf622cbcd01ed82fca1f5037d3c2a4b3b97212462d0310fae2b0f818de010074b1f88d649e96f33c832ae9db38e27163189379750f4059d4987edda16d2a8e4fd23ad996a4206ff6b5cfa6ec06ae26b342f100729f69ce1a3d6eda2051ec811d57124e2f155f244e4713fa19564fa84b2f258bd499f9cdebceb9251ad4d12f320d85b6c5572a4120208a338196a548d5d30307df7e4188cb3a40e7deee562d2657755f3da7a47ce6c6de6ea3a340ffaf465feec667d17bb56a7a5efe6d439050e7a71ef4d2f83860450189653a3c143a318e6d9e5114d93a7efcf7f1d597db621fae6252905f4f4772bcd379c833c21d183ca4092c785d07526a67bf733157cf630894f523177078649473783eb48e947055cabfacc0bdb2793e24dea96e0a8078a620622ca260c88807796b127d76000126b9c235d7d0707dfb5c6f82a38b29ec7d3b30803257da08f6c4c043b68a5116443bde130e6630210872367c46ab9cf70484fad190e19112d2bd857eeb8bf676b38c81415c7391408ea0f8a6ede619b1182ecd420b37246f673846413a53983d89e042a253f1d171c53a6b4346284638e0541daa9c49139ce5c0f0661e256bebb0e5e1f3dc920b0bff59a1119a3ed5881de86b9e2308cc39abccd4167dd6e1dc7e2274b511d3072272276dca934f0be098077e3c3afca27209063b89191580c3808e0ca50cb5bc4a9d0d0abfb209bb584cb4e074e25270adcc4d0906005efdb79cb10ec33da9e5f8605e65ecdd268ecd756c50cc8f001b40164ed26178fb50f42c824bffbe6ff725f0a53a28aa094dc78ec86f83e23eba60aa5da0100488d0d319d728c57e1726b2b98cfa50d0c6dbfd44e4a338aa0d9657e3b2d789cffe738fe922501d63db803b1228628a71ed978a713fae21aacb60bdde82913be448d645a1cc957d57ab5becde6cae1a33a2601cfbb34811f9aab03c26b0cb9b3334069c1cb0a38b7b9100111e66eb06d5c0ff4a6e225a4a42157282dc1859a306b20954b05199fee561b20b437224883106022344821c6c3e1a4f219bcdaa55cc8e7c1edeb2dfe39a083146b402f8ae72dab7ee5d92e11f111a51ff53d60a8cf71034e6f32cbb925c6a41ffaa1c4d9a2cf7e2b55cc544905a89ff4de385c1d061f874596c4eb7f7b2ea7d1c635014d5254c5467c9c768c87bf6a9e804df9082e88443efc4165b56fa0ef5842763df9668a08be2158f2552612938cfcae63ea15c98f41bb3289bf6772526df7fcb3d7ae5806098592c37c48509acf76c6c473ddffb126c05841105bb9408bb499585a583a2e018440ef18210584f9d8d98606e194529005b56995d1ff7d39a3a2a1500052296e083e8875e65c21f5e25773d0a5a0f1868a16625b1a5a2c20dae8980e98aef7e9112264d35860c5d0911c98455ae84358911e74894aca55a492c6f44c6b31002095cb693dc8aa3e8d7ff135ad0828dbb76c51f1fa26a6079cc9e2cd49d238ed1f70574eb3bc2ff026da18e9def6aa38fe2b26ebba7fefeb1b72fbbf50cd6d1ede398362ed0be0abfe8add1ff6548e0f8f2a2bdf075e06b6a3249626fc5e48441fe2e5b40d35309188a0a5c8afece6c45eedf33160cd0ed773b570523ab6751fe4d8b3deeb30132baf243f5a7f2c57f5b50f374d5e7f6cf8940542b7d3ab848e0c211ebf95008279210c395d2f4d8853632babc11813df851c03282462e1fd0ba78023c993f2eb4341fedf99f048c7b9f344d0d4b7a07072c369ed28f1539d5f4c2a8fc87bbaf91079afc1ecc33589297355cb278b8cb940dee04b58762540f7c8f5ff48800d14b4595838538e92950b448b4f4f6c2e8b0ebe15c1b0d047b20c239c8d43288bc91da28e3252fc971c064a58dd3b8fe9cab0891afb9f1c4c8f59f3ea0168bd0d344285a1a86b35623105b031519cfe7ba81e747d4cbb410629e7548e7ff6be8d0d7f6baf779d82d3282284e1a7f646186feb8dd163e95033884bdfa8e7235d01a1dae5766d738e34829a8c33c3442a20ea80af922442355958e455c489d8a1caa286499c0d085500af93e2e7a1564fe7884405096a9dda51e1574901e67192911668d0e0e782c7e6847b7b7bc31db660addc123a7a8885acfe063fe603f83c4e72718245ec2427e4bcdb57b103a4a8144c2a7e803dcdc2d16a45ad42391ccf7ada234a848e9aa16a59f656d0c85f9e5e51869aa7cca71edf302f2de384e66c9a0d5188c807099fc9a2ba1cc927a4fe16115708edaea7918fa687dfb5c44e9ce4d25d1603ca0233ea19410c20c2cd4431cd3da9cf86b8892471413849a6353c317431a4fa311cef7ea89e5e1e9a33fc6eccaf2a458f281634128c0a9cc24c9bbfe46cedefead148bc889c08ceb1871870f18dcb8e8a40a021bbcc7c1f49d18c8d660a00a8e98e915e54e0eded10102c6ffa1bd4a2ac42fef3fa061794469759601d21fd4d61ca70cb2ec13292cb35569a770be35156622eb6b2bcd6d559ecf1036e135b14fe5b83a70d6c181f3a647212163747dd667de5c582d4efb88e5c54b25e60296cef48175a09ead70686aa490e9452748b794ba025c9956c9577faf1d7382fc17ca76b37109a2e6f69a0afa489d906027722b731a0a63e85a61d177fd209c2e70d3d7cd280b7874dd309cb0f2d601d871aed6b535dbfdaa40f47fa00886641dfbf28fdfd6c31ee9d8b91523174b2e96ecf5f84c2f315a0609f6147e07d25263bd0dc81f1dad95970d989b47eaf4444d51e260c35a1926c0d2ddbbd50d90c9b92de73b0c5b2421e83e65687d872a145a3bbaa5ffd1bd73146c50b43b0cadb18a368795850a3380bb6825d1288639bde5a19a341511187f1b5acd0de770946439efc17a1d807169b06a2194101a1ca5dd81ede9a9bdc0ef057006ab6cd17c933c4a654ba052402533d1c2c37388078204f3e16f8d7205a3ff4a0ec86cd5eb480af0951c24e6d033aaff973d85c83aa38ccff2627284862131f26b74dade773cad2be8c6af013bb591039468034a9b928e56204e69261d92994384cc2142a63cca627e2074988a56d37671ad59d75c659d2c816432a3c3ab98a5cecbb830bb13a4a4aeb44c57b34bcb26985277127108c5b272dc5bd98b6e3d4a4d7e938490bdf7965b4a29a5940147082a08420897083fa7a6cef2f0e3ad6d452ff116e0972840a6bb474597e816e1faa9a35f553f9950748f4840d51c50274fd110d67e55b5aa5b4b972893254a28952ed1bdc38dce1d559f32d020c577242c0af96d267795cbdc45a0f6da9566d2fc49162bed96ead4255a1ac1daa7ef8648874e11634b841f1f718e13ef78eb393dbc84edefdb1e856923b968475b08f5239970ff5eff0ec11de6f070fc25bf443ba7c651b8b7bf9528dcc43b66e07e5dbc91bbfa8025ba03a17624cbc3a3d6955cb27dad9bd20fe06bf2e4e709f4fe904441fdc384bbb6f5c1df5d2477f5c3a75d8f00924a5bf80e6b70fbf823bf6e1b717f47c2f6e38f250ae3db9e9abb0a501304f3a6997a242b896479f8f592ed2b5ed28d24356f62f808a592968e3fe32a239a50885f4a5f84f43cae437a9e2dc3ace09c3815b57b3cd43a47ebf5710fc2c2eb8b3d26397a4c64d822cbab9ffbe2f6afae36244d8228ba9529aaafab4745fb0caf1d8a4054ea804ef17efc95e763f2dcd86b53b2f18957e5c8faf7f97ef7cf9f3f645d7ffd2b51e0803f7ffe94d7eb6bc283abc743cbde93e32b87576f47a5bd1d44bab85f87964e65e8b49763ac8bb8a02c25fab5b6106e5d6806df5f2fcd4064c2e9d3dfbab4f668c812d55b7ac899e1a7875e7fe883241ac25e2e437d3cea807c70fcf426595e3f49a9080993e7e5eda797e84ff0fa57d5d4d4d4b4a3506cd16b5fd36c2d35c913bc4ed1e688553f3fc37343bc5a6b5dc1cf0d7ad5e40a72cfba5cc1edb93451bb7dab248a5594a9ef4b2f47d4972f8d087650ada12326461631205c5101460b55912c52314634a1b828d8bfe58e9af4d6e7d5e7f575955619441c57ae8b9552f9d886e46870faf4cb98973b124d35862232f2984eb83e660e7383c6653a01e5d1e114334ca76ce6c765133d3b335b5833977b080e3b344c4ce6b49897a45f7898996caa7bd410a9613a053531b1eda0eeb24928078e2da6938d8e99f13663e2dd4175b251d2e0347d2a3c319d1890c2cce590ede0665ba9a660c09e9a9898e4202dedcec0a1a66506332bb3e923a306cd74a257f69c9d7d31984e392cf39659c880b10263636accf4d2a30b9949c3ca569869c9222e53fc360d9363879569c90e2fa0d4a26f931dfc306f1305e3f24285e9f4d188626edb41e5fdd642c70996e9a4b788995f17392eb6984edf971ae65722d90eeaa33077b9f7ef7247e27bf0bfb2e9ce4e036647a26ca25b808411623639895dccfd4efacc93f93d5836994d4ea21973bfd3d706cab879fecd6d2274d64f3c77b01dd48fdc97c8625901cd8be974e574c0cb55d77bcbf16b4e95871e0d19ddfe5884467c6b5570cff46090f56658f5629cf5629ce9c538d3f445e4aff8331959af278eaa65d86d3aadd47db26b56ed925da24b02b6384a2a9779ec1259a8a87eedcbb046553f0dc96a50d6286adfa3cf46ade1a7aba6e223ab592b5abf57ed12993829fcac6b6a3b6f5bd7ac91b5465019edfee8c100ebc1a0d283b184480f068f1e8ca8de0bb5de8b18c4f45e805da507247d607917443fe9d773bce2836f5fff77e25ef1e32e9626a8b84ba6dc41f12bfedcc59283ba412d996c1771c941dde09e20bae6206710ba0451d6713f6ffea2ea01071944d75f4439a81e5c5aa633077503ac4b0e7e7c4d82e58969d7a2588e9f64f5485a1b08df8336f14752b4bc3d96f882e0a06e701fd3b08a57440a440a3d1029f4fdc5e170385c2de39b04fde1fcd5329c16a171252a592da3a2c59167edb812b8bf9cd69ad570da45b367b54425ab65b89bfe1357eaf2ac6520d40d92b4ec08885a225097a766ba1dfcdbd317222925a29a96e589b15bdbd3db6f6efb5b7edc6d69c286f3e37e97f7fbba062c4de01eff0d579ac8b7f196cbbae6569eb5acaeb1dd6e9f64c5bd7321605effbeef44ff4ce81fd5ff91e78b90ebe7898e825cff4a131984cc4fdd6b507d0a00bdd0dfcaeffb3e9367eefb2341215421529341e46889f27f24f837b286007e067a4ddefe23f3df8248282ddb8ddc230fc90e5fd7e07bb340539efa77da83a2a2d6e8b535fb4a8259c77d0a7fdff7e9bf3611559b951f9975f3fd9d3af7fdaf3c99ce8ae2fbb15e804e7b2eb67a1454e7d069cf855917ef98d7b0da4db368b5ebd29e915923fcfa6d59f580765d5a33cbc3e19fd66cff19961a7f3eb7d09fbad70f44027df841240ffaf08548fd4124101932651cc99471c994fbedf77f6f6d21e0d2c42de7febd75533d084b13e3631172c7db9a75fdd44ddd406b3c521b0962b7646eeed1de3c2c753aceabf625baa2ed6f7fe9f894864f69deba3edd2dbeadb4fdad3c754fe5dd6558eebe9f7e25bfaf4f9bebea934e776e1b08fabf5d64e6c6cc8d991b3337666e72509bb13eb6e8eabc4e7b2da4fa7ecd47db96c0feb03c45d81f7ef8d546c2fef04b84ff8995c9f6efc5b29e1f9bf81eff0d33bfdf8b0fe6528322e2dfcf6118dac84a3f843f92967e085f93987e08cb93e95a5b08fb4d88248c7d3f0fdf7e5882bb3c5380a27f6559d7d40d802afed36bf1d5c51eb240eb459df658ac607374dc7b5032ba88a3e2b64662894a76efbdf7dedfc0a57f3ff75c668db0cd218af42d796dc5186334fa5d9c64e927d97b31be18638c2fc618638c31a61897e7098c31c618e3ffc4ef52da7351d53be8b4d7c2ac43afe4d9825e37903a924306e48e7eb02f44762001406a400640ac18a3b0cb1387807bde71bd5fd350a0399df54a7fa360d671c79128f86a79d635d583fbf44bb047baa75f69a57fd6b34ebf524a29a5f42f2d7365f839e29cbb88c77d6d130b92ee3df133d94e7125e8dfb39aa1e0f6b3765c69a2be8d845d9eb5ac9f4ce2e3176d1ffffc98f091eebfff4e8cf5ef7ff4717f7efdfb53f7ef4f1a42e8bf7da40b0afaf3f6dc7f5f69080dff7d5fbffa95de32c95ef1cb12146370c418c46369427ff838043138fe3d31f6f04fdbdf52832201590c41159f95b2515fde5fcea1388ae17747f0335bdb677b4d345bdb6a687b6dfcf6bee1c60dde6e3771bce172c6371ccedfad4a0c472efb3a3bbaacffd3daa66dfa2ff8177cb18ef9b37581d9bebc6c602078b389e158c5456443388a55df57b9c0328be0c6816288b3038afa9311661154a1bf6f7f790059221d0aedc558ef7b74cb4b4a5f205814d43ff8432d5a2b5b6593d829bc439bf5e92424a41d4e6581541bc21d623b65b3406b65ab409ba541361bf0003dbabd7d16dca35b7982be39533b3163fff8d9469ed4937dda6173d40dec13ed9a7108da270d85310e41dbb64f56ca46d91c379ccd661311be4dbca9a1ad9985a05eab1b54519bad7d67dfda867ecdd63e35b46fadec57dbccd63e35b46fed86133ff076bbe1c8c6dc8495dd221e2fac4cac4c0c2b231b2b1b6d6165646365371cc6375b08b6db90ec51edba44f6f7d23dba5d7c1ec07211f168085b55088a5cf68fe82e11d65d196ca492b7868db5ed7665b07104abfbebcefbeb832128567111d980c5b08a6bcb8a8b8fdc26623f1fa23548bfed107cfaf946660a82a42dca1a01519e96b1414307c88e4b20416079f6c70d9ca1d275aa4ae94a05b43f10ace1d600a6d470fabbd39e5696d33eed356badbfaf24ed7a77da31d665ba83eadc1b5b87f126c37863282c3e61a81b62b108da5931b2c66845c952d3c1c7fbfbb270f42f4bffbee73a0ef051ce198b47cf0ce8194bace79c1fffc5636304f0413f3fe837cce65642fa7d9d955abfff48c2fa7dde95917ebfe85ef5fa4d3337b8c3ab56bc23e31b47b6ca8e7f6f20b51ed1d171c7ff6d19773ceb67cec8133782a4e3d73a1d1863dc8148908e3111b08e9f17d121028f2ff8a9d3615daec39087daa29f203ee858cb49c5284ea36b00c01853754c04867ed6ac8e2b57c7f8d570ddf38adc74fc48494a4b55773afe12250ce9f84d388156c7cf8214a43ca9d01575d671af8a4ec75fa7aa5410632504c91654c75fbbac11ed0d71a1e3c75e6131a430af967f83a4d02d967f17ba666c207a745f34be11eb5f22fbb98bf6de31f15b9a2da680d2b5d65a6aa9a5d6be0d42e3f4a96d092a3fb645a4d2d2252aaa8f77547b6fbd63dab7f66dc698d4e132c80e08a4226c43ccf70e59a2fc9697df921e2c514ecad4ab7e25929496ee91fe4c56abe6dd22a44b9475417378dd4ad6e8c460297ffea41172c7f6f3634043e0cfbf8186b83706f102284cfc7488b4216e9da8d704f45ad205f4fa4167fcfcf4d747025fdcba77280ce983a4072c5ddab5c5552b15bc936cc8c5e993b869e647e9eed235643fe4a108e903b35e817a0532d6ebb5b45639764ac4d2ad50286c16a0262eba44481bebc4548de2dafd24d2218c731d2c510e0f3f8bfa6ec41df3fbefebfeefefeefbc520344a57ffd5ba27793b288dd78b6477ddba4ee8907e14b9d31c0e5e5f0caaa2321b81afcd5db27ed23429213f844851b21f5338f47ca8651c14e4fb5125a69f342d8380833af4a7cf8c98adb5d65e4a29a595d29cb556847c420af09cfc7ddf0b7cecb4e763ca875459febe2fad4c3fa997980b76052e76daeb9125a7d0438a9a1e5a5e3c77daeb6125428f2a3c0583a59b6fe8b8d3de1499b01c433cebb665eda50dbb78c99d08f4eb97f68963f20dcfb6de7b6d0a51c88ad7df4d38bdf8da14997e4544b15a4bf64e76f1525b2f2e71c518c594b541cd6c228c28ddb46e401f4f155d228b97703e7817ac609847dd5863dcd5cf37eac61a23c608e019a01ee9b7e5c8c1a81b6b8c1a94e161d4f044c313dcc5dce9a78f08d5e1afd3fd77ab07d583dce9570f481e6e78a81e501153faf56541c05da98f4dc4edf4478cf1bdd503a50a817a943f971e2c9135aa7fd230d50392871b5a832c444ee9d3be7596a7734bb92f9e1f8345f899db9b73fd9b64ca9dde7a4bfa4be84fd2afa4754ed7617fff81f0bd987b58f67b9fc91ae9d7ff81e05185d2daf696c0d0b5d65f0208beba7e13ac9150d77fc21ad1de92adaeff042c00f797d35a02e3f7059227d38b5cdbd725d75a6bab43510cb5d690a283e5616bb14e1ca1f0fc670e8b6189ef6772179621ecbf4ffb0de17bf06907b74d89da0b8640fbc9f49adcd5dfdda71c0fd1f6cf9cbf9eb33af1da72472234b5de5debcf5a6badb9e5695bd60fcbddd27ef0a9295afbe1dbcff5e159ebffb4ae52b786b8eb0e42c34fce7534c4d7f1ffee185b5be29c1ab76fa3c0f7f6f7f7160576d1abb565d3cecc4b7cdc5c2a4bdc91d028ec1d899b66ee17ab2dd307642410995a9b88fc0f400108b557809a942e695a77f67724f6d6e42ebf7e6aeef212d524bd97ee6cbf23b11b6177d9da3edb486de25af1f7999984f8b6b79528d87e47e2a699b6b7fd0911a85dc4032cef6a3151e347ba447787bfe812913b5c2ef14b749fa7e908a4a2bbcb6505a8b94b6ef23650422c03f677f779f7f97dddfdccc7362fa9e15048f2ae784bdc23fa489fbf28d3b0f1c30fc3203cdc7e11efeb58ee4694b93e9c6a9c9bbe179f9a2059bb8bfe7590b4dd8e1908c39d4b0a3be82c2fe796ee8bdc45e8a2536b64a3c04eb78b7dfb7a6e8ddfafb54a4711e990cefb12e5a31bb923714d318787e77ccb39a7c6ef5b0a8c7fff96bb11e3df31c9eabc23f548624b94ffe6f46c5b066eb9c37f7f37e2fef82559f104621d3549997017fffbdd4bfae59c73f540bbe81918bfe9f663b9fb6e4f6d37ffee2b73cef973ce6099cca4ce625c0bfc1e55a0db27d9a24e916808daefe5f7fe25c20f54f24b248797181f771fffd23db23d7f8c8b82e870b09f455119b8fd2d9beedf6e08b4671b17d78fbbfefbb47ab03b7d14eedf6e26bed72804fd75ea1fe6b034c184737e1d8adf275e26bc9f82e5c9843bed597f7c29e9ee480491bb5a8eb80ff4f7819e0291f93718fefe7ee72d1cbf122791025e59859326fa881324544e7c602d4e5ea470f2c4e18d0a8c87e72e456e745d2e1c77dabbc185a6d5bb610493ddf8c1e14dd6ce75181af5bdf7b3dade3c74eb43196bfc61fce98cafbd9a526dabc557c9f21e6079f475babd0db039e8f44374faa54eb7f7ad9452101f68b11e34bef66e3073626b759788665bab4d04ea65edaeb52ca238638b91881ae37ee0d192d6625e11d283401ceafe4070c83e1952cb1b474a569bb546401668b43c68b45b0ceed35aebb02c42fa74d59fde5aef2fd78bb506cb73eff2e47da8d36b8431bea34dc327c6f80e95e95c6479f4e9bdf7ea718dbdd6a85eb0eefcf5db64636157e912d55a6bbd0208c5d1463616a6346eb48d9454549431fe7abf02056d0d196390006198f3067323cd607ed18601ff30c65ff3fd0a5e8cbfe6fb15fc3e8c33b7812f068d985c812ea70167ac61c3a801e7bc61c3dea0860d63ceb65fdcc0a1921c401130878a3f83cdc1260253dd7318790f7ead376b0e92f839e7b8ac15a318410968c61787ad5c10b1ee3b668c33a8252e11089656500034c4b527afc42876b0e996923ee48cc336f0451d045e1130581220dc1f6add81bd69eeb651b4e9176d23f8620ec7c1926e909f49378092f2f2132003404024fd90bfec59739b88fa25e8d8581db94d04e739219b88b11025348c43d688d27a9ff7fd5f225bc312042f3d7fd710dc1f59c2dd802e41437c5ff502baeab347cbb3f7c538fddca61fec2db9197e6d938d6fa723ef4b15162968885db9a23e9b08bb75f779b5e209a5714c4bdd444ab72ed87bef0563a6df19b88955b7b68c4ffff087d7af7e15d0ef5d7383c6921d5f6ff6d830af59599e3f35cab28a68d919616ac091c7ab4c88d01aa28974e8bc1bf7db7e9ce3b2a986f5e88d994d4e7a0616f37e9313501e13bf53d532626a78a1dd880d1bca26ca05cc6c72aa55e6fda616d6c4ef64a34c0da5164873a41049c9460b641b81ec874160474bc93e4a063472ceb5aeee46dc26bb5536553466a6e0984d4e59862266ee9b9c707d96cc3085c26c319b9cea97992bad97ed407f935336ef3bd9164ca1520b7c14a68621fcac5f7c2b2c4c1cededb21de8af60f648e9d62f6b0434fe99eb67fdb26358174b0d54da30a57b64c52c917e9d3bad86221cd7bf645305a321e38fd9e49481a09942ef645fd0693a8222546a6910c29dec16f3965ae068bfd17ed436be25475203ac12bedfcfdf86dd231e3771f2b7d930fa415b305a8d2da3ad977efb65b76cd73d6aaa55fca4e9994d4e79071bf3be5335c3656204b0309b9caa94794badfa4e16cac4a516d89bf05a81585b7ab06161faf57f251fc5508ba66bdba6ebd3cad97a5b2996bc0cb361568c86d05dbf1db346fcf5db33d6c8a6bfd086d9303b26023d5069c29664b92c4f83a4ed0ac16eddb8f0effb057ec3f08f27003dd3ee2730f15ec9e858b7619748077dda86599e7e20d28ad10ffa3969c72c4f3fee4696596b66ed9945134337d0bf49325dffcd8bd6da6ed9adaaa9a6374c2726ea320dc19fe65c6479f9ed528911afeb130812c9eecdf91d9f6a8b9aa16808163404d655e14f6a924aa3d61d35eb0d38ed4159ebf72f78ef2d3b800ff43991cc59beff2d2ff7953952880c222530dafe92ffb71771e48dec0085e3fed4e1f08b3a3f176103e29ca41dbc8140385cd9c146d2fe7de1dfb376f12399727e6e79190f8d9f1f881e155dcae5247bce9f291314fd90bfe81e551694287fa6e2a2a3e7cf336e5e78130b2c2f3f0d4bebf99772c6a510f368668235fa9eb2e060c75fd12e51be5fcd2e51d6755d071a627ffe137217ad98e56536fd84dccf6ac6a29a59de19fd90ff0686db33a51db3bc6cc5fa7f66962867a0db73dccaa211e9d06971fe4cb847bcac5396a97a90cb6a836ea05feb8a837ed07fd2192cae523444a62168d7fa2b55f5d2fb4b2f69102c6b14d502d564791a083fabd4dfc6f041608dcefcbbad4718618faaa9cb1df8b4046b645feb1753f0fb6795c295b7b22cc312aa4aed42f13907b5ae55f7887ea12204061a2545acd698faabd53d42b1a44e11b0373692781162eaaf52750a4bd10ffab70e7e0e49e1df5586e5e9df658deac13525d2bff7d01db22bf8fd73a86bfd746f6a835f2b259ec9f7c3bf35e1f7a9d640be3ead659697a7c0b29af5e025dcb2d4f57bd36f135fd0231128517e5d1f8e87773063f931a9443fe4ffc85c643bc8fff1a268889bae97bc4b94f3c9eb190f59a3efb3d65aeb124c28c2f107a1e121f8126888dcf38360e3e9b94f47cbf60352b49b706a2d905d3d94bc1e9ce65a54f558fba37d5c3d7cf1fad4e6c1729d7dbaad589f2d2b5cbf90bdbcb8e17bcb8d6125e3e0e093395c6f59347c5badc07755e6e2208fbc876b1bd806d79df6b66260395b5076f85eb332f00f8f25c383d8f4ca6826605250c2658a151b87ef4e7b4aa0c050b2a5c42ac99f0f2c7fdf87812499a19fd48b8a0bb1c13ff84d0c0c7cec494922e58671b1d35e12255538069df6924ca14912e3e6e0419df6b058e82b2d35385c43a73d2d365a4b4b4cd81418df75dabbf1d44fea15a367834e1dce3bedd94823c6719df66c84f9b0a1650b17eab46763091f1b433219cf75dab351638424252d310c3aeddd080b13b735e25643ce0a055d20cb2dceda9b6d146d08dafdbd526975c6b7a85f5bed57bab74ec7fbb576c38d084a982b79f709b833a1e8f451745a666d41f038bef7de925779b5568f11a9beb75e8cadee5783fadeefdb22dee40e9720d44e9f9a5f1985648b2e0fbff93db83f727f9d466df37b718fd7ee0a82d92602df7ef1a694d211b4699be665db486ff77697b4d6f7761096a779f8866d226ea4241c70de7bf9a8ef0622b9ee4bcb71ebab1fe72b8487d7306a3f1c8f7bf76e2114370e67e7e67befd519cc5f06c52f836218e230c4a098c3b0fcc28cc3ddcbd74470e34031a4f92f2886f6e9830a6172bc38518b2343d88eabab3354c0f0d8a1c20bea0b89255570883c11130665e6069f331692b870c6ca17113663ec589931858c8d5b8a377160f852464f902a58648662380227868a175f6e9c6024871e2d6468cc60ad70c521948ae14c18588f179e70004f0a602f2451f3220b15240c88c18e171b15f0e428f2b59006e54346575498294836a470258e131b5aa24c617d10e505581216f450d191a25be809a1f28387581a075bdc68c111a3ea8a5614211d428ed4f1f3c20517a64ec1ce1a19286aac7c745da96122c3191936c4e69cd13c635a78128354932178a0e87254ada9816df1f142050d94332b52c4b162c4cc13ac9c96b2277f56b0e15263828209d9923f549ab4a922c70916065074fa38b1d367cc183c402af86963c68e15590a2e0fc8ccb133054691192e8e0031e323850c3e4fa47634f1b27a11e5c81b2b2b7054c420640a11183feec461a202ab4e921c78d87849d903e58f1a94971c49a2dcc848b3244b01a5975698167aae7e3c8d605c2c2cf942a5c665cbe8c33021a3e2426a4d18314eaeaca4b85a21ca1325571cc0b0e7ce911c6651fc08206d052f44cee889329504c91e2a685c7cc1a3664d5a8d31592ebc5ca1c382972bac959580175d547831660b4794a9531c11aba3c7cb1358d695981198cd00e227063f294c49b103c58b0bcd9a932058383961a48aac5027cc932c3388e0d953850b4e98922bac2b26d041252549d6da10341b4a76c07921c559153648b0c2a0d882ba33c546131e30bac6f8f1d2fa532609176c85e521894b6f8e151695143950acc085cb0ab4ac3a4668e02368275049a5d91ab344ecc9ec89941753a8a8c932a2411b2c216dda94a153a7cd8a145f70908dc12a72b55393c30c2d8d4e8d2a5e1bbefc803323eb8c0e1644ae86967444e14344053e552d98c07cd8a9f3630f1ada10240fc4e5eb4b8a307f5a58a27b7267863c5e75faa8c142908c6e72489901ca9f2e7076dc28a32a8ba306cb1715aed86ce1e23583d91a255a4c2db5438b0a1c75ce66545dbd601567889c3e3e54b0d2e32085cfd6d48e3a5b62a48055539859c3f25484052436c4ac51db32031c3029478264a5618090203eeca065894af3c64eef0fda982e312140b010f082192cc8b8b0aed27a68ed594105648dd61f2a2400188136c7cc98b01a37b070e4393b5215c48d8c173faeb209b4e8697105cb9e1663567a71be44b1b346857dd019c06c5d41e365ac07950a40a096ccc922c393203db2c08aa4a674f819436384cae9499eb2144f79b6aea6fcac49a1cd10192f600cc162260675658a0b0c952c3cb20280474c8e283b4b6c6485e1c0dad61633542a804ceda073001e2da63041a3244f1c0d7ce9d365b68646da1f1d2e58e06c869e273fda88f1b2801838a4ce84ad0dc1caa1418f058dac3264926c7540242bc911364ad0f47020591381cb4c968ea834516a4ad0d5236cec0d102b436ec8c0030385060e3f63685913f0a203466a4896322c6c3820863359666fa86a80a9616aa935506a2cc12ac347ea8a05165e148933c7cb183233c870517db549e1821a548dac1dd6258e1f2f40749489c1d451b658c961f2b5468dc655d9038b8bda952fac3657a464f821b3e329cd97196e30a096038796a914738ab82983958506cb131c2a646009c0ca940e19525b60634a48f0a2d50b03054695a818575b10f084060e2579c67a69505cf11893a68a183774b4c0e073678a4714b0a719c458c06111e931a74cd91bb217714a5831a34b1f312b3c6428972675f4d0089235664614965a910b21643ec26889c18562488f1a6dcabcb051e107bbc032a3b585c9121868c090a1052c72e0cc60e60532dce28a8c470f3076f65c85091392024c970c3d39584f5c5864958923e3859637625e28dbf1638b99153b675758e080ca22d30a80c20e313573f8ace0024d979f314ba46c4122c667c5ed8f9438688e90b122232549c88e2f2a74b0008312ac62cd182c32623d346fdac890000d3471b260a03303951458690588f2e5ced7d8902367c2a73c6ebed2d4b061033f5d75b92acec8d046ac0e942037b46ca18103a5e4ea0f560800d8b9d3829438575f4c7dd64556e78a912630f8b1cac0459317a460a5a9f83262ea267d604033039a1b1a7dcea6e88859d385cd96395a2ac005c3959c3160a6b2acc1219221a7851573d86ca1f27d7c7ce5a0a26143079f2b3c344c941ad91d225a6b74ac008cc69f2a50ae74ed41b3848b8f33292ce98241e705646333a42103e6e2851e2cea4505b12b3c45e8f8293335113f606cb820862b8fda95591b15d4a0ae50597132c6022dba28c9e20226a72c0f9606fd7b86a429b022609ef450f5d0bac2440c14b338447ce0619186f5079c2176a63775c6021a019620b9b291158385a73b571f0858982205cb4b902063327801091d2a6a5ec6aeec20e9a0e12b4911372eb050d1634d0b2267a47a4cce94d4c127765cadf0a3c7580e245bd468edf191650d1c2bb40f48c0e3ced9191a58e040b1094bf383ca0e1d6c9cd0590001c86c79f241050a0b1f5856c4c80ad247cd45d49c371dcc0c910105b622491153f7bcd4b17ad1a7aa4b0edfed99112587880a6462f0c10215b5828f9f31206757588a727c19f192c74b0c5afa1e18a65e4812a7cc551c0a830c2b70ae98b8c91283005d3cf284f171e1434d06ac183e80c74f1e34b0a8285f2b6081a38dd9182339bee05cf5c8155b59ccc26ac8598182870b5a29bad0a849e188195688812b1665529ca59821a5a6868e3c565c86501579f301858f305dc6e8a0e9313162ea334ee2b4a94245cc15183758f48e06606b696278da93c6ce01fe7059990153250b4f1bad475a9f34065fb8d6bb0e0f1680c46891624c0800809ce9a9e1a7859836b7ac532f8d41d888f5b5abd716eab44745eb0ec954e35b75edd25b61aceb1ff2509e2790346419227937ecb44765483f876c976c8fead3081506a7bd15be3a50a73d2a61bdea5a10b9a4ea18ff0ff13eb87f82e8203ee851e931846479f53568e1b49f20ba2541d80d9df6a8ace85fa7bd296bfde4f50a6328530370aa010bc7e2b5f6de13482553b55d6c4ad45e71b4295c99865db39ab656d5725af859d4eb99e5a1595ead516647e1d7fa4b23b5ddbebe09d7ac8817d28d6f694f8cff44b27de9747b2b255d22912c0a419d7fdb2230ba69d2a3e71d95da6523bb5c51c2aad159d36a9a351a2daf8617a887071a82f635bd3ecfe986acd1f7fa352a8a1245d5287b34861d417d5551fef42a7b0435864989d26b2f0a59af01e8b53725ad7ae15b7926d4a81ffcbc6a7a7d134e9ca0c91a41b1c01a515121eb224b1332250a0a2434bca099794d7123835a6e06ee5a370677ce7bca903d3ec0ace08ca5ccb1dadff7c5c9b3844819940c3680c60c64e62e37488ad04f3f7c2664f03e0a53dce4091df828ea06491dad24fe0bdedaef53b353d76badb608cfafcb13ba7edff230b9fb26e9db9adc7beb1f2194a4a4d5df67a7d0fb94d224bb85b36f69924563817dba55cdd65ad5e8efdd4558fb842f9a4d1325ea095ac727ece8d7be1301d7e9e3fa1117d867c2fdc8d37d7e8968692d6e53ea646d2d63bd0440030074d865c04187c1060d39a120208ebbd9463104f7a7f327078d786f01083080210194e40740030074d865c04187c1060d39a120208ebbd9463104f7a733be16630c7ad1c0a2f7a40ccd5553d65639bcbab95fb87ea108bf6d69b102b6e222139cc2d58f27457299274038bcc952b29e48ad71a13e188b0bc9908f706ee6fae13b0c1b27019e36a8e4ec174539e90cc3060000000073150020200c0e87c402a14090078a2ce91e14800b789e486a4c17ca634914c428088218863184010000008010028c51d2d819000ac57b074ea7716578f8d693acb73b232b83ae763746435fff72019330dfabfeb8bb79805b382a61d094e1de4f5ad634d7832e8e0b57ac434f5a0af7502b5c8bd86ae74c51d640bb4312f245efa3eb13f3e4921b40e44bebe1cb72adfa155c6bd63b26553bf36b74dbf2c6bc0342da42f7b311ebcad042b7ba331271d372e14d726b8b9b4289827b93cc5926b98a06cfd2e1018c8592abd726530b512a9a0226f3aeddbbe5cabc4caaf64d9de5ff2c2b8b9b46054669f1c9482d6f9eec4ea4e65a6fdc49a06a7910ca4bd25d16d5e5af6b61de1f547e654ce3ae586a4aec6568e6e1f03ab4ea52dc872ff83f11612792f88a3a1cef60705a2fe356bb8b2a1e5cb9f07dee1c0a3aca8c3d7a97bdd9664dd791cd4d7461123d27ca07417c692cf285b8e55510e5960a3b50ac869ab4085775611489ad6e4e125d79f0b35c24d9b6262dad02af04546065a4ec5e2bf6737b46b427aafc31142d780fddb7407ffda4f202bfa722d51f1bc0e62679747407095730f7eb9b33d52cce6da805fa75f89d68cb6472e93b48cf955b99d67770d3cb411f72817fe7c37e6eea0215d86249cae6748decf4c4be5949eab8bb4d7829bf3255ee43fec5b19264f8f6a330be507556afaeccb4ba6315a65b629dbcbf692f1d0b9b50f333a8e5458601b22c975b19559da821d06d93b6b5c2ebe1cb8bc3ac98dc22624f9711751224f225dc2e0a13ff3d66f3743b26955af6f716e68b0cebfd1c890b44af9478037f526a68675926137eaf76293e45961365720cf307670bb7b73dd6e945ada7105f1c5c7141a9dc94bc59b2c6711554e9c7258fbda4e4dd17bbf8471ea015ae523c4a10b85de75fd0d474837283ef4aa373efdeb8eaa06481375812e3fcb98143391cd15bc451c4fdb88493b640f44a960650c8ef9ef1170ee48915f245f55761f4232d4e925e6f0eeaa56559936a7e075f9ccb5f73bd55351cd7862f7877558bb25e3909a3ed6c51e865d17f61bd7e32c1e02f9acc8bb3ff79f0cddf24af2f9ad8fe128ba4d0835c260ab8ba652aee18574f16fe244cd353954c89b7a90bd409bbebdd11c364a654d34b75abc8bcc4aa6a717d6a1f4061834eba8aff2c8b2c9133b1c917774af612748c6b9d34963dea4a594db16c2a3510d68b3995c2a29d90b125dd2cc935a5d87501a3d8d009f720e7de44c8e8839eb82d3329e4f820c1b9bf718bd4eae957cc417402260fc3db055df09fdd7839d0215f0e5d900bfa27293bb4ea0acca2d0fa48dc83c3ae1e9827d25a02d8381594f1837e694b5a60ad12b31e5aac20c50e357937f345390d631911924ba68f3326e047cb09e7b6369175f1a5d120501a0c61e2ceead908090e89fa316894130eebc725b1f3fcc22a01d28af4fe32651f33e956a64cd671e1088376ef6aabcb4060d8025603ba6b5df22326ba730e2c31d4114a8cd80b09344db27a06914f605b585d02d5a12ed98fbc17b8ebad51f386981cc5b55ca1e864eab32220eae95869fe35a2eafede50094a17f226323837ea0abc60864ebe6b04b6a1173d01666e5700669c66dada68aef400d0bd539c8ebcdfdbadb990491332e4034c86683cec40a8d74f1f0f9649a5025f9d95a2d3fa741c57b1cc4d9e54c3545a58f4eedee6eb168879624e06251d9936b4b0316b54eceb3ecd1e9719d879a053b3c39a4abda11303e1f361084cae07b6a8f64ebd5a82cbff64c9f2df917d97e5889e18797dc6b0e93a8aabdb3ec320bc3a5f0e0153266e0d38b4e47e2130cf44b1423e127a58c43ec22812ee11a01dcc066a1727410ca43a8a896050eca952c77c28d391ed0a84ccef397d3cb83ef5dea2312040f3468be036dc0521040d0f2328264a3904ecb82aa4432abe2827f2fd5ea20a2b1be72721ea2b18c19778f80ce4cddf9ca8a91ed069e577357d0cfa207fcffd1bdb3513c802dbf53a28f87c3f7b670ab6bc9bcd4fe7476f114d2835ba76fcafa52a6307eae291103531408b8845f48470f8e892474afa91b763c11c44b068c0692c5fea8267f222ff1ccb87be59430f21e14c95ab784486aa328fcabdfd30b0380479d0536e7d99f7c5f9770fa22d3880ffee97235d22ccc2bf1cf112738ae36df4d5fbdbc6b6ef8f462c8853241124da23c4f992c75af2b0bbb32d99f421201e2323077e8f29875600bc32da556e9f7332e156c1908e88730aea051393e6ab9adf5be6b56db3f9875f7a3c4efa5556bd3c02158b10fbc68e39eaec3e629b64beb06e33820fdb6345dccc9064efef70a6b813d3c218affd9c87b28db5b4e6227555c41c80f6c24b41f432bfdb4809dcfda41ba7c3473b6a5915c6ffb18f175f5630048c57fa82191e4f33f5ad3ca4efc355dc756831a8a6eff92a9387f6af609ddc46ba61f68e21a43b3d7a0070f127ab16aa5041d88a8d985fdda88cfdc95ab1d65f86c6d3cce424749c440b6e1398d36b7836ecbdaf7896201e7f4743ac8739cd67fd209acd6303fa6aab658b0f86eff23757e36f3e8cd355fe4bd454e79c7f7e12da2d01377f7ed5204c6d4206643c9638de68cd3c8ae81c679812c4dde7da7d87309046a3d07b80bc844cc9844c627e97c6a1c2a4315e62f639de0869d15e69138b0289b3a197a078aeb254b2dc70f6363a118994a68494be73c44b43e915dbf34592c056a284460a282525b7d2c9f321f17125a4f6bbccec0df391222aefc21eef8edba8ca1f2c60acd1053dff661500713f348a7d22eb26aed965b76cdf26d77e8bf40e991cccc43bbe1b4fcbde94c6226e592a752cd4641555330ef7cf0e93767ce689fc383ccb037cd45a89eb0ee6f1ccbb6accdce4b8c8868423029a17af815dc46cbf3979cda24461ceb2c171a9994cbc459a8ebb25e1effc234bad1b3a12d5c87185c439b05890b7a448615ac61dc4d71d194ab8833db31a00e203285e4b4546096c4a398a6d325d348163a06866e9a0a8d65ae91c4c08d20af0a8d4741f68cabc4a3163286fa1b12bf06c8d5fccb5158ec563f0989998b192b0a9f359604339ef70d23a10b0015787a9410a79a705f78d8e49baabd8d2b1932d7e31902a769fe2330a8ac7edf6fb0420786275ab1fff43add33e7af962279e15efbec1aeeb1253f03c523784d7571c393e9558cf9cea2fd155fc8a8e6a7e546b8a8ec5c320efa0f2308191e3320459d34b76491c51054fd58507624587296fc565b14a72eee69171426e7eb66cd36e390097300ff371c1d1ce99906e0b3841cd63adde61ee01a77ea9eb18034e8bd87f8c1c38b1bf1c3d6f53c55204cf277f0538dead68091181f2be3c8cd83ed172eb6447cb3946ee5e0a532b6310cdb701aedec47a74c71e504b4299f5dc1df3deb2c7907d258265c6061b509a44fed735c81f67246baac062613e04e191632334a350d4c6294f7d7b36842afdea8060a9c711c3dfbbfca0397919270117226859474114207e9973828a23ba9ca3020b40b0bc03818a21fce505d241fb302ea0b058173f508e3447e3badcaa10caa641318df8c57dde9bd397772a58810897702078218496702cb82004977720a86004cb72127021424b7416480182973813a030e24b59c7c73137a602e3ce674b313a0a5a062afc81efb33e1459866015190557ba2ab0badc5d00d0e1c7f9856c53fbb37a26c70376362dc0f2bd127735b6c30ad22aaff40ddbabbeedbccc9795443fb7dbff0982e678449541b1366a6d84e1e5f2cbf28378f09694002f3aceddb418b5021bb4690f1abcafb6febf4f974f1db4c59d3143594e53e37b0883d8eacafd4200450b5947aa8e4581169ab93e19157d6e5cc54a9ef95ba45423138441d7d5eebf60bce70a55e7fa954590f4b416b88acf1fc815ad761dedb20d5cb41abc2ee6dfe27e431686244bbbde88cbdfe08030fbbe678dda5f03ceb27bd9a3476d413951b9b11dfb4185994c371411a17e46f7c24e284d6fb3a02dab1624527e6b3dfd9876f44e2f92d152bf1540bafe7612cddfb1b6d82c47a063c1587497f1c19de1124f9ee2d429f8a3d7471ec3d3702926780c38a32a85da727c3a22200322567ec33f4769e1c01f5b5f38b4bfdf34b582f418e9170f6e9427770307216f22896c1e28b320f10042104bfeef3d53186c03c18009629615be796a7e707ee486fe779eef1481bba275378b6e4407b2841cbd25eb942ce6d5a212b7abeda2fa183d45f72473f9284798c0acc66b24ff39ea5959e11ed5a035239fec0eb698698e5f77e5ac54e8e1feec21631a251ebdf5591acf8b7be23a677f3620a6d6457471014448711c042a836489d793cb387d759ba0a838f4ec212ebda86d09134fa16d323becc08503d4bebc21f9dd60201015ec89a861a7d2991573c703a096d54617f035dbb8f6e1fecb34c480201e9a884f24ffb9046b9f5bd57275e2a79ae5302b4125338f25cbaef6fb0ac2402a6a0495d1ecc97515b6ebb0d8bebb2ae66f3aacfa351fcb466c3c39de13de882731fd432f30d3cc5ea09d869f8e502d0bccb4d1cad8f1cb8892407860f166a28b43373542433acd9147d94e1c122275552d093301bf36f10c99f1aa05555a26d2dc4c13c53b52845b516f899cbb8bd489127e1e2c057901edc8a6300310deb8e51261b3505e8181d281b9fe50de11007530c238ed1092f77e478293a25ebb262e9177ec09b4cc405d3b5335a65d9fa2c3b9c22a754d23ee28cb1ff120a2bc6b68d8df6820949642e7a03d7515ba6f548f23fdc07062bcfed393f3814ecc2c5f864ab28f4f59bce1f3de85d9735360228bf78ce4b22352b82c90af999be8048b68376552af8d8c625f70c93f6dbfdbf3a737bd1a9ad8fc0c56e06b8d4b979c9269fe64913432df7d9f55371b168663264b06250509edce3f3bb2d9215370aaa61f9f9582b44f028f2550c1ca62aa7b51b18173308bb694999572752bd4929b99b217b6cec50a9a3f84bbc54b8d0aa2f89a76f15a538ed50af9f76603a588468048d81543854f5dae376dbdf5ebae2aee6abbae478361ef64b209484fe4aa74c5ff586ee9a4ee02fc60a0963393a3e376ea455adf02aaa4eb56b7f8db27a4f581db4cf9176130aae8ac5707aa63233b4a5e2f5060f39a2861fa82472f941bd0c12a04d5b8c4ec39f31feced748ba965ad23645ba9eb21572f7dae5e5e427d4dc746bcba570b0066047c4226645b19cf9cd92b82c23d05a429c56f183e2f4fef6be6ab091526d396909ba0687622593b8f7ecd9cc903f5e902b218890dcd7413eff79a1c198956b17750db0e7b5ca2d6f5184c12c5f43515f63c78f0b018595737db0e5e93830b45e90bad0f6398c7d3bc5f3ed8d407e8e703029773878b921e4e273448cd2ed340b9451de9dfb653499dcfccf0b47ab0c90241e69fc6ff02e9281b1bc770815c0300652adf2d7d1e834d7395ff0759b9ffa2cd87509ed0982bd1f94dc95da0cc5aeb33921b5709a9cd22407612e4edf463a753c1196d23ecb86512dee5d233fa5670ef51e8f8acfc2a974555599502938e474554fcbd43399346a46b50bce8a03089ea998e76794d0619c6ee89dd4b3d99023d8b991fa687181b33e3b9cb0f1cad7cb04b08d2ea900573355cc0c1a843eff8b10fed288fbe0e3d1eb39e1231feee33acfa35d446a1fe8ffb61d61a16251a5cf41ff4693b6c961da3298f83b7a31f9a299973158b2dfb4a1015746b7031702c36976758f28aa74a59cf97a15648b96022a1e16bf9298943ea51a52752d7ed690e528c678e5ffc048b154f01289ad994f74336c41f4075ba44af667f05ba6b334178efbb3e75357c29816cd6d556928c1713f1573edd990cd536f12b20f1f58cea1ba8a3294e6a05aa2a5453ca8b0d34748db6e4c6fdacc67b6349887a39c078bb8f1c73eec96e0051954d5ac96bcdb1d3e444f499a961bd0234abe02f99ec4a8463d7aeca5a4b20f07ef067a2807b0503a1cbb4dc68bdd012cbfcd6a64b25e9b5c22420377d52b37d8030292b5aae005217f57ac3e565df1fd4c0481406c04e1a9b498e7f19823ff04a33fe61982ecb2e00a80661cd63b1b771b9286d3726b150c92f732fbdf752bdacf15e282e066eef8e397fe74b22ac20ebb0218bd0b9b85f08d4778de0029f81661e9222b1b2bc369ba5a0a04499c05441bcca29ff31a8db711584ba8bbe92d850803ca62468b5e724347a931e70d7b0549f24f6158ee41888bdf64a62cab71f22e3461f832fe851628626a89417591d98b321bd038007bc6749223ba3566e0f6eb3d6351a6bbd7ade97a0ffc34c8190edf12620053ffe0182fd0f9b9630f22c20505dc817455e4236f1e359f5f2e01a2d50bdaa12114621f0c2bb407b32675b2835cd619eb76aa9f32b73f1204f77ca7180ba29031d16f704a0a69a54999f9161bfd0dd893eddb01977121c4bd135b3fb65672eb8d49e7e3c6665788d36c3204251d8c4e74eabb7d315e51d16758562ba5b0e72957440b7484e7747a9c01a2069ced6df7e3275cfe955732c08e02f442961c8939fa75b6594a5587aafe43969cfdefbe3e53beb640a82ad6500ca595681074b1faa5aca68e489aee2d3a553bb66d7d0c9740241fd975f0c0c93e7879dea982a5d338443c2a4d11c9363b121559181702820b0d78d35104624098e243d8213d97edde0d8d0b5ff4730ccb2208d01ac827362a027f47a1db72be449fbc0ee430b0065403da0031a37fb6560af3aef95a10702c386c8e970102dd2829fc44ea11e4022ed66917845c2b928a005e8594b99a25fe3485fb6bcf940d06930849b9ffa8a8dfa8d39b5f6554db06cac1dc51fcc3396cc5700e623591d148e0c29d63d49553bf1ee40f406c036456f2e7c5a20214c881d86c3dbe757d4f7600da967b5038330327d0f42ef24236fb2c166e2e95f9321340d4fc7879869cc790ac0599c6d310a8aceb5fba8fba0810176f9afa16ced22cd184eb488a13fc454f00d87791631f0973ff9077e90efed9a841c0e82a0a3ff0919ccfd28ff4401452cd5b72fe0206b2e077a4be5cee564f660b24a7a3277a00867b3dee46e4475b2e94b571ca1d952997ea9eaa44dc28d0cbdc175348abe89c930b84c935ec900458d6aa3f6a7b7db770204a7185642d6ed43538cb3e41fb1f8f66fdcb7b99e7a6d749909f557d459e256c09a7dccc3aceeeaea03d5bac2a765b89705e8c4b8fc17d21415bec10b711b98c7f425bb53e4d65c38b3753c2166b4b2ebc1a0c5c7fad0509c8a307239dd64a62dc8640298bbc9f9f23ab7069b184f0f718edd1cd071d537ee0eea96028169908491d217357f6be91080a0edabec2778fc407b736074f21092c078354bf16d9180b9b69f1a75c9c39e913b26471b85deac8c8c64c7251c56633f21a0c7a0b910024694dbf025d4d5d30999c3ff2616fb927e28ba3cdec796e9c69438d2a0c76251015fbb57f081b5e1658fe5efdefe1d39b47d7bc67efa352ae10007f7e4d73ab65e31d99edffcdc93f677c99439217293e476b5f25712ac0ece21aa21eb6664a1f16fc2e4aac4ed4a74a714726d730aa727b7f5d3c7701d6e634f9752e3a5b05fc1060e5bc076f777dc2c9d6978f97cbc5f9c89ee8a6c26f2f4ab39934b2faba88fdd42bb3ed62c3d224858b4e840b8aa0db90013c6ee74b68f3eb01be6d735f3dc5c37d7d6d6f08dfa59562a66426d4afba09edbafca4b0e17a8205e0f4d64f6273b321141ef40980929682738cd6ce19025afa518725af80d313846f72ac153dc210fb2c2b20169b36cdeba174fb418c2b1aae396e6481ca842c4f3578d017cc55df825b5c6f811b3c6c700427f255e69de9368f2c8ce69d76c7ddb0dcf4e6fb7707bda8b764764b912681f1a04a010448dbc31202cc8f14ff1e96aaa93aba3ef8deb7036f74722cb5b0a60e226491e000736049857a6316734f727efed7eb2c2cac4b2601c384a71eaf3cd08ace37b578cf8a54aa3a371d5d585592c30af835ba0c61c6309f7b3de298c95b2acc8f0be081fc12e5ca01049b41ee9109a52e758fae18be8240902c44816db77c1118f613052e58c0946d686ad0ab3929251ca7adbb4581a63977202ed0c7c7e32a4821baa6f019d40fd1448111df6bf4b87b30509de9215a1d9597d936efc0d63bb06b3d30af1d281674c69a5236b0fbea6e323be4516140cee2bd2f93d1a4a1ee646075bd2c0e5b035d125837bd74f762e9bb95360d23dd9fcf12338a709f013db4517a2471ffacea13ddf6fa9a842013849e8751b7879363ae9f2dae46becf750d6dd23fa04b58a6e0088ce0d7d492c094aeac290a5fe55d4e51904751b0e7ce1ef935483bbb04ce4c3290560a2aa6a3d240ab930b1c9d7054312ca6b02b93b6b4cf2ba637275dd52f16b2c601ce3ac17844125a03d2ecd083118910848f81e6348fa861c526943246d068bde233e0648c5a0f3b937bc11b82c0bd749219f87f099bbbe3a4473ed3f7c74892b94d91e82fe61b84f4e8bd60279b4e138d2b1bf58eb06a533a333d46d360b07055fff29373729124e07a77099c70ef4abb2929a5f016984478b4929b3b0a09bf1cbe1e90c1d4aea9b07b8198fb560a92b204913b5bef608577831d4932ce426b5810a24ba33f6d6c09230a8adf8565da4907c9680073a56f95ca490ea5944742732dc00348c3c9ee8dc3c3d39adc6aabcbe7c103c0e85f650a6395c3ce0fb7d98e6908147374a23199cc5f350501890c7153e2c3d65f51769ee44e1daff63d023f2da42c0f3a890dd11ed17c00a67fc7a24ebbfa6050bc140d84b00ab6b2facb0e0c38dcfbe911324762489b05ea25341072309955abccf0e3a485c1c12c1c68acc7824de8716c2534f9b1589272b3acd21fe467b01857bdb10104a578cf91562fcb1c8eaf7ff0e558f4d0f4edd321523a12201b7adddec67c719a77c37abd9e49c1185a5f580c825b90809151c5fa7512fe8abe99d62faaed54986dace821021df2f020f452d4547b3e74074928c9830414bed572e58c07ed79f48dcb2b64bd4013a137985d7885bb0b0c88840b56db3a4eda92fafb9ca34ae40329aac638498d97ef22a188410ee6964b0af657f9b7285f2dddf39046312574f2c0d941bd0c237dd99b6db8df22e4706814648571ab9553a13367626f3ac16fae5d3990d512a291a3f3bec41ba4f6c05e7b6624661514cc6d51206c3982a87e921f6aaa91cf3c60408c33aa58b0c393d4c88e95df3624c89e30a9426a80af4df671a50ce82bb513deb970c240e78d74d0b4d670b9f3de6c3dd611d87f203b555f1035ded001905ac7c9aed03a9addf627254c4d75962e892a017bdf3a8afd84424a51124047c20eed9df0cb62318306e926b40bc7888e2e48accb2192978a9f86e390c69ef12d8b2b6fe3d09dc1608894d5c92f868c674a228e6c35ea1423bba95a1970821bcda1f44549520d00c16a16065a70034209d702aec698a8e6fe1a39bb407d2f5009524d6035b132a1d297d5c1e895ace4379fc7fc5762bcd1e1d8361bcf003a17cbc131a5cc38c418636c23908f079f68e6dcac892dad3966cb872c649c895392e5e3b42f6dfa9896726ecf891b68fd84c759a181be6587f8c06253166f370869c9586aabb8b932b74e0047a0af31b09afcaff9c3735754d85f04a5c53c5cf350c69c233fcad718491c5cc76c5260e9b441cb93d24a864b39bddf4f79222ae8ac6c5f617d864a85d7025add93b9b5dd276197d8a8c3675dce36334cb45046adc85b3718bfd6e3670c28deb773b0582684bd80b56e9edab17493eeb9affec4caf364a46161e9eab22c0c761ea0c8f7bbea0e393bfb7761786abb00f228a885bdda24457289545aebc7876c751ca4483ae153d4f003184786e806229320248b7b9b5145733043cf727ba44f2fb9b1cf90e3e7f11f0e38adbe160ab0f983371a6b4ad8d5dd68d3b50f534525d7c101b121f691063c0184c94a2e223a809620df181348e4fcefe11e9ac9e4384d2a8e382c4fa4e6b34b0732c573b25a1e2346c334e3815dc91675196227e6a743e4dbb145baa1061ccc72a5626ceb6e7153b4022fcd956e9c6cd5c966c904814e9ee1eb6ae0d5c2acf6b07d6a6da08e27346f4f2e6d11c73e5c8d503b8961632fc91345eddf709db4c227e2a906b58c84565a2af656e7ee4a26b2a9c31fef0c45db527172e05ce974f65eff85886f53b5479f6fd960ec7bb8ecb5f8b9c51024c7fb7517751d57ac9afad0e004cdf4e89b1aa78bc8c602127097b33201c4f46852bd6c3ea74ae9a9bfd368d8a3a8c52fcc7b2fda9ab71ea5406ad8e7745bfa8357dd4b4f68b486abaa4bf83b36d0dd6359b0694e07f8315c7028fc8da820be91fb6f294fe4850867c3b5816511da071f84de56c93ef088541732aede7e68933894ceb8bc9f80dfc414bb31bf9cb9d2d6e669a38d2a1617fba2dfc3b4e8b195f7b8d98f16f8d0bda87a6a2f5f542a9ad921800eb018be9e8b2f5b0bb670b3d33fe13f756d9d8675491c3ec5dd93b76ca0aa606ff0d7c07796e4c400d5b2afa547f36c8eec694f6c5d9a707592c0747ef2be1b9fd24e51f66f17b98557195131d8e5b6ac4d3b0a0731f5dc61d65348c9874c9f3bf7bd6c158a36d3fc86a1328031f4f8c01844adab6a075ff70eaf78bc4f74c42fd03d353f0d2e9b9a66ee0dd8f7995f0b5466004a104ca517a989c3e72befc41823ba151fca147c9b05417bb5cbfc9c04031bb696d26af4cdc4456ca1130d5be0fd41e5131be221dbf0f2546fb71b8e48538b70fdc048acc473658b5cc1a2beeec834cbcc6523269db062c6deb7f82a3d66ea5eb8a0fee506cdc63570bff1462d00b5957a6505889a047bca3cf5413ca11eabe8165823e6e211c6270038fddb12935787876e826408fceaf411e9af29461f03cd58d05083f68fba252a20dcf1eab0328605be9966dc7ac2009626612c9214154e72b3adbe2e3b3efa395eb4946f15222c027daf48793784cf1db60f55243a0f16f5ae58eed90cdb3f7ff989efd58c5a19bd0e9685e6b9dcb4d3f1d49f8c540fc8905b631446c04087014754c6f4663378b0e20d8139a712968c6b1569498ceac02785421e43e0c65df56853ca868945720e9447ffe785185e4f1eb699847ea66d9ec77c8d8eff970ba32a843c55a2c4ce33e7facc3c6508d965593b3db7b619a93787fcb80adbe4236c318dc2634b2f2c0e769c53ef5070837f3be65be9df22478105107cc7ae1993113bae798e2afe622143e825c03e1c3d7518ddcf8c185ecdbf21c739a1b573a6de951f9f5ffe294d033a1429439ee969242ea9432ac7e57d04cb2146d04be31b47d1381e45e30ecaae28e25c2cd7c2754ea954a27f04288b8974ee1941682e8f6666e2e351ddc0f3fd2f601d51dbe677b1062a44df0f0945f3de6c44f6f8fb85418662d144bcc50bd06345b8fbebe16aee5d951a4e1d7e1db09cdc13540d1091a77ee841a3938495687cbb5def8d57c21c6a1fdc2e7eddec31698baef567646cdf7792033a6747ccf9ce888c6ae70b897e4a4197a36cb94bfa9c1dbc16c2056a0b2eda1dcf7817d1fe0b80522dd65e3968a7a43e09d6f9b1f8c15cd7a4e8405ae8bdd107d7e0e060c34199a77ff476320e3ff0eb0a32c71a080bfd915c562c57b0622f73c9c53169fc7c55f13e50811530f499d75d2d7499274bf6c0142538845af5545061a77b28b9942251e7899bf3b5db084b28a98503688a3670a02132484068333100122cadd6140d5ccd4e3d2c549bd4da318ab78bab84610c1977e6fb7126ad765aff2c6869d767966990c6e383a150b4b5294a55c299b31b1a9b8c5dc3cd04d453d0a1a98f3baf192ff18bcd57ba5ec65b35ace851fe0480f480df20c33e63022333d609574fe2054600f006aa6a6ddb3fd6e8f863b6d6a1955a1cfb980f34e0e1561a97349e1a7e20868e40228f505bcb061fbf97e152bd3d0e79c2d346c26f9c67f4ec5dd51cc6ce93ba5f3ebff4fa543ec537e2ca5a64a4c044c0881f44049bf228705a3e4688a4aa39b8fc9e1dfdec5467ce7a9b29afc47cb439fad83563448582f62a8212dd453edc1cf749396feb2c723495befea97cbee232cd29215c39c7db67a5e0fe7217f1a9d22a212dabf2f9cdc282a5eca33c5208edbc6d2be50851a3ce6e5cb8892f585e703c1760cd1624e374f9bf4aead66c80c028c508bfac188ab2fdc6617e40ddfcb5c5121dc300fed97dfcb6b7c9de2005725c9671e41b30a22f1bd632eef35d403c4a658dfa66ef308b01d9de64e3d330e8614eff52e3bb463cbb9e1c1290e01f50a0f6c9a4b9b871e01693988c84ee2dfebcfa17bae200c55cb1c3aec20522db8b8667ac11569ef8c002902c734bcb72b3329d2e630dea1b22f638350100d292439a87874c8d215b0d5207d54d88388caf64da55d648b39270188a68bf5c6ef134edfbac99865b5169499f01a400cf38843dcdc5991a56db7a33422c50db0532207dc548b4b0f2fbd68b9f795a66307c43fcd9c2973bc8bb4f48f83034f7643e7cd0e1b3ef0c24663caf6b586927ce434fda72e13c54bda6fb9e644353c7a54cf4fddbc88d58105dac009b7b78b3c82d9611ee22199113646303bb42063f409c796440202100b4f307d495856d9ba495e64987d662dabd9bfa874abde248228b818ada41952bbf294c4662e046887c4f7e9b452be342b8c39a327b5c059ff8623016e19a14f10d66d8b59901bb2917fc5e48ddc2f64306f20eb8b99c0a51a2e55251064b224a038a91f89ac1fafae16edb40699ec1fa14a2ce212ef529e266cd3f2db5410648fc6946b34de480c10779177126f88e3e8f7f78790f69e0f23ab98355c7438fce719c1aceedc2c2af95ab5130417d91c06d701c1d0006d6fb225bea3774a10e3162a9254061ba940b30f4015a268872362c600f1efb4a96cf46a01f071a3f4d2516b2674e4cbd720ffe01c91a0bc262465ba8b1ff0d239edcf105bfcddbb628ebbc391045833de00842d8712a7c6e0059d5cd39c93cc7d47f70cfa4a91e42cf3d0c7c28aa11c3fd9e1c5308ec864fd1fb9457c6c88cbefbf2622915da1aa0bdca5853b119c9236d5f398613dfef021e7f27c888f37c701953a84e43c47982bd6d84197f85840ca1734ebb3573890601a5c913b8b98fcb02d5a045f4582976ce25bc8aae52cb6927b40499edc3be5031c6dd76af2e38ffe0e489fbf0cabbb0dc113f5b010f952060f9f5d54016b099fb721feb1e9c5b3071f205e26d26d98d7cba57c7842a4c91f89cb3ec42dbfebf418213dd8383ea44b1c1a319e8a72a66af6d5bb5c4a130f5434f63bfc3a9bfcd2bf5068005d49678c26e7e25182357b2aac71837b3c11804f661cce2b82b9a52616282ad4fc37fbb949e5168fc400dfbc49d4496cf88fb29129cd2f24e37b753f5e737d57a344f37c208ac4166224ced6cb0d8afa16330abc7baa491be6cd3638d26f5cabba1e0d2c47e2783f66233ee793ef230e5adaac0393195300bd61c081e235ff2f570b667639f446f18200d5a23dc7c0fdaf77e53a43b5161e279d29d5f6bfd0a7df3170579987c5a44c5b5080e53c90c03c038f446d4c577db173fa7ecc1bad96f775bffef1286aa016878cfe1831e26473358737d006980600d2c8408a151765b382556a3dc8343f632d9c41c28291d880a717ced71dd3182e1796e0dbb337e6fcf702d8180bf2ab1d63bfdfe390abe0027b8f12a221769d052de407e65706c34d52099b3c24d657834606860de7c1e79ec6a3499565062f47b14340974df61ae7c786299d185a940ffba7e53decbfd2109a7e0a4327fc15985eac46eb7932557cc1412eef1e0c892a1ed0e9bea1604bc100c8979ab0f6a6400c5a017b4ab13023f773579850e56ad647923627f8b7afaa97c1728e46b1a8667079192e7d8228af2bd724e23dec8ab9eb230bb35c1733c3091c871b17e63bd6442b16e4eabb088660374cfae91c16fd78a6d755c162ca9005ae94411ba83220f4712cb05870aa5c675e0a2dfc2d634bfd351f0bc5cbda4d3fe5aa5d6f327c05cc449276c31fd004ec229f21f2d1c2908b80fd1a05148676321ea3315913a8ffc6c74c2821a9379fcce1627084c2577c677dba8c0fc9bfda81deb04dbf72721e149404869a0a2bdbed7acfc58aaec758e383ddedb2149ba4aa5bfa2c79d729ecf032410498d6655e2a4495447c3df2ec8e20ffea381b748605dc340976f4723a91b66cb576cee6ceb29b87fdfd08dc200123fcf1e8ae82bd80f2e1726c8a1ed269b37af1655534fbb90ee37c54ebf119d7564959762b0663b48776c30866d1daf9d4fb3fc937d222dd711b8694de2e18ff70893337b183bfaa2230419114cc02838d1e5548ab3fa28d569e069320f7f50f21c7b852054dc9c7da2dc6df57e9e1ae9285e2807210eceeafc8116ea5ea22bdb524c9795c76b5a5d4796e39e9345f2777ae26f0d0f3cbc032a27e82b582b702014b9be4e366aef9fc2c9de6b38fded17b140fe72ac104dbea7dac5be501c227e3f2745231666b204fbb9d72188da94e0550dc934e73d08ca7dba3f77b21e84eb0fa3fc11786ce85a0a3341d707d30ccbd7840840a41f71887513c65790f0bc7e3ad367cf222cecb6da2f21bff2dab72896c95bbefea77e09034380f2e98f16c3f9afb29e138e6eadf8d3b528186d9cd3b4c1ffbdee07141b91ea724f9a45c5676bb04a374289c541f2ab9dbe92a8522f99f0c3f9d066ce7bf14d45a01e91c5572a14c706a056a86557747217228f0de11154c09ce7b74089e5a2adfcd7b51b108b9b08fa82ac5157f618270802645ec7e6a9222dffe66ddeede77ce832a2bf33544d8ef9c940085e2e54d6fe3c682e57bfc2214158ff0a48aae6a9cfadde0b804da9252e26102c43b31e5e00e3ada5134450809ccef66c83da4ab5284d9e7eda661dbddc46641833019278b7041f94ddb8d25f9e66ecf1c63c9118e960ff7992759c1e7174b07c14e3633e48b41104b5c180d4b5bd108b8db8311faea3917bef201ef38d917696f4f3243d7f1f638ee8b42f0bccc3302a84ef0ee4c42b281d7b9a176cebc0bcce4f26e3ffb1fd488c3018451e7ad143d3233a43a1182d32f762295f4f57ccb2b9ee7d4a1bc3a5059a438de282240357f609b9b2acb3ba4f17a601d90849802e25a71e639c1f98a21b19578907391f9274c73e9a7f0c43079825ae2fe02ad20ea404cea5c5d98aa46e69151b94428e1c90aba1c77c5592d265499e343e4dcc93a2d62caf598149c5fab7893aa85db4c70dccf9d5399dcdf22e43a80f8d0425b2b13a440e6304ea57e46e83c31e5961ce8532bffe671c280904c4923da20095e3066422c77d551912257fbebc687b10dc0acff92b5587b341ec7bbbd512f0a4fc6a25be8bd04eeeea44c12ff2d7e618023f61229737a0cb5382f80835a91237eba104080296cceee3f50f6fd66a52258a29496e15fcc92911339aa0e9019405f10c3dc4a6ec9ea26a06ab0762d3083607a66e6478737bd50ce2dadf7046ab07075daabebf9e979b8d63298037902e135cf75fd39dbb3dfc366380649ce334a7ec2122602e644a8bda05b7d782a52ac1aa997b73bb9cfce64875ae4429acaa03b511620d3be0deb348ea6a3f4bb846451d34fc84597da70e8d90c2b840d5216e8e35de5c5748d9302d1afddcea9b8a69cf10ab5386dbc1e5d4637e9b1a906fc13cccb8f4dff3c8b8c301e26f30c925b28655de76a66edd3f8115beedc0c8445bd9715e78d1c67e72e28d0ca0fa513fa36d5d3898d213782ccd8856bd07f99bb055072e260b1b5c0ec4a5dc638ab5042ceb357ae95412d2c35ae754d7f0faaf75c06261b333f8ca2dd211407a329263fefd93ecea965f1d65064924603fd19d4935905cabeeeeaf51817756940a08f747bcf7a519cd7e527ea68a8c13b853f14148871915e979d87d895d0d72dd6bd4d2cd344e4e30414ea532c7b34137a9acd4eec7cfe07fb2ee2285b9c2661f302251f46fcb9b9c6d529453ecfc62ff35f15a3ebabf232bf980380456e23b1e14357d5b3bcfcfac1eca6a228e54d8f514947b6d98c549bb2785db3211b816324fe0d287afb67dc4398ec4f4b0350f6fb891efc4563b105080ca1f90e4c21cac6600d0dadb0e8b53f5ee839224a2102c67bb7cb0d01012324bdb95d2b0ea550ff6bd2c7027df16ea22a2c27ccb131029d60df1f8c4fd1935ccb7f8d26669f608c762af7fdba8942d461026226c35c69932d0d20fa1410646312cf0bbe173fa226d4f20b24bd051e5df8663b594dd90c6134acef7705b4286e80d082fd85f4fc092545f179c5e7bcd9b057372ebd2743828cd93ebc9596b9a8c03ccb9b5b7aed65b9d30e6f784b1341ce4ca24a341763b6d4de3abd28477a08605d9a8cc63cdc2850cfdb61b0394367fcc63e5a5f6932564cef2d75019cd409d8d0d60c46d90924aa205fa701e41d86619513f84e563adbaddd5df075de13fae42d942dfb85f8ba84fd9c023f19835504a581564cdfaca4cd2a098fe1fe6733dba5d62809b414aa981199ff68a2649a54cf2ae06c5a69519d6270ab372e2a05c40ad45f6dcbaacef477fea0d01691fb7fa969038e34fb0328142fd97bc368bea811aa4a4adcd3b3b9f2d0e9ac9d504dab3491145c26a6f8f941595001040790fe5522e51351744aa0abc5de5c22f80c4cbc60592fcd098cda36bd4b1ba9f2d26ee20814a8c3d894bc9aa360277d40a11e72062f935acfca2294f34a405b1808e7c302967ba83df743958d7c2ded7df05e6d2e17d92c013fda763577ac42d54e32bb90439c156855162f0924d816b529950afda5cab714ca06da01cdd990b51529c129dcda9d5db18d3e4d1ee19f4a794eb295eb30127e45a18db44b23918fb32ae137ff7bbff18491215a39a44f88ff0ec8ca8bd03ae4d110c237c7efd869e023b0468138dd2630782c3a4f960447f5901f800473aa15befd0a3b6e92b8346b2d12d3188c9adda3146d825bf39b974b80178c4b30cbf675a9a6c51eb9b2e9ecbff24da4de2a18f8cf26131455e264ad0afeaed7e3d63c9d0e4a537edc3660319b0aefadc45971b8cf8407310d85a4a7fcc5cee1cc919cf49aebd9c0353799ef96cb64d42566e80a62d5f1474689213da713a8223cb9be704204a36b86c7f393f6a871ba7b058c3efd075cc973cf5b7054ee9ca9544216a4e8f4b1f37e0204dbfce47c72efc13d5088666d7cf4f7848bec2cb8935f1fa1bfa1bc334c54288b8ec834a31918ab89519e352f71a014ed7e0462e62530b808147122fe046cfa6c808d6377a0f44292716c5460d6560015be3576c8f6725048d76b65b32274fcb36eabd73ab38f177644a787017637426ab74636163be4d2da4a8ca0a35619039c4d9a866fa9f5f29b425ca05e568033ef4b835584c647ce602274934bae0fee0a55da70e9bfda5e9165f8c4e60a11a65b2671049cc3d6a41574d214e4ad7a5b8223d3c942f2c97dce01090258af347606e3bd455eaf4c6bc73b16ca5b9ac11694aeb9bae7016536c52ec57458d3ac1a4e246be6651f2536c0edfa74d41c69c9c40451d55a422077ff0f34f683352c1ef114bfc40f804c7934740ba27e57f017957649be386a0034ef87ad0308d51f06a6ddc3e8947ed70be7c2a3ed59ccb8d05768e98f185ca2821c5b16195c9901843273f8ce49278db5ecc10ab00320f70181873dfa1f457bf87633b60a1297b6f3a979624664ec60e9f53e775d0a08f58248f8518dc7a6c4a1d8a04bbb4bfce856ad2ae65b13591eec68ec9f165701143e3bc3ad19df6d335cec6fdfd737bf631b6b35144e84a4948c70d7968d3a8e76620ca552df23408a6e01b0aea5ce52b0be74f5e104a9a723031613e1af9b38aa797b9bd71eaf31c4de46504d5997185a4bac403bcb1bfd511df74c3d344b02eaf655d3cbb966ae179c0bbd83e95ebc3b6372e8d9e61106afa1cb544d83d1e5b90c374337993c2f0cc68eaca5420285a9f481e97e502e98b51a5598d68869af63a144c82617648bd1aa36ea7de8164ffc764ea60c6e15cd7d4a8e8bbfc1c7fd46ebd53ea28cded1388adb08537ceca79b80d906507b7e429b2ffbac27705a89a2402422f593c3edbff647ec1786084e10e0008ee221244d1843564ad6aec99ce723bfb228f304653087da4673e6611ec80380c828385179ca57ce15080b5f6e286ee995cf5fd601ba42b806f441c395acecd701a024b4d655ff613846127c97e8dc08f1e91465470ba8ffe2ff342dd256604efddb430148dc9d34ae33a0dba9175aad321ecde00342dd0d3bf5c9c29600c319995f1cb20ad5376d8eed98dc9e9d193927f4542104a8fb2e9baa40bd03c149cee2631b272dfa829eaeb2f2103020f018d4a4d24a8a7910b9a2da75469164f6026c544a58aaa55f4c297bee188d45c0bb0f1d587ecc51652d59a7fef8177d3957c4845cfae9dd83fcebe260c04a10aa687684760f8447756da2c66b0123292e4c26753c645b1f913bef396321e1ec73c0b7ffde6caa43708d7f3aa79589a902eab3b5bd183330126c201d5d4aa82548b8113b4c546f248e44e269bbcf83ae8f35808744b08c2e525409fc17373aa63538cfab8e41975228a9b3fe0aa2208e05355e0b254464ae2ac7dd95ef2353fb83343e5ced6369386652c03c22dd869d392096ae072dfced3708e773bd3fa83021684efb0caccce1aa512be51a5afc675432224f99a14f398215c9bb502875b14644bc82229d906996e4b51f20972cf9ec9c653a48dbd22512b3f22595244350778bb959270c3e3316f5fe50b429254b0bdc41036e0b8313f2bfc10988796209a3f9401626a0684b7a6250c964454fb603b64e2f5c4ca1c4ddcf4cf765c2a9f036d3623895b0f48df440004149f3ad1f66f335d47b6c7a342a4c1b5f1a27ddf2f994754bc853971d1117689854e0d7d1f6905d384fcf31609a948dfbac92d765b469d76f7030c04b88163d334ff0900c0739fc860739ac8aaa89c8735ea6e8327dde6ec5bcc81ccc49226a655944d60e1b0d27b75639feffe31971c4279927efb37466d590d43ce8487e065a5f65280a198579cd34404f8ea146459ed1339148975f9016c93203975ccd88aaf0ea1aafd2c6f20b97ca4ad7302833ec7b1269c2054f398d184f0d356a3889ec642335b52c7e126e3a7d582bdbbf473d94532061001915aaf55672a5eef01508d1c0a445507a77a01a591a94b9760ffb27f5b7a3e4d3114159e25fe2df2263d81a906a3a341842b724027488c94743ae92ee4dcf8610867c2b8552827ade70a38cefcbd48b2e9d210eaa89452be404ec8bf1b03b950da944f2de417b3c5174f53e350c4a40fd9065f25e7cf907d2b35b1b0094a6be7667bdef571e281dc99d52a0703dd212ee81f0055c6f187c9a90492a89ac7cfe74fb93817b5625a9a6e19ac2884982447b378f783ca02e0bdd1f704af817de55771efb4d8b95e7ed11a8d0a292419fec44adf6386b6eaefb600a5e8b627606f9e5bfcc9393ce3241610e20425c46e3a14f47c1c88868fc16ef7185ccf53667c6ed663cfd4874fdeeb915fafcfc9c506aa4efb542693fd82f89f6d50b95f57d7614f118d5a1dc727a88673f18d670303e91adf6b7b6f766d3e92561616182880d4f4eb46d7bc79fd5920c69b176bcc08a4b7a0f7f76cf9295c6d77f2f48ea82f60ec99a1f784e80932c05a3d8357a63fc17880b3e395e926774cfb0c239e38f1a11e9cf548332d71aa9c7a652afa63b80c50d45709506d5e97d81535f9145f0e1f586e95d83f7013168ab26f7a6bcdb66e4b9791ea7ceff88130b4864cd2e0d926c4d771bc852549fa066f8814465578fc1e51e51170c3536910e1bbf55f410e50808e7f584464eb9811c8a112c76509d33917088806f6a808db3146c8c636fb7a41a368e49a9c9b20b381609955e64cdd5b6a6664643a2336c412340a264ba649b9cd5a85030203aec97691428826d514fc99392eb9b3330f0e9fcb5035dcbbaff7c73675e3de953aad51029d92ada5095845bce3d9eacd7899480e597fe94797061051f77f59108a9d2dc9467882fce8a7b7f620185e1955ec8e6697cd8d68ea07b89a519c3b00a831392c4cf3ea12661e229a1a024c2446ad1e28d606d60cf8a37f3701439f3d524e6e1c45982e26541e3391633b09eb38065fc48329a6616f53ddc31be07e4b22e58fb56768a9185c66f63a4585485c11765519e3c13437e1884e00e90b645c67a0ca9b55d897e118d0060206334948958d23a474da932349187f5040ab188ec201199450e3c96ad613109138d38cace988fe1f4d95400b838e539fb010195a1eaeb721026c46a613c73f2ceef26e97160e59e5b19c236d99ec8e5975c42c7e06823053c6d2e81136c9ee59802164ef47b01444e4489e2e0e7406554c587c6748791ca627318581adb2bc60605ac75eb7896dc7a96e1f8f8675672b584ab49ca1e90509195aaad2aa8b058e73ed40e048ac808b9e9048b8bae4cb6431329b8f4c7d0805d0b8509d84041668208e5556db0bfb04a7a656751c522407d47435a2f63f1a4e31b1f5dd4f2257e144a508b344777f440f4d7097fe277628fca239548765bef5e26441015be6474dfce3221227418fba8cba5d45c87764021ad4dac1f9971c5ac7a20f0d7c302166c3fbbdcbe5b781150e1837e2ca0ec86fce1a8df06052a008a0c511e6c8e703083c885a4b1d221a5d46616c644ad84cacac3881d1367f0406e8ec08480e88e897e5954f1444aefdaf7aa9706a3ca88d35ab75d5b7d0d9a3a7d558501eabb643b168866b00d4896751da9906f23d85b2c67e84a837df2074a20542c7dca0d4c9d3bbefaa6ee4ff6320b34890b0a6d69846e75af0ef9b52fe6cfdebb8ff335684fe852c331d21cc5a6ab8a1cb3416fecea086c918c10900396021b534a957a5d4641a9ee6f20991a3e9e23ffad980137a217844156ce044205fb07d6a3d01822b1dbf027a21ebc885e2aa3b69dca28bf4e484999ed834c9020b960c2798fa1e1a31de1c5ec23ce91869aade45505186c1508ada351b4b684f4b62bf7c071086231e04853b220cc33000420db58ebccfa79ed8ba09f9d4d26a128b5cc28c354e02eddd798e8ee50e4f9e265551879495ab8b2d32632c6e775d379a15c261e80e9b3de36dc8095e3264ce5654d4849ced52b76b12379bb647e2f1fcf0ee7843581012d91abb718af7fa63cc2c491892136b07f94aca2547af9c0dfc070dc7729bd7abb539403e1b55f7b23d187c97719dcc4f51d1efa3c1c207006dcaf437d38b2f75d068b98004a4280f560ae17480c43f7305a2f83f97eb8f37167d335add809c46bfb9efab0d250f0c51b87d19583a58ded802115333ad0f17492463a0b198ad6ddaa6e04a48279094f4888208ae7cdf397fbcf7534a2b0752b801f472a43d82264ef04b5f2cb8cc9e12e1f9d911e0a370a4891f1ee4eb891487377dc27a997e03e9f8d52fbea80a9d4455d4cf4c69ca29f67d3ad9533f88d63266ba20a405b8fd163f6598464031f1aee119392b254837abd78876e26ddcf2ff8aa8840001ccb09a9737fbea57d7c9c97f3a380508fbc8e38dd827a79007aa97631badc34ca81c64b5b7e165700e27381eb9b599a311e723a5e3286243265e81a00ab0e9a2f72446134a9b107e19ed5818d32dfead2b5b7d574204e8c0f825521e0153e6cf98fa25f859c68f30f4ddf0a9c85a971ca4a16a98635cc7aa64ed49b3c82aea0a02a6d8f3c79aff2cd4b384d648b8ea80ea216be3d6937014435f6fc2b8b9c274982b59f66c42a0d5c3088571849fc2c9cf71d0e8b23bde49b4be43665b893c7531e3607259c9020c1e06987515b27ccaecfae6831e38d71e350f9fbe545c5fc7baba9645453c806cfea68aa9ffd59d6b89fcd69d5d6f7f5b6fec73df2ae1c4f4bd2e6a7bade0ff82578dd515fdf529d115c17da9a29914a9f12b8905f68adb925165ad1834870fd6d57ea8c4507520dcd37f74e17384e0c23ba4af9a8e95b98f496060f94e0913f90a45e3fa625f430c73c3f8b9519af46bd0587e04be8b648cace4441e381443cea8fb8e4445d6be349e9583af24244be9429ed45092d1394dc9739f39ff9684982ce9f82d971df0a82bf93792d8f058655ddbcd19e34b32b65f2235b27d38ca4ff831b343a1cf94227eb4e4caee56d4d8d4204656df75472eea2dd5fb1ccfc24014d16d06ce508df999325d1446d95cec2582544d49954104a74b30bbb9cc086e55fe54fccf5e4455dfff724b9aa09e81dcf92c85f93b6d6d0b219ab3a2d2961487d261cc4caeff3ec479de07f9f441537edd3199427ca5d785f4d3d0a4b7a97e186ceffe636fe32096d576644787c170f9c1a312b39bbde42e45fedc8ad16529664e5ca4b3be4a12ebca04a7c40c4c5a4942c77a57929b416b208d29944196e45e636079d80c5e24f9203480336d16c98c026a74843156ec155c4c70004b51ad5fea6ba973b1795f64ca5381858fc6a16ab7553371a8577e6035ad91f06ef2768d48fac60a92da599b3a6ab04d27b60a9562e2efe5a5b0e4a5f9195393b7ddb41c5f6452e442c9ccdebe2b8f0f490f0b69839b3a3ca1893cb6292d38a8de6894c3a2b64916d50e91bfdaaff91af70550d483c1d2fada91ca091a740bbb46d8471d5969a8e5b57b5bb95b7214be301a3dd744c85a4285d9f6083abfc2169a4a2e38aad5d42ea95d9fee5897a767594f8e853106810544b511d3cf24a34f361514fd212b9e040da536de99a5d7c9c368624dec876b276dba8add6c78932b703efee1e026327a2b54b2ff21959884ab1ab97d87cc68937da12f45e3e9c05a47bbe51f4ad2c0bec41ddb43ed71839a4686944bed90e8b31cd05135338c06108a26e6c384a22ee387dc808a5df58542adfd4b333fbdea2399bb48d5be0c17b1c794f724689b5fb986e3e154fb2957a8dbd8a2f812c27e1d36877238e76b6813dc60d414b6f48b880e39531b41287c926d153021691028d30b1a461747235f048c7d6c1b5073a7f33bd049d5077cb27f3ccd74dacc76c081110d9433745cfc6e1f8eb5729e657eeccabdcd58bbc76213a8e32e9951db9b388ee394762bd809a3ea434623d52c3da6ad8df18dee2623d1247595733e0860c0f7b7b5048c6d2626adb059ccbcbd6eac9b7a57108a91dc3184ddd01c8a8c84b830b8463ba017a1a40f3e43435cd4f6c6cf6cade379b2c10fc934432c7d40eed4b989127b7bb8bff78fcb1a6b325fa654ae46126b537f7f890ba5b849879332130b034f1c9eb0900adf49f5061e97d6fd72cf757ae265e600f2b52f5a6bf4239889b259100034025fdf59a6f96b0d3f4348cb8fb0b99ae84ac0300f2cac650705ba0457aa80e21007205c38f34ad8a5275402d3e9d1d9c3ef0330b4a6b2246bad1559ecca2b164f2c36d83fefbaf1d39d40221383093934d017f75e20ac92c2253e65e45d97d0924d75b883021c69401ad823bdc7f0fecccc8024b41261d72375a72146a6e77bdf4f64667fedcd9ce202097907740e3879b5937c9047a430026f9cd8c4667d4db2d1882a2dac4a8c050fa0527e223f9cd00197c2c6d49216b32c3fe0b53155d3490dc83f7164a9e6b1e36ac7f887b178d4e8167042debc319f6d8cdf00f58066a23fa3d01cda470c88da94857cba8ea0c5256601d181e4f22d0bd70f28350050d620d4f83405c7ecc01d56000e6b4ef7c1070af061e98196e6bdb64053229d65424d51b31e398da8a2f04e2c16cdfe35e8465ee380d5b99c5737a743356da3a8498b2438201bc7e885f1b519060d60bf8a74e9390aaf6b5e1cab12209dcc4ea18b126ce91ecd28096f822bbf6ddc4b0acb146c33a9c30062a5dd94bd7d04c40eaa2721e445c336c58ef85262a62469e977c1bb1fd1f208f0b1f75b8ac89c1bed3d583d7055d478ea44af9564688302164a8577ca8463a590c97d600e317809407b043056a5c7ecea2c981bc8e80d2d49887c3f230b36fb3ed2aee14616f29e199ca01d9db6b9220863612d0f543b0fe3aedc052da1d4a007e4c856fd89a41795cc8615e6e58f270d7f5b8384b936a43f3af94319889db249c78c972735df9e59ef0e4c314691f342b6af8bffae0b8d13058e781d787a35686c114745a261f55f13aaaa6f8cd2eac4ff0233516e404aa676a3ddce59bdb700b02e43e49e47bb4b3eb1fa87a9c1de804eb9dce0dea414cc92d5a48461a09a23cb4089748e35f2f2b61d47ee255c6d2cffcde3f269841838990b8776bd9773150f31235ad2aae928764ef01e6f3e94c24fcbce9395f7450cbb87e0888ae9ed8d928e5388819544cd1b6cf93a35220f81e1b9b9585f6e16059aa31ec13f1764a8623009885457f19ccba3a94bcd95bc1947aeaf1e037d3501f76bd054ee0613dcc3fbb31369e3dea284a46b973dee2919acdb85d9f704dc601de96962668844db3101795fee84bacb987c8ca782c8037c436aae680c3d285a5371aea6e4094f0e17ab6b45a2f94178649e52681b17d4f410e5a313f484c825ca52a2cc8b45889d8c08e9a9380cfdcce282a78a4ac02930e6283d77d719eb1d40f37434608d6c072170884ef13a8e7aa205908dca3ec441846c671269cb11eeb0ad0329a0a861a2263c90308ad59c7be29a9d3e8b4f0309d46285b6fb75064d417f25dbf7bcff3600e5b3262fd7077d08c9db4297027b361fecc88a6a2c80d15c9e81199c46a6fd8a6aeb4800bbb9d4e150c65944c1ab7ad31ff4acf28f528a5e60177534f501887837a41c3c705242752665af9760b04b2b849cad18108ea35292487be3f0b0ad9b90c081f46111f9bb651117cca2a7a74717ae79e00b3406b2235b887fe825d9e58f6dde2877815e0e4792274c7e27ba547ab43be8119d6da15215fa6237178ad5f05aa7c60d6651ee41663004336dea82cb124a4340166a9bac0943b13b4afc075ff1fa35dc17b9dc611d0486c685b11812f4d857413966783e8a10fc48318b196a99dee1745438a47cb914537f8e6961326291ced01ab17810303584607411048abe71fa297e1563d083b5531ee99a55850d01e0919ef58b134267af01f426489f733e36f612b4580770011f5829aff41f921432178742d1d7c727ae9739f2e3cd91ea79419e9d6469e6b5c8d5868e6d0da9313c3d2078c1faa716a94cc0145fd27cb7ef4016096da84178a78214913da1e8af89051f91f01f7503cc67e252e0320f6d2b0fe6a42b245f12a27130596c1cb3b216f0d59f9f85fc93e20a6c11db26907d566e47b3b6f2f481b0e913892afde8a4cde5a61f8f7190edea80cc86f2e0bea4f24879adf8cb125ffb5de67224909943aed7ce47e2edb5c724c0bcaa60f3e087911a54d251260038cca94b631bd21212ab7d4d48a8f4f8933953d54cb4a3658ce4620b5d752d48d0932f894d2af97e2664d4b6680c83a6585e3ba1b0bd315c0320e7584c6b460af08f204ec4187c26ea783736400e2b438bd9c083a68d25b19c721a7fdcff1bf1fa56cb40ceb2c2895f3b06c3bdb98f831d1edd83d8ac245a6b7680f30a3f0507142df9c149c946da2f02e6dda902ff512b8f6f0282facfae569ed9a61dd595145cfc4394e351a54ce428443749c2dafbf2aeae0275a74c167fb770e6c6e975bca4fac8241d94d9393b14bff8c8aab1729dddd94ee380e03949a8a9482fa4e1804c2959cdf3bd66d4ad75e49143235a50b43e3ef057d15dbf98293eefa88329133867d515670e605a5d1f864c9493a0c7387eb8b038a892908e8ca77e1a2f8b1cc165b4af23ca670f1c3984926fd6d415420884c0ed9287c8b6a8ae721043997038189c847731676a18f69df6e3048ee23d3d0bfdbb15ef708ff6dd648de4a4ec56066e3c948c4bd3c1a9fe2ee21a9a5ed0828dcb7edc4eecc4a634aa9272fe6bf8c0f0ca2d4136c13439854ab329c87de60cd2b538885ed074d3ab4c9e3a8ee64aae381fffa80939cc42f51f4c2fc7cd3f6b9335e80eecc53513e00fa979614c9901aa2a43aac3de4381ecf87ac175ca32220cbd72029742923b7a0ac579da860c6a2ed6365c678960aad19b77387486da650a8aca5906042c0ec72b088f74001659523afc5ac4fae79ab0e23f15af6239f69d3d1f241d2542831ca82df5ec324304700aa484b6957c4bb22f51b3d6a35949e04c32e49f93322574f8e538ff9f504f437682305b83bd81637351fb5cf6cbef33fc4787dd81363cfe43eb89a6863c9e33fe1a6a40c759d961c43e653828e2d7d670b735683d4464a79974510df87c3518a548a49456188d7f6f5a6482db266eefd66d471faae42e77bb9e8fe6ee2dc560dec5ebc2fc2bbd91d552b9b606a14d1c362e96e22b67754fb126a975617ba778469a001758aa06d736e1324875cbf23fe9a6c9d1bb63b3d1ab2dca08540afee3118b1fdc3e1f4ab1667087835095ee89005d0abc4c0e89c328b81978aec9c56f53aa1c9ae67e0c0529bd9c8a226b0969419aa913b884172f84a79c4f52c2daa0b9cca026a56827e5a200a5ab53929b910b7fe1b263c0a4af8aaa86315a78fdb84ed9e065a4cd73df47f66020d7d2f4511bab7b0a0e12e02081818889583a9c8ef9392d2e06b752247f0bd23b13bfbbfbed28cf56f6b6653b3b5ddddddddbda5945206640913076e07e367703e3a7e0df247727c74ccc0e45c3b629fc1c93518f39b8fdf5cfac8df71bef931be037df2d71b03c9ff01cf273f03f46324c993a68020af417e8c3cf90e1e35507e879c7c097f5cfb42718d9be95265ddf797077e3caa90836fd7dbfb4070b783147fc424c6bf23f1dbf302a59dc87fb0d8615129e331880bdeba0a45df3769639a74fd401a1c23c218a6be0a0d21c1d1840fce46f001c92408e295258454e474f80005b804084d050c00bde906b040f199080006a0d956f40cfd70042420e680da14893345000430f582ca80742f60a64a0911a92d7c61a8c05c4d60ebf62aab2b6bcead4e961ab5842c326a5396989b10595b50b84115216b869b9c2c2aaa8fac29554996949a42561375852c28d548161215842c13d42159445416b282a84eb27ea8266479a016e9e5b975f5c06e797a40a824f4bcd41e3d3aaa530f8e2aa4c7e6e6430f8daa42afcc0dacd75393f4c0a8477a5537227a59d40f7a35a8417a32a850bd176e717a53d4a5de93db0ebd25b79e0a6a54ef887a42cf88cad41be116440f845b0fbd0f6e787a4bb730ac226e3f600971fbc2f2e10607ab4b0d014bcecd082c372a132c35b723b0b46e3c60e5702b024bcc8d0ed695da048b8b8a040bcbcd0e160d2a11ac186e5e58bcdb1058526e40603d519fb098a83fb0a0d411b092dcee603da94fb08ca81e600d518160055197603961319d58d428578d72d528578d722d95fa020e5f62ee84e90a0347854175214aca491329264ba2b0b00214a8284aa454809242122428481d89f204e504134ae062e4491112880c19414a042141420001c8e7f4fd80b2254ad3074c3e3c80d243ea5b8a127604943c46144184141e30292d75a20c2184541051ee4001e287283e7cf500c50b4a9d2876baeaf04027ca1c28ea941c95677e18cc902f4fdf07268bc8cd9b9b74d5ddbabd02230506aa3f5dadefbdb736e94abb1767adf94f0c2d74af0c5ebaaa8410ea805037fa7e15eaeb0da15fcae41e223abb427c82686888e8cb903c9453887987fe7ddf0b2e3cf4dd2b2badfe7ddf0934a9edeb508771f5248a9fde01eabcba9a726a532bb57d158788ac7a59677bceefc5aa04ab217dfd50eafbacf78f7e1798d3fa4d4d7a5ffff77dd77a31a2dfa7a1745282a1ab8e0f2b197cc0830788a6611d7e9c765a1a5a37f17d67f865d61ae30f0460cfffe9efc356749cdb992f7733a373b657c415c0ba2b8473b97b03191b6ae0dcc5757b55a5a6eaccfd9a9698beaeb039a9ea4285a5af2b864e484b2a7d5557f8a86a41b5aa7a523353c5821155496c3154993044d510af2a1048a8627a7244ad0bcc36e587da115db5353bc0e1ba426393226333418c2d042b22b4d8a8d4c0a54a8d2b057976a48460c24685344f5924f81064aa4b936d862e3d3e3022ce1029fcc0831d9b07736a38bc51b3c646c31931646a75b06a74be78e9b2844acb9521556a7081498a90a82b2cd8a252b03579c253644b845a1e2e40de70619221ac1686081b93206c55be6a77ead47ad8c126a50d98ad1a96199b08639e70a8056165b3b265851b7298c176844acdcd546d8cd40b4d6c803282e48b0959889410a4c8961f44b6786095c70605ac0710b52f5e41e86c8113858dcd05343794a9c9e95d81b1f1aa6c4e59be6aa8fd20c39c177e4ca915f1c406c2922515ca1c0162a4d66604164048a2e5031b0a5a96a08aa8a11102890f2a74d9bac869c14d4fcd085ab51d72b05589b135a5df550d2cfdb880a1b2c150430d082b3a50b129e1d5c2a4d4c83cb18561d2d7211b16a8beaea89dc992a4afe857d4bbab2c4fd6f675c52dcbbd274e10adb82a300837978b60e8aac04e1808e885ae0adcd4a36332e99aa6f7997a749c42e7fcf77e3f30beef5e6b4d505db9e3f87510ecfaef8b4feea3241949dd28bbb8f936868ae92a8bd31596a5ab1bc0c6fff86a341ae5bfa335a1bf6fbfb05d0fddb2727c37311f4863808aa923dcf07a3ce4e1ddd4a9303463785ebcd9940f3c0314602a0bac2b8c185e199e0072e011c94a2ca00117a3a0e265db541aded009024cedc0c5ab32a7747709cf01e0042008135a502178727ac0905abc9f2935bc014c11b18567c52331f58607e4f3c31c5e6c8acb1ade19de3905803a2b8ae0955316073bbc74ca01393abca92c3af0b07812044d91e17d294636fb8b191e02a6ee24e0ca0b0f3765440fbc2178bc0d2f8e50d885f7420440d414f0c563a1a7ec9679cb8197899c9411d25435268d9910b439d2c312205173b4e06c11c0923a52588c847dcda0a386a8b3860e142c60de482900881e6060889aca43555aa952e7cd11302cf4dc401100969a312eb450b555049a0e44283285841df2a060a48dd4d03d626b853136a0704311031001c90f545f968c34e182a2d573e55545480f45586972801b1f5662a4d47879b139b9aeb4a0a4eb0957940eb43082093c10ac9cb6ac8132f3e04ecf8c0b5080900153a30720314021e2a6cb0a6aa4ec500076660c90187ac010d5c44e9415108e703511b215a5003eb27a3cbd1056e40a18345e5574a093070b139d345174008285af3b75ae906c893164062c36f47085881f684e00b18282c48ac7b352c1c407192655a488b87246ca47140cf403121de884418186293944544822a407355161b4723ace1d2e2400b9a28208787ca081ce913a2a28093323958208104e7a884188189a5410c40976cc9ce0464b4a072864ec97253ce850456baa6ac90a2d5849e3c5094c491929594b78601881c9852f5b96d470c4922b3b50e1f083ccd60f4db0e481e28510420ad6073439e0c005e585a92b39488153c583ae22bd14747893e64915272e9c50864dd418077c10840e68a8384959c2434148561a2f3d9484d992f5e585281eca5cb13365cd931235338089434310614c7a52bc30d1ea52b3248e0949d69c241c61c7480864e654c1b2793a50a285054cc9112f5b4a4e965098c1ea0dd794225a8c1701402092278a481039cc70a705a82c72c0e02084c621ca08868942c4460dd8971c8a28c1cd9007c0610106b03426e0f1008c942e24e2cd0fac2a55a89489c09c1ff0605123e50bea0b940060296307cc0829a0b00391353df2ac19c2f5c1559c1c429090c046082e568af41e52500188191bb66cb09292815949e8d869a342172457593e6069c1862e57b4682f7688de123c64de9460c74e0c265f3fca94f015430b555c80e012a6082e40b478d98011265c2569f38399315da210808d1b168084496181091c2f2370ae5a2843457391fa810327707549e264c9090f51941f715cf8a144090d7a8b552a9242579b356ade9c61327205e6cb1031c84082168bc74c9a37594e681ac23b9a92214c1c189c7aacc9a2035a236531597fd6fa06110eda5269241d46e388983c5b8ec652bee29ebe8ca67eb4a7716c7bf80f16bbd9cffe078b5dcff7f0d5a65d769eb6cf8e6e3f517bf90a7e696e71dca21e4a71a653863820e94aeb18083fce850f72fc1fef80d98d6effb67efc6efca6df8d3cc54c4edff43bd10cf9e2eb5ec6308a3b923f92f7bb5bece17a63cd6f31fe3eae7b4a1b2382fc84f476d096f9e290832eb4be6216310a9df96941f822b721b7596771289261d2941ae7a79f949434a506fae7274da9117bf49378924579d2508cbff9e7c71efdf57bcacdff18ffc162873eca3f9bb5e648baab38b785702e3d5b883abce1ffc0005f3ff87193e7d0dd28734be2dc85e6c9195ec71d837bc50d70fadd0f0d1fe24f054a3e46183f691c4fac626ffa1d2dc8499acf0aec6ee439c41cb8676ea4bfdbf385e6168729ad289690de2eea0b7efe2fca62f8f7c534835cc439179a6b4c44ce196bbda6b405488b30c637e71b4438138888b4be7aaedb2b2d2b308775e099a52e7e89f25547475fef55b4c0ee6c3ef9aaa39f69fa3ad5e9eb948b14b8bb8f17e1f163eb394344f7f843b068c733501d3f1a7badd147b9f9414ed28f8b4ffb559d815fc7d016283f79a9df76d32c571de19eeda66ffaddf73db399ecfba6dfdd3597e22eadc0284a0c2e294331fc225c861c9be78973e779c4037df38b70fa6fb59c3afa28c94d9c8fb4f6b61f3ff6e73ffa2969db3bc0af7d794d8c6e0db49eba7ead27bde7512d2b9df6250cfcb22f39381f7d7ccea0a1e8cf1ee5f64a707ecf799e5cfff9b2bdde7e82f7e4a205b6b75947ca9edcd7c689b22eecd91a5800e7c29c96665aa6666ae29c529387af810d6e6014e387e78b9d7cad7b6ddb9d79923a2c9598aa9f1b5a896c6f7eb98f747474e541eea3d085f9f96c619e1c29db3651d6858fc7f5ea5869fe4992277992277992277992e7af409d24637f6edbcd11fd30766edbd1532549beaae207ad90def85994cbb13cc3176b5fb3d96ce1283e49a3f64518ddab521f457d9e5fabbdcdbaac3b7f9c00e7c2f07141d2d586a9117e046adbeea094b22fad19ab1e41b757669274adfefd9d632dcec5be4cb7f9b17d3e58cfb40fcd74b693665ffb529b69896e1c09298a72209c1b937abef6f6b480f6b20a6828c72fb3a329db381fa9f8b43c8e2307b2007cda97189be07901f8b32fd3d34629336b3fdbb4976173b6edee667c5aa0b4abf11d3d96066db6697ff55901f0692f9e1728ed687c47cf8b34f0693b29fcd9eb9e6d77b36d77e75e47dd491a92a5a24aeff797e7b87fcd686eafc518fdbe08db9d151ab9d18749beef0b41b0ab8f0f6ee57c5600fdd8dbd302a55dcc883e3ef8f7a481be3e2f403f86c6ae8b925461fef9e7f9fadca291f47c71da883dfaf9b44069879e2e2c1763af4f1ab1bfe705b1476362d6918fc91be65e91341e778abfeffb46307cb1d7d0f19361ba7eb37c51fc3ec849fa83c5ee7c11fc52243f1c4b71ebe8e1db0e822198c6194133490f5f07295dbff9f69ce1627ccc739093f4078b5dec631c7c7cce389fcc3f928f4ddbcb202429c9571da2288ea118f22fcd4ca20e41ba01babd2ab3f581e2870b215dd5eff35ed3ef81f48fff81e1af48fafb212b8a6f3b38829fcf16a0ee638cf1f15ba12ffb28add038967f395943071f95d2f5932f93d9ab02fdd9cff88aa4fbec35cea55fced2c71949679fa63fe322eec1b274af37cc4ebe59264c3f3ff39e295f39e8e9e3bda6f64746c3b9efc32fc228b739dd48baa36f4f18e7932b12299e3bdd26ce8d5feef506ee478ac7f1c991c4b9871392ae4239a11b668fe004d10a8cc2e292a4f6aa4c1213a3785da4cb88ae3ffc7b5e60b32e0cd9802f1e656bc374fd2007e9df0f5a2105c32d925b6052c8678c1f727b255891740fff72f2d71be51a7e109234e4fd0bf7c79172d7a999122791ff5d9191d24f18f8496e716e44c24619f794ae0fea6f7c1d6eac04923feef5afb6e35bf1575a1f7f7c2bfe0ad44730c47f1476bc6fb796011709c78091c50f42928a7c55fa7a3ef387b5fe2af1e3b880fcf2296077e56f11041f04c1b7fb47e3d2fc5247c76f3e07dc0293dbd77cdda06323f1c7c7df83233fba5be4eb87d371e4ab18b4427af2bd7e7807ad90fe60b12bbf7c26a7ffc162677ed3ef4c6eb3eefb711f89e5db8cc5ff46f1c1b27c8bd34fbcb8b41d9f3374bf3f628cf57f18638c31bef7e2abaf18441dc28e58fff84579dc2b929841bde291afe2dfef45b08e743bfe62587588d476b15b9c08e96aa926d07f1b90c11fc334d7f5afb99e3ff249feedf1412ceea3dbf1ed8f03e1d316fcd212f91f0d520cc3ffee23e51e8aff33eafd337edfff68fea3bfd4a1f593fc67fcf2c9d77ce5c08292dbac5b37e8d9087c7d3fd4fce823d71b161616c622eceb3b02d7edd518aa9e83959e767b958315ce3ba6fbf6bc407c2612e3cf20f619e3f1ed99c1c96dde91c6b82def7fbe23b99fc778ef1dff7e8df1ef782fdf51840edd7568ecd1a03a7ffc1d7cc7f9e3af250a8eff039a1f36c7babdea926387491e144afb56c8f6aeba7690911ae5bfb65b6bdfac80061be414e4dba11e853e3e6358acbe5aac9e9fc6e3a8a4f639c829c89d1dc56e4b1bf22c56b73c08496a7bdd764c832ccf72935bcd3afbf94e89ab928ea5155a3354cfd80a16452b39455eca1c5bc1392fa9bd2cef666a5291f2528c8cd5ed83c52e3fa943704e3e9f3f2fe5144eff400fc4ef57d6e5f711c52f95ab5a57c8f9ba9f5fb620656feef5ae3afa88fbb5e767681f773765f6b32ff1c61c478d12eff33504f0ea5b9f27218012dc26ddde8fb65ff4698fd6d0af3dfab54efefbf0db6daf3dbfde2f1e18ab7b8ae6386aa84fe26b9478750a8e1a40af7e09129cef507992fa403e1c6fd5e8884558d811fd0706edcba77df9eab63bdb3ebafdf21f18e5d7befc1a977dfa3418e5e5397237eae1b95e8431584ec1f5a5c11c0eb22ebfca93a6d450dfe7b30f4fc25afc57cb05805fed97d02e007f5fdd3e7f7f9476b8c7e74f053eafbe0d1ffe195c28a0fd76872bcaeade7179387ea9b22ebffa3eeba58ac1e37e6935f8ba52bf278c2f839f57b9cdba19c76da59d5dd127f9fd229ccf97a53c47ee6baec7360cb09f1f80fc42fb02605fbeef9caccb5b475f73e4bea6abd1e5481929dfaf129f1f3ff964ec9453007d7e3c24a720f14f4fe82e817612d037f960b1c3fd1ddf6727f97c132e49fd261cdf817bbbfb6151c209f7db09f79b036d27dcff8c24f68f0bdd49ee84e3533e6e24bea5eaeadbddede514582bebf28be2b98dc0c75ffa60b1fb79a0b7dc45eee5fb3c89279d7ef88ea0b73bdc977813c44017af37fdffa844365bdb057655874bcf8fe1d8abaead9e1f6f6114b77f4eb103e87d9ec4ab4fd4877a89b79ff3e169d6e57f9f07fa3525b17e51d6e527f13ebf0e39b159a7721a599771bf8307ee4bf025dcabaf3e099e661d900fee7ca1fbc8d77cc4a28bffdb078b5dd07f7b552ac19b821ee84d8e0377fc4d41eff3ebf838f3a6a0c73dc9d791e700bbc8a382780724fe13532d9e03ec3e1c278a40696ab3686e14e563f4bda5eaf77411d581cd3a1cd501eebf4b55ea6da9bacfeec066ddee0087e3e252c7f134eba8ba3d5bd0507fab5cc531a51ac6bd50de17df53bcf849e9d8ecf6aa0b4ed77f5bd0d40b56d6b12266f03f0da2d05a058edb2f88843b8ec142e7ac84882672fbfd4ff355a95b13f6ef5b1b43ff67f4696b023bf120a503096114113cdee1d73574dc7114adb5d1f7a2cce29cd5bf9a544d5d3d6f4bf543abdff33f141fceaddf9f31ce1821e85fd746dfe7fc5f9d27fd7ba50e437f270cbdb4a43ff09471c3bae6405702fce089e3a5b8af40a36540f878e7351db2839b8293f2e528d13da084afcd542db4cda7d5fddbb6176a11c4314973b7577448e8eb09dc9214777b4567483f61a9b47867a023029d11e2d071ea6b2e6745b9e9b53993f6f48b5ad45f1884f99d201a1a22a202f58b5272ac40396250b168a80ea98b2690039575fb3b5b7ca228ae39b3998a62dacbba222b56a9180213144db0c352d6d916df1b2be89ba9d671acbe4f8bb8bf79a2e1cc81f385754510c0b9ab759ca5381f9c0f8109bef2bf92c301fbe0e4d138285a7c03e5268e1baebefe88635a4a2b67ab23e130f66a8e11ad35be5d09df0f5cf0ce10c5e29e582070501e0cdb24e162d2c60c06a26dfd34208c42b711330271dc0a5877af4fb7576da8b491d257f17fe0a0c03c99982b88c9c52462305ef84b13b9a3c1b228a6bc53163dc0a638812db66cc2acd101d7a4b556f58b311411727980d3a2ac35913b1a2c8b5a7be12f4d53d3546b38611d22adadd66cb6ba7e20366dba7e218b73195704b459edf66a4d958e767bb5e649175728575b2d7c9a6cd6a34bf344d7d80f8c1f18377db0eb9e7b69b3d96eb67d7b6ddfa0edb5676b60b63720db1ba4bb02b19d01ba2d70ee0b985b839d812b81fd721cc71b4916659dfd300c89b2ce8ae250d6d9ef0341f0cb9cf34debf45ef176bbddb8b561b1ca5ead79eaabd84d7ca586c9d5d61d7c6f683130bfcce0935f6ab3dc6b522ff389c1f96479bb3e5ddc2e6260fef9f9243f7c33cbc898eb07397ebbea40c23ab43cf532863b923a91575b70aeb6ac5c6d3db97d59fbf91fdbfb3c0ee871e5a74ffbd8c633f44dd9ec7bc07af94073aed26891e9f96968c2f4fc2669da1386ec315fc97346f9e9ede6a71fdb16a328cf0c661bbf39db698f78ca98718b73a9c9ed176554b6d7d9dbb73d4a9ae9364b33469e32685f92a78c98b97fcc2ff9fa834169720a90f8a0b73dc924717eb94f128f92d836ebd00f4f19b2d983a78c9ed96ca77b9d3d68fe784e70bbedcbbd964fe3414dd292e3b7bdc98d6c8f7223a08d6d3120a01f1f1c0ee35aed6b58add5ca5d8b99b52ff1a71f536bb52fb1592b1f97b572df628f315f4b5c96e9e38ea4e2ffb8309f8ca5b1bf1f3b63dbc87c1293e46c66710ef719be4f5ea5b1eae49b694fda83d738755b8ea66dd5d1d397bdc528740f5a7b8b51a01f8bedf357d3269e2e6ea7d5b61112ee34be9ee5e9c23c29f0e912e319b8e31fcf182bdee897eb4d77cf93d8413fdbabeeb3bf2706243e88dbac93fd78ca483ff6e229a3875b9c9b7dec8bf26caf48d805c618d8ac5b654f227dd9cbc0dce29c8c946b9cc339f34f93936917b70f961109df5b6b227cfc62cfe373463e5ba48ff7f9e6837ff13983fc92660ad14e174a3df6e1ffa42f7bdb67dfb357f02706f9b3277fc67fd2ff89217bf4658f3e4a3ef837cac9da03d0643bf6e976a1d4635c688b393532b98a739ba8e42b804ccb807b7ba4f6cb9721dd03e57852a084e5c5d9023f0cad7beef684912ef51ef67b1eddb02c8ae023815d7c1ce223813334e8e151892316fd5a1360c8ad8d40eb7f6be27e3e516be266137786453b3a7cf39230c20767840ffee581af7951ee17141fbf3602677ce0e34b6545d222922641fc46e00cb387cf570f2875f07511c6f906fcd445b32cfff6300cc317e2ebd7e39ca7de622cc70db43feb535c71d75a6badb5d63a86f823bf6eee56c5bd76d045b083f7c70dd4b37360598ee3baa38b1f6ecd57fde24cfb288a604a7778f02e57f85ae4eb38ea7e8e7bbdb7dffb970a46717e39fe7abbbe467e715ed2d534531a46f1d1c0f3c5bda63de3241de37807f7f07e197e79bb4623f1f5c9d7f5a2b15fd31f6573fafd31c647beca3812ee291fc5f38ee38ba828fe0d477dc5f02fbf3c9c0b67b37b67f7c6eedf18e4cf66b10f6f50931449f72bfbd0e21cfab4ddb3cbd90edfdce3bdb31dfe757355fc7aa9f410932ffef86b587e696e4b6efb75d906c3f4d8feacb47a20087bba6fafc736d8cd6dc3cc21f7da41273b284dd9fe7abaaf558f6dddd1bd5e2e62f8e139c3ec3704fdc717730a19e25f2ee2dcd59924fff2cabf6eca17cf16e59d438e22bf6eae04a1a5aa558175b393afd573dd7ea9e2f5136ff60fc5fdf20341537f7d6f8772b9ff2c8abf8e9fc991f04a120de572ff24d109eda5bd6c113e5205d587bafdd2c54e2f2d01d20faaebfe85cb562f6333db2f0882a0be3374e28599df6a2ffd8551880fd57779eefb44b2bb8573264d24b5d75551fb7cfbd5468ba093429d244992ec799224cd1b47c2bd871b81ab8df79024499224698a2b8df770a2fec50b555740b75fbc3875aabe2f997d7bf7e926c9201886faabafeb8e9e1fdc245ff50bf3c130839fbf2525237880f54ceee8e093fc8eb98fc230237ab8dedef51d8ce2fcfb57fc55df01ebf76fbed7bc77450aa27bc1cbaf569774154533fdd2efc1f403f79af68c93c23034a2aff962a5db7555dc17ef60527f61d9afe987b1af9e3f0221205a17c5d7380551d6891c9471f0cd17ff726d6991e985b1e2b2ae203ad145f03378d71847c2bae76be6d75d5702f0efcbf6fab16d662e1211e5fa4a548eb30db2eefbd9a37c7d15f30f638c31c63394af33735c7537cd73f6e56c835f6e71fc5235a797ddfcafb183690c3dcdefeb7380542aa315ccd5c14f63a85507ffa4eae09b235f4130dbf7cb0efaf8604ef24073bab2911c24331971a7830d728afb947bddc11b27baf92ba6d241248c976698ddc44c5807be940ebe8caf39261dfc94af9fa4831fe3ab6aa483413a68f235045d7b795d152051bf1cbc71a293e309921b8d1fbef832c2bf7cbd5b93e35feb7555e82f9cd35e570290f7dc017495b9bc9802fbe68af95e516b916b1c3847890e660ac69e2928f336fa5efc1234571efd87828ebb086ea3eff116af8b7cd5ff7dd092f4fbf5762de9bae617cdccd5822ef5af12f85e4bbae62741cd71e0aeff929fe3f055bfb8fdebab86917690af4a13c826b02bf86363dc917f3b7eb3236d8472b41533c2070a5102767bda680013961df9d9867623256c479ee49f36f2569d22613bf24f1b01809af252ded99206cbecf6b441424813234a4ebc8409882f58d06e4f1bb6352ef898137b33c5839323616169b7a70d599b354e8ef09134e5cb5bd6c1fd6d1c31743fba61fd07fcef7f5c7cfde8fe0f0d1f77471e55503ef9383ca0d4c52fc7d8a331be44ee50121d77d4f94519358a2acf92fc18fadf3e1fdc472d40174651b1b7fd468e1e55f2f4c5f34b72177b922f91e0be38beaf20dd31748e1e45727489dc9dbc02285f2277e9977c89dc958ffbb7631ca0af51e7df504ad2a3c813fd74c73edb48635ff2250b67873e8cf0f39a7b94138b1df9d63280822d63ac09db57ac82822d3d2b81edf73f50dac9becc26ba774c41cbb2a4617e119e117e36fa48bef4edc828f28b72de4add9e2f8ca2c8b7fd46087ad4d287cf19b66e87b28e2aa928ebf00f75d2dadedbddf96b1a93f129df7f9ebee6e8e937ec1727583d7ca3fc619ac4c1d9ebe0aff6abbcf2b2eaa0518cdcf3e798f51b7a4e96fe89fb8886f9dfa37b87f9e8979fa9cf16347c7ca0b46b9a02ea73068bfbb5ef90acc35f3edabbbd928b8aec715da821bf5ea8a40f947653be27839ed2cc3d60a9fa910d33cad1d36f9488e18c0bb1184fc24b5987ed0ee5f5152f31e11df9766794f99a1fe4462f947afe1cb47e83022c7cd0f3db2f479ef4150fe938f39ffc1f08d3d70f8031b78fbb2b9fdc4d7857f29ffce53389e57f1b070cdcf34fc0eecaa35858cf5f6a1318d81df9455847399dd8915f6e1f61585818c96dc05022a66995f7571ef7c77efff295877dd3f38d2181992c613de97bfddd5072e1ab67de81c749f7963c40a07392fda2c5a92359381ce8cca392ecf388f59edc601ff35547bf8ff7b5dff3b292cd680077a506f0c409acbb9f71349cf082b2f3e49be2c51355dc0c6a0ee70297aba8044cf6863dcc32e84624000000b315000028140a09452281400e4451c6980f14800a8daa4c5038108b04318c6218006118000400000100000000008000432c6b94e6070e5d28c4c6cb943aebe3db164fae30974c25ab9555ffbb3ded281adde01e95b54b8dd8c6dcb133a3ed9916f57c0e6f43b6dd716e9d5311cdfaf9f4b7cedfb1ad996065dcc77148063532aeee22e2857b917c9f7d09268060011ded780cc73cbfe097dfb9e0d6fb025cdd2964b6ee468240e322d53f61f459547c97119eb4b7879f44b0c48896895c30303f9dc4de4c34ecf316efaf3a7e9b2abc5033a6b9910678b43fd6e84ca79c3fc149d3d275ba9d9340856eb065e4b68d6f8c64ea227b1939ecc3a52d2e06c4a2e4c3f36c727cee8b52553cec21fe7de3eae561da61495fecb7623082c6de8d3f8728b9160167ab3889c42b1f609b159d9571fa6cd03df63b163bc61f1ecc657c91d8767bbc5d5a7f7842f59be72e12d7c3b206b360d5dab90d7e957cb836cb20497667f76ad72844f12c9ac57bb747708413431aab1914348e9f0e877c687268f5aef9b83e1f63c240c7313e1679855c11be9cba66566ca44ca56bfcee516f482778aad2d755f13218284e8e0ab18108aa912e6f67d4ee920767c02f4eb3e6cf8ea3e36fecc161b8396a6cea588a5b60a77fcd5b11b94410538c1aeaa1e4a223ab5c490dfd7ecf3d9b99fed06884f9751550f32a8168106ad7e23b342250a7f55a6ddde105338e607505542fa3fd7b7a996fa5679e79cbe2c3f2d2ccfbce5ec7e90a835943b6930229185a1aa40a1ba79505ff20490ad497f05f49612004e3506afd56c92ff4b03eafe7e6975110834b82f77b3088f4a9550b5008215088c8bf806495402eb542cce77b8c4283c3ecca16dc4aef50a61c3661fc1ebcd300bcabf5372bb149fed705469e6aeafc3a59fb9fddd74b76aaacc54d870935143808731e8476b6bf69a81cb0f08f184517df532b861d40580fc83f7700b03716303880f0139d03593775bbb5cca10a663d2686c1a10b579e988dc9a491d2ebc3f34a6e6466f0a884608faf543850a1c4006d476830525cd52ae37efd125663fc1af316e66b43873f1a25d3c3a064df6c06e7a34b9fc7413a3530c06dc16ab8a4ff0b7c8264692d4b14b1c5037d5bb3bf9c8fa31c5e705abb4f83eda370d554186999f0c16e4bbfbe95007d616e8c1e242cb1f04d80e67d562ccce5707d788c2f853526ef56f9122df8e280d6f5f2764031d8603dfb6c1e9dd46b3d96a07f495927aa5c2b250c17e06aa90e02c0aec220cb25d42ac6ce32ff55a74b231b980c96f972a39c2f8a2fe64dea0a997545f7257450745aec538bb9cc5e6c25efb0a1c08a6a98785191fba002d74f2dd9aa589975e875414caa824130430c0f761ed56bd6b2788eda5b49117af6b11a821693a6226dd657e1c18a935701645bd40de81599db3da9e383b3fd460d5510ed0b2481f7b13a68e741f07bed604eb02b2da69c1d0f78413f880af586a8ced3119e4515f39b082a298069d572ae7bac81194a86132e7555d15848dd88d3431f1766609470ddf4ff224787c56854088b6a669c9dff645a1013f99947a8b798e50180387e467520d8bf38e488e5d31a0af184111dc062ff8150399e2779344f5c8b8622ffeb00e6156b1e86e58a5799a28c25ce7a8ddb514e4716fb073c9ab572618024294705eed9720a7ee300107b1831919243267bc4815be0a85b21980e1c9fd8fad9c220e178e3239b287ab3f0e88a33876f020b16d10e663d57cd770138664351f81137cd64efa5de3305d8d6dc0289854420b620bfae8d2a9f30d6bfdb3043dba31a3570ac275e7794b5c68300774c90ecad60b296a49be9d86039299810f01be17e5fbc1cd3f066eb7acac4c9e7179f26af523f60e3aea056df65083c13acaf7e2bc0a4631a19d949f0a165ac25e28ec51fbb2a5f0b04ace14f88c38b7808c4df04cb37e359be0bb19422b0abf4d5b965dfa56908fe85199feabeb1392ef198b11d0e5dd51ba13f91b053c6ccf09523e6839abcb3f52c8b5cab17d46536eb3aaa3ac818a9a52fa3bc4f5eeec05c127c37dd09264cded6f8e6e5c8a33d72c8e060eae0eb577b7febea32a895be52797d68b62ef725479936685086783742a06844ddc992bd21476e2f06975ac445c2d3674913559b6b21c3ca21beaf5bacedb9178ed9a15f24a65f45fdb64c91e0fac00c984ededa2c6003970e14e716e04a22c5cdc6a5466901c22484e4fe097834287abe2ea65284c3633862c11482ab64f2c639b0dab9a18d8b987423c3be28b10535842ae2f55d7bc9f4d2a3c4e9b45c84a02c0e15540b2dc37ab268ff4370b5b3b1efcc0b6743b531b6987816e4dd27ac5141bdb03b3451ebd6262646cd0be099dc284c9382959dfca6297d217ca65e66bb50dde583ecb8d7b9d06672489b7c11a34e46c66f76c9a3e3802b850f745f223dd134dfa194d3b58f6eb0a7acd122ae71736e83d4d190ff300cb89feac85412147b9c0b6bf29a274c4528fc64d801a2d4cb6edd8ff637c35dcaf3927bff324db4a10789a7435f81d0062f959950418afeea89575fd532984a7191601e31af5c6d5c50c103a116e92db31663b98737a83b63151e709df2f4b1e8bbcdb20e8352d8fc4774db3dbc89de6e1d4c7a7d6990e7ea2aeb905a947b64f8fe3ee1c0dcc3bb183bddc33f53a21b5a0f276ef108bf282ab2e8cb0772018c57e02730563bcb6af3ac3617ad9a341fa99100332be1e2a4c92648ebc690b5b5149286101a7f2bb18adaa0beb18ad8906f8022bc0395bb05812912738b82a987f7c2ce44b0b3315c8ae765a2e19a3c01592043922aa869fbd3fe9b7880c43904e8898ed9f025614efef0227705900daa48a2e2c18aa1052f3d76dbfb1b4f4131493753b1eb0f4b5a486b7f8b4a80fc0d1b40e7fba4b1741fe57e0d41c602acc12e2a91ac2467bc2e74a1d6c509e2a02054f3bb34aceaa9903433059959a05929aba3991d7ea5cf511f52ebaa8b6c7f20b6e02c27101fa3e2a685ba24872f2f59eb67fa04e1c48e2b3e5a8ee467297e881f39c6918ba51abb633029dfed313c11fc6f7cf40cde2348247b3afe83c33291ab295b51a6882660baf8bf7560ecc5df845e3d057b09649a9ae681c27f765c14cbce3f067fdee38823852138968f0c6d55c51436b4c4666344a69c7934f98917bb73bb7272c3c9d2dbcee1e284afb092989788a2372063a7b9adf9287771ca5d79508682f59dde7832ea5447f8781d85f236e4e24577b269310c939fef3bd5614eb41a5b184fada09923def2ee454fdfd0489be60597f07490b9952c5a780d5f27639b04c63dc75b6681e71042a9734b34add2037a98adf5d5ce275b16d6a0884ea603a5baa22a0a25d816565a94c628bb6e208a984f0b4891924728ca89d272ac0194b2d209175352635feff8d07408818ab000cd298a99251eb9ce1d057cc30543728c5b5399b9cfd5892bb81d5e5d8023af308c16f8b5361ce3b63b6d6c2f32950a38219f9ec19d3482693c75ea2ad7573c611e85b0f7ed500a6b6ed71b05090976dabfc7e6c849b7127dabcbe4a08ec205eb43972bc1b8931a0b91a34f73a95f54e00809e0288c7a82f7e23d918e07f1a737743fdaa4e52f77be816000980ee6e2421d57225742de8263b4e6ad2119abdb3006c4b848118589d30448cd60b04eca614961160a8e081e3534148a4245e9576189d13b67ff7f3c08f2096881cecd3cd41790eb987259c106ae9b23844798eaf7babc6d0bce9704eaf4867fb665ae6e244d4b6be6d112b154438e6b9836db59f91aa7e9be92c266346daa07e2e876d7831483cc8e19edac4657fbee5ef0e822fc111b59d609c863ba80136a29cebf9e35a54485a4088cfe1b2f486fe62b1789f8615ca6212e59e19e718e1e3212e9a00c28395fb9a6cdaf350e34d32ed221e4364debe4ff3edfdf448411c312743928ca5bd0bed63728de1b4e07c961c086cae09c143ed8542f27919dd2482eeadfd13eff766baecfdd6339780299b565f0ebe2f4d0cd634532359cc45d5f91ef6878481d33572ee52b002cccbb7669237365e836211948505fd35d3749569383ba366fff911dc1177a51bf2813e3b951ab94d033fff0bae19002d0865c6b5ebae5a6eb32721f3abc1af58967f10ab208cea663316193873b1dbd2d6b8d6a195cca771422b4694886d6718c2ccdf2cc719b57ef51882315114b752aa4a9f3c627542a3ddac49c813bb1c72c3f38cdd57c6d981ae4ad564235959641440e82125ee7c8d3184e70fdf008465a890c369812be8a3cf692f51cf725c391545b2c494291956fd122294b66944ee1b67ebf9ff484dbe0d86cc52a07669876ee991bc0a1eeea097e3d1aa3babf01526011bda0f5d51fc15f919fd485b877098cadd89b31239cf3463521586a7d7a9d923154f10fd2dee83f816da9a71c1ce7eb094c2b05b78ae61b4686a1d7285ff375e3b4f19000ca8f72bfe612841b3f83dd8f880b60fd122e0464872cf6318b07bb0d6ebb1be8c6b4adfb8dd9addb0d28a976dd260cf699fdcf8ff32f9bd88df4c4461ad5bf053f503c58239cf0a61481e842d0e19320b3c98ed811a21607048305cc658fe3f8847bc15bd80139ddca368acf78865ce5b5b3cf55a4f5839ecca5e50c95c8f6d7f536d46de047013027dd4d3002f41bd48e3f004749bd657c1fb3385d12cc18991515a05a66fa4497f863b28d1f9f9522143648881743855537fada4c69b557313fab29dda30f0112d738b3e84ff4593d1be6282e25b36a4b34eb552e1566ddaecea0f7621ed4636dac4a88b51408b8bf2973789b4f828e5633cb3cb0c94dbb3239f0d0b7f21e1da0dae62e0a29e7a3607202e756e255e4878b1ce325a10bcd55f5d74dcb2c3a5c1332dd0e12e7593c65efb780c36bb0e3dfc4d1c54f1b941ae440265fc787c7d906dafbba44a2c8b779054a09968378225006b7b939a3b198ed8abaafcfae3ba78a1c60f900460546b0a0f511fba95af32cb04b10d2006ade64f36295c1b34f8a76b2247088880184c3136d989e3c31784bf409cfb35f6fa0c7f10af0e8268e4850a36c1411ab3cad48bdf218c4e2e0fc53e9012b540a378caa1dcff58fa6e01fa752da69fe2b4e484462a5921cf7c1b803ee477eabf4a90393319a312c7e6cf591ade01788acfcc1d0d7a31d29bebbeb18958290a596b44f273133be85ce3c9d6a1c9f8c83203811af0024c080222fbb369104a08cf4a63d3f8db8977faeda7b3e2b96ea1779c8bd273b120e99fb2fea6cd4821abf2703a521c84aef86e1d8b3ace0ce69516cf243b1182e8a75ee2240205c7330f4da6d55c9c9db21fc0640084219db0deeced056acb117a50a3855a7895c186f2d56ecad5cba6d80bb3efd3f2264ff7e3178561adc61000f9ed4c136b1389157cebaa655f6b7fd804c10ad58d39b62a33da9efe234803f8743aee36e47c17ba07035605876a93eff3bcc5572de6ee3a53a3abb72f178dfd509363a621ef5a01068bd0ec8a12ea288a8510e64b1335c635b8ffede9342994dc6c07981239745b78e1d6c3515ac53e6efc17db5f6b91237a969a5596f98fdc2b11019080bb2dd11202b8b6e4927dcae188180748ea9d009562069fd3fc02d24ed7e494688a969867037d0f18d78b7f9662cbd696dbd719fdda82bd4ef86ab1260bd58880142812cf666bde175224ee6eee3b87e0eec5f068ecec2b5546c04a83779a9f4202d7256cc1fc0ddd3de4cd3fe20ebb7b7b68914c91f07d3dfaa5897bebbdff27ed5673270a905f06f48b57c87197adc9850c504731a2e3a5f78a3c3838061b54bfcb22151b40f44492f6e3c28905a449299222ad216f51b844b0aaa3db9667011f1bac2cc1d05046c74eecb09d7c51fd5478d9dd90822e7d5103d71064158a956319764bb15f1ea3899575815db9ece5d7a9f963cc7e445f5b5794518c37e4a3578286974232c252d11dc828d29ab888f9f340c935136f5b463fbf1f81b75fcdedc2f68b537f41c16706ba52f48e0144bedcd0e47baf1fc5bd7d73760b235b059d1df52f8a803a324ba61ef5eb32bcf7d48e15a50d26d6cdda86c937bbf86e0a7d19ed2a46fac1cd8d3a23d26c4ab2082019555d3044d96c770cb88e6a000a32ec109e8c751ed1db306e721488f57e4c000c280fce0ad061d7d536973550a9a9b2d573f9da5ccd1dae03592ec3c83a48de54a672e4a89eb6226c1035ebc5ded239af15c04f4aeb78c218ca5729f635f8c43a5432f7bac9d16a8cdbf6d06c73eadf2e6a28495e513dbe86188cda1cccfe87e70e4473d47d0d1113b60e5f0638d80f86c74ba8b0bd8440f70d58f9563db62ea006e4b48c94c0443d9b21244e9298754bf6714555dc4d3272a1326a920d9285a0f1aa1ebc3ed23404f0e5fe50ad6edb34bece3c832e3d2792b89eaebfcc8e112ec20d1ac8abe122df3aff1d36a2dfd43a55c41e459886fb83b260a1148e684031168ecd38534e17fbdc7688c1fe81e36c7fae93a7be57b71840159855349048c9e531bf9d7d28cf135b8a9141a17c39f96a3ff490bc048ea58e6815f4ca3520de9335c6c7350aa916755b05841193f764c7e4ecf4d0640ff4e8a6178ece5d32a29cbd095333eaedf8e8eed258ba663c783884b88d16fb7c90a04227dbc83414881e0f006f822d9a50bbda1a51884bf50d0b18ac4bc1c7e583816811649c61fb2cf15a35ac188cb1d18353ab0f0aa16eca15515d5edeab23ed39bef4c9afbc1045068cc130c2b30c51454f4fb83201df9f5038608b46159485d9f84290b7c98ab8eeac1ccd161b9a168f71855b003a7152ad8b7b7bad2e613a9a50c3da146dbc7a7afe850da335cc2699ed780b165705df7a842c185cb64fbb97a7fefaaa0e30f401c7f671b3b1d5d16d6d27371a15068f93f0b5b0cf5fe22c27456e172d962891b24eb8729c0d11a4eb5706f9239444f9b4c14b14b17ba74b01032ffb98865c8dc13b79fe8666265838f22a201f81e5656c5c86c229754b98b2255667dcddb07ba1acf0274cfa8a94768a58e5beba27ca2fd9c5d0039f14af1999c2a04e6848e93fa6045d34c7896e78f447a652f67d48990734122f969327255d2b995d404d3b9a09d6b8f35c66f7712caf97ae9467e5143c66865298ff406b31dffbe8e2030fb165de7db3f6147a4acfa7b58ce420523912b81bd56f6fdf06f5c73cd9f0670e05ff0cb17c2aa8cc99e301d206e50bc49345c2659da2373ac206dd5469131361872a2cb3d447093681e547b8d54584ea7408a65e3a79f5d43b3735a0b9a84e9db948ce7039fa1402e339ec2723ba4936c5833c1e2dd7424c8c2d6bf21ae600970748b090ac0e8af2a90705804466b4b3bcd7fab4c7a164bf5f1226e6b8921a200dba6e768c604605e8b978fa512a0db83ddedbfc20abaf8bf0dd1758f629f17a764a69595584a0bf4ef3a6d30013df2be5f8289c8711e447f0181a9e45592a8a15e4e00c69845eac3034828d4e2a911d080e2abd813c1cb845e7643882eb1b55ea9dfa95d948146c298c7484ff7eb959241bb860ec42c1108a585ea8ec5269bc0578ee678cd210539dc361fed8a71a197aec6f938839a6c2e660d0d246909225a75c7c0ca463a4a7b27502c1d2a3d279ef983862f65985dfd25ffd15d94311ffbf7f0a07508d8bb4896dec4fe09ce212ffbcdd9247c87b4431d2791db4d2f32eab18d7a21b5d6da5666959423ea410e10c04c01013973a1086bf606661d77dd2bfff1e64af7eb7f319d03283da31eb47d6856d3a1fdfba5ae748ad8cb7a615bdca78fab459b4fd7830bd217382c685454ccf0716b412788ab528c1892dbdc17174e06c1b81cbbc00b99bd3849fbfeb5d09b2f3546df63c63bed85d1c70f105c81705deb496b509f3be47b2ea00f7c484eec21708b77d65fa65d7e0298b9e18d8b8bd9772f7978e07b2990f12d6785e7f1bfb37b1422eed37c3119ff41d13eb2dcc031233ba14be7c891f199635dc51816df8b39ffc9d62eadc0889c568d5da1a6e4d80f340cdcebb3d3849138492ff70a51fab7f06dcfb06c6c731d9b59beb5f534fc0002808800f96fd49a9ae5535c4cf4bbefc4ba2794f2cbdfed7efddf10ab3589dd33b8c0c4837ab1c8ae83e050dded34ecb038403d5c7891008b8947e74bf73f2c74c33fffa4896782bb300a54556475567395977a4ad15e783b3bddbf353c57704d250cbb0961765520fd5f23bf7fbf449965cafc268ffc50480f32f6dc1434759d418b4acc9aa02a915e840264877f4ff95022408e9b9b49c73c3b58d4eb5819c8e284f03604e352dd1f0005b3a71ba0968512be52d4dbfa2d450bd0cbf221fc8dbb650f0c621782a8c9ddd5387ac50db4ab0ac0e3614c99c8d22669286580e9925c49203836caa400d242f243fd3882eb82d032faeba6aec2c2841fe45d8dff60806dc7817957042a118ada8aa16e83999b2d0e44302bc6259a1c7337c197fff656232b2c3be6b417802249a3428a3494f6c1694801e748cfc46da5ec9fbd0c60d1752780a2b680548837fff33ed98ebdfc69de729653cc4a04b2199758ae8149552a92bca873f0f8b58fd76cb30c6e0beb3bf8a411c76bc2f7d2d40df0c937407838729c5c255fe4573f8e993a04c8f92b1a06b044d66c99b62da618a0f607a7f9cab83536e774a147047eb8420131820da0e026aad7d4f81f45895aaa087da9eb31c48c7a5a95074af995313e11e7489ff2b1714161bad6a61efd0ed64b1418cf389205b49b3fdef0d3d44a1e6def33ca908197a7341746a27a572c4add33d912f56178011cae98e765909f0b74edb18bcd7eaf48cf394b42fa10eae81e14a4a5605d51c97b0042e43f741e4910e6048fa5106e0060568b7b21943c7ccedc47ba30577bc974c29172bed283a5270ce93c124d9e7689befe28fb184e45bf3a086ca2b8fa2e6975b932fc5d9a5ee9d55f3e6242cc6bafa7d65c788bda7dd715d71e52b209815c8596b7c133584a49af4a82ee871247aee249b987e3a52b0dc1238a80e33937b8bf35571d872d10909794a8c133b4849b8f89358f8655f6348128ac575d890348e50d401aecd5cf4816a507c0fd574d96bb3efa72175bb121d9727168829b23ce52e94f50a28d864e545b6f66fa624b0e1c4a9c1e984b1d06119012608340d0c60556d2f61e9d6fd10d467ae2a8a4466b52b59acc77bf3a2ef674841826a35e35ef01508317e4aaf4343f198323a63dd0ddd5fd6a1d6d8ca0214ac11a5f7fc6ef9aec0a16e9c59356d4e2cb7873d25391c8153063b4a7f58d8a1385da3584c16fa3ba24cfa9d838e7dd64779975c85e7f9826cc013888d3f7a1e233b12f334d601ff376e602535902a2209498d3d1b7dd890d121dec939e6aad5c7285838e8c7d6b8cdf4388bd50208b58055b7d11947b0009e687041403521763bd2feff6d0b5f480216cb3d1f80582cd18a3c9f1ba580409280c6e181430c4980371285ca5e089286a0bec67e0895f760862a55102e9643d69a48cd140500a94e5164d5070c88f4919913740531292e15a92ed2cfb80aafa8dc5384fd8876dd1446485953c568a120b64d108726bbe50125001e73a88b82c9ab43320b12b2b763cb3e4a8e57d74b368d2948a3110b25062468427ba1a4624078318f876c40ef4030a16a700924a8b8ab7c4420ee03fbd2b2a849da1a0be19346915c85c542cd064e5dc120b91aa84ec908930f583c97624c7d342f03dac7ec506219e9fe288a5d0ef3e82d02eb4e42cd1030587b65528c97db2c341ad93beee25ba487d5a8c0fdc7149365821a7951f179c4060c47c00b074cd1a232820b147ed9bd45413d692fa7ae1e7c2174031df9d5444a66bd9fd0a4f6fec8eff059efcd0a453510436a1c0f70637bc7ecea47cc81ae6ff124199e834a878852976f9e121551e73ca9684570e2d02d2edc008647af54dd9262b65a469b6ffce84a6f342f990bf8bd00bd97e431435b0985032441ca9e9065a6b0df19b356b1ad921ca20d9dc48d98adefe60f2bc271527e51ff480075f4136b4e74225358bc385fa57501829784908e524f41e5a0202833f20eed29d3ccd143a017f42db1ad5225f4e6b3c5ffb3caccfcd7f57a71611129640322dc8f5022240dc80f316bfc077e44349383df3354e0e7db620c59b67efae63309ae758954c316fbf998b188976918f27c5caa36bb4c7cc2a5423fb7aceaa0565186aea329281e8e801bcd05eab0a0cecdad6fef94d5de9ba9d89496a21b1c7a323878f990284934dec384b276b86e2870d0cd7e26320531cee65b2b51df4ce28e56fd7286a675c79b71d8731944bc5e70707a661ec185c01123a3b835f7c59fe661e64a4c1ac59a1052ea5cf21866196be7393d69f47e8f2f196e308e679480665114449e859b4b7f0d2d2d87f74cdf85ade16f5a4f68ce01158d0c1e4768e0435601201081821952269e7853f0cc93bb0992fec918fabad6d37236adee87af9b861d10aa52e1bfa7721802fb07a379eb32b6b697d0a224813edfe065122e931cca9b42780e4ec0e8f5863e12e309319ad0cfdc6d859e9a86958f44af65a56d54af9eb2df7ab961992b1a5864e523c4c55e86673eb6c4b856c1405ce15698cf79aed76a2c20f48a8bc4defdeb6635420e277d589786092352058fa64d06b44ef5b026fabd03c6f1c01c7c88906639a6065a0949ede9e8d547f8f7918207c62a6ec80052e3b9166ed2ea57227b3411e98032d1392d93e31c202abd921e44999bf22768e22c0145b275ec76dcf3617a51cd9e749ff5605e1937338b8fa61f460ac59f9e7bd421a17403920a72d2154269a917185b0d04c9d124aac897c2f0904457860bd3b95e5cf4110dbc839f204a412d52624e44cabeca4929e437d8913ea0c96ec82b69e503111c3e063c7414563c3e80c611baf48a36101daa3297fba75a6311e0e8398d9f985b9657e6471ed3c01c5c089fe9ac858e8c55dec0ba2e129f47dbd8d66704be4871ffd4d904fdb657611b4cfe0b52f3c2967030bc5de4c6564bd09462fd65ca52431e1c8d160e1cf7c0b2bd34af4063c1e14d2b9393e261365cacae41c80bcb49060c65dbadcff45464b2445d91fe644536a6f063c28848b77159738d7bd5b05fe3a8231568bad89e02b11574016c5fd9153eba99a74ccd4b11488d6e3cc20a13345861a50e4e491f04bf54784ef70c96067fc1f8b622b3b8a606651f3b930025c1305bd5f09782f2a0429753aa560776232d01a518c4e4c2c623e9fd44e5522bd7be20787fd30d3105ad2f32a0ba07ed1a3c4ac04f2bb9b9d5578637e5288945c35c539d59a92087c48ec0e16a771addbce54ce9c164d49d8531a572f398723c9819335339f7ceef123005312442f201534258148c40af455f238181fb0c2c61dcc52790fc4b42248ccc804e130086229daf0f6ea83f1a1f993c634691d14bab23762c3cffd1989c1b1a57e7f345290fe86cf6f91e25369164798dff562a25dd557ab894df4c4db75e31880a3119b49893d05b33949be7a4a922f2594d600ff460bfd6a732a67d5d9004372665b3402183cffbf13747aa1dc442ad7e34af7173abd1c152e28823968e43e8777a53df42a208dad4c552b4561246b82d6b01336a45c46856e8387b1887a44159bcd3e3c832f85f427beff30d4a0ccbcc1b33b33f274012c3aa56234b0c88bd2f5c93810735892868ed0acdf43ef4e76f52195e2f44be1ebc4b81d912aba7fdd1f83e1cc52675da664c39dd55af4a73efa5723e9d27f80a9230dddc3d2f84e62acd9e229441f7c4d783da9ba69209ac01af9b29fa2b23886d36d4e7c380d612424d4b06651b34d4edf56d5f5911cce651a64b8698a2f415d28ccb15663cae4b8d029e73e9335639800118e40867bb5d206d15b90966572089c614d4a3757a6e2203fbd0deb862f6d72928f898d21fe787c9876ebf76df63566120c91a799971e3bafd532a3265a74cd8fb2388f929e929593e0caae11e9024a23f76cc6c267205fad5ddb84102435687672a0fce14c820cc83f8e14f3ad4b5f0884fe6856466dc5e4ab8e6cc7254087488df29d6aea270638cc692d9bf2176414585169b61f69addd4e040259338084a0953374f15e49d9e2d8519e149a4256b13eba5992e57d8df274794c8fc75e2a19bd7ab865207184bb624b72bc2af51504daf81fad16adfa4787e25ec952f8addf0a2819a64d4c3be0600c9188251868e0be12254a8644b253195a8d7561f384a0ae9e2af6c49e2512837578a1f2d2fe1055aab49a319f233067a704fc99a34d4b08a1042701c37fbaa8788b551354d406b71f2560018f2d086f1b8420724bed049cae84760f4d62f11f63004d7c56a25066f9c3bd5c28374a4aceae44d3c5a96b3e154dd78ae665125005d10dbc82c760857280d4a5b39ada0029745999e7a3972873a9797e273a82a5d11125fad8ed258929c89a66e904419a074031468229ffecb7470191bb8ef704e07a5bd42dfdcc99dd10a6019cd652ed1a1cfc29fe5ea656dee76c006d8c221da122db0e6c9cfbbd40360df7dac0565b052f7a7f2654d70daab48a2455fe87e9881e956094caa1f272557b0b950e4aa7156ab4055386a07fbf805140beb8559a41e284ebc426adc60e1bfc3e71384840fa9a82466aee80967b0acd3717fff9f20366a87db99d245838d2bd24bcd781a8353bdc471d37f53d18e6577b9c76a4db803e2bdc6083d7d70efbb0130851c4e93cec483e0d8d3c5d22184a6d0dcc293d66051e9e276a60be5a81e2b3c294dfeb6a29eb5ffde63108850c81ff8e8d6eed8df55a461d370893c008252a08e5b25160549a5153f55281a88b9c413781aad2a4d4cee1fa6b30803808e068aa822229d43a11e7179d835681c99329b5ca6f3aec575a5da277a54cf64e59de03a95301c63bf550408248c9f9bc576851363c0650a0271a0fda9ca16a70a4c8b170dc0fe6266f48b16a21cbaece31f6b925c05cd7231929b874e56a6849bdcd425e70f70ad28be572a8536e3b555eb743911fc592efc66e9fd1f1cecd485260bef1cb71469bb5c7231247ca435610ae00a86412d823ff94eb7073e06a7df5d8f5e9ec5112b76dfec44e21d20d494570e5aeb4b0495037876a0a49dea7bacf0bb7cc9a3e52349a46a6f9325d1c17904c2394ac17f40a71887434b3872e4efd50178994c273bacb94c3043281ac430918f490efa4752bd843b61cc107fc763926b6a3133b01b39a0127abcc54299dc9fd2935d44398c0b2841b2100f5f2e250254bf82d45fc735daecf58f247f79447b3508975bf8292efda40055ea68b1e04b51a9d3fb61d34d2d73f0e6a55df6312757387cecc5f8eb42ea85467ad628e7d8f2b75ea9a53f82f8290c517d2544dc10cd4324d9c4021c1a9a7ba357903ff686550b5fdc51978646eaf36193723c43f99e87ca4053a7bdeddb21c22d58029708f6fea05ce93f68fb26e52845aaa70901c505b92426dbd0a089f9cef88845235216bb4996825eb071791aa3d8a08f9f77cea691a89ae3482f5e40c591da537bd4c424d0ed3e89211732159ed9138ad901c2fe582e3b3b1044e3fb2f2f490c915de9f6ce4fd7e8a4615d885977b6b256993c0975337f07cfa98c3701118667111d197c9006e4bec0ada3c74617dadb2d744b8528d876f566cf5aa7ea815fe4011c282b440957429a311725a7c2b5aa57d9219531f32902b2251ada813000267549b849f43a41096a7fe3b87f800f61354a8b0e705718948cb89530d39c6780e5c98b5080a2abae0828b07c83682b66852c2cbef1b6cef25be18b64fcd5c9a8ddcbf4d08435dfd7bf072cef184f71746aec6cbab57d6979ee87be3c80146392ddf93ae02d347316017ec9a50f104610c846a2880aa3dc68872c84197a7cfa4ad854acd0e0cac2c4ca6a662fe3c03ef3643b91e8c71e362a8a6d6a65875cfef577ff71d8e832929c2de5a838fed1bb9da4d539255b90433008c0ba95bd061f8d3557deffe9ce6e4f37cde133fcc3f3fd126e6dbe0c32ec1404e8e7fcab09bd2c48823440a28aec643c19b154303c4b37d198c90808ecf488db2b2304ee8561d168aa5dd315e9efd39186fe93e054130605371eec5628dbac1fb6c534b976f0058c8c3c29b8ab8234fedfefd411f8afdd64cf9b8d47166c40b3a222f7f899186fa6b9a9237674b7604a2cc83e57416a95b61322fb23fcc2cc75f1c66641032c284d6d2d4321b2e2620d27529e279c44c4ba9b9b24923d00b8a0c5c70985a2d80a319996e8bcc699004f08ac60141d29cf270a1e03f98ddee99990b95f0ccdd8b0d1a9ea366c12100bba959c11741b74b7b66f2d4e079059cb60f46756144df5cf9b91c5302a344ca3394d8cc97466f098d9a64f71187597d36bdbea263349408e362a3d6dd0c6aeeddff4123a5e9dd7d9d831a173f031da00d03f8427cec12952bd7240b10a199a9051cc8fa15e099e8b9b77f88473f8bea72213ca181384d09cd88b1190f5ee6ff1ae6ed45a44e1f1c7c4e41496d4a3ac0552e1d9491d710df5ad8a6068df8381b15f50f0ab1bdfbb591d9c598e19f120d30b634d0878a6bc74d8251fd069aae4dc602f4fbd0dfebf916bc63aad6c3c2eea4b6673b76f709a6462ea606c5550c25beefdc797b1839cfd783e52e5b6ba0dcf02c51b676a370bde6ae9f9858c11c53ab6057629f0bcc99701739df1aec8298aaca54bd5ed509f92a2296cd2354cbfd0754aa079181829078e7410756c8c678b910bcc2970db808fe5c224bee6338453145e1ba7d5f055933fa0fe159cc400a16ca5d7508bcbbea1d5d4e1b0a871c422e06884fa4a268d0e1e8d212867b682ba643796edaac60fce70b8828301e78d03951e9468986039f7ab3d48a2dc2698f43820178e7554977826837077b7ec7a1244995d68b8d0b8e5177de3881af8dc083c70fbc5aa427094d822b37ac722d7eb966037200107be4fa61b262aea2185b33a84de8be0ca166a83fbcddec41528602210b3e729422687b550d1e3b688294f5f943ee3136ec9e37b7bc6a7657ff86ca0ff43bf40a2f6e552ef8970b209ea9f94ee6cf16e810db67a03936d13aa5889d6f6549aaf50cd95dcaf1b21b9c7cdc41cb4f1cc4bcde88050f0b92a7a9c4ba6a58231cf6791691478c73f3f7a084318e9a90101271c4d9db5513668d168971199438a14517583ee34e011d82a756e4809e71124f06297e10dfbc85a1a2aed1e477e9a01b122192b5551e2b4f63c11a6e08792322db3c48a4d72bdd22a633368598f12eacf5e6f8e7c3ba6fee79fcbc219c4148fcc81e39e16bea09930cabdd34e97784a35d2b2ee3a3a3f79cb792c02380229cbe59481a5120d1e74fc63755b925eedfbb599b2b9f2eaa9759463219ab4462284ab30dc50f676efd7f9101d6b30ef24de97a0d0958324d3e2dc3c0c0043f37affa601037b863f97caa02654e9d8a047c253ed37a28c573b73ce853c9bc03bf1e6b4922da36f67c5b2f539d8233115c1c74def76460d7c0f16fcf0f67e535c64ff1f4c502eea8d24102a92b2512670e4c62091ae8e226e067a6914a516316d57c83c1d6d254e175c685927b5daa8ed8a462ec9d147e43db530eaf6ddfa906e4054a0bae8a0f44e7c0eb56e3eae77a097c25808ba5699ba6590aca96aa9f289abdc6caeec6d661d5770c4df97cff806bb68c000e4bf5a9184cdf4ac2898ba7b983bd4f8b303ffe374fdbe57630e214e8b27d5a193fedc96ef532cb881becf902fde2fe9918fa001a9fc356def6b592a6191a5d9e7546fbcd74303ff7690b14a87be30e70cc2fc0c039f344920063f599be2bff93c976314e25c36cf76946d7ddef759f4a530ba0f441c98b7e9f5aca45dc1435fc54ee9d271e90227fbbb1d29ef89cc5e4a949f35b17a97d3d0b96066d1cd2b486286d8755caeb981dae5ae2f524047bd41ed1870924cad75890ad2dbd4ecf72de35b96590b3d3f207c2f00848210ee5667fe8a1d722466e0608ada45ae0000c51ab017e8e8c755bdaf92296c8ae216548960f46740bed16e174a860ffbbb055d3226e416df9b55e5b5a5adc968556aac5a2556fb5d8665fa13659163967166fb7b45bdc2dca167a8bb545d7226a4169f1b75c5a582d8e16450bbdc5d2a26f11b7a0b7f85aae2dec16578b420bd562dda2b788b7a05bfc5aae169616b745a1856ab168d15a2cf649a16b51856b1fc0633dbf0071b5e5aa556b196951f4c3428d27b1502d3c5d91f2794bba75dd526fd15886467b3e60c82ee9c188553686d4b389e20237bcb18a84e13484f7b7234de16eff26a78bd00aaca9c1578626a0a4422d09de9a60b17fa9f1b3f6b3e6b22be967e97618ef8d2fe6e1dc79a2503b26e0005a18fa3674548be902051adc4b0111dc43070b5884030b5884018cd8c7010a59c4818a58c4818e5904008f5904000bdac4810759058047d9048047db050084db050084594680a348f2d043bc1af85d7a1ae6dde00200ede002006d2023e07d9042007db022007db063000dd063000dd082207df041400df051200df0d1600d10e1600d1061801d50a7348e476a041958db7e91eb14029d43a3135cb27c6f1fc29cff99616ccad57dd2a398599e5b756b0222f5bdc19c0d6a1ac4cce4016d644279a53afbe5c734a44b57b521ca5667e72280dc0041cb0d7452625f32bdb00f90c0b3f983baeef516a368ffed64f2e83010c01e05c9fc857b56e1fecb04142d4a0ab7e1938f719914b5b5a20063e30f056b60a0def303cdff9df987c2facbd46bf259f33b667e50b0e602f5888367ffeccc1f4a7dd397f621fbb7f389740f685a54725e6e541311b8f86848e0ef253c3946d28b8c036b80c1dcfce392b517d5af2a42f6bf67fc50a2d6c5eaa8e6edf9edcc3ed41aa1af7fc9e62f9356eff732078ddbd0f9ef79920e02f9d84bc02793d5b60c8d814c466c4ba666540315381b7faaebbcbe9844e63f9ea6f6e1a0c67bdc7f2e45f1b1e1021e68fef914d507075b2bedf87f2f4e1374075ce9738a3983114ecce5f62f10a0de6e64ce429317eb02297c458806da6d3227024a3083c8cb190a0103d43e2c811fd0c95848778a2734004f51ceffd2069ab3c3feef3c7174980664f129ec380757aeb685eaf3834685734f53dfa7898571c19dadd2fee503b4ba038db3f0c4d8436be51c1e204fa9fd71e0341e1efeb22ca514df3124f288f59fa754f277f9032e9d58ff3b630ff5b52f5357b3068ddf9ef951c13a0cd4b37547357737fda1b0e665ea1b51d5f88fe9e4692e134068b0147ec031abd84d601745a2f20b9e88c9a822fbc401c6769203018d5625e0163e91312f9652ef730cc06ef4419d1a8cd07953d4f59fc9a4d0b820e012b920f1de869288d7398db5f56eacb217b0c8b8814c5acc0ba49bdb860ed8cd7f2aac83993a2bbe74fe63d60f056b2e509f5142fecfcefe51a9357d9fa164ff3b99381a4c0334c0119abf70ca527ef722003dc940c80d7c32e65178ee1603c0a4d4fb5de60061249abf31f3b382f52d57878cca86ff8371467dacfa3aae5b87311e4bad2745cdeb16fbc1feed6c321d01da7f11cd8b331522062cab5e8a33e0c9c778997471d42200639f3c17cc045a922d891b70cd28b8ef0281bc8c2207bf97e1cc1e50dcd0d24e4ffc531a29d8abd0190344eea0060a043c66d958cac568f657525838e03ee0d8c9953c0f124f2accfac53976653869f0bc4d02e40c3e426001a0d08a8cd95cb3e6bfb56f8244c6c5ba3a806596f70cd759628264a4fe7b1b9004de805145cc0e318cc0727c416b131cc4a91dbeea64e6ec631033a779379a8fa155bf2cb497f82588235200860d83c3bb45e44c073bb708ad8d752b7f890d32702b2987a0e6dcfe655ff05477e0d930be01408913baf12a1d1a9fd2c8072b4da7399fc20663c071a6c80fda4e66349cb20aa1b77a425ae4e05985c31d2bbec48a11388c113af4af53aa78eeb6467e995f79ed89c3317a531104cce0a310e8eb72851c31d01f11b66ce5c1b02b49ee7878761bb18871fd4bb8f99b1026cd7b26edfd23843107d41d7206111631f33cbabfc93b15d6d32f8e03cabf17532b352bdb4ca0082679218b50cb000e8204afc1be66cacb2627ab5df04b827b3d814e754442b419f6857248a7b8c58cd26f45ac6167d872ecf39cfc59c07c4401ec6c2ea299dae7044a8be0284d1c8c50f5e74191c797840a94e3c92d5ffde210db46a0a247da2f9e0dc672c1d239a316b20c3ebb0970186e37e81cbd0cc4985a78ece6f4985cc948e36e50589bee8abfb0aabb8fc8610a3c95cef53b95451e68ba34652a29e0d0ca45aa43275f488b600b62e9a1f5fbf3acfa760c2bdd4a76e42104ad6e7c5a2023c2fd9571f2c0d979423cd980c0d43ac5e0f1ab7831b672ba7dd9ecfbf4d48cf641f0027e0ce305c2cb37e4080216ea34baa4ed842fc9a12ddad4cf77d3f8e5b5babd027a4e8b8bdc71d6a88b660d18130cdaa6818c64bdc7da352a27307e70bad9a9753b2d6115472f960343aeffbd023bff34a4d7c8ac886bef8675336683b8b1d45b73d1e4615120db7e6e4016be6e6746a4ee3af58e8f506d3b97155e6ba0dea52278b736b43a8376dbbac4fbe11a5e426bfd18107e8f544feb1ec0060a3c57b100c891b52bfce629d51533ec1e00d0b312666800158cccaed19b9cda0f8dfb3790572495effa701d987495b19bdf40e11b2ef2800224e07187501f10d265c039b2c9cb5581dadbf912793d683bd1a1cd957474a526bec62ba347a60a40aa5c375432e905035070b5799432df412a87d4aa23930da8068f8e73e038480e8e13e9e071911d1c3d8d2a382ab09b618301df9535d33aa972c1c744b824ff40482d58d174c0aba0d49285a7ca2e3053740199720716934e7b02600c44c514d374406392a90785842632eb109715e83b703558b6d889cf3a724517282e9b7a57483298acd40164850e202937652a885c5148ad3bc97e8150af0a8bd44205e50e1c8328cc46d49af3ec1314f66a22d19d50570d849ada8098e34f08144003f03578b2cee122dc8296e54b565a117967a3589768dc83c5a4d39e007805ae755399898b292c30eb2ec23749ffa00ba0819de5f560a49fbc5364628308b68d11b69bead9f9682c8e0b6ce42799060874c11f15566c30b9b7867604ecf5a36806c4df499ac091fa4ea283f49284f675182a1ed41ec84aa34e0c880db4ceb4b01cfb90a5fb2b44124f5c42942fc0bff29c85af4d72f8b737e6036634c73d83bdcbf538ad5f2aeeba90e9b9fd7111be87422a96c0bb92e37d018cc7d939879d76c13801005d25ca57ada088923c944c18b8c268b862e65375cc7211012a258d2a10044d3d3d9ecfb4b49b3feff2749a642ec088ed4c2474d9399c046c113f0c723bfc284c822974ee8362c9c9c97e9f6d19032af1224b3d73e5d23596717e653ba25f224978534fd2cf4bf409a44507952278270dd795a4ac0d309edf69f659f7c1a48ec6692566c7d50dfa6b0624ad58199a591e86df3aaf1cc622d67dd73b28683c8ae598b31c5d043b6ad9a51213250b15104cc991a7a89a80456c14a0c50c9055420606f8c622d657432c8baffe5fe1e8a9ebb77bb5c3d995c170301509709760df3d0b8034c798e231f930e4ee165aba1438cc71d117c9e2fe11348186fa41c3ffca191102f25de3782e671e43094b537fcf345bad9674b5681773c0a5eacad0ca7cbab9eb6b5d7bc7e7350f4f8bf63b637dcbd52c572dd754d9cddecdaf30ed7cc2e0bf493dbd3c832ddabad97b61d7984b1417fd5c35f7b989379b3ccb5d76ae1ee3261c575b2e5ab4169116548b3fc536ad96b75d17baa672a37d8b969f10e77a51a75717b4bcb6451b33a9ff3d5cb5df84595e05d2b62eb04d764ed0aa40078fa27571a56d89d1eae769f573b95acde2dabb3bc9dc5d0bef6ada42d16576dcfc95693d276c1c03ad0908a6499a652f3b574d6e16fecd50a77a376d68c2e393919b8e2e4f1d4de6f21a1786f1692ba6ed35372f9baedaf64c7bd79b9856d6656e93929d5c68adb6b8cce84debb94cf8c9b770178e5cdd409db8610b3427a2935a165c9ede80905d04d86fcdd83c097c515db5ab339ebf70de74b0cb5ab4f4a7f6df0df8896fb0d618bd6e1e17df96cbc56caebd3813c899e6362bfdd49aeef2ab0b43fd693dd3869dbd4ba8ab767ca6dacd784c1bce6d57b2f67cffc99652eb512e17fa0a03991a5718e72658cc8e4c22d4ef796bc3e1aea256d416fcb92e7c4d4476648b564b4fad2ea6983d00f0660da58784a2801aadf32bea5fb0897752b87d322463c915e9dfaafef546721184b9b39259f9c2b68cd24b7eb1023dad7cd57640c985d7145ffca7aa7fb1a10c2f61a60bb9fc1920b5146b5132ad037d11beb15389f84db920b82ffd87569a54174d607c515d6d7805d94ea5e453e5e2f0036f58f29e412dfcbee65a16b2fa5441bef00b0bf490c46a284abc19fdf83e4a5e9dcaaa9487a456e68bfaf21620c24b83e4c2bd44b369d104c65f6d0748795953782f56591662ec833aefdee94781168e935c7c2d51b67831d073dba824f6d28aadb8b80812c6ac5d5d37e6fd17492ff116bb038c5f9721c9eba0bce626d7af32d28759c4141193be892d3ecf60357931d227400fa8083f14706786ee32936147acfdeed0dd61d690e0bba10b944b8b7fd5024b52c55c46ca71dc5b549aac13985be013df5e974a5cf0660274ed27ec29a473b1136df086964aa5276b91256f91522856c5ba21bdb4efa3a9a371bad9c32edcf606f2781fd4974ee47ecde5ba8ee9baa269e12cc728859ea692c890d5226e5bffca5b8467bbae2a232c7a02aac77d5c5d301422a50305a0835d49ff40bedd4ecae6e88a01139941c9c6c6146f4957537e2294349ce23f71aa9e6f1e56d476db06b39d8c6718bb3bc66a51673bf501f82a4dbcffca028d4deb6d58de359644cc26ec9784ecbd3791524a299394015d059405f905302c37bc0a86a5884b83381a84332c4fa4defea584a62fab2863ac90698794704674398d98ee80ead0af7fcd50e678b279628d301cbbf5fc48f8d26daee02fd6f0f5f049d23cb4fda2606c3205095f1816d77bab261f21ec88a69792b36102f737e7ec185f2065eb9e9bceb16eed8dbd79eb1ceb365bcb8457372358124af0d13cf1ad17a960a3ab097644938730239e7c021ec28c08f2933a9daf6a9eb8a43a963d35cfcea14ef3ac61c304969322813fbc4388476c407cea2390d03cd1db2912864ddd84065b3a09ed69ada1503435344411e52987598c31429cf2ad235a014715daeba2f6ba078c21d45ee7b8b104248a6790b4d73db186ce69bf69c7f16c9ec090468ff9f3fff06fdf7c7c1f6f8f71fe36d75ca3e9e2d774364de0c844c62734deddd0e0bc4a6535b4383f3be578042969c8c4ed6d5bf06dd2e49526ebb0b91b3f0f330af1896a5cc70197f8934b292595271dac284f9481d9d97c655783fa8f44e1e8836c8e6eb0019bb011fdfa742dd5c9276fbd1534dd3a0cb74cdec690bce692abf1a285740863f8c9b14b4e87f56ffae56abcf0d9b970d971f5ea38fa8c0bc1baca6fa7f29a6e4873adf5c2699c76ad4cc2f0ac6b05690ec33587915b2fbc1594721a4f398dd3bcf0d9a9565c08d3eff5179d8beedbfcbaaa453754e3f063fe50ab9a6ee83a4dc6ed5d9f5487f31dbd964168af6f6e9d7c7628c497ae9de6297359b47de6a7a69ffed3a7134e5e543febf2730a80e801d32f0781a3283f33843ad72da7c33afd9136ec0663d03c65e07e0833c2f5d1e18f15e6741d347f462d1bd0672632faef554002e201d743e841ad486c02e184347ee9d82536893788704e386d68309b6613ccca96296686a95d37843de99c6660cfe7eddd0bbb69e4520e736afe8c525cfeb6aff9537dbde9fce17c752d7f5efe74bee6af3aadb5d69deadd83330855f007020d2d47f3683e1d841f1a37a8ed265783286e9b87d0bef9d1dfee9b32be6ef7e4475f7bc8f853a631729566d86508ed66a545ae866725bc271c9f526618259482e33ab3e78c90a24e7132d14d3f6aed757b6dcf2a2975d9b27bd2eea652ca8ed1bdf3fc8183b2a72567a305731ce79c0d11f8c3b932677a9c4f1ca9739c47aeb603da01490ed40e903e7d6e1f4f47dadc380ee559f7f9f8ec46dc4d407a4a73ce53fed3280b70fe23ab6fddd16b45f34fd56ff7236dcd5b9c4df86491733a35a266a1b4ebccc274a5cbcb2695cafa4df36cf993f152e725ce4be9725bcd006f34393e7149d77554becee599bf9dff7ac8f8e95f519fdc79326fe73814c771fed3a8ef08663ae2e56ac8cc65e799ff34e4d13c31aa309be46c6a2f7ae699dbcfe208ed7135361e9d08383c64c7954a868e7bedd97a6aeee11354a3a40823ef21a8f0a4bd8612c68b151c2d3eb1cab7cd18bcb587a3c46dd2962a0e4ea723f347bde9473f71ac9d76ce39e7c4a99d0a7f3b5d742cdd69afeed04abba3df11722ab4d33c3b64f46f95d43756f0f5769c996d6280e391efe6e39178241e699e78a4bd8f44570837edb53757c3d369af6fdab682e6579f5fbb55fde8bdf6dafb7eda1dbdd73c5ef3d41c027c119a8747ad3e9e4eaf56f077bbc650744a9c8f192adbb22cf3cf7b529e6559d539ed1c0ae599731c6a83cf6df8082c2795d2650e1a34004ef99cff4ded9442a572917cceb920c83d8a3bd1efd93d51b1c74c7aedeaa79f9ac0dfea356f545f557b5ac6ed4df8d9eab56e273654d41f67ce9cb16282cfd33c34bb3f707be07cc65b7b6f7de3fac6471a1f3ba2ee835e6c58a2f85a966f0f9c3fd5d984b789b7286d9041f3509e1f14ba768d856384b7b48b2fd45edc113f9a7f68b4471b079c11e10ccb11c533118757d768bad62287bd3bf85d3e83c15c2fbd15d42ebdc625ac88a6af7d08e5354c58f5928ceba114d7cffc2222401511209d7504c7e942c5128126557046e6d2da0ed7a882b2169bed583260182fb9c8eff2296c2ffa552ee08c13a2ebb18b6691b3d167ed5ab1da1867f7ddd6a5598d369b411687dd81151f391d47508ab81e85a3284d5c36e413d7cf26ae9f994892717d9651dc760447ec84064a594f15d26c6f7dc373665915d4a4a88a42a12c0a755128d449436528140ab509a13e0c6cd427ec0a2d3036d83c71d5737a36ef969d3880339f593dd55a2bb55c8de699d4379fd35bf3d9de2d8233d7321fd282369ff8ad755c3db6ea9d766a34de99cdad5fe3f29a7f994f2dcbf37e994f08637c10768515a7fbf54fd7a249295b388e6eeca454b794dd2e636c222329db83649e3776085831703d785397efd8d4555e7e4b76ad997750f996cc153802aa0e6165a23c849581f23654b004588067c8d42c04cd571e00da58e1fd204283ce4ac2fef98ea4541ad634a41f4ef909a6ca53876fbdcae9d6e1b74e7e1db6da61bef2d22797976ec3bc1c63467a15439ea61d8c13301e781ab91c4751a4c5a1f9ad555e97a71a7fef3c55d72867a3d6a1cd699c266ebd6dfed3349adbfc65aee52530fc86007f499203c1c82b64404bd6637335ae7f3db2b79e552ee8f459fe76bcb45cd0fdeb9ae5709cfea863c376aec6cd4399dbcb8570e26efc6459e697c391d174b5d2d42aeb96bf3b0107828613c8000742109104c8e2b83f645dfa29c751142db33e3d4e6fd74e5be46c4c9732cbdf09e2c89c734dd5cd28ae7c9639f50ccaa39c260a2e8ff21a4598cf7c72dd900b87314e35bef99c4e6d4cb7d86dd70ac23e1dfbccad175a5bd41076cefaf5d374cd6bf7451d994f9f7408723a505e73eb456ee15039769563c77ef429e73aeab3436df9a3ae390c87d1b9e8565ee7d3b5825038ab3a9c1d1d59963184ca20380b0247515680c0d1d1572ec751142e04a746ff6385d3d14bae33cd8bea9f40f480dfbca83e91fdeba9ed079100721c45796d85bf593ee59b3fea957ab5619d3ae470d8bc7339173e3d845191f4323b0d0fb02f55be38790883a249cf43d813645e4b4197b19303af98be7d88efce6997c2b15ac01fbcf2d323348f10843dd1e5dbbfbd079c21bfbd5d9003af3eec5002b5432a6af8f6c96a01c7adbd1b34314d370f6162b4881942cc0f380f616288e8e040c643d81428804d4183036ac0a2d2a209ca04618e8449ca0215468916446c2db0c181f510268590d643189830af8281d1f22cd60caa158c172e542d6a6c50148a061d42a8e261156111c9028bc24c3bc4c9d2c3cb6ee932a73b064c08a38c31c82e341d78c24a83a18d0f5ec74f08015687b3e6d975acf1042933110a474ffdeb40191e9c79147acc132e2778fa23b5f9a9f06de383af95d239a5ec8e3046ac390655cad9f8e0218c113391d147d16012567e06af7510ab0ea29bbe3f888793c85357a9f0453207fe565435690bbe1d6795c4966fbf514d0e5a1a9bb7f66296a4a7592551334b26b409e18db6133958961ae08a05598e68e0a809d288c2023cc3032d7a175145340745a696e686039d365449820e0923af6a2f763024904e1b994cccc398bcbc6a7bc2e5db55cd5120aab487f23cc9801530313900742d455580db044c495d0ebca24e6058c27cbbaa0665148f62db1d6058ac3c74c8499f326e76350b67700e9d0070066a3bc92ee5184b78667637dad69de8e6f3b7adf3da4375048031b68eb69f4e1b173477dad3b19b0d96bbd91c813fef678417c5651c1843de1e2ed374b773a86f9a6ff3351cf400550074389dae9ddf1d9c5f3b88e9140de2f497e5ca7d98c6bfd5df7bb78d524a5d4ba13acd693acd71a76db79b5afe32e99b53b1f9ebe1104208a13c39ec3ee8c5e7bf1b7fca26f83ccc43d3a78b596a3e7fe3509d8cce69d7b41d6f193d3a9d63fd0465cfbdf9f3ff64d8b8d9569af58c018f4d11f873cf26863ff776baa0b6ecd61680c406509b223c00c3f2c43e846169123123663e3eab8c17c17c8c8eadf8e82366444cec6e97314e981a008e0ee3f644831d3312e6a3434e8bd66904eae482a45b692d96473536098c7079183372e5838731233534bef4a6bd86312345be070275b15d0705f85b358db05110c6902b2942bc3c9422a4e95b349f105f7a4ba2cbb924c981a267415a9ab8e8db7e4a4a296d29993db6ef96122a9aa0171256382bca24c20e1e904c16b5886bf3194385e633065a0b85143e63a24bf53b56ee1551d26483c8302bd5cd14d65a7bc4c30c2d0822840f62928200d91f5958e044145384d0a10a201bc55b5fb9e02d9129041813660892224360d0d4d474634494c462e8c1e73f9f6b6b132c4820430b4dc0c0092049811ac054e145892660600292f4cb4b29a5a4ac31130a28b17dd54484f85ef97d1823e264225591030a45a44f5022a2b0c0c29618a09002049908828612f060ca1337a04e88108ba10696122c22a2b7a0ca0b60c014679632cbcec8f5b5fb1ec66068f2ae87390683131b7cfba66a8f859f5934d8302489c170240603526c0816b1214d4dd389d8902d50aec45ee0127b210c852236c40a98d8902798b68a379517e9526efc6caa1b1794f80f6749eba2b25c82b0549ca0a1bac1b10f632e24e14295a62fb1a42db12424624955a4d0e8c9e392eba70e69a95da8e161ec033dc43ee07aaf4ea97bdd735d45bd73a86b127237edd19a57cdfad254e69d2534d83d5b94929504752ed2c6c08915e24397963ca99c487222248827b4b8d0c3a5e20492924f3d8c09c9e1b587312148a4c48424fd7d181bf2e4616c48ec0533b11690bcf4feae7065e5793a16a4497e96fb9dc47f322ed4a9aed5fbf72574d5aabdcb8461ac0526ff412b9e42fc4f56b1f9eb1b34aa0fcd3eedb5cc3bd5a57f1e4ffd018145840f083f2d68a7e8512932494c227ba4cf8ee7ab2c7f3832317d3e3b3b9eaf7097974740ed9f440267c09743f191bcd15294de4cd6a9abfba22b1a4517d04f91fd6abfe6a11a9d89e0996f4fc17ee7ef48c8b7c7fc250043200844737401492c3efa67bf2116df379a2728c80da01538c3be740879828238013df81fec02400386583c048384c5953332ecc08815a0207e908269cb0e4a470401021050c4a0c08a2c4d2f20e92bd92369004203104c51028b2d37000960081da8200a0d8264210590741fd90367175b031c2953a6488921c91063214c0c480e6a520cc988640d51f33086e4faf930c6821920562004124066b02a503d8c0169e2613c8c01b162998008a939458112f3c09798ab49084bb1c43c4026a50228406240760092c409cbc9dcc009584b3e3ece4ac1ebc57a317db4f23464cd11731d819db181d5845e7ac4cf984b498ad5c3cad389b99c7c011ec65c457c7d187351f9cf63da416b77ff9139cab5eec792509651fe23e5dd2d712eb351dc3a632c73ac6b480dc35f6087e1d88d96845c788c9e72a1e8a994473f65a195a3b211ca577947365a127ae1311bedc0c82fb2d14fc6d968c7c8658e7517d93ae7b12581e9990bcd931b693efd9485a4733666a325a1762d1bf990991b2d0945a1cc3b1b4597ccb1b163cc4623c81ceb9a1b6d4eb353d3fe4597ca21500b8740d14e08745fd5192ded68918d2250cab1d7743f34cf9ca6fbb124a4e598e4470076c0399563139963ad0780075c7f182d4d0002d12cffa00eed7454273dd37ae0e56d1ec2cec0462da1ad1dd52d10816816a5c8b63f1891032b07daa7954ab26eb0d6aa626f7d756686b78e63593a9caae4a0a1bac13183f4ac87303340fce921cc0c12ffe94c21584b707698500a0e0e8b098c074c303334602559452f5e819ae2c2ca7839b194f80d0b07fc41261e3b56ee710f616566f0a987b03256fedba94cca282973240ba4873433607ba9d9d27b8a882184104208218449681ba593c6f6f2d33b362036e08b5e34ffcbfc2bba7fbd68768c9d653273686db47ecaada039f4136e98d64923fd32975eb3939574ce79e399bf990cd2db0c23d0f7146b161a1c414996d5c86ab5b65a6b6db5d4a7f716abb5f6356d6e51cb11726904c83b379a55eecb7c089e4e44f0c9331fd2e654cd39e7ab9a9ec87e0a352eac4b8731dd762b94964a1d412172e6bf23282ed7a3209bb8dee613acb87eba5c5f94057107524420c598978dd20c50f08a51a63039415582a3a474c54b014a3d10d280570b065ca50f2811afc0f0c2f202f3c2018d3c88e1a554458cbd94b2784da51f4010491089e0e0650919ccf0320383b885c71536dca0c40abce050850e310092c4c30b395071e408144c8080595eaf4c4969072178412cb0170f93004a4d26782921614416d0880c39a861f2f2e1c92b0904482753b06006174031464b91116858820c0c5e20268a0c21384245639225d66a44042dd430c1415c72a283235eae266213173cf1e5a534021788407ae175431c42435264c1aba134932a5e57bce09595945e4aaf1c8cc0525e36a834508a4370f88108124994ec406609305a90d89205941ea8000116353c1c79d55000267290bc94ac7829c12f1f680902d622365826910a275e7188235e569498a278d528697939a5f4daedc629a5f46eedcd2236d879f27acaaaef524ae4291d42338528a383bdc0922ac8d440065a847002a8c6e0448725548c94e00a19d41862478ec8984c79cde0a5146d28c14b89881578e9212ed1255679bd16f0da945e3294a278b50030a55600509994521a238d944608218410421821842b90f1ddaa696d96659994524a29b3ccdae8030641055be4c38de00c2abb938fb47eb2b18bf5c20306412836c91d2d93c421f01787741224d087ecb9c143f6ecc81c261f1f29ad2545d473bb8b29e993369748d2d5b14b6c2287c0199c6f4102a5783eeec91b4ffd5e9a7b78972d472e5b58b00b924ff5295c274a9d3973a6d5047fd1655d495a3d60cebf4ed23c77f386567c44c275278fd0cccc5fcd45f6698e4ded45558e5faeb74e201bd71790804df1d06790a793461f9286aa7795db2625e737aa73dd7773addee2017f904c982f2259976ed43cfda59b6297c8256e69cf0b8c618599f6aca8d55a6bbbbbbbdb7e34c3654b982f2d25fcc52f1f857c277cbbdd01191f4670c6298b012f8df662113b3e786a1c7ad619c91e2590a0e3aa1b397a540e5d04d9b3d334529e7526f8fc10761ad768ba166ec2d0f51acf5af877e36bfca7afd7641e75be45feaee3af26f7f0f9cc710f9a0ee71248684f07ab6247d8da017ff8e6cb9f3cf3ccb32bc463c78d1ced893002c5a215f928810408212ca1c774082184d08578ec28b22fbdaf2cb2f96da50047323f547ddad8720f48e676b5d50447d7b4cd6f07c9bcf5d60b7fd1159b9a87f3a2ceb99e694d5cf6d1def5e9fa91365af1271320999fb9c8beccb75d9da587cf5f9f39e79cd3041f78a5e37899ce8eec41795d556eb677a1cc91395afeee8eccb9ce755be7ed5dd720a76951cb99d7de759cf6eed4b9d9fa8fac1df5ad651576e26d429fcfb2ac868f6fe7e74973aaa5407f88fabcd07d65edc95b4cf0b7f3d7af6bed657e73fbd6ad3a27f39bd11cab9ffc662865be3413e09709af4c13e0971f825ffcbbdd07bfd45417fef9a89aab2d6aa5a9b8ee903eb2a70499d3ee227ff855d95be4fe1d72e7a76f256cbe71a70ec218341dee26aaabf2d337a8054fd7987e7a66afd3dbc1b7344355b443682a604d7247345aab1ffdad6e7dcaea9456cdb672c0f32d17816d72ad1cb6ed0467dca65b0a1d655f5b5db6fc210000b8696138351696bea4b30d5e21f60c6d85e1ac53d55ef56fd5b58ae05a6b9d2ea7b41906a6ee40e4265b44f0b76d58b5ba79817fba8cc6da0176815b6836e2ab68b41618ce6fc52253a96b35cabce4e43f5d6baec1484bd7b3ca0479a65fc7dcd3ffe906a3d160941631465a8a79b6777b01ed484bd08338cfd16b308260f6d16ba918694c45ff66507336a6b74baf5c100672f743d3dbb5149e9e310820ac1042086137695b872ebd53b865f37dfcdf65e9004b2592daf8b0e2a0b207c24f067138a44f875ff390ccb865021cafc8018a8338f762f8652f3328331843eeb48ce04fe7a5ebecc8f0a1dd09b1f3922a454813e466cd1b94d23e6836e26b58ba0bad21c410cb1b3f9c61a4a59a55edad7a0172763806dcbe750bae87b122615ec6c35891274f74c23f0d71e08f7631d292f420be1461a7d98aa1c34a71e607b2ef855148bb30a733c4484bf1030dc24b1324e5069554a8548df6a4490b99a21900800253140000280c08860402a15038241a27caf00314000a929c3666401609235990a218886118866100064100000000000163884246730fc449512ca55e4abba640bc6e470ee9e57152a025ac6b3148a5d49792ee499768289853b4dd1130599988a3cc28a1520abd14ef29f428d77b6238beab3428ac30a165a64934c4b3bb3eea61a78354d1a977f393b84ec27b7f02ee91d68e4df996628572a529c0cbb9263b704b5127a2edae40aa8ed2d0282f2c7640d5ac29dfa3a033918362885cda29306276eba76c39dead41f5f0da6ebefa8af2aa28ba94b2037c9bbc7c3b09ed9eb609cc072832e8d36ff2b2f551d59f3e5f27f0285118e86692b8f74931c40376e253c3636c9475272835f77252add9a8ef3caf6cf17a27fdf4a2664756514b09151457a258e43d516848a9d4ba94fb52e295a258fddda76a24455714d1825cd139574618acd6cb4f283777a3a09215e59713573f2192d7e964523b7a482f0fbb09aa7b5c7527aff2754a97d79d5026c19e52e7f7aea60a8c22da1319599de9a5d4ee838aa3144a815b1ddda4d4e907efb8e9a456ad55dbc12b2f53fc2a05c61214bd59919a7c73c69a0eb874bc725eea76ad79e0978501faf237ba2cc151692a05bcdddd53b519653d8a3dc63edd835258c921ef5a4a19046a23cafa405852f51bdefb72e264cd85f05357401195f26a8a25efa7cbf53730a4284ebfe3a01ea7ec1605f414eb940b5e4ead8e58d54c51cbd19d384b075751708a7adff1955a2917bc31a9e8602305fd94d37ff2c2c9bfca0a28a2535e4ba1348adc7e914a235230b5bcc9ce48522a527486342339d5c5d45da7cae329b5eceee2a47c99bcf07d1575944bbf2696ca4757579cae5ebbec57b6a0edcc56d529a2a198f594c4953b26d506cad34fe1e2bac98b4d93e93f65267d584dbf4fbdf69f4d4afb738dd57bd543ba1057c501e31d0175054574caeb289653de6dc2c5c671528e92aaece2d55c4f348cef52d4249c5e77f84f6a517cc90b5e538a39253dcabdf69cfa6374d29fe1fb5fa34e163869f0acb9345c62700a8cf49d0193a8a4d8f2e89a5b5d541bbcd59bfc577ec5f5492dc64da814a9d8795667e4c1d82045a7f50e71d3967e9d70c19bdcd8b929f332013d9fab9cdd8ee546f63a6c657f6801923ac54bdb0130a76916ac3207fd13dc03e08ea4552e02f8839a03db4090bb951db458f3df1eb466b21de2782621d7e9287bd5ccbb5039c28e48283a024ce6f05a9d08be362e22f380e1d10f03e39749e4b93e04aef7ca5ac15269460c263e029cba83bca3716751a8f03053d445a9bdbe3a9977202c863dff4d2008a7935e8a6d82809fb2e5fa2e5e7539118fe25452b693c4efad27552ba87a8753f222e52f934b0d2d92550612d23bceca510a57caa8945641a994d285e7cd827c3ab8288a9ac01848251647dd949ebc7ce8a84aca8bef091f7993123be11233c51deb193bfaa7176130494ce044aef2a8a6efc0915e0c7607d4af4d60e6dea76bf56faf262fcc0dc7c16f93ac6390ca796126e788b749e604c2c4b9d16617b85ebe179536561b8a4978d79347d1767eb9e9b0ce9080fd73c5822c4aa24ec09370302e64b3bc87c035339cc8048e61e98d2e43675aa8b8c284ae5758ac1b1010e930727b100fe28110e0e3171987f9da3b24faa2b2e24beaa8a98e51c61673c41151471661b52cc1545244fa724a1e90405d42718c505673a80ab4581083d7babdf6731a1f00c24c3f5f967e82a45ea7ed8e93a34d8a278783ec48c282cb2da44d453d7a6e69717e11adbe314fa448ba4fce44c6d2b76a4c5cc4709017ec66be9c85094753a15306362901bf5ee09399977e866512be0d507fcec1cbd01067846132d585e5d205cc15231d28324d05bd0ab17e3385a2f4cee00b5b649bb50ab8b1e18956c2ffdbf0b5632322da477d2f04de3e233b735ed5a76dac10925ee7150aa98101bdb0959a578c20d416b6ce334651c3d8fb4ef638e78204188b70f9688b736bb1823093f19756e7f76aeaeb21145ccc36d79019c81379c53603d856e637b6f16b737f6cab3fb2273425f336337b9abe92fa310cd1c3b8366f03d09572373f3f10de1323ae7bb1fbe2505b8a1882cd6dbc87da58737fa38339df36ed438bafdcda205b228883975734d79a08eaf9360f2111e07bbf05c1b27d9c443f47af6c0754c58f6769c26730a5cd8123878a1ec223ccd32f9b9051f00081f003040a0d3689657e15bae0393545b1cf09547da38decefc3978033ecaba052e96e42fc9368c46bd8ac2a56e30edfc4caa5b6a7f451287a5d7450745ee58b08a2b04463096dd4ee0b12490d8c9ca11d2f8834e7899b4a43b011d1cd943ff626adbd4f8f0ccc5b82c9c258ee649672fb02c198e4c5e12439fe239341a69a23a367e66837ba6eca5d2f7d7f6b3e6451ebf70291466e92453300c39789b410318b6e824d4811aecfcaa214b544847b3dafee9de8e701644d0677f40ee95e37b5700119f6b0c508b7e43db056de7824480c72a83e16aae561f58ed7da1b72ff938abe2b29c857eb6c39b72d4b0f16f00ef2b8d578a69499538161b02ce62c746c4848ef365c49a4f7ccd6b9a837bd1827db3e7b5fa42d715d32b2e0e0415149ef689353766a4bc6514bb7b3325ce9d8a108e1f9aaf754565d63b61cf3f912dc93a2908f739bc6b9c1f80855dd357c0d180bf6ae07f8499bb709ded02ed419c49c1b02797eba3b647dba7727e797947867a693a0084a5dbeddcd253214aa8f4f94ac490511deb0f7ee2acbd970b7895c0eeb803542d66598948940895203bd9be19d6683fb41dcf5afd803da449d89137d2e0aaf2fac71d6679b7ae347d654addc3e2e96c74e5b5166495a94fdaba2fcef03a6e8b9a2901b875cd508db1d4bead9aac1b4888c8712c3137a5d27a09ab2808e508e002eced881f2a9f6813b81df60d2b72f21fa58569ef254b7b66094e7a8be04558826a0d3fc14dfb49b84c6acea82928c3d192a7a853b271724f62b8d491b3333ab21669c39f4b0367b18506116f54afd686ea7fa2e7543b9d7728cf3845cc93f39ee6345fe7e4eb763a9cb24720fabea1930c21d5290793c44e6ad80aa62662750146e303304da6e89241841f8870c005382d12e4537d50c09c2611888ac92b7a1cbf3c133680a8d62b68a41a582d366ad17da472dbb0d1beab5452dbd56a8a89c476f91d45a80362ae7e019cac63879ea01685ef4427aa358162721917d4806dba1191902e23825ea5841bd06c2a43068f29412992cbea7e88f49d0b34ff14ec89acf1774e98a3be024d5479688a8bdec09e268084e16b0e46d145db01473a723d08f149b0c50bd38848f0b8c6fb04f827d1c86b7e9c60090705ea8d00c8f2370e16ad570fd499260f4edab6e784075b96434831a9e602428b0d13c352b8f9870345a87f23bdd03170d44c13a5f8918a4f80db3325423e3a0c0e4cd1692919aee1fd31c95d1ce83fe8c92c3a2c48022b01abf19470dc16636f9f05bfe444754ee8881cf315ebfcc2bff68c506a0a2d001556994be449be32483bb723f4ba5404c041c6e4c30ac086b24e991ad439ae258eeacf61b47d01920d407e3be5e8c7e49faece652288ceaa27f3c91b34db2e1372a288c6af981dd7feb4ff7e0115a4bd4b16c7582f895047766c5020e767585efb855f7f74ef70fba6a9b587809e1d9a153e94bd5c1a3a03d7d8f2c0954be2bf9ad6f4571f5ac978e25a05ae04632d005071535ba6361868b3e7edf161c32841d82d1eea60b9e3ddb8a59fa2c4a98d891e6b708bb02ee2c92080194ba062422cceb95376618bff595af8c6007f65eb7b23cfeeb853e0beb6296cfaf5c335bde37fb10c5980b10bd8d18d7ae543bcd384e54a90edc013caa72ca7924ab93863f81f7a163643e367b651a81cabdcfa8ac8737c5742dde8e32b83c1ad521f2b9547e6a76c43aa4c6eb70beb0206a22865aa080e742524b3a38854b4446e3a642bdfe4a39d0663aacd37c440360889691dd970418478a7c3ca7a7663e5102e9364e20cadd84cb3c5edf8fef269dfe2eaa84d7b5a682f384b360d13dadc3e00b5201183a480f3360844dcc3ec5816193d051992349c52623a6105464b045316708dc84ecd3ed5497f1c5777f35722b0ccc8ce0cde377b3b78164f06b5f22509486a2da2f1cc530d02c446e58bbdd92a399870e9eb6f8af37c85ef7b86ebe3be3daf06ea01832e8dd56c1a6fbe1c4a00337ca086c0270955a016462f357c1909cc885fbb73dbe43dbe2b88fa55e1259bac2acbad029132675f080ddb4d0f8c99241e2a85a1c1e6b332cc079d30185433bf290802a4b5f1180700d4ebe6050854a40d055a9268907546de4a4ca5df42413e289d7a8a9d0d728c8c4ec487127c1b7a8bfa88c6e6540db098f5fab04804ef6dd2988f949443002b9a617b55e436f4f1925019416675f58f2b7bd410fd94ad643ba2e882e7e98bff020463c899be9141db096910d4c17f16ad810b8fbfb4c767c0c0e3a7ddfa8b19f800e9bb7f5a940279bb5abe20b340dae8c0e0849b710e4237d365f2b880988e289bc36080cf1631f428dcfe7c58c607777e3322e704fad27285e4ab12c6e253f3448b50f34e85c5d7202251e8c19b458893e6a221494b8b66baba43c681e4fdc51505ca385751f5451464bf35139500be6002181ebad7e10798a530049df07fa538863f6ae0d0003d00aeb278ac62fcc1063bbbd12729dce4ecc975db6f967a5ed5b251ceb73d0ba755325c5d967a9699cb3836657c6e65443e0babf27406de68b633018b6a11d3b1a45096a94697e4ceac8b7f50e75b6a799d9cd80b0cc41aab91d57da4e39d874326d90e0b2096bd9355f14b01ab1988ec1b38d4451dca8f3bb5c27590e68a78afd567ef8d3c3cbbe406db658fc7f93d5f1388cb90ecd9d36c6ab59f69127246529401b409416d98bf0d87d2281563018950c02ff74688ad7fd4ab6589ffce8a8bf4889d549e41b84387a9cdfc83e183ddd288acf9a910d52e26c5a80fb1e32eeae3eee3f36ea17c97041a4967c207fa71485e9f4ef7183f8b2dca81be15473fdd183eb19106a1cf1da4a105e8f7bb44eb04e11a1704ba969f3cd8dc1a0005574201712a1f9d7411fc37e3f82a19645b2102c33799d1412381cb32c08ae870e269c727b403fc848790ba9d5f0fe5ba1d740972a4e721a0516862a6bb0e88bffae8bb1dc4add50e66e8393780e90a96698b4b395e70c2d9f400ee9b106d727d03811c5bfd96c1a120f15fe6b81e0d9f9cbe2935bdc792aff6be1627854ad1b2243775af5efda79b1c0ce66e84bc933d310c1688e45f53bbcd7a41d2b304a6ac77ab3c44a4a0b59745eabb1ecd40b16f1e1c993ae5dbbbbd6f1cac666e144df2c56ab845f0e8bf50b3bee552c5c98e7f45910ca53caa342b2052b07257d3b622d182330844a5bb12ae58928990fa8c70d60034d4af80b91f921ada2f9bd5efe34591e047eeb58d2301300739473111b89f483fa514a3f5fdbda707c6ff604c44e0e1d9bbe372e035aec6ff81892726557e5206fc54b0790710392ce07c32d5ccc5e221db316bc200d99f6a7483868e6c31495dfb80657b83df83df8bde52b134ff628888a0f57edb858d36aad5bbb7ccc651cdaf0b2d1956b2b439799238b01e7102612c7b64d80a7ac64484771422c4c64b6fd3feb28f61adc7b5252dbfcd6ba62c20a533cc13ee3ca80fbfc5a8bd5d6b3e771a7520a2e89fcacd3750aa3dcab523821dcb58afc40a6df36d08a6c03bcba228d7fd2c7bc166ee624c9a3b275e624506fc3c5fab8f37493282308a324621de2ded247692e430c7a597555995d1de8cd62c2b1210266c533a2d2aa09c36560a62ebb68c34f395a6ecd140349bb1f3bb7b1cd8a5bf72d84a38391bc54407792a835860dcc2f658702a360c4fd2fd28a8c7fe0cd57483c6eca8895e0fa9f5490081e314154b425254cd1cd83d4071cdac3e80f76f8d20e229a78597bc2d0fa399d456854c0fdfe7f801312fd2b7b19a8c603d107c348ee08f0247f91d9e12742dfc48158bfd1a185c05856af7f8159695dd7cc655d9b5dcb58565a1eb22fc2b5e5a9f231abbfe1db450d06af7dc412860cc6c005c5e48efb6bfbbdabc06ed6f0f93918c4e1b808facf62afe55a3a655a351116781dec7973c31cf7be62d7be11ba5f8899924e0873b5a2d8f5b6b6e2af28ab4ccb14c4a8f489cb3b6dc59943a336957ff5a54cf31c5982f2816532b810dceb6c35ec0b0e52a3f22ff54b85a46eefa4414386612465297a75aeaed4f7dbc9c5d55b8b9dcecc2b6ed5877fa33d60686e55bfab189c60f6561214e7bb57b27eb4818f0ad4a10539054d673a5283912f6be9c64ad62b34fa685bfe264d8d3efc1b13c7a4928a11b023cfb33a1d52bfa7450f6fb8cb70d0c2d9953fe8af34e78d2275167ce0ab3df873b8ff35aef47329fcff836330d96b3e747dd2c0932ca4fe65499e8c13a5d3fbc220533c7045207100d8f293627ac930d77223239780614058975e307f49227e8a748c7ca9ef198f29ce1c849a7e95c501d8794d132b7161480ee9895b5e02943ecbed994b541c63de79a965f7f7615d1bd24738991c1030af02999529aa724aef2dec33f24f271f31d5f811c723ba4bfed3e276441786d9f6ff8d49bfd7afb58c77442ca012ffb2cca0f0c69a981993d0c5ce8f9e17cc85c4c7d7d5fcbff4e04c98b86d99a08b1bb3827d8aac0750287de5f7f9abff86f90367fc5c115daaf9ae22e6085af32fe5b8c2eb01267cbc6d8799487c2c3a93d5482163f1b02f89dae8b93fcf518ae2682e0e13bf7d034a64fcc6b4d9929b766f735ad35aa67debc96ddf66624f319e7332108c587aa9e950b930084adb937adc9681a6bd382a438f9cb4deb45e9b7e13c1b734f8d750c2b581e668718af0b4576fa7e9ac26442a813dd304593bd070324511b8990deac95dd41a77a9dbc024ef9948c3a8e15aac5812d8569cba0cceda9340bc243393d6a060d6f94e2061dc21055222badb529c4f45c96ef8dc2504ac8d44038d4431d3377abc6eaa952f4029304e72ee6c40e1e7d0f5aedfee6017558661aaae1854c3b05840011839a1ae608f27565204254e8d3eec68d4910e70797af1b400244b4b1bf647fc336b46c0cf18b6ab39eb1220a4edcbcd32a0a911c51bdb7cb2deb6f282e3933f64f3281caa75a70379e0105d2b0405aa7244be4b008271d03133cb02c3a7639efc1a305ff1ce539a066f8d16a16dcbaa7d17b0c38342774b4d7f854bed14b7ccf784d00cbcc2622d4e41df94f13cb4bebf002e09564b7e98e6f368fef6be5bd06d9ed79bf17c509645fec5a06393383ad97ec8a662430837dbc09d0d5b18c3d41d641be8c0a71665c36e8c4a0d3b20049205a7d21e8f8d1c255c3c100f98997b72102ea259bb878bd0c99b362f1299555c3e7a71f2b5284292ca24d314d797d78eb97e36a7af41f8b8206ba4c25eca2f7d045972cf560c601642a6619bcf817141a250ba34cb1c82695b0c6902c55408c63384cbeb902023673cfe3853bbf188a6b566ff1c1afdca067af55f3616d8b583e12b2bef01c371ea42519c2678197e3b5485c17b286b7a64018d8924624a1fa110931e67e271086b74da1088a0e9cbaa5e8bf688c4bb3492d58253d8e60ca1734b04ee23815fc457fc452c903884a96dc9a08b0127a79c4859631869b1887ffa1b68402581831a59c62b051bb29bb7903140868d2a1931be25bdb21401f9be29dc8348bdf045789de23733eac98fad0c00cc76adedc33e6acf22541eaf73cae52885accf4c74a47da039f7d359e5be04b14828dd9b4a755032e3e1062b43c479620d3035bfd83a998c1d47162a8fc0c09f55a42dca4672118f3883150b935061b1d31a0cdae17b0027080fe723066b4da6a87244a0214861157671f386a984a482c3010827bf2442e0af84cd0d529c32ce329974b0ec08fb4267bdbe56b7a59430a7c3bfd167f5673d93945950c930573ac1fc3bca813331238b20bcdf38f5b4de7fbc5419f1aff2afee82ec6387e154fd210104385f33bf8e76c7f8ce98e1e84dd7900b66c533e58a6b6180e7d3759a414bb442006e054b53734016710a35f42e2cdcf0ebc80a96aabbfdb23cc1529190a3de55ef33e6cc646307605246557559a2246009449831b64b3aebcf4def40244131e8b43b2956a4b3c62d69f423dc1e06282e196b8c2ace7e708c6aa7deb6b2a390ac7de5fc83bc08c894bd74857b3266fbf18d115a6349119aac2bb5c6b15a62636542a671a7f49a35181783f7f1cac04f9f5dc2ace6957733d100452cb237b5a3e11247de12bbe509346db6caa2bac805d6ae34ff24bec14dacf3500a4a17269a6b270c8e5be7763df9ee39772f7ba23a9aeb89fbfbfd5866caa2ebb8bda6932bb6bf035549f814aa7106a639fa07045e34720718d18d1b5666cdf3a0b607c2b8bad3c397c01f898f788212981f67f4b0758e0cbe8e18deecfbdd5606da8cd1c8fc6005a92777f4c4cd0d678dc2796bac1c06ac279684fed156129bc283be4a886d42b8a104a90c1aa16f8a148c69fbdb5d4aab048837524526fc491b44b9e74211a637454882d680d3022b8c035320b724e97c6f8b840244e49b9fe587fef5370beee82c6e246c55960cd5000510989384658621fd6d75fd706f92da26a4cbc08d0272ee9a1263995f0ccfd3a5f40f569cd5bca8ba990a34ed1937099449082dd2362ff4442fa7b40af1163e5894fb604243691aee6f3720fbcc2af6b7b9423428f6215326bdc49f7c8f974d3720e50c86b4ad14437a99f75142dbc1b0f711cb23bdc60173e406b44b92c6ffb14cbc29718d5c1b0d218d0c60718ef4830faab823232d73d002aa3dc3a09c8aaf097b60f006fb296f0b4d70b99c0976285fa0b3dff9d9382f09fe87c58c025da27bc0974b31b8edf911e67da6a8d6b68b6bd6e30cd047e581aee6901cca3fc822073ab549d56cee26ed9d88a0984d5ea4bb7cd192cf7d1e441f4ccbf854bd70161400852c305aaecc733420da2f448fb72ea15d5e45465f49e6b0aad453b2bd1c3c2f542e65910ddc3e65910199992efe67844324c97e17c6bd2e7aab8264477a06343b450420623a48e67b9dc15d779ee14898b75eb5dc75081b488241849e537dd880ee5fb67c08b1a53033eefbc2c888a403d3793ce3d40a778a649fbc44ef498a526ed69a27dbc5f62926c1fd1db08fb262ff79eee91cc449fd6c682ad6d97d4ad11cd0bef5125ffa4669d19c29849aa4ccf1fdf4701d4897f3562488db7f2ce548d0a246a168acb09acf01f8655727f627b576a3095bcc7e20b9bec962ca3238aece450645858453e18c67212c86c8bc0f160ec6ca5625613980c1894ffcbe53d90764b9a9148c3b7c19c07206a649347faa03a7a52c62c6175cf4b771128991e683dddc4b07c47e1a4d663bf458a7ece86afd6394aeb093e38715e9e1f0295d1d6cfdf03eb01aef7f37e143d207501a2065d3940101d5002d5deff6fe338e5f7061af70ce29111f0b5e95fe75ad346fcd0bab758538280b31513926589c4150ed9a1fc349f287e1c30b9b4abc1f9eabeba3b14d45e7f248cd3d2d31bcbcc1ef6e99b9f8253d24233b741798fb3563c6ed60679fa691dfe3a969119e743b39d3949ffd9861621a8db40f2d6226dce9a6ea3ccbe4ed8be1c2dd19f50d91f1b220d8068fc58e23e6cfe33522b444be095c9fd2e2e1ab005838d3a6ddf5fce7ed5af4aab758365a0c382a5a2b1f56128890a94cc466e48d85d4ac47b8155370dac97b64e2f69851f1bf2fb2b579e8766505dd631c96f16ba6130266d59932e832b7c054737e230561465a7870029de11df4775961a303f564763933ed0283793aa97d1432bad37e4111e80981308306f7a3218a7d1b0cb5e3d4f1dcfd97d80a9dcf8874d00999b435f3f095ddaf17b1628364d97fbf7864769645d16a7cdeb70141562d8c63b89be201f3fcebd0f742a98c9bca96bc7de1d9c783e95d42d0d7a4be2c6908cb7f7692b33f5ad88a2181eaee62e6a3c799e0ddb1ad62e9d0c583ab3126caf814648e101240de3c580f6680e6cda1689e65fba38d9f7fae640038bb68f57a33be1e1578eaa0456f674efba48fecc64bbc552b199a60a9b670dc519a78ae5002ab6396db98bdd4d440458f2b75f2a698f2b9535705754cab0e3e427699ae912421d1b0bdea2740a6b31c41c3fc93a42fba1821fb9e337d6c637e7dd6fb4773829aa9d955e47787a80f818ccca9096a6f39e46634d9e24364122be7420fc43f00f0d47231cc7064a880723886eb2ffd8e3043a2f3a2b8241336693c12c8eff077260a7c5dedec5a938b74fe33bf7b748c5c53e712097531ccc25bdcdf5329e3902c5349c1adef51eb3a67933099efd029c143528dea72a1603a8559964e3eceaa31bba7b614f238af36956d7afc3af240665996e528a5b06f2a3f9a219429d01216691bc8065f6e48c01c8999198961d8772f71a616fcda9c874c9cdb0385aba2194524302df51b3d135a324b51f6a6068576e449dcea0a913ae5bf33e3e06c63d6b34b253a3b6f41456977d215b30d2e86126e24c160abbd43501054621e6d4e133f6ebaf6b418199cf4d95850acc15fc1fee1bdd2fc5e51a65aa0aa9da955282c9bf98d4674d360d34872cfd552000f6990aaa2c2c76eb46ec02c0dfc7924b7eafcd54dd7e39cfda4559007dd3f467cb30d1e94b8eaf9672aacd9a95a2f32214f8bcb13c23bacca1be3fa1e31b0700ad91fd6505fc135ae59dfb215e79dc9d8226066e6cd05cb843c2e8df5cc993dea9964c29655b2be5f11d7d5766255b2eb6ab4ae0fb91ffb8d3ab05e032bbd6d2387229e80d49502e1ded2787991d31c6bff4bde0e2a6ae2d10f742b40764d0b14bfb59e3d992fcacead16e48400fbee1274f7614d713f22656621148a0d296ac57eea0837a377851cafadecc533edce9e06f96a118715f92346bcb050fbf19839f8119560c2e4ccf6a6da331267d338d87ca97dfbe72c1fc9d172f23dea0e20f01c09743b1a080405c283b7b6270af794b1ed3fbefb9a061fff6a84f8180cae53b3aace79f3a0ca3c020efea8ddd5feb3f47e846164540f2aa8d4b518382d7f3e2d77ee6a0826d612f1e6ce2d3f735eacd69550f46f1cc7681504d26bb9bc744b01153aef33adb38604e0883c3ad2f8a7579d7eb13983fadd3344372d7bb2585d84fbfe7867ae4fea442c67d78da43422e8de65045d86e8efeca44360e1e52029a4dae331c1c8e1aa0dcbb08087c483db58b85ee3764b40f36125d0607dbba00c5b8be5d59c391b582736defce5d8ddc16b49013817bf55853664a71b8dbc4f45e668f6cefbf91c45c1b00528ccecc0b5c7e62257738e1a95bda98d0b33793f93f1159c44cb07721d11fb231932340f63d9d6eb2dd7d179aba83b7909bde2651d81ff21ef25f6b6c011b31a303981ed2e61f566ebfcb1d3717dc33ac3f16e6273bf8b2539d72ddcf9ff1a92af524fb96ec4b463d3a03d268e081cd7eee7195c451bfc10289fc0edbf7850f88aab1c7a2753a95190834d7df9b983540199dcb2045e99de8a498f2180e17e881bd4af77f3ed24fea427033bbc8db51b6edef72990562be2e8fe321a5077f7c97ef83120fc0e02d144b9d211e949b9156a6462294cc3c8135ea9fb45697dd323759322ecc09898b07d00e7536562c05c2354fe5d106fc0529ff943a040bb4294e288feb1f431be2bf70abccf57fedc6ed44effda2dcb2f7bbed3408eb2ad79f58900f9ae5077111d73cae678184c655ade7961e0b0aed88334ffbe24bb035fe7878c5733f33aa02abb34e563c40e1900ff393afe40fc5a27806cff3cb9320de189edd57a643b500c9177c240951f60b2fca16c05c00106ddfe5f4f5981002e4ba2e4e807e05d683422128c58b0f0003515b563a72455670d56bd5452027dd18541014883b2bc75cd9685f92082e2ed9177aeba11701ca577642cadd7025b19b8531a0e8601fbc75da92b8c4a10ce8cc91e26769f48e5dafcb63b0592e154e0d899cd8cdbf73e5150d8a03343ab8cfa4540624d991bb455750e82ded2aa8fd94ffae05b04030ad1039adab4bf23e7962797d1ae2e11bf4a744e59335c6339e9e69fb296b8ef6c3f4ec879ea64f562e0889f6a30dcc72f6c5066ee403bf556a6e94198e6e20a1ded171e6b7328b5f4ebae896ec417a7a6cd7ef22f436ef40f5d375f1fdd0ed7769bbc77d505bde6090e628549ab5cdbfd15e9a725654b071ddaf1dc7bcc897a447ef3d0a90b41a82eb78089b372683ad36f9892b55dd2b5fb6d087125563bbb94665ccf50115c67775d33858e6d6b4e70dcee8d41259f908b77e91d2197c6e272c6be9ccc26e17335eab92cad1f9f4156703729b6ef6b5ab703a50b58ebd88dd9352e5846ed5cf3fe314beac25b2f89b8ad7e765f6b6e830a2753f825e86c72736c113439f1e37c150e0ab2b4b6985efdec9e52351e17d4655b6020618dc660869976bded0ae211421b68940367a4e18e7c9f08c77a7f102886b16d299dcb349938dd84450e61167c5a529e50fe1942e88b304191f68aa444ae2ee07a2eed0f88b62f86ba386864cd782b65ae056c9bdf7538cfe58696e350ca1e4e75b0621dd6f64f652d4aab4f6e607d73f0a998c1ae0eb9bf3ba3c6b98a04079289ebcf80e6fcb40bda9a9290714d3b43004d54ec310e54797589243631e4c7442b052cf6f606c0a829cc1756abf66dda3469cdc9f9e843bb343481a866204556e4e0b472a04134302c72e8532d220c6678af60f80017da35ccfc52de440be856107464ddc0d5d995007b878e3a0ded9fe8853c9e96862aee465615a7a3ebf01fc92cccbd56332a5d3f600a76e628e119e3b271eefaa83d98ee298c617727d70086e4b933062dea00a97b02011aebe3170394d9889e7761d03a604f51022ca33a158a9ce142fc9b6dcaea9e1b2276d4b9460502b252eaaa33f088909cc0d6fe2595b33c57316f9e600b0df6dd0bf809cb8879a7221c8324e29a133b03c9a4525b74ecc653b4dec72544aa7e7ed08db66403a4bc8afb7dad136df164dc0853a33911c82797e44e2bc0641c210d465af4215c1b9cdc549ab06491fee1c51dde6dc9a78c0852360c09e573c0d42045520826a34308e27866d8e42dc573c64be37e8156623993298b55d45163034024548731491d7be9fce5f6ef6cc7cb59329dabd583556b484bcb74c82526f7fede86f83a2961864cdc49e5c321a94570681c353dc2efb3b49f7053756260af366ef4d88db9e63093e903724fbe3ed7938e265035ed8ca4b2a20714a0662df25c468853c5be42b38198ced8b9b058d1717f3b8484d93f785f420fb13587116e44961c87e30040ec6dca82aeae81c5df1214124fc5889e243bdc93a0db160114324c8f57eaf42875b6cdcd53c52a65c4d56bf3eec9cc6104cf5d7e6b4b9810e9dc20d73e9d5e815fe78c2847428feb60a33d42564234096aed9df6f0d304f116382aee8199d1101084ef75fb87692fe7c836978888ada63d52ce42be8272b0eab28b1514f8252f7aa4961a7307aae192fbe11e571edcf100a550ad1c178a4968832a4abacd2e9b451f2a236747a5f914dbfa14e4629ff9b98e4f59b6c888d5bd152ac6a27a25e537057cc9027fefba4b12542bf318c66bd77d7280baccf75f57f42baa784e004763d51949061caa3e957c2b3d03dda3f9253335e09cf894392447570047b2613bab75f90460756438e197e51060d4061621f14a9174b1902f34bebd51b5c3478edf66eae9b11080abf801d8aee5f24e78eb3fd4a8f8b4e1fdf9645e017379d4eb128caa23485a00d94dd758ac40ab891a1b2c40c98eb9ef6f67ad8c73846c5d5341fcf5188c2ed5f5434ac99396d35def886a7db2e24774dcce9d395046877d3b18fcbbba5ee31e48ac9a4914da7c876344044524f8514d51dd661ae0c1f0596020cb05f90af2c477b26493a917ba89c238e7475e71924f8ae46f4cfd80ce42cc21204df48e4fe8fa36c24e41c03c10d69c64e334a444cc70b54318dc9727d45039d6b7c070d1549a7e828fad3ff5badaef9133f794cfcbc92b1b6c2d04bc3f79f015a1fd65c7018da067112a0026341c6eab2cd0e95ddf6c8728dec13107f461100f55fcf7e43361dba2ff21dd89bd348b54118754059f76356c3f3b0a2d690d203a1176c5083b9fdb67fd1154d34881ecc437cb5952b6341e56e1240257233a494ba983045e2bf140a4bcd42567857263bdc77001885c1e90eb0c2a18c886b191142e2e53d574a555b576572e715bb545fac0d30b8ed5bebdae86e43d5e4744960269fe583b120ea142eddb61a479c6b7b7e72fd946b4ce8675cdf4d8813e5dcc0406c6e3f3cad17cdf590bb2bc13e5f227ec8dda0b7d4478d4e3e85021343fc206e8e2c2caa242506c31ff09e8b00abdd5147243b595f59a743619bbd515a4929a3edbfb000555791d83fc634c7e1349709705ba5cc3d8247d54787958928720488fe0f338acc86f3a3eb761fd5607aede30c8d188d604df761b57d689b9b971645fb806eda8b96d0df7e530f414be2726e412790fabc4368d6db9f31480487635584c8d4eebdc42657ff842e698bc0637e8c507c86c94c591b56498ba29fb29990a76382171072c789d88036766adbd3a5f4a36b65b078c30ff35d5caecb7f9ef9f3413d20dd00c3013607c020ec7ca185c56cf248a88c5c622daa90bb7bd877e918df6dae020376308b981781e2bf9c0c57e48d977ee6d0e3597033ad48d5afa6b3c56ae8ca24506ead0a5a58e60193a7d75de612a83265a02b16662c6541004e33d82036785ba211475e5403bfe1a79d732d9b33f0470a94e076bf25fdff9576d158142a4002a249d15b20b64503b1ddfeb27e0fec1e74154699e73391d0702131908e7a8dcde0d4d75808d1f94b8a91211edb879ad34377676f8d768a211e63800eefcf56d654273b3b1e6a1e68c3fc690fe1aeb92ee4578723f74b2226528cb24c21af8c54abef6add900cd07fdb730153af0cdd9be1d03130270c5a5e5f0ecf491cff27809a1a5bff7efebc0a6f0b610c1718fab0234671cebdd72db11f76afc716962effae4663ccaf500c32d9c65c131830ad4633d10af381643901d319530419049a05f68dbf892beb49bd3e091a21a82512ccddf4af522f31375bcfeb4c87baa3ee2d1c73abec3c3b5f5ce41a01e8bd40037ebbeb0c272cad4fdef5ab271b7608d89494eae851b95ba0e91c69cfef2300ee8d5219c1a9e21659f2800727bc4769078f3acf440af28584173b39092614394c8e0dcfe3701db272216d64d4beacdb7748828d73a5712e12dae85081d089053af84f1c69719a4aa26013598c2c81cc4616b834a3cafd9ac3b2bf429dc378a0064a8a32a2f38b02f5f984c8de70ffe2fc4c5980aa396f07a92fcc9e4c96e8bb7f645220398dcfb998f74c2ddc8c0ab9cbe02cb31364ef8821e24904b0ecdd5e8df9c1f1566d7cdde38e1be6d909104397371ca4359be58cb45d6c45390cedf4f25fc99ca7872ce030c15efe4786fba0450566b70692b4a8f5e4549c2b87e6ae59006e4d1fc040f86579164f50677b48e11e5508812b9094951d6e89aea538e5c183dee99a120142b54e8f39d7b4304d735d52dfe33ba63a894eaa86343645fc0677e872c8eb4e7e84c3a1d05637bff309af9249704e0b39b11ba14b50a08c7ae03415166c7abda4f88942e586b640e7b97ed81a9aa8a1b721a9d3c1ea33eb681cf281fd612794eb6bde6a43ee031061779044799ca403d2bcda11c9fd4410336ddaed0d88f870dc321a824c2d4a702cdaca0ff05e801236345edc7b05889dbb1e463b2ba8831d03919632ec4e91f77232f980b71f99087bbe77bd21736eb993fe5cf147d161b4a9033b10eaf5f29ea0f6c0d6ecec0cbc1b90f02ab31c60e54b61e6e3107df4cffc33fe84802033f094f2c82c4c8bfbebca8e61074bd00565b98c41ef4a1778dfe7a2aae2ad02ccdc884c411fd77c46f199e85dcb13fe38003ae78868a520bc5518e1b5e2721584b97640e03bdc801c559f5867f134ab731ff7c945bd0c71f485df8ea769e08bd8878fc4121994dcbfbda72b823fd6961f188acaa4277a9afdf2767034780df7c5d17c1ac6005243c7a46cba8a0b9593ccd7167346ef98e9f3942742328b097a04f84c2f260da33071ec38afeebd0d8177739beb25159bb479c106c58a67bb26321bb8369387b24701e240646c3fe099b2450b8a0f1be479aaf6763f3ad153469348cb17ca180314549cd167dc56274b597414365e85ebbcda56708ce81c4f1a9d358167119c3760b3447b685eaea7471df76a2a8f033f94c626a30ed69de1e14d85ee1e26913492ddf2ab46c629cc021eff037e0f5d30701941c3074256fb1d8053b214d383166666440d4c4a44cc5d314f7641eca2095607104bb9636de625bc3d6593a210d9249222ea42b7197b456e584ffbc1e7ca4dd7820ca235ad5b4c6b9fb740522283fca5d8610661a86b71df3be7feaf6cd54bb4f8d2ff15c737fc6f14a36579162564874c696a4cb55e1f2d8639f7e715f3bc8126479916dfb7e91d1b88dbc1beccfa822ea5013972f0e55eea310b1f37ed170717de2958dc38fef4167108ce34e209844e91757cbfb7f9337058258d32f2e7493bad0894821086c01639a347d0d6a48476e3f30e8b292a5804d7a5164d28babd77e68d8dca6e40f64d32081b98af9bff8af90b3017ff92ef307a27e232d2e97f8a352f519881dc35db80511f2105d93762a9e4a9e88c5c58458606c2437db3e889931d490ec6472e114563f1ef41f86afb1949ad6131b9f376f3fed4e0ed25bd546aa30ce1ae24cc32e83728943df1cba03b8e00185a2784a1a8e492cb92261d82367e4106c6ac894557d906932cf4a60cb3a95365c6c4e396dc0297dbd6ce3fa08e6992675fc548c4302dfd513aa66cea2f7e2381fe4e2bf67c1dc6b8fc0444d443ea84658943a75815a8e0f620a4022aaa70be0c7fd7eee891d3e7c44b10edaacb44178c32c434744bba6722ebb355b4bfb0c69c015dc8a3151faa61ce4bb28e78a4737dce3b9bba195dcb6381f2b27eebe1b670b169f70bb37d7315ea83522f840a5e0729be15e4593f3ff4ebfad54007d4d2af171dde124da372a35a1e18fa50f187000e75176d69965841b815d5f6df616b119b85358f521409b004584dde63048cee6e841f5a9066da8eb0e7008bfcbcf69eb8ae5cf43bcc6975801a25b18e2f12f3df28e324be9fda75d3885a67695ccda31b6f7aa1461569d5043b2e9b59879d3fc03bd12cbac3ac20c3e0d80c633b6f396d0d06532167b8a8150c95eeb4b48389987fc73873033ca86439415593c328c24bf217b51b3891164b50272df9e4a47afdac1224893853fef078c3f9cce47696a3703a0f6fbd46e8c4c50d95610340cbe1e3af189457d30a66c7b3bbb31d06458cf8038dae71787808fa5e09bde644759fe4d8db2eff529301268e570f054ad9b53b613dcf24032152c43431118e7040a83745ab83173f0931bdb1a9f7b28c95b84293099868f15c7ad52c5b49b845323d54934c8e6431ea53b34d069edba3b8847a7a53386e1c0e164caa7960a8c4235bcb7c46272ca4eccfe42ac628173f6501b5a3854ee7410b2162091754624f1792d3a46b8ce8d7c4188cdf370095b2f959fc6b5b388dd17fec254a4b79c431d268adc19f0e4ec13432d928a3600b41749b5bddec11e4b449507440a14238336905760e4fb318a57ed118ee9abd92f246789adee78f046354bbcd3bcac46c7a6a93cdc9325addd5939ced6643744bce53d8943d72054039dbdccccd07073489191e1502ce969a7a0b9ed8abe86e15d765fe84239d1a4e1ca2e12894b913cf819f2a1146b2203b0e943b10d9472be918d60a5277e1222866e6eec8359914a07fd7fe4729c212d8f200d47a3090c1570aefb3471c3024f01321bde5660dbd703ead019206951880233dede1bd3609466b7a8971924a047bba865fa0fd5113663225e10321b50a6a431dead1edb11c9af52b76f7d407b35cfd8442513cbd40d7fc879a0b4fc50a9cb43215904f63e609510042063b525bc32b5fb0018860c8240acead25be6f812477dbdf1dece2061d7514b8f3e0d64bc7d70d6d7292769ee01be8b49a3bd9cc4661fc96e0469d252e999bd8da6091f3db27e827f3c92009aaf434d540b6d3719055214787fe9b85bcb8ad36e941639597cf2287b3f26b72cb246f93601f9c35de6a869708e6e68d5d8a009224c9b78117abd093efac9529a5f22bea6abc06e1351d3b0ab6c049053fa70977a3ad24739ee36a0acd6ed930764c4a453a159b470259261f7eff153c35ab66bea5c2fd556741850fbd0f49cd8aa8c37ed6a59567b08f523a523354a5b4a2545f3bd1c42488b7718a625343236175569cf5596d1df46464167e87f7e6d297642509221e4eda915db6adafabc20f426e7ebbd5be456c3408a6fa21ccbdee81cedcfe483971b445ea38ca9589cf9b3fa8f34ec6271f2871abac7c5093c5d8ef21cd69495c961ffe307d6f9e4e8d3d14b563e6341e399eae4d8f09cf39fab0c2b1eac8046d0bc4021d1d5fc8d221fee824916ed3d7d129928a4ca194403a80aad1a08a37d804a232d92acb43811efcfc2034530f81841a3202b4b8dc5c5981a6944b6c8b9680db0884b1971ebf406484bfc797974424c856648b980100b5f979dd90f82911e4f1ad42efe80ba9ba35a85a3f1460b713a1e60741096dc5e9d48e889f4384c9e1b218f0821d3e116bdc49f53ca8163b98f03dcef7f10406af65a1127aa576dbd9f73703ea174f5ada19dce912c1536cdfb94064964222ce98502275828c13480c1f512cf7a10d05a785e680a10549775797bc0ea2d7435b60bb8a0d78923106742aba56c37b662c6e0097f2d45996f3188f2d173f5e34f552e9e857ffafe1a5fd17e671d6bb0b1e72bed22e59fcb93c8728519f90589b3fb757299f6ae4ebcd6f30dc7c50ff1a95a949c43ddb23cca5c33d931b5459f280b6ac7126a0a4b2ceb6ca04d11829fb551526188d0dc5beda6676b0a33fa8de44c46881e653e4106c083e7c49aa3ab85f02c86a30267b79175028263fb893b3452b1d6e1e2ad801e8949e601389b3c533ec3d64b1980d74d5a35874c9e9265d8661340623cbb7b69d291f85e00ec0aaa0639e92c06a8a8f3f0550d38d5c5d83f9720ab066f8fadb6a30bd9e055e244fbb31ab8fdcdb3d47b4acd7da0687b52137f2f88b7e2e3e40117d2862ad7f3f053c784978e4e43cdce3dd51607f9664740fdb5d583211abe6437d241ebf9abaa90bd262ebdd9bd09416080b0c75df8d487e8ebb6484cb56d09415a397ce116548a35a9299a6579662d7a1615f889eccff5770401b556b9cfa3b4f566cd3a0a0890afb9d6961f2721a82c0db48a1e3513c01c9246ceb8fd1d3be7d70a0ee5efa2613000e8e640b7a2155a3dd6f619587bb7219dd58f38d1b7a6c8bacd05385d04fcdab867a0639a65c9e4bf1176093f39d033403d0546a8ed093c1f8d4af22a22f1cda54e941053e844826a84c052347bf92f5dfea13518a9b110c9460028248a0fd3acb63944ce17873d13274cde3f2deca8c666f03390dd2b6d6814cb227c2cc13118e7b93ca1566d3876adcf13fc220358774efebf0d527b13040f6feca58db538be6968065ab820a3004a06d7368a54ad47429fcc27ace1d3c82af32b283e3b4b619bb94753c808220772c7a980ac771adb0ac08c3e4d291f29542d2a2b7098d12b6304c9c5812126b9490ec1686ad0987dc37b36e9ab0ab451e013b2aa53958a074ba6cd73b44962ce507211295cf350d9c8e6fb15e2038966d012e5e62b4e6da7114ae9ac1f446aa4c2b5659ce756c149046347241868117d4435e9a13220245824d271ae27c63ed0d96d6b62453fc753b0a3ae6eb9ae07a63e265cb9065bad577dab61f6606f3dc2c168800518a9e84968ac11de829cd6236962daa064b590a2ee58fedc03d4c4fcd8c0a6839c96643e4ac9f563f6742ce2d9efcd8b28c3a3d9952feaef18292c0e561bc443ce02770af04152dc2d97a621ad454de71958632bafc1f96772f6464c923b441a68a99d86fa9d627c3422ca80c4d6972487d7e55b87c61bae625ed397b8d4dab7f616a9781bcddd0d9706defe66f61280ff512357eb574c874e8c15f7a92496daaaa0e9eb7f8258438291bc3309f93c9c6f2b34feceb50eac73046ea28443104d10104e6b3a7a8d2ee0c240933223525effb096cb125f4de6fd5a8615e1de8e013af95b2aacc9eee24b3722db5af4cbda61636314aaa3c2159d6b5bcfe7b8c8489bb9bad64840443711b2f7de328d117011430ebb639ede1e94b5d6c85a5b64ad253a40c40324eaad7eef95c7f4387e8100a902f2030815101f40a680f4002205240a081410205555553faaa8aa7c544d55f5a892aa8aaa82aa02f2a3eac78f1f543f7cfc98fad1e387d48fa81f503f80505551fda0a2a2f2413545d5834a8a2a8a0a8a0a888f2a1f3f7c50f9f0e163ca470f1f523ea27c40f900325535f5638a6acac7d4d4548f29a9a9a829a829203daa7afce841d5c3478fa91e3d7a48f588ea01d503885495d40f292a291f5253523da4a4a4a2a4a0a480445545fd88a28af2113515d5234a2a2a2a0a2a0a085415d40f282a281f5053503da0a4a0a2a0a0a0c2a07217e0aa3e75604f6683b5168abdc98a2caa814fc055c55bf384d85b49e75175d5bd777add05543dbe49ca02dd639f7af7e35f7f353fcee977be021fd7d59c0bcbe8ddb9dd790ea8778f5b6b2fb0b732ef72dab7de5d6bed90b55687b558d69638a4ac2d495268ad25c0e235bd60afdbdb88eed5fbaa7edd9252f06ea1bae2703d5d395ea27b14a7e9e5596b07b0d60a60edcd5a7bc35a6bc35a2b0404654e99514e1cf7615ff5f02611c9580b64adc8c65a9bb3b7510ccbb78951cdc36894e9c38472aaf2c1774fbd2828281f5177b79392427f44f5a89c743639ee77f3cce1ee3cfbf07ed2be7d793458b1066b6dd0dec6277c9b42f6363660ad25c0de46256b519ce6db7b8efb70f7dfd33fdc1a88813aec4dd463adcd616fe21ddbc0c65ccd37d1cd0ed6da02ec4ddc62ad5571fa421eef1e4d57fde3bff43c2b7d1846d5fc184c03f1ce05af905b6b80b576db9b38c4c36039e1dd38eccdf2b1d60a75dadb184cffb067de0d5e9ecd5a5ba3596bdfda7168ad55edcda2d6f26d76608fa7d3f43e0df7ddbb9c3ef1367fdae5b4f3753fed72faa466e1bea8134e83c1eb3445f5e3ed7b9d70babb9d3f7135df1f2fd5ba3f05d7ced76d3ee17dd114afc0cb9ff8c69cc993b57626c3afde47b1bad78ef7ab3af7db550cc4691098bfe7bbfbfbd4dcfb056eddfb6bad2dadb541d66ebdb7112021d00059366262a7258186100302dad1a5852cb3273f183910c92c37a259f9e473408a33f16be48f0d36e8607cf23b10bffc0dca74d1fee737a052e5af641d6c00c25fc99036e8c08624fb195207b3af2155f92bf269481dcc90a6dc409a72837cfb1dcc44150c0c5a76c4e0c2ad66c3dcbe645f8aa79521bd07a41801901d8fa0c8f6f8fd768e487bfc5e3b47a4f1c7720d907d5114c5f16b44fafa797bcea090a7edcbb22c7f9e562b693f2569a389e24f0de98b2ccbb224c9d24bdc601dc96b8353b4475086ce2ff13738654850368032748ae34f0dc9abf6e417d217ed9f4643b2657944da3540f68148afda93168b94ed5efe0c09ac3c8232242241d900ca1012f1acbd1532820465839386f455fef83212499c3d293e7964a190a7d6ed1c9f08a01fba5d01011d8d0f344a19ff8a142b818046a0d102cd908824b0fdcf17981fa4e1f8606c4843f2c5232954ca17235ffc71fc5168abf6e511150e7e5eac792026267604820357e4db8ea85411afc807c181abf24929475482beca5ffd3ced888a18f92212952937a4906f1323df86440548ec480a2941d7d6683baa225611af6aff7344050407ae6c5f45bcfa79a0f108e84b212209ca07fa2ef245240e7ea8d0be0684c4c17340bb914bb2d98b573bc4cc90bec00cc707332c5f142292a0fcf1bb487b05240a6d8de36c0ad00e2eb7f181866e646dc716d95b1e32214096c78e2be55b1e25eea84a15276579144249a54a89044208e5f8a290b803ba1a8f4000a1a452058412a90c14074ef24527407614228c105e84e842bee501448abfc45e51f9a0567bf268070a372f51e87f5eacfdd89f97bd28f43fca482f0fbc9a04bded9b20118d6fb3f1b60e7eae886a6febfa41221a918e886f036903d99510d2940eaea0886a48477e88b682ae80903820dafa19422ec9e458363219d1d60665baecdb5e7c7b760d7065439ad2c1958e5c92d951a9cbbe8814247f469234ac1d586eb247a11c6767944c3cb8b2bf84467bd98e136ee457f92b51ece0e7caf6a258ca9ad49ad8b721111de9e0e7aa4a19280e9ce27b202626ab217160bb7eae2cd2eda82cbb06b8dac07665919e5c2a4725997daf3f4b99ecc91f6932f20ba01d2580b14f8a625922799132d2cb7696a598bd736585489975f073354312fbb912c991b4ff800937f1a7dc181b1beb7355135f44223af2a7f834a4f4e704131f094cedad1552e5af6ae26f012282c08373bd9dfd76da7f6014133ba19063377690701bc77126be288ae4189f3ea307a7ec8818c1d3c8b1312844476e374ef147b1d978d4e7b4e56c1cc9b1dbf825398a53b011d99c160848b4a22d499b6aef9cb2b7efe5c119fc396548eacf58073f1e11cfaff4e72c91d49f130a39f65ea28d14af0011d97f40143b3d3867b32f47aa08642f4211fb9c2352fa73fe9c32b13cb2a73893d1c41189e848ed143ffd39c1a0d04ef145b153f665df9e50c43ea79d3d8035c0693b2d52fa734211c7be768a42118852644860806a6f796c0952b3e50c7a9b073535744eaf213564ce21d9d78cd8190ea873f635f194bdbe7dd95ee865415f0a61d93ee86fbc8d07fa598914343bca713474e4259e446fd46439818e8880841ee8c6d70c094c3c694f7b203188f637443b96366633a4b74ee50389378e68b5b3f644e4db376ab09c42477654127aa02328e5598b00e9ebcbf65b7c1b4f432a894e1b4750c47fa346cf495353e514a59cb30712bdc6d9ecfc9a211dad089cb327223a0275924836eb64a18428e1a475a3b38654245aa70d75cebc685ab77336133ae201eee76d0ff473b4a1ce1f2f5a0437ce9f1fa49ab5cdbc6a4447c8d34671feb033242faf1af943469204530504f26a8a387655467c11053d694e8872553bf2a29d5ef66b4f3bfaaabd1551caf9268d9c934ce3c5294a39c9347a4e51ca59b34e5eb6d3cb3e4d94527b722604e56d94933452fb51484b9c72d6bc68489668f6e2e9359e33a4724d10668208130496204608224a185636a3992023abca2a229465e905107980f0e2f4526273c50e31a3313b6fc6220fd81f5d3599edc93971ce1feea0116307959b578ea11ffb113284f65e5535a4aa214fb3e107346a3ff021674842d6b8d9d3ab0aaaa968a8eadcf101102c9c049cf60d104e0001476605c8fe51929beed36709a33e467bc41a3993c9aa104203c638442673a3c4001e9cd1014d137baaf4c0831557b219ac7891c4141ad0d042852b5998356511341e82c00491a4ec6b502be040e3852cfaa1a12124896684b26cf385872ece8c914412787a9c321fd038653eac5104e5830f60f850e7f48252c307373dc839812cd3edad958962902dbf56966559ce8cf80cbdf1810a0d5e80818c981dc43c61c4d5b8831d2c2c88b5a0821a62572318f2b46f7c20d5d4a0665f8800a2614f9c33b2c0628712ce5ce178010d11544409a1073ab31a4e234601b0d1b8b0e12993b039910349116c86dc6e43e418badd86d0b8b4f0a5d6c20d03202982cd105a951648a8b5b0c2006c900cb99df6cd1939361dceb8a99d294276260d6d68e895ce8c99d5ca929c7d71c6cbd40d6760b8dd867ee8b46fce7c406588cc4692a38c48005b66ce1840bcc931c3050f226cb7dbd09b99737a29c9e4f0187a336f6c3f453f34b46506cd00363364826a6698f962a6051c66a8e0e0814f8d873c321ecc98f100068d072ecaada157fad3bee101091ecce000642b1a89ba7e1ee87fa08cff803d958a46fb1e5cd9e7c1c3f63c78fca854749235a421d97ba541e7accd6d688674cb612db974bb915d807a406384977d73c6ce39bee9a1847344eae3b881ec38da4f72f30aba018526afa6539cc5209eb66493c310466f465a9124b43274caec2953c6e9d56447873765e81cb0a30623346eb5f20c12ba71060905599cf8e211790ad910d2123bc53140496e7680b21c97c0c00b1f3a3664497346149e1671c6d0cc80c59437b32c2c786121cc0d2d55ce324e2051ca82cef2b4a5cd617394a5cd513e16af1bd02d28e84635ce4af16b34afd95bafa05376743bc51247046cbabc2923c4390a1d7940b44ae28bd686ac9645193acbb33f90904be2439d6249e5260c3b3fdd102168faa3d2d0a824daf214bf6ae8b46fca7c39c9d3be2943c3998696a228caa4508444992a462c8c19b9a0469a31f6dc0900156438517442124553b0c1c207a32d3710e9a9a1088c2d4532ac4034059911842013a5080d3d68f01875e1c2a8842a88ccccf9e08d510d441485f003119d1c8886005394420c3fb44034c698128c801833a5688401106d6186510e5e1899b982680d0088c258a28809238a70088228891d8cc8d860144317a2385756107342910b623ec0c3c7c84a008a9400a3042c88caa0b3449c22219028aa41cd0a66a0186344c20c45642152c30614d2d81082910f7d944883280a3188c8d0a2e8ce14559a30d2c14d9100d6d4e9c1a887324403f05274e585a2322a1011114604a32861c4ace42902820c2c5b189950478427b850a2c8ce1028a06183439f2f4467c050e48585222cc0906034068c14a30f0400a70c2bba2032c38aa22e5014f500c7c84b117d8038420724c21075c185888f0b4568be98b0c3172a445aec299a724691185f1871b143e445146098f872c40f698cd4f0e08398a22364287a8385688d1aac108dd50042919435e2a041b4278c22006461148214443cc829126b53344608a335678c702043020d455b6831c14b0a462878a9a2c318d1126a146d19438d3b4641505114c60922344910e56163d4820f30dc50b4a606305b88d4ac6024020d2314c1a1210a91147a8c6ec05314061745495441e4c41ca22bde143d418411961f8cd2dc6c399cb9d9c014b9e15234c415231966b04224c40c2110f53056e4451e2df010b9e9a2c8cc1567444114441c2d6dba5853c4830f45e040540518325c8c6cb812830c569e9021842f634400c85304031e15ba309ae18a2951648963a4a54d510e6b8aa2f84014001c8ca4802902814b165776e862a5688c2e2118a5306674268f1e3c467401c51544604451d4441c1ada189db0c6488c0f443fe04074068c145cc4ae0c808b15a32a5c42286a618cc88a3c4472f014e5e9a2a88c2b4088e24e1ca32b6d88b858b3860f4533e0505405182220b810a571a5682c062b46616208c1ce181179e6e061d305d10e57147189e28b384654da1419b1a6a88e0f4459e060c4031827b83471850e0c5688f0c010421195b1223579d0c043e44317446d6eb52bc4dc6a51188d20a7484e127c88201223883666822833e70b0f1bb89c5e3cec50b1050b0f1e6fb6a05053e25186931ca0f18de8dcc6b740a2288aa2588a221db1468a24293e29fe179963144719597a912f96394431878894435692650e9a971109aaa0d4288a34470e29c6f295a696c81fc9f18d16300ca85171936d41c4c4adc4a288869bedb46fb4d039bda68aaeb83131f5c3b2112d1ba2d3bed1c283161b4eaf221be4641980509631840a38ed9b2c5188b13394450ecd5684508d871b2d4b985996196632328b0b4165961182c8ad212c7d82b09c81258b1b9d17b6ba261895b0286143686b680d501096333f4034242c646c3f46596e42a77d8385cb69f4c2ede7b46fb0b4f0060b0a58c46eb3a207f3f3b41fa42d72960690ec0e8eb2e869485fc4c26d76da3757ac181a9a41614b22c808d9d6d02b09d91132234816341494430d0f2282685f1b6f6faee870d268b420251e396e41431f1494a348002ea7170f3965806e03d8395d734872345ae2e665d92419828436a3d1581042e60298048a8c4a4868341a8d051f4e1a8df63c6833a322662539b24132e40a0ba797d2d905909d31c76d68053e2b4c318243a3d18ccadc64a77d73c5cae9759b52a1ca59f4c28d76da3757a29c5eb7733694e356c4c3e8cdcdcbca9960eb36f42ed4397f4efbc6853c2e7c717a29d969c1a80a23238c90e0c1c3e888190a17a4d9010f134ae8f9c2032064e0210a38329c31c7ce0c4b1a54963c64466c72c8a49021a2b0859d2cc41853c41820c688a9a3a68a28568cf18a0b576e604400801923e6cd1055e8a2cb9830c416a0182306a006254a125fdab0f940cd15256b761873e70427e088e0020b746e8071630362828b2f79ac90418d9536775aa8010d34264831c6ac0517941020cc1825317bd0e033464c028e0372c688d1018c31621b1b14086398be881963c4983352476316a009608c18314d0362c408606c0c51cf1469c630629a182306fd76fe28eec1756f4d846ff329bd38ecbb5b777e3335b0a66926759c36f58bb7efbbce7a937f7a6fbaf2d2cbfb5fcfc2f7a91955d7c7fb3e76824b31184e7397ab77779c130ca610fbe3f7670ad9bef58fbfd6fdc7efef71986f0c86f7a339bd602a16dfe68fdfdfd3d36ee54fbc1e3c2053503f9ea87ea0d8471590dd0f1f5140a87a3d9ed317ca9dba46ef57aa834fbcaffaa9679fb57c78b730eee5f8f00639bf29cf49fff932165a6b77586b77b0d6627b6bcac3b789a679ddf530a3a24c2927dd53b3134e2f8fa358f565ce7ffd6ea1186c638e9760bc8ff07806e2705cc55fbae3707cedb773619e7ad37ba57b2ad670eb7e51f52a49efc641adf402b7cee2fca6448afc78fd06794671b8be7530b8f21c06dedde3c3bb65add5591c5330c393b5a38e246b6d1b06b6d8171658e0a1be81a3ef98f77a32a70516f806ac1e5571136b4b224a3343ac2d4f282128b14a24651026217c9b7d6bfe74637a8b65ad85b276a460a94abfbe0c76b1ac8aaeae9af70d58bd8ad35cefe13487a69af6d439fa0d34c0db7ce4c15a1bc5de9426b0567dc278f7dd135775ee3c9ca69a474117169173eb24f2423e0ccd4a3b948a2cce34e14060ed8867d4624c47aab18715558875c89419220ae98d33f8e1ee319ac132faba7f0f0271ef57fcc161298aea8508f928a517f2cfc00d63c4d86039b0d652b1371e58f836579eb72f4979230c17d6a8405c2194a20899460c0650a182192d886c10424e31a7870e18b69480e69c22d99ce0dbf2844191312b4d640d6b8eee0c21c954e1c4832441ac480418640026ce074564908cd24bb10b82c6520e924917b717f6c8b02508862032c80b372f5b7c9142d49258922f07013cb72f4ea834f12167248c39014f0f43b61c80c618461060499280f152e426c62867cf0b1b48e1054c112177c61ec248d104d7132d7870a1cef842165dced4b98200146ece18054b011504408323ae2be08c3d38cfc40b4f3c09abc1883149153e01d07106d299459a31ca873a6bb8babe1082093363016a20a165d38085cb1332229f1a5e20628a0a202528e045c4c28a235cd464e992d3628bd8a60526334f0670a50b0f2c8864dcf8e03ac28d0b17345082a802081680a082052f1c4104155168a6eb8e0cc32a86841b884fceb08569608683af0fba78350390862c5af0082148c5a4294432d003822680818a422a28c94d5f88ba98c0da338cb8c0480057508cb474593a53dad44e38600ca6c25a35395881ab4a7053268c9d610cde0c51738cd893646d152e5a490be8d0826464ca02a170a2cacb982fc47ed67259e9408a090dc07812b4b68acd152634488246000fd6ee88e20090303d2cd8a8584b96090be30832bba0312fbc9853c36d8c892d43f88cf1d0840f3a26c8c200dc84c6589612d2c0b1e9ad2a70c418eb20cd163554051c078471678cb7460867ce986295b051670c4b0c0f1e593257e1893963e69d27372398180832833396238b0359202147030fc818d147004be4a000131c15d5439a3e578c502b43cf9a1b047c99e963c40f45822b5809f3421c327d6cd063432e4e95ce010b5efa58f972851a2e68b64063654b9f7e8500843c824b1da861a14f052e647d50420a402cc0a4843e0e2491664c3735041417953e0a84b0cbc9d20d202061833e3f67ce940923664c0c4d5f034f00b2d0b382154598b140ba0614348ce94d20949b420d740d20a82093f2e060570395276b7459e18b0b13412890840b5d6b7c70441545920e7862092092acf145c5cd9c2b9c40c2812045d6d8daa1cab787c9c70e270859c3079ea91f2c3a98c86c31b506511710e22c7165cd15349ad6b051f40fde282005d786071f2e5070010c5d85048b56119f3744dc58a052b2a7c98f1c7c7490224480e1053d30e124888f0b37c0c14a6148181770ace4a301185b9084099041c21b3e7c2e0c50c85829f325893368f039f284044f94a298689922069f2613e4205006050ff808b9c30787104d52c0737e0120a8ce1e35c6843af011224d1dad397bea8c09f6d1d1460b124a586b6d1f387b86e0e2803864030718b9c25a6b11e821b0655115f7fb1c012854c5b71d7dc4f85ff7a938fd9e7ebc75afefdbf96d071d6badbded10c3aaced2bdaa730f6add7688d97477fb0adc81ede350fc43f4e29d5e2542bdb7beda7a6f2342bdb7be12ba41129142889526889549664c2fd2d28872fb22269305d11698224a294354a923c8cb98d9086265125b013f454353c46c149415903b80fa2ca876a45635fb21830cfdc8de88d5d088e57812c5f68384e18ca02bc4646362b2a003002016d4918410b30dd9186941644f3216aa100064c01529650962378e6e1c914e389e6a4338c6a4c818a855d18490374821352f62a492a8a7d9cf8c8c1809343ba06c028a22c532a86cfa3922638046c1ec80d9cfcc2b2847500edb90ad001a05e41a52660790394891b91153c0ab047e4e01a31217746386a31449279248b915a46336d29cd088685932026c8833205256069124399234b246da7e8a4a92c68426c08dad1f1cb4194d2469e554f9548a350348a22836046463c46c908982635612d58a4829af9082947b3bd6a70b29e83421270937ab8f2b05148c5c39d0c00fade221e329e976a346b3a002adac3126e638818015282c578668b9228a386dd6f880039827730117d66e85ef34cc28a30e14738e38e34107183ca96002adac078e20b04347016982f000871b3ae0206754a455046c5c610514a0d8589f3c6a3cb140470138a26883c4106b7ce841072b278890c38002275a595871984062093558905031459c3647ac11e28b17123e986246195140b14688343b5011c32896111c42656c71e78a248e0802083336a460024673183cb1c009969120b8251c4271984802861752a082510c20c03a622488dde24e1c269440220820cce860830a2750b90002ac0682e07e4c452d0980a3b4635bdcb1428924903822082074b04185144e30814a16b90b9e38f064f2d99324821b36aa2842a10412267002358309240cc3cad8c6c83ee31ab23de3006a634a31a30d2318516a8c22a14413c8896480fc0210188b4422da01a401e250a9432cc03680000290b7f246908d9bd00141060015fde0b0d16a33da389bc964a46867547e14782346b3d16ca58d1a15cd461a057545c942aa29cd7e6a5565d00db10c9ae54a212944e228e94cd12236b331d26c65939051d50d623f4d82d0b2c94694718a48c6a414674288106b2049111c53c6f2a74cb294478c0b294c72a288321c0e04864419cb0348a7a078642563000ab1d90c812d2a04dcb8fa807c204a086206d89c04e508ca91c111028235fea38698906e7b40a7c28d662385645fa5082544a995366646e28d1e51ba98c1c604002a353d576c8c40b221386840ca08b00539481940a6f473e46781d99392890644ca0f323c20458c95026e50548478494630420c68edbd304548ea86d8a4880c4233802aca0f0dc8eca76683fc81f50069f473440db11f1a9610570d099191233f3624415ca8901fc474944d543f33dc0042b31f202348187c11fba921d9b123414c46de64e24c82d98f2cc88cc9ea0a68b525d590cc7e68060815b1f128b36c3a72142d7040014c35062258b240949f9a49eb21d4e307d6162da8a41d20c39154b6a032e987d06cb49ff249164159354494119147b202a06c351e09c44890a1da4f01b61f518864014dd5944a1e258f991831261b65111903b21d361e65d18d28d2488a98f924923dd2a924651a2061b082105ac5e106396c72c0418c97113ce0208c7ff5304f87c1930a2668c2846b2b09044870553d94165020812f9138620c8f185d3860a500d20106d0ba2c0107cc17098c3880332220086866441a20ca8401e3850619bac0c04429e9c97c414b17d7181f347615e021634d4ee350c14aee5905f9a1854901851f3629e8d8100607844a470ea09f1aad88c8871e9e60542b0b02ac23467053514b02e0b02154c6708208210860c7871a1c6e10e38193263fa88672944dc8094013ab06a86cb4990e2000b1c30c2eac4082065c6288c18a56965590a420710f3980514f59c693317a5176316221b3234e31463102c00645d09cb18931ce9866d481c461fc2abd441e2202352359919001a38e910031078e0164028c38c45b69630492fd8cb65a6da4d164632992a238b3d65a06acb53fd652590dec6d68caf26daa79079bac158574e4a0438ce7bfe990e0a603cb5abb80bde948e0a663c8eabea77fe995fe319ab99a9fe7eff9830cf7ddf7c7fbfb5dabcff3f7e1ae803c0574712b408b5b0150e874ef53332fa7fc55fc13fed23720e4951e55f13720e4d5ecc3bb0b4cd3b4a0f39911252b5b722ba066d58d7bbfc1a7dd7956921b01faeab4971b6614ea1bb0fadb538ce21fdcf7fb28fee265f506856c881188788a136b4530114a1090f813a684a277b8a484819ae778369794762bcfa1f88b877f3c5314ed0086c8409806c1f8aa66a089aed6da0fec4d0016acb5506ff55dbd401355b5ef6ef469e8c3fdeece655c797275f03081863a461db13a6df23049a3740616001e1d70987036bcb12e1b42ae9ea8c088002a1e6590e8e5b0c00e5054285aa073230e046af0cb8a2d240420e029043a5270d9423c11820558cc0dc431eb0b041620bff4f0c080344be4308511659dda1371d21023817ee7e90601556b905764b1992d5889435ae4170e08008d29c05c1943ad1a035de38580684b329c80a7051f90c113250110ced043582bf4c182050a83082b463959bb838a98258586589bf5d6d2e4586bdd583b06d1a28495a58185b5585c10b337ae865811842ed626ddac25bdb0d6a2d6da1f6bad387aa0e234ec02470ba07a6aceba590c38895e5c5d580f6015c93d80c5959be054226613ca1462ea1bb0fa252515a726effb06d5244125eddeea2f80b2a0b7eed2586b87f67683076bed92d2b0078138c7b3d95b77473c8c4af5b4578698ced280345bdab201d1d2ba88a80c8748b337445901a20db12655feb0240be50eda58abc94a5214ad8ed1b4a31525281d102d2d88ccde9889561445996c6a041aad288ae488441469e2288ae42c83511c45da58c012519c89343b8a422639ce664a3f2f96e358a22096a238fe88698ca2cdcac47224b1287a8da238d6988c44a338ceca510c6314c5d9284a20ea104572ac1521236936c40244511447202301355284411cc5d9288a239913c7f2c736350689563551c6836c40a48d631945fe8ca3b874834ad4a08c023a426e8db6b4630d62492a95b25124adac05310bd18ef676bb59d18aa5388a6488b591491447d93892a2d8437c126b62d0388ee38c8898348ee5284291269001b5054421010e18af88b2d100b11449d18e5be3ff88a51df3ccbe4e3481b44745887608122329cec492260a89249671ace148b18a14c7b1fc31c8a624ca44910655462100258e3fb3da4813459c388e549033d1369624988834aea2483a8936a051acd1c471c8b863dc311a9196b4e20d71368ea2507923cbd180711cc59958f6441b0f1148368a32d1c60fa2118b06641bc55d2d88368a128835512447b1149188462390b168041a69a34c24c5511c459c6834028db4522465a428fe10495149b48941a2280611778c3f244dac95e2288a38519c1530e610cb5194952290114824c71d22498e633996229071140f187f449b582b47511471a2d1f84323c5b2568aa2f8e3c521a69a10920199488a36b11c126d361c9005443bc4044a711c67230d8b3702a0809088e2288ea2283a599a0dda0a3c10cba0800cfb14c8e0851c0a8eee88e1e4667103132cecd8aea3292c970c4d60ae1bc72e91210d0c4b8eb49604327895b175a786249161470090dc222820320c3d01b936c6fcc04288c78fa31f910a0b710d2add580c54dfc79aba3d3b9c7461c6263b5f74d3433131d0a5090f02ba0f42e0750860bb0c7081d5c952b05f4eb196b44fac92b576cb5adb81bd01a1b9fda2398c6a5e56575b92a31515b0d65e60c1cf52d38f921207cfc14fd38f06ffb86f7a0dfeff1feaad7ee35fd750532fe479cfbe8c0af5de7aa7556badd8edcd46c697774fc055ed590dd627b6ca36c4b7898397c7710fa3bcdd0552f583cac7540fa928a83a70ac7ddcad26a6b6c2ad36c53eeee771bd87d3ff1f5dfff9f2feef3d9cea38fef1fa053670d44003d65a1ed6da32815badc8adc6c3dae7b9afbb7f9e5fc5298ea3eaaa77dfd3df57fd47d65a246b6d4c6c4f6845d65abc065e4c7e851a680daaacf9ebc3dd79cb40cf9941189327e17497fb0d02cf0c7e3cbc5febde94a6bdfc4d190cc9606818f6287a89586b91d8dbd08dc951fc1cf8fa0e7fa81b86e9a10d8e7d38cd60790771bfe9e571dc2f0fefa8a2561caeebc72f9234bd44acba846c7dc45afbc3de846678113ab90985c09ca002460586630d62bd617d725ba7f8fd09f15e83ba2d9df5e3e5efcaf530ac7b27ccbb6abe3fdd3b75e9fe5bf74e1aef52fc1baae76f557883bce3d09f70259e01cfc2b9388ebdc4a6b29d4e7b832286b5664f9baf557eaff8fd34c5c2e7f7755b77de3d52e4bca6aaaf6e2bec2ad1bd7a81afb34cf5f29ce2fd99a739bf3fbc6946b10ef7f0ee79eff1fd39a5bb750b0a86722481bd05e598bce757f5f334bdbc747797dc8259d6da06ec2d8843bbd1415dc45a6be27e7d7849a753e23bf7bb84e21ca67750e93bf6eddbffaa18a8aa5181ea10cbc46476ae539ea62713d39b18f75e5d1fff7a135635fabdfc1b8361a1fe7d930eef35a8fbe1ee35d034626f4031c0188048804de810fffa0f774acc25e90d69136b2d117b4b07b8a5b42f33d69a4e265f3bef8661aec7e5306feb9eee9dcc9efe5e7a7f78f7aafe9b5ebc73287a75d95a0bc4debcc0f032c22b78f3faf21af2aa651df205d9819f183f2c3f0e7e56be32ac89d11b5c7bafe68d795313bf3f5d1a5c8b1c31f5c619e0dd4ed3ece44d54e78d83cf5357adaaba77327550bac77c55afb0f3d56ba777f0573d7cbc93563d7cce71aa32797349f7e3f5bbc3e1569dd2f3cb7b357fd35d7d79073c1fa7d3bd93b9cb6138ed3d7005e6b00bd45da77b0cc6875798deef5c03d30ba68761fa2ee9e95fc7e92edf2cc45dbdfbaebe1fc7bbf7f755e10d72f9f0cd57e4c3c1646fbd2eacb5269a811b074dfc9553e1eb783a9c4ef74e38be65866dac32c1c161cf0dc3f40efef845f2e3f7975ebcbf783abde23f7e7fbaa762f586042fdebdb7965f214ea7875f210f7bc36e8669baf638c73cdeca1fc561ec89c5acb55778e209ac557130787faf6ae12a6b4d5467dd503d76e39ee6dea35d7c7b0d629e8a37eee1fd7ae30c6ed70d0d62142dfaf1fa05f6f495bdf1d6dc7854acb56693dffa75e9e5652366e75dddff084f77e3dd4c2cec78f7d8017bdbb9b126ee99eb2050f39c54ad3ebf3ffcc368e6e5956bf765a29877d320de7c071ff5a95a67a0d36935c45f523dd629aa758823f8daa8e659e135bd4d863802213cdcc45a6b646f3b6b6f1d6b7bba63ae7bc1a5e972d0e57498af8f81f731f0aa5bf7bea9e3dee53f542ffeba1df7401656d692d3c94d5782b5d6d4ed6e3a1b47ec2de7c6da239f9a9dba56d5757fd7aaa9d3e8f7556354f38438c782b5d6ec6a066204ec2db72497c45a3b81bd618086b5d6e4b8cbdcb8df74e53add890110187431753a22e6d7be40bc1fa895586b87ec0d03072ed873bba0069cbd5df07581014ceced8911d644719a9ee66f0dbcc3cec33ba33fbc40221d73a95abae74938888b9828e6176f9e9a9fdf1f0f0739aaaecfd57c817863e0551fff54dc64a23883f5d5abc3a8e6e97e69b8af9a774aaf656f4f96dc9e94370bd8586b4d3c4c71bf7be5f1ee6be187e51edead9caf8fd1dcb55ef2183b7926262626332cf7f00e7220eef9d3344760adb5b2370bc08217ff9e2775150355bd33988a7f98ee8098f373879d70ecbbc1efe9e7faf18b0487ebfaf1fb4bb5de19e92a06c3565d41dd31bfbf20df7c63e0ca55cdebeaaa89f4322ff77a2bbffd16d9462a80d315c252ca579dc1f0ee652534d58f7f5d56385c179aea5b0540ac3537e6eb05fee35fd7be51a0e7bc518006f36e1afc2fbd7afd120ed7719ade2da50bf8cd6974e516fc898289069f5fe1efb0370a7ed69a28ee170daeaf62bceba2a0016b77a88ab98458b54ad34bc4eaf9fd2e2142c2f4559a5e9e5597909e5670fdd23a89fe096f130c719ba00b139389558d3aa9ab56d5cb6362327f987615ab17b8f1d66d8208acb511d8db04d61ceafe1bf3f535ba7209759ade34bd3c8eb5b5b687bd3921e3848c9317acb55cf6e60489357339fcebb22697127b6b228635f5ebbad64b74ffeb59d8248a5b13316b0ef1974657fe42acde5fd209b1aa537a146b74e5e5aee25f5fcfaee27d83453ac7be8c666dbc03aeaa160ef7e31749d77ae736462f46622584879bf00ba0a42e90eaf141aa560bc230aa32816247b2ac79a5c12f6b2d8ea52308b0966a5dc56068d64d364ed34b44cdbebcb5d2f41259b2c5f5e607ae1b6e5c5cb84ce0fae0c6d50157065c9d77bebb7bbd38038cf7117ef11234d5486e5c45f675b9be06754cacb54bec6dc91016ab7a6bdea3b8f370300cabeb371d59c281b576c9de9674596bd19cde7e7baf6af58558fda67f0cd45c1a5d395730a747301811ceb10ad4a87a970481b7730ccc5d77af5c0917df7807c44a863da7b933d1e8cae5cb3cf77455827d1798f1deda5c43de550cec1908d444789a3b133503d19386a7a79e774f7c7753b00ebcfc09a39a47830c5db8586b6380614b69ad16eb53f397ba31987e00f7bb331870cdbb0ba779977dea7a44d5595c1bf7549d95371155676dac0ab586ea99c3a8567170d8350cd37bcb5a2bfe60ad15b5522d0bc4acfd218182139ed42a48586b459ad2d30742ac41e0026bad78447f612982db3ac55a2b7e3027063170d0008a596b459d0531d07087012eaeacb52405c12563a0c83116006b6d1966061bb60608c2cd0f6bade8800a1668a120020c69acb5641a6360b0039923b28c61ad1549080381a52d1332c65a2bced9491df1c4042855586bc724461cd882842412f2586b4902acc821e30a96344e586b4500e079208a1f8447ecb1d6ceb4b4a0479c83eb33c45a3bde4923850df85cd1e287b556f6828e96e5f7c6eb0aaee2be5bb91346b5aa4489a9d3bdeeaf5e5ebfb97ff4021dc7e17a29e6d259f0983379b309c53d49e5f975badb31106f4dc4e4fae1c660f8fbfde9f0d644b289c1327e6cae3c1c66c4ccc1334d2f11b3af41353f066a1dc64774972ed8578c7b697a79a62e4d2f111dee35fd5f354bf0c1b3ab1838bc5b18f772bae77218f7549cf6b07549e79a97cb15e1b85f1f4e31cac5370e0e7f39deb1ba5b7916ee39cd7155ef15abb98e7d685e3b5673f0fcba9d8bf3dcd6bd9ceea93987bf6ee7b98e7d3c0c961be22f34d5bc1c3c314fd559e670e3150afe75e54c1d8a75ea54adf26e0e9e0f98c3b4d7d3a87a7f6a46b7d6bc54f374d73bf87ce52ae6aac660f7f798ebdecd69307879b95fa0eeeb7df58bf73d7d71bc63fe3dfd294635f07d6a4eafeacb9caf26c7dc2977edc36ade179877f0797e9ed1cc51bcc33ef4fa7ed8f16ffb38d6d6f9397388d3dd4df305db184df5fbd4dcb47f1dc57cdd6b5f8fbca9eac76039cddf31eff7bb9abfe9c7f3a919ef54fdc314ef472feefce2ad555f7ebe71c7c0bb5fa7fbbafdb1b64edfaa7ffd550c861f67a44b2beb4d8ef7ed69bdb7debcc39ebb8ad1afdb79eecff30ff1d7d53dbdbcbc75e7f9970657cd7b9e1fa72baa81d877f9fa380d026f187ef57cb3f7f47d9e734334e73ae6b95c2ec7cd1e86bbaa79e9dac3aad69b4be8be3f139b598967f4797e9f9a7bf94d9f893bde4b5f5b0b3b563bbf3cf4eabd7bbcd3aa527a793a45710f621eef3edee982f9c7756abe7da795fefeee5b07f17eddd5f5d5fbbc67e06ee5fa8d55a1ce0df1574feb1dcc81e5150acedd20aadeed33a39c78fe5e8a79cfbf649ae637493170f54d510c5c2975f5a22ae6718c3e5f77cfdf74a5e29f933751ccf90d3ebfbf1fde14a3ef53339aae28fef17810f3c27ebcef5acd8faaf7cfad2259e792073a7ee04dbce215cac6bd8d7b0faf7895a00bc53edfedcae17ecd8dd1adb90efe50bdb99737ee3f5f063ee71898fbe334987bba02815bf7360e3edefdf0023f4d2f2f8bdfe759d541aed375aee6ebbbcf39567b7963b0d7fdf15ef9e3af0becabdedde769be1da3afee8bd3d7fd53ad83ffa5c150fdeb18f8f8a239bd4d72611df3f6aaf9c69d7737ee6a7eddb5fa4d1c4d71bebfd3e9ee51dcb5fa985f9c6ebdc939e6e91ddc2bfa28deb8ab2bd729aa622050f3f0c67a93e76fe28f3b4e83c0adbff3f0de1aabafc147d59ba66b0fa3a83a54efab9a7bf172399ed9d31cef20de6abe5dd5bcd75955ad4278b889ee6fc7d25de57863fea8da79ebee3c77f576aee6e7f9d7f5e64ea7bbcfd2e282e0eff3fb3d6f9d2ff7544de401ddf78b3791cfc1f3eef534ef5eef07f38f6fcd39e661f5b1b6cedffad7d79beb3ae5268af9fa78c733c72af605877db87b54d5df344c89bc79f77aaee8779df2c7bf7edfa7e661cfe955d7dea378e7150ade18cd607a073f07efeb3646d3bc5ee91effba72f7d7ff8b877f44b8a9fb3f50efde0ff705fb34cdc2bffda21cffd48c7b6657f1de2befc7b39a8ffc300d06afd9b5fa5bf38c62744d79bffebdfc1ce75ee6e120ff1f2fff848f819ad757bda63c35bf7a3f074f275a660ededff86b6b61aed7d3e67ff1dbdfa9d7d38f7f9deb37462ffef1218ec0ccc1cbf5260e0efb0ff1d733f0c2bb794e8be4723e9397d3dd1a7c14bf91242711ae4771bf2aee97a76a1e5ff2267f5d55afafbabf1cc558b526c7b9e7f4aa1bf730fc7f33d8a398eb6018fe21fe42f1d69de35fd79b28c6fc550c967dc334bd9a0ff1d7ab3a738e39e6bfb18a1f781463ce81d3cd47cd5abecd1cbc39dc2f58dec15c4eca9c32a19c7c3abd4d99c17bed17f75e07f6a57bfce3eba338dd5d153fdea1eafd346f1c0cc3cff3bfd3107f596b8558203e35efce950b720cbc6ae7dd205013c1e17818d53c5567be3198548fd52ab77130ec02bf783addedf476dd736117682524ec02710ef3bbb392eab10a09bb400dec527b48d98db7380e97e48ba7d32b2b14078379778e03f22b14b5a4a07c90c7bbd7fd3befe97a7b187d9cee32573117df26ef19985351f7542c8cdeed0b3259d2f94d927b56b132c8e955f3115ee66ade3dccc8300d064f20ee7cc8ef6f6be32d8b819a0bab3aab0b688aa8206bc16c10a830be4d14778ed5dcc63de77838c89f78180c0a03becd1fbf3f75c5c0dcd5758741596b497b7bd2f20482b5f6713addf7fb386b54c92073b0c79cdf5f438949d855c2c78e05cbfdfab050079f4f1045efabbdc761cc85371fa874779f827d8f177bdcd83d28ecd159f3558d6ae0efb959cb559d335003d73b002f06908335ef00b8ecc641eda46a1547497134af7debe0d7d642fc757b9554d41acc543ea490e48458c51a5db9f448a0c7479e3d79b0c803431eb13c48f2e0f21ce59941a1861735826a50a981238d3ad65ad3a766201077fefc9d6c8f4b4a6f56b5ee59baebef4ea73ef4feffe775ff57e7e1ae77307fa939fd8ca27bd0e0028d1ed080018d8d4613ee3a4bf74c3ea490e8945ea733755ff5f08c17ce20e18c7b4604678c668cf1831934984181193fcc20cb50538698324a28439761a48c253c03c0b3c51a3c65f0848047c533c4c43cbd980bf774e5e55e2f17696ac2e9ed5f5b3b39939ec9e479e75f1737bfb616debc663d9399f44c1ac9ebcec34ddeaaea953ee96b6b275a5bafe62dcc5375d233999c8c720c3763a051626f637c8df1d65a53c542b113ce2f061a560c2f41318458cc7570afc1f7f58e55308c62b5733cd46910a3dff90a819350073b56c7bcf5f61ea877c73ede3d02861875c0c002c613309280b1c017517c21c217575ef4f1028f174c78b1c58bd49a5dab37ffd7ed2a82bf6ed733f9f0416536f0173cd34741995016fce39d0251df74e4cd0bba9ee97df4f0e183ca82e7375d79dfb4f44a5d3f4ca980fcc845454109b12adcba5704ebdfc986c3993df3f39d9c9cb8d871f1c016635b5cb145962d42d842c9165477ceb843e74e17b3f3db7bad7be7f788d65d4e5eebad359a6a5e9067d2d9ee8459abc5065a04d1c2968500b2f8210b31597c6591c4ec287a3e93c9559d79c65fb7273dd392b9d34aef53f3107f61a102164db020b2d6dab0372c84ec786107007670b02366ad4905062615c56507898abff4cd607fdf0a9c153caa08a38a385574a922852a28a8c2481539aa18ebb8a973439d0eea40a963d629800a2ba8a0818a12a87042c5151537a6e833451153ac30853a8591b576676f520421c52a454f8a213a4bd0c9804e531476a2c062ade95373d805865d254021ee71759d9599a079dddda17a9568dd95f44cffff26cad1cc24e9994cadfe7a16e20c32577a572846bacee2e12649cf6476cce5e4994cdcef170fff14d5fa4a9f34c45fb9094e25389c540f350f6db6c77aaaa83589273d93e99573422f1f8a955ec73be6685e77cec2d7bffb4dff190ca34d4c40fe5bffc6690a5cf9150ed5fb611798a38a5a5ff73445625245ad1f76815066d4f38d7d78f75451b8eb2c73631c7c9ed17d857dd57f7b6a7ea1fe3dce1def20aa5ee0ca2f886a82b2604815b5f261ba2ffefef3ad97778159cdc0e719fb2ef0a28ff7ca1ba65a7320cfeafdf13050c53c3573bd93931300320092004006851850c800050f8a2e280610c01c3a738498d3c29cdc9ca127ea585378b710d55d6f27ba1be940bd7b42a11ee208d05413395555a8378ae25cd233994a9f94f44ca6ba3eaa0ef1d78f777bbf8fd10b7c2788c8c109a1133a2778382140136a58d1840e4d646902d8849326aa9a5040ce1e396ce48859abd34120eecffbaa751088bb96e89ec954af0e55577d8488ce9aa21ae2af9cee994c14a7178371345b514529bd8ea379d55145ad3aa5d7e99ec9f4a9f91fb7a4d329310135ef797a311867f24e4e4e4e7292d821feeafaf7bce7dfba1787893860e2745973d8f3d65e17c87530f3ee12eb12132c21009c35e0d86102ce0a70a2c081008e149c2538f64d00de8401c59b326fae80f0a6bfc17a53a5441f25f028d183123628f181125c09264a1451428124d248828c29d6da2f7b4b62c85433f01ff79b854670bf4bb8929ec90ce6df18effbc18d81ab1acc493838ec0a62253d53d233994eaa563be6e73bd970495d6771ac8b64619eef924fc0d43d35836dccb5dec916844bd561e733e13e012993dfddc3f05e7b5b51bfa46782c26d11e9faad3f0ab7558409d56ffd53df5415cc55abd227053355df3ae8c35dcd5552516b303faae2609ea25a953ee9a9a256aaa855e993929ec9dcd8865bb2527a5c52d233e1b86f9f9f8089e28d75d673a1debf8eaa7aaf58e52beebf8e817a079f5ed561f739d87633851b36d65aac0abfb6163e4fda98af6ebad8f4f28d39132b37df66ac4d982ec41bff766f53c5a698d76608cfeaab97d7e6dba0188930f6a6a910abea8a44181243acc5408d44cdde60fe078eb063ed1168ac89e6de114160eef988286b55eda46abe667df1dbc539de287a7ef1dbf5c56f3722076b4d238c4062efab46bcb5c0a1aad5b308318ae8a0882422e458fb3d1381c59a4404ad1d22cf105e86603284c8a60a3622b09962c3c01a00ac1133753a9deeb7ee6d2cd4294fca1ba35d6f6255a7bc269f9a87bba7f927fc61fa5ffcf626ccbb41fe1755b1efa23cecb55bf9a769ee3bfec56f97c951dcf3a7b9739d4e8777eb7ef479cf4d9a0f77ef986bcd126bcdfb1ce7ddf1ce55ad3e35a7e9256265658581370f7bc6e1863d77be730f5557bd97b8bea98912122190582186ec60b054739e513561acb5dc889aa0b5d662b0fb5333a4622006a679c2da9dad70b82e2161fa0acd699058b3e72ddc184cab690eb0e267d8552244f754ac61d73d35779df70e0bd37c817878d320cf687a7d38bdfd16d9b8f72cec688af3916f5abafd16f9a6db6f11a58ca2d76a639f9a7bb9a02f18c4044140a93888dac529ef5520d858bd71064a5d40a83a77dd1f882a6bf6fc839dd76ad70f62baae2c265a447211246172953352e45cf2c016931c12ae13496e8253c90f50d6decefbaa4f347ab48aa68d357dfba6afb5159a256804f0e1091fb6983ded646e1cbcf8c7fb1f6f05fec5a9ee7b58aa0f4e3dd0e9a18a35f9cef8d753bdbbfa75d10c147ed3f00675baa487a333650c53207c7883bfb113dec17435728684334fac357539dd679d48ba9ecb8812acae37b2444bc9eb7efcfe749fa5f5458c24497212792357dfa595f55d5c4c943c171692ae7d714a840b332998e9d6e4b9c9a766748582f752b792eab1aa38b55aea52c25f3c9f9a7d6ae6010b0f13a81a0335e741c99ae70e7aac5d7d3bb0b142dcdbe167adb5bd97d13f77180aa27528c39a5bbf54970e5d74d0e900654dbe84b7062afd50bd58a339d8b176f73d49cd1fe4730893e61c7ed6cce1f6f8d7b570b063fe700893a697080e4fae306bf53b1e7ed39f565661177803901b80cabc29b3411925abea4ca402252d339879b9ef1bdc38f5a999ffddabd3fd8c6220106b0c14634c18331c7325660c3157c44820e6c7062f6c48237432559c3a85555081aa95a697c833f0153c03af6bca5b67dea4f5a62e4af7c3347f4f579c5eb0bc42b94d39ac53b1c2e8091345981fc2ecc24481a963029d54fd4d3e3513f9f2e50bd79707bed86a9853430d3574d52073c24b125e36f082e525070d6c68f0a2416b86b119c4cc00c30c593390321c2143f099fe1978ccef554fe35e4e9f779c41e6df04c49de3b8dec9ec2a06c33d6afd26f4e2fd518fd37ac25ae27a069ecba753252d9dd2f78d7fbc7d31ff9e5ee0d3ab837a07dfc7157695e882c1cb335fc7a56b6a52b5dec9dc4eba7f90c93b99ba252e252ddd3ba5695e42d5abf43a0cd45c3df7b0743d8777c30bd4bd93a9e44dfd13fe92d273354d314fbdbce779ebe75cc7d734f84d3ceb1e67ea38ce5bf79c2eea9d5ef73d7d7b99973bcf5667d855f24d4278b8497ac1f40e06af9590ae661dc4c0dca5e29f706ba0e6b91cc6bba77b1739b88b58cf4a1fe42befa2d585739d7e5f9b8cf47567c744b1f00ab9b0e122662e7169da6114a3316811030ac161475135afbe7d5fd53ccc1ff39d63f8d918aaacb983a10c73498e798301050b431086a19e51bc79dfa4d3fd70f7c2ae2d76acd561a5b7ebae2d613ac77b8bce5aabbb12d716286beaae66e00b7aac351fb0b717c25873e905317e85e70b43c0fed4a26745b5b809bb4a700618ef9e16316b4d9d9556576fdeb7099aeadf4d4b1558eebc8bd1cc1fc5b997510dd472bbca22c7daf40aef46873d67e962adb5c1a72c3f6b4d1d0fbb4a741cc5c0ab66ddb25439e11dbc99977b58c557596ef6f61463a94277ad3bc74dac30debd9c10ab45ba8a81aace5d9d63144b102c376beabad65bf73cef9bae3ebcaf8871a5e9f90d3372e55e4172010d6b8d7c02a6ee6fd77a0faff07d6abffcefab77e53c7f7abb464f17627021ab0501b400450b685ad8622ea97bc5bfae6614eca68f9d283d54549ade5e06cb5788ea9f50f74ea692c739994c5a8062410d16ac60a18a99400aec3fd3c4ad7aa8001020f9eb020bb8acb549f6b602172ba0b042032a74a1c21a287b53c18a0a1ea860a610450a1ea4b084821776dd5de983187ffdebfe4d38fd7e7d6afef525a5cbfb267e7f9fa6fce254ebdd9f8f733237eee560e6e1cd4d93d7f137f126bef150bdc35d10efe0aa874df9ebefc6bba6251d5e77d761b09cde5c10e32f9dd2f3adbfe99b50fcc5d3e90fd5dbefc5c01c4e7737f71bf776ee2a0a6650a862cd2e2dad2598b77b146c56aab092c54a122b3aac35b76edab897dedc55dc790ec3429de2ddf39cb43158c63c1dc6fb888eeb7efd623497dbb8a7331fe3dd7b34af50720abc1be71ed6174f274133df18ef9e8a33d0bbc77d373d72770f33c27d37eddd4e70c15adb65c571b82e2161fa2ac72f0f3731edcd84344c30c234c1e6c3de4a98d393542de43a95490950245441421512848cd0851b6bea887cbaf63616623d6e7a1dd68fd7ef95ae09c5eafd26350337ee187dddf566e7c095b733efd3f47e698d90c008a5083988308108b42a74aa4ca992c4d45ddd958a62da0abe2e2a87a6fac7f1fef55c8e5f75c969b7f21faa79778e7757af50a3bfea61e79f7750f7550f55fd73d26a0febcd34bdbc55bd3e55a7f7f7050e558dae980743c82184358407c109103400410b04da07704c141311fe121125ad7732977447f8bdc2e174fc0687bbe718e5f9d7a5f4e6be3cf7b0cc25a5d7e5388a719a87bf6b15c57cd8cb9fe6dbe3dd5d9aea9dea9f10887ffd8740dd2fe6fa80850f42f8a0c9073cacb914a5a4f54ec39ec3887c020998b9aef5924be50b2a61ac3597500c96532a5be7143d79dfe039858d353bbfa9aa357fcda784d95f9fa264ade5f99442861431d69a4b5809c57cbdc195e37d5a597d93102342c2f4158e0087eb8a7226cadea2508912255647ac8a5894075784e0c1530776acd9b5de3fdc7d7a7966c77cebce71bf29c73f5f36b910abb95ce77817d45d83bd10abfcee9e6fdc3598d63f9e8a773e35fb7c37ed6955a851aef42baa77100a0a2aea51ecdbda09efc7bb1403d7547715ffcf977f8f77f8eafe4d3d0cabff3e5fde9d3fbfbf61072620e980e4808db5e6eee1fce3adfcf9fda6251d139dd2f761aaea2e0eac70200107393670c2c4bc5fd7bb5e4fdfad33d8fde11dcfc0a78dbb06fb255659fde6d02cab9e81398990ce7392b3876135bd5d48b09a53150bc5a8baea2b15a738dc11bcd7e0d639ac811d6bf234606351f46a109fc3a8148e0d89999a24994210cdc08800000000731300303020160c888462c9b4a818661e14800374de4e7a481549c5690e839031c6106408218000024064604664c47a831956699878bed6d9bddb9205512d5bce2d05be3a17bca4e069a1a4286c3338f7d8106ad72b1c6f454c8bfc0aa21b206132da7af260ab61c937c541d362dd678d2c9978b645e356e76e8bea350e1b8070b4635edc868fed8f4a9a3b435dd31c04e7e1714a8aaa8eefdef34d70a3544ea0e32fac1fb139c7679ca134cf12caf20679a1c5bc6790f0bf5187927779544309b61e7d014c4b3ec3215e115758873c813a72c1733a78ea368dbcde3ac6460b3da1759c78229bf45e798ff61f7c7936c11ce6b02f86f4e66aa4242a105d5fca28615dac186e75d80f085f87b123f436a0f90379892836bebeec578dab47ad7d34155211bac2d725337f195a556678c80558789a6903884abbbcc2a74a0a4011f8855288f3bcbf78c1390af1929eee8c5b4a111ae3ae2adf05b9cba32b96a767fb2e5e84784dc31b151e871a8817df3c015c032d4a3e2ec0f369a06fffaaef58031c27c017c6f423e4f53b7eff098b9f09f4b9d69729e34e700eaea67fee5afe76c87b85f678ab3b16f1ee110e63fe7bbc9f84edd208d358be94b9f4d23e9bcb2fa10917af3542200f46be7eb8b1fd9838c6643a3d1fdedf92c958e1032b6f9f1484db42527b5da761975d78e4f53192102ea82728e851322884137cd76f071de1b87cc45cf460ad10dd520f0855c49659444a9e4998efb84dedf1a1c7b95da3cd8fae2baeba350758c35930d909084f798ee8f9f1e6c14a69e283061b909ef2c1fb4e13de6db6b0a718bf08a5904c3171bd288f08741755b68aeb350b5a4f07d7605bf60b13e164099d348e16e6e230300bb66ffd255d7f2b99689f37e719a1b6678956e5bbb6181eec9c2c524b12c27069d01647286437d5023f92c8660f01a48561b28041060ed78ad50fa3561ef46870cc28d5133601d160bd20eed24938b84af06358ff26ea7870ff75f4068ffcbcff36ed0a9d89fc972476c8f16cdd5bdcbb74b3281c140ffccb7e8eb06bf5cdae4ff914085ebd0bd78ad4f796cac8827a3c99b9a738092fddcebec0d2372e17cd9b88be33d495fb6188086c894bb77fdbc17520e212bad484751cac9864892f268bb0764dfa0c67387449fb0a80674c5cf2caec8326b834d8264b6e8ac3395656501a75e0be0c09addbfcb66a650d86172cd964e1e16f48396c7c0fb6f0b48561ed911948d3f08e0190cf04692063c4cfcbd6a033da0ffdd0c3f33077a1026ddad22d6be5a2d7f5ecf6b84f4692a906f7f0010cccebe77c6902d54faa88d3d1e86a4fa09406d5813da22bb01355d558dd360d7e0241963cea105f37cf4691f228d2224b7151ea4168b281905d7598a87b4b6c852c3ec0e442ca84c20163cf9503e65795c3956bfa4031371285334a9604ebbef97d42a537ecb6fed777f5fe17594add41d6a81fa989fb86771015f48defdb1f4c0b16f0165e403e71cf0b818e5957179c0506da275b0c711270b8271bf60599de52bffd1c896716b61909c5e85d70d471957777eea217bdc85fc26045af78b7fb1185e43f6fcfcd71b1dd01bf529362bd4cea758bb7e12fc4ee150ef4ac94f54b329c08e1ced9dc8d7dc1eb29fb0820f44b1679a8a81bfa9dc6fcf4967148ded55ca57787fd386a97b1f9bb3316c7e8c4e0ce89fa1fbcd33dd47f04fdc11970aa19623ce6c7e21f06d0e58ee793839ec53eb11a3e67b17c8c450d78c1b60d1454e020870e0963671fc652feb94d0404c98494fcd3d538dd7e48478bd2f94e101f354750838e9586742fa8e3f5a9c0a7258492fce58ab96357cb35a1378e02ef1594d6778021689c21e44c4a23dfc28ba45946b077de3b54dec1eaa5aa0ee50832e29c564b051a86758b71abd2fb81e87d61e7440dfe67c37e055cf7d541f6d7d7d53a565c4ea9bfdf1d4d7338b487f7efdae9226fd06c55a7e75dae3fb0d6f192e94cdec1b38fab53275eb7517eb5813e93899b5b79105e8b3a401f3398321a2335cff100dce6fb5ff6020153ddac955bb9140e5e58e23408729ae99458130f60c0fcb21a3a21ab27de3c6ecb6d9030552ff67f996e8534e358c00070c6e4a145c923c88c780f6be0b00308b8dbefef4eab4f637bcd206fbe60f527765abbcfab5dc2e5d2fbbefec0ec92901721ee3d8c6b0bcbefb35d1fc6ab47282d6dfbf69f24893bc4438722d2df1882d3e1a1c9ec3d459482de51cd4a864b1a3d618c62662652aad94dff36a9985281db86966701e5d42a1dc9cff22336a6566783b6557069fde379ca2f45930950fc66f956a7b0ccf88662d1b9e303f4f2516e4eee8e7d7ce6f26a5cbea573cd373f0bbc12ba6aa94cee3271f7e62bfd07d5cc368e6aaacbc33f3342e4c39696869901a03dfaad83bcadcb97638e8d6102631d803c1f8877dfa78950c5e3fdc5f516952358bdaf8b39704f4ab863f1948a6c47851c3b873ba1bb8897b964c7222a3a0c72cba88a6e81f410ea6f65d1bab9d5108c5efb6cd4fd20ec6e332fff87cb18d30ee8fdeb6c0f367c053cde1f2f7401e9bc67428093abf378885343d93bc2cb0d7c684b035b6c84484e468b82e1f3e34068633dd42901c8305d16ee3ccb780843cd3997568166de78208ed60cb8256639da423017a88b66957f834b808d877e49a319a3b110d299cfb4d7d14fd462941d9f2495416964afe8f03661b8f94e56cffca0ed2f974ddbb2360d1808987f2e7226570d8bb865edd049ac928edea02342914e662d4cc934184b84bd7f7a2d9cdd3016c38804166ea987d2ad8d7ea17fce8b8eae4e9180bef2c7cbee56c1027c052527f7c87c850fd9857389bd0128bf41f61d36c2bf1712c11d7a6ae5974bc50c30be0344e055c895e3184034142e6f7534651dbe1477bff628b8ce9d774a87dcba92cf004b8ec2d152e8131e4fd2a42ac414c4036a6e5e337660328a7f44fa1a8ce6b913b7c801eed1f94714a57bd262356c91e2aeae4dd4b991e6abfaa1f31a8f84fc17554de81df6042ed85133c57947984a44a1e44912850ea37490f72bc4a6bddd8d8595be2d233217e5647dfa0fe4002a4acfc1ab635c21b9518a93fb9cc26985712bd9cd7ee3b7e5b3f403583be043bd4d55c4317f34245e8fb2191a488a07ec1a5dda126d8c6c84c49c802546da6acdc46433417149149627f170808a1ed77251eeb1108f0ff8a2bbc7f91108f90b6a6b81373b3ac5177c7e4fff118cddc3c41d246b61f856bbcc277eca7cabf2044a0761ff5ce85ff04006f97ba33e4a33fde70abe2ff6b04a53e0f73239f3c73be6c48135ae2a3071f2858e9bfdc8ef7be20f52a06838a930bec39f5f9a44be2c786e699a459859ad345ea767539d42162cbf7bda1d085e2d64e6d1aa138f5a9b0ca16a218b499198c5523069d3051b1e86616bd64749b78637478a009e5118024c8808f5edd3a4a5059b67712625a3eb1b74084f9182010a86999b935f9365f582cc41a657e6342de7e49e13932501b8272443ac1ae875d9b46cd23350452a26615588309661b839c084c71f8026159e82fb6380ad0b7a5953518badbb17006ec7cc4771da259f9779236e0c4f91c007098ba3d36398604e15d5e31a78c523dda069a77be3fcfad2347b6c3dd7a9d41d69347ac3dc9e04b080089b700ba4b8ae632583e5dd9dc46689567be25c191145f7bec212babd13221d24a7e5c0f9b5ba17fac7410c8a211abe441accf80298c721c206e4f8b9dd916a71b061759cd8c09c61e18e732b5880a52677a130e1149d20694b606b9dc8a6d59eadd4c20e0257941d1ce6481061df7b4b2d41f3c3d874941fa04eab5175bc49c7900c2a6f6f2188fe8acfc1f727c703357ead7533950ecb4bcbdbfcd2ba618fc3ad3c96728d24268aa21a661ca55caa9ae803ae3680f7ab6b5deaf914743c60a2ed14751bea69039085d99ed9de83177c4b30be47e4b3f930e32e6aadd39e597c7ea3f466dc76a4cf7d653e52e53066f8a33b37fd5ec6f2ea93c5f568dc489ab6fe3b1ae8bdaece68d0ea31879d40924fd7789795516c607003a9815e948b76bbb83eca47edf306d110889642a2587c6dc6d3b1763d942d5402886f2e877855170d4896733252721d40643709a279af1f7ba86550e3e6e57813e1a8aac9dcd7a77838503b55cc010fd7000c8ace785b4481e9811d5c40c6f83621170b13cf936504fdeafc62cedf4dc68683b8a79d9c42c27c77da7a2e4ba5973c21d91d097d1ca8135ac0dc225425e64a0ae490dc23ead32345c084a21b921e8974973a2a4b307e72a01e257d9c0a1fa4d7c844f7d32b918d9c01147df225d49c7975c6ca2c96dbad654fb4a9c7130272f21fde526750a9bc1cb99b8ca0e02279d8a98b00e4bfbfaf0750d517ae04aeec03c8dd5d3e14193a7a285cb56c83c64c301b39ebdb1de52fa23fc996ac82f3c3cc17ea95b70502d6a84a3959521c5ff70f7d2913c3ddad42f3cad3c2f5095c6e53b4a0cda073621dd9f8d12eea55c0745f808695a7a7924134f2eff224d80c43c868b16eebc6d2db8060ebfa8357b4b6adf3254ae7639ce1c15d148e7a21c49c1ae53d83f3b220bfd70e70a0bf8711b176cd066c896aa6093744ea21877ef1da674ebc1a5c59b13d371a9816ad98b89843e833d164df2afd649e8d125c57c7cfc6c3e14dd35456c6b16ff658415e98eeeccb10d6c71cbaa91843b1f1247935ce9b956702b4a43a3dd1d43dfbd35e01256795e63dcce637ae7fb830ed66ccacfb514da71cf1255666794e60c82d2b494c9fde0f7e7cc0b412e9262494aea63c0bb6bf5b789a31fbda0382234c9985caf776ce970567f436f0061ca71ae0977b41c2d51d6b4b9e5e67162485eceaffbbc5d7b07827fc7900257d29b6b05dbfc15010bf9ab2ce6fd3cba3424be5bb711b00d3127ba25ae44060cd077abcc3fe05c4cbaaef276547a3ae197ce36941cd0ac357ad997a9a797a123bc29afa0f977c868fb255dfd09ee342dc58ebc8bdd4ae9d5476bead0cd7858db3bb15b73badb7a00abfd4bd81e7ca2dcbc45bc821bb379a4b4ed896f0441c71229868abb9a21909aec717544b79b6ea2d1ae8cebf068afc34fc6338f98d0465fa180896bcb3a77f9d83ad9ec743a1a8faa72886da002030205d6d34f75b446f1925db473f949aa7334b4346e4bd19aa29f039338e755defdd70e180083ae5bf37b604f41bec3fbee06cac1b537dea2babd9040452a770ccad9d45dec54b9e917abda35042013848a356b62892af8b9b17f007519bf9c3d8a12640040ad2180e951510a0d9d25ee7062b7fe91d083edd8bc968fbcd5487ef27fff157c6e19298d083de64a41f2a4df190377ebe829f4b099f23424218805746446932ef8677d1d4c86a94917f38d72defe678318b13c077301c59a19063514f3b8b4fe52555e3bab461e2c25d5fb0490db593806de32cf335085e3adcb4a8a38c036a32909e55d71f8269295fcdb634750c08e316a27afde85b182454521404a47d36a3e104bbae47d010b9aded70e1fb7d964f74bf75cbc6f4c2e01523cc60ac2cbb6b3171e92c9b6e37ac4577fa2413136bd0bb4944aae3ed43e384e5faf097f258526e7566040e98b933280d520712451d5fada0f43bcbfc49d7d3abf1057d69e522d86f6349a173d796bac87c9e7f962ffde5e04a791fa63daeaf153f2efb0d675ccb6064bfd43654af1ee18ab9546dfab830a248feb7b320b31bdf4e8688b6a11d0daa7a501240b13ecfb90b476ce98eb0c0d7b8bd4b334f7737c0b837f94d83c0c4962ffbbe3c89661f878fb2f7e3f991bcfb97a4deb308358041c0517c7f78c9b574d600c5b85610b2534cc5bc6c60f36291482d396cb202989750d114bb170381507568ec02139aa2a799e98437ab8bc5887ba1dc998713f564f7652a1063888468a1afeb21dc4f5b5d04a46e7a1d436520fa45e883543e03124e20c880fc82d5a925ecd30fe1238410206e699e95622eb6e1014e59e6cfe9616e75ea7a5d88d264abebc51d84e05cf7fb197c831343543f04748b75bf3afffc5a06f68108184ffcf116c0b2ba3677f65146b33f3dc87820c2b3eb1bcac686869531fd3fc90725d366b0e76bab30c0046ff83d1621d50105605b40d97e757ce65e55a33f10b4a694e044780b90bb07309e79db7c4d80135b846e743e1601a4917f74befd617c26a2656cb5d510aa3e9395440c67b0d665afa3607b00068dddc027c5297cbf1a67cf911dd57d8cd5acc73525eb3b98e21e9439d509b18c0e6cec60868bdd0e2d722e20e9d0a1beb8c4dcb7f240f02602cd7938669f04c03c7bcb5eb20f46465fe422cf86d41a469dd8f18d241ba2642fadb43033455536748e0cab33861b72c1dfc590d829bb23ce08e2ee10139246b350831f39679eedcf41802cffd6e3316a785a0d2749ebf4bdf986013938d078f0dfb3a321df1dba3657ca0678b625e5a7746be02269df2ae8df8ff319a7aedbf4b493dd0b5649ab1ede2013de8a32d40ed37acc5a620ec958ae3666fa5c167afa5e75d86fe2a4b1dc8df2518a935bc431640291fc688d41f36c22cdf40c0a1ea64a81d91865be1e8811388517acf64984a78fe53417035893086d106519c00e0c1a581689562167ee388e0e82e477a0ddde653d4fd5a1debee39621f35b2bec4c0f5efa37f082b66ce7cfdb8642aa97185d291e6d5d64fa68cd08484e43e164e722180d336425fbc2d53da89c65363893273edf72c60ecb725e9f60271336ebec4b514f95dc3cc97dad1a329ade655aae2df0c56c42fd4ecc6ad894132adc75d0607f16cf7b4da2eac46145d71ce05b8f078d9f032550bc6460c29aba3a17d921be07640707adb36616047c99e41b41004e784aed7e75017d1a0d6234867634a7e2956abc2b6c0d8bd0649e2212599ae9430c59f2c31eacf19a4829e9d48032b063743abb0cfd8c327ed2f6774f6afd1a352034a8bc50e33ce5f0b934f628e97fd2accc1311ee29d6a644d7979d5f35e01b6e6b1388c98fcdb8da1731ebcef2200749de4a8f826954a13f915254dd15be450458e62ba9599db7df2ad3539715fcce2deb38b42a63b4ac69b04344783e2fec2f8903f6ed257abc4677799803707d9f37d313422c00c5fc663247f51deda4e00abebde28b711d7a067d23fb13893f8b2c114f620803aa9ab6ce0d80f36d87cfd6807fbc4565837100f9888cb50d6abc8db47566afa3e0354f12816ac6b3cf1c981ad3d0df38af6b7e0e03fa3c47f54931dd0becb7afb91c6f2269418350e18e96108c16178ca69732ae441690a007f47f4bfafac7586356bee1ddedb814c38283bbbda65b3e399368bb1286823dfd27ac570e4ad297d7a36fcc1957885dda5854c4fc446a76a29845ef37a35b42799bbde9cc6f5368022bd36e00dc4b9f81df5d2e0c480f67ec97598f07ee99556f8190962d33fd8c4d71ed807f3afa19888fdebca1e50430a7fea19d4e98b60c33e30dac5c530062bc019c616dc5fd95e9c1baae988fa2bd1363e0c3aa84d2684859a4c91d8b1e32e9b4666a08772e1fdcbccd2d20395b05ba1da04b41958fdedfc90fd0dc70d4fcb87ae2e96f0d7af5333bd12593a63f36c91bfbbc41ec4c865dbb7e7bcfa58a46c996cadf41975f41c7ec6a078241c09c2350f5e8dc4fe86c6670645991ab989a3d5f55c5c6750318bc250db814f09f3260dd7d29c865b8be44aaba68a9e779c4acd6429344c79d3f4cc5369fbdaf1c5cedd40fac8c93179714af275e51f7e7409db6b04820844c822f496d248fd78c28df644ad717dd5183385f14df294da9b0947a68388908c5ab12c6c982867760c63dfea768b320879f87d50256badb022e21d87e6542c31165fa577ea8bc60afd85ca5baabcf2a59ceeff7f472dee937222658072ac97511370752c69db542aa38b968f463fd5abefb35f654e4539d783d14d2b014441007e122fd09d69035e60d03a350462c35818880ae96acd6f9f5b6aad6be8c6274412e9a97006b0834cd0f0247510c147598d98c25005d28ab0b5a03e08f7481d19c18c77284b1259f969c3e75b6b9b33cfaf2c9e45c300eb50775104d5f20f9cb42f0066e08ef7c081296a0a39366b2c38c6cb9b8df347f9af54a0d2f2e920ba0299224c8f5856cc8f04d670b395a21602a58e490f1829c2fbf571d14430f8def2d4611bcc88d435c49540ca0fd99b884cefd7a3f7405c7b7728a418ea85e8b00685d4ea26c9f870c0b1a14a194e8c0c32e2b05edbea113083649d9d50e7409cd0b8ca5c3bf6f4e264c14ccf4daf95ec204d7e8175029b92cdbebba39351ba229e11758e05737ecb384c79198fc917158b0551c22cad0a544e3429b6889a242464faff8ecfd9eecf912fb05e326abf6b5ff78497cfafbf5423762e59bb238db32246b46d12bdbd470f82018218e0917759a044478d6b4996b24012c23da824403c102690a8f8921fa9b218f7cb06ee07862532d29cbceab6475b17a9a3fd2598b14d62f3b6b17ea871372ec77d02affc358e8b674164263fb303934a15431fa5c11fa5ce1fd6ce92a0ac0312e7bf5265bd7003c06579abb17e9996860e83a066fb0eb00bf169748ea06ac83af14d403b97280a598da81cb2c9dbdb00ad8a7459126a5ba10cf1b0149101b2a00ecead22c50b55577f239cc3f70c6566e96de647328077c17fdf842de1375025620027f095a2b34bf8f67d50ecde41ab2a03640e6def747af185ea7dd57017dd8a28b488689f1f2415d28424c8a85ac097fa19cf0a034ec9ea4b635b0e1abf94c31cf5e774a5cd4194099b95d3de9930e3a52c02d09986eaf41214596c80485bdee0e6fd72985df2e0f612c50729dc78fc3ef3cc3f4b226473f47d9780341c1502d4efcd40c7b8b683ac5629c9998825fea1d3f60a171a04bc3f44d08749c1fbee7256b9c067f94737ef716d5f3cfc92f5380d90330226b5b91334b75d0f2f8630421ebe4506d9bf496cbaa96c6baacda6a97ca939fe8f9f51490146e18d2b1c9a00401084296b15f3e38c68574eca09594d872f617b62b568583e0e00fc98ce73f7366f2171b00d5c469ac088cb0c9e0f2f40cd5c535b38de66f0be91d91da27d0d102b3a52869fd13e2825826c4af216cfff7ac20f9465a33753fd28e2c6a389bf646276b555e68bf517da9013f2953db1e8489e60dec9a498fd7ebd82d8d8762437f57f25bbce46c469fb0fc66349c935c79010ef0b7a992395c14ff5f80e5856190fb1764fb5f85c7906b9f4c7ed134fb4c91fc8e872e728bedd43e6dcf472fad9de807663f88cf8837b3b58b378ca5ff2033174f266ee257cd032d2139d0434b520a6f789a5d2456386454df5b8e8a35f80ff0947ba1a875231ca1cc3653ec6b8b242b9479587c92e20f958402c2bfd8fd6849fab0d600f43768e5cea9d3ea27d940608c348da7b9f4bf2782697d3729c19a135b361c50e141e0f0d72dab841197feb234440f994c481810e04b69274cedf300fc3677f99bc33b35d1a0c1df8e81d08dc4048ea03f7ad22c1992f55a24cf34489dfbd0b74b8221fe35986af9ede310bcf3a811096347caf5f89b6dc56d9bda31ad642a5a7122d1f9724e402ac95b651965440616d0e413372849da84d3d47caf820ac675af9f4cb2d6d0e5e0fe890181e81ea7dd562efbbaf5e25c59e7ebcfdbae88d90b5fe8c580228b6f2fd044dce1e6a412ff1fac4b0431b3b5ce6a54ca43a463794c1db0987869532d28f5ef282e80fcb61eb23d748daf1515936ef3b1f10db07c37147447d103c4b632fb91d8772abf8dc947bdbc514c35cf9e87fc386e381ac35ed9dafc2f92fa081d0bd23b4fe75db53eb86fe8b5c8d63bb2ec2de8244eb3028631952169538434d85ecd094f647d316ff4f48e604ceebf4b4596da7eec45b64195e7a1d68819aaf8e6c5038c4226bf69791bb5f11be4cac61a5694b50379c44b2f6d6a3a695f4575ad86baac900a691312ba7278d385a671d311deeea8e23ff43eb7b2215be857cbe0199dfd44f15ba838476ec6a2fba0273a7ff625c5f6bed71ebb40b021dc5326053a2e684ecf8f8f46f43d05759670a0afdc36f20271dd2f44c60d88dafc78c29d1a79e7e34830a25781076ebda9fb98963bcd841048566a38acfe06257683b3c730ba50a3b849bc89db29c209a35983c54c283e31649197671004383ed5042dbd9010f1f95ca7dcf2112587f0eaf98a70961bea98174cf4aaa4769aa8315802902da6c75ef37d9fa13301b741ec8152d4813232d1f2b46383a27885341d51ded2737aea0d89fddfd54c09fc27f8debec1005a52d73894a40bc0aa44ce675ecc3e97073a636a52ffff5bf1aefa48a289f52ce07a58016ac618cb3ee00ff8105eadce076c1ac574c4cbd3d5f70f106d7fc2cdecedf5733504a3a33796944af0872d0bbdf1088676183b4def3ad017b03755fde38bce2a354a598401bb17c96d6199a462236e453820bca6bf2232185d0768d43ab97603866dd16c44e8a948ad72cd90b8c0ab7ac676f3354320dcdf51fb5f056333da74fcee7555ee6ae4fe041c47988f662700395cee32c8fe2a339f89564d16001096f3e44f8903f0df5d2c6718363dbb6da831d1d26355b191b14682cfea16a10a7cb873967ff9897fed47ce5f25c7af368d7086faab8a92d59065a974b5c25f1a30d4844cc88dbca38bb6db2a74d019121c9dd6f191a227f7d453308634b5e115d817f23e9caa39193e7f1a18b5e54634f392d5149c3086fb8fbcbbc2605c27cdda0b8e24aa02eb69becef783a35a8d3a269d32ad391ad38bbd6c1c6bbf01d6eefdbca0e03d08760df3e84bddb49b012bb80d6f5bed2e733e5af544a10b5fa335c07b703ee9e24469d07076c98f94a627787feb38a1eab595a04568bf759dfcef11de7fab8b7fd5d60acfd0e5fc2e54ea7ea6811d94356f375269a7ddca0ce4381986aa4256935e3154ee8f56b444396aaed63cdaefdb991c963c535b5b8d76a0416bfc556adcdae00ded3649b90219949949f9f3fef5a237a46551e4eb47271304845a2a2c707fbea10cc7d007d1acdfad31a8dc4cc535bb577217355855dc144e47bdc74f10de2951878283320f06af1ad7ac1d644e0af30ca1108b6745b4bec0e512943450a458846a7f65bb1ea6b59debe7344d57dc69b8e7621e63384ced819d9130c62f022ef16be333b98ed07c60957be308e0b808cade01fc761f0441d7a1053f45d64a256bb6cd6cb367fd810e2ba10bd7b316b31f8c5d67e387b99b59a101879058ce4e1e2a09f0de13df785740a5d6a27d835e33b0837d6007e9055cae1b90d74d859d98f94b7b3526f23380d2322fb37793b28491dc21634817fe4e41209e37bcfedbd8fc7f522231a25c5862dc748f8a2708573f4fa08e02b58c28aa6f69d66babfa70d2118cb703e1d20ffe5ae3e7bd0981ec73d260ad8982608602af35bc7ba8ef21bb5b56044161db629877810da15b48452e9d2b14a80e9a48d063902e8b882224618587f0919e3a918dbf6e08a3550fdb45fc7a9cc9fd6d253caab4a0732af1af608805ce07b2b7d0c2883101aee9c5ab27d7d220f24174f7e5f436881e6c326bee0b7db89dfc62999d0ab641342a4de3c50a4c679e7464536ae73bb163f66ea550a3579ca64f569a7584ed3c7fceef1439700ce8f24fe18fbbfe4b43336d4c00b5836016a2b98e18687380ef959943325a3cf104e2102bb16d7d7215dd104a9e63ab96da547b41307a01c2f74f6300c29a43f31c6d4e14ff205eeea8fad6e2a8b9b9e191289b57c8f0e96c9f5cc5c970c27ac3006c8aa7a03397eff1ba8386a9f4e725b8a87906aedd0b32e1f200db9b323be891a79387cfcb8cb00ecdd300035ab413a6ce9b862a5d38d145acfbefd0b1c0e006571483b4263d88509327b8bddc36d30f1b5110049d7bc5e075302c4d98cf1195521b9cc6de311e4af2287c2f68fedaad60d09c28f11cc8a70956b6ffef3bdd6b4c40d6c61775838d74d6207edfac5283ef5dc786140f6acdd89af8a539fa85851f45920a7484bc14d25a3272af8aa842bc72e402caa75a237fdab8edbf88a2ac06118e8b37db8a5b16fa6eaca2fb43ca9d1d1effd73b8777c7d70290e0b0ae7976cc4548700f41b9b03a3d673b5b04c32f9e27dddfe5d0b56b80a0483a5a5030a9ab455c85a5d695c1fc81c4950d1d2d392316525abe86ce432a742b6277ea9491eaf8cc98caeeec1210f93738019facddacce875c0fef87879be6c28837ca908515cdb7d9ecc3284bc00ffb65bb7e80be3bc9ad5ef096a7ae17ccde0bab268d385308a726eb3eecb23763d7987b56257babd099ec12151fe4f0b8935041070434ed9f4110cd3aa8685867ac801bfeeb585447461bec42a4d3f648448d83061e3aeee2fedd6dd1fd731a4e898d4edbec16a5d5cbb1800c7f2240669fe5a8cb905b2610e315d92c964235a980a8056af3ebf22fa37c830da99a0567bb02ed22800fa917e7272323de20d58fdfd324bd62f2498ebe124f8e2a9e6f72519d9fe61816f85576b713e17556ef7c982e0e47549f2b3c363e06ee2de86d2b8d92552b8952f7d6ac4e9624f9c78623763c78ece13e0e22ced5612168dabbf72fa8a86b22b5aa038e24e3d65bc613d01cc677dce3420982b24bdf505d8cab182ec795fd7e277ab5cd7bd337f62771e8d6ccf17041967a9269ea4e9425021b82e3dc53c1e78c6a5c2b6ed9f654fb79ee0bfa8d6f014b9f42a60dd8f320655b3ec9d84ff7e754d9877c85248b80ae4c3a8e1c62990bfe2739d21245b99e1f2d5aec6bdd3abd3c69fe836e491f27d56e04bc5baf63f4dd9c4febb8893925c067f59d408339739700a231847e04e60af733711a383041a9bff828d79393b95f0b106586848ae70fb0e49404b3b64a02941b6c854ad6f00f2b1ba448306482588f38983d2038844096d61fa2274a3fedfdb73e44a9cce364a0bb45405078c0f050edbf037641fb0c8c2726efe70637518549651f681eb5ace379cc0333af746169124fe05b2c42c11453c3dbe2705ac536b2e59fa040af5a6929de1e3558b32907de19dbd103ebbcfdc989c22c63a7dbdb643941304f129f376c676e6a91075f7d3112d94994af8d2780a494aa6c43b6b5d324d5aa5f3a8ab67040e10e4b3c0da6e9293c8e347d97eaed19b2153e46ae90f7f839512198c8c56a11311202467aa8a1b25b79f5f38a50a23c5a762973e2b0742e7f45d9de8b0a00898cf2af1b6e2cd1c27183e5aaf8f8306da69119d4fbda922f106602b88f487687aff1bacda4529deedc2962b0544f859c2d18ffe11c12c0ef642496a63a91b4d2ce5b5d30b8c42b8db7229b7b08484ae598c616b1be6cb16fe2b05a1701736a6857a81bc6d661d2844bab967d172391e34e8e25550b0421205d6930cf688cc4ac1b481c5e1d745262b64ed80490e1605fe4d9903554eade4646b8ad35b2f9cf3a5d0a1f8258ac512e4357f3e8c2907cf7df8ecd9403e02bbc5f04bde4cb06b3e4c3eb21d8f87a9de10c147068594a7b2660ee6c8a0f3b3a132af77ea3940d177e6f7b08186d611c9d971a8050c9aeddfc9e33d8b9b6d99cdf1590895e0ad369a1c5c3f3c8b95a4e730253ae3c8f8812e1697330c2ee201f3e1b82273595e31ac19694bb3548c75cfd00385b8981760238218b0a5ea4894aad0418f8fc420f9dfd79c267914da0a4a69835cbcd9049c1989b62a433e4423f8a015e60176ed3a7ec9234d3592ec5cf846d012e2b8a0f2fea6b2e19e6233456e4d6334ed865c43e957db77b34978a3608c89dfe5c00e80e2372604199f2605860617081c39cfd765d4e0ad8a183243d78ecc607228eb6977c7c78d7e9fcfb6289fe6b5272578e0c24a87d6249e87938c567cf7c08d31944d88767a0fa09dd5a7e27404861bf4c52025e45351ca96c4572a1311b74f7c22388773a655eeae062d68d0052cb4d281a5c7a09418070047f35b203ad28950cb04ba7fcdf61c7118680388fc75bc146d5d86234a1f25bb60c492c01f4f37938d666d061b95fed3bf1561ca18fb6ed1e895821d793f4b1b391f48dcccb4203621ac70d338f54cb62b2ac2a8b4429241611c6a8f72e1c1b48a2e77f9dc98725e9ddb60f68cb7d439bbdce7bb9150e33be87dc6b55e8a1facef5a2427be414b78a67b28375698057e01aa17863fd84316afbe38669afc8d43005587e8714cda925910f0ad1a17a2bf3d475772ecb1bd2f8519d5ba255e36d10787c7703b5920c61c7f28aa901a7dc185b925e6b554fd434ea34d9fd74e0e54829076c3ecf0d9809ecf9d95fe4084a5eb65fd089b9e4c5f592344e23db7f5fecc3c1be41845ba80b9fcfeac6b6eb0571f5e01101774aea3abd68563b54422fc4dedc24c4241627a6ab9e818a7bb2d8690cf633e80f58b04e198b7d118521b1b2aef7dbef85d1f489a03d5b115d68698637bea9d4d440cb7bba58f327230fb21026635a64801b7abbdaa88d871061042acc9c600679016f49fc2df9397c27a2e65544ed8a379e21f7fa6f96312704c9978475b8e27d04a73d16cb4e4f7fc3c4a89ab900ee770e6f9ebc491a523e5be8607c277a2c2444fa0a997e58c32af6402abc1737f5f0008466061cc690e4437bb6d1b721fbf0634e16a982ef2edc3373ee217db9a2b802f336e3f4e52c0eefe7b112aff9c0a1e31a2ba8398bb674cfd11fb880d124eca47ab1fbfd3be4584454a52961cea469c828ffb40e8d22108a44968f5cdaca5788ac8b33f5a7e2b643c2742924da0e52bec8464535dd34c019b1c5e2c5f09f634a96a73ce098fab9ac9053956a72b1f49f3eefb84cbb027c076dae2bce293c17a366ef28c9ebd0f6490f73b76739353ea0538375b6c81d7c61ca1ae783d6385cf04db329b585e84cd6caf4c8931f30bf3c4c6fa38ecda39607f58f2d7e70b8f205f507b52a12bfda0e9d34763abfbf40b044a82cc1389ea7cd95cd63dd093dc6f6dd0291d1e230df9432469cc8d4b8d6a734d9ac3ed14ac467c62a5593915f5ce3bf84fb2886de4a24e7453b558d74be15d2fd64d80596382fa22a50d7b44dbc081b9fa06518161c763cf86715fd0db4c2bb7e93ecfeb84df22fde44fab91f1e2b510f66c7d93e695026a4caadf45e0d08ad220814f0eb302170fa92539dffc3eb8b3dca571d928695f767cf79884744bde9da96264ccb8916ce4154e3be8cffec82ce54dae2eec14f3891de1d45de9c89002a0bdb61eb9da1129dba66ae00ac993d55dea98c7c3ef3045c8762e1d3d3cc401e5b996c1ac57d0717e35196404997e8c63de9ff82ef28bf535d0ba069c5496ac70701d2944f90c35fcfaa42a48e7597de880a33aa0161c6ff84035ca2b39d3e642038f014b60825f16d6c900530c88665dd4905ef877c85496c1153bb40e5d439ccfbd51e9009adafd70f74d1a6dfa45a37956414291724fc15d6f4fa2749a2401408303f2a1fb17e5bce8c0acecc7a5cc7c53865526127d5125dc70d600837de7ab2bd10638a0893c00b1403ac7ee1255815dea2c3341c761cbb122523ab3d2cb37534bdd14349e2f85848c7afd4e24c63e85f8a47c6275a0143bcfa1371d97db134a049056f8d092ad62cf4d2ea8b70bedfe6524f145e342661676a52cfdf11906dc45f88ba6f8c2d63527837134e783ec53fa408bc3ffaf911da1528162f82d51175c3104b83daf3037da0808e287ae980c150c5cafb74a2709310b1b5fa4d3a7a3fa0fb39cdd67a08b5a3f5f6a634129e943bdcc8e71b4c9f72e7950be8700c21e89ba58a5e3902e133811850df4b62fb8afd840a0fd546fc7d89efefe505956023e39822065623df63688de8648ccd2a20bd12ae5ef6a6a412bc38c3fc0c661de818725f72c05e0d90d31c3ff0637f500ba714026061677164b2d94e334abd40d1b02512547997424a589105af69eaa79ea20d4a9a1c4b032b3a3373053d8f98c9c1300c81c9a2e5dbe1d79c7cbbaec45eeed10384b9c148f5ccf6d2a0ec4072bff0ef0e106585f3122d2a73559c6eaf7b0dea09d6c7ff837680bae7d8ef1d54342ae2e9237a77a0bfb4466be3d0b0832d7c9ece5ffd065a533c311022a6e0ba465bd733b7ba1ccae1acf10461a24632470695d174448b5a5b4552cd41332496feab07b629455d11c0e817067e339ad48fd5c815ea3b7472da201ec27fe04356a125c482dc0ab3f7e60fbd5c72fdd2ef22ff556487962876f337014e55a39bb499add7f01e2646aa8b896de466aa82f80747c4dfa37abd135c6c41fd845fb6cdf47e1bddbc162381c2be47435000064067f44b248e3f68dc70ee8149a151db3bf86b77feed0a552788e3920bb5a1612fda920338341880667b54a54ed31d04cbdf53a8ec5373ed4f9f2fd4c60da390260e4706a1f3594ee58bdaa4391a56172615296aaa2e302bb52e7f51b56fae85e40449b124c40817d250c3964ad7923690e07affbb84126773178aa63544b89f382286d8a2e7747e6f6da9fef27b7aed55a593caa620e4300e3961684ae55547e6d478fa86c7b7c4010f8cf0825c02e1074e4d3654ddf6f78d418d3ec662dd246b448631f2ba2ec0a526a0d54202a3e1bb3efbd3662a41f09c21488d3afd467e64fffc4e2beb98638574322a71b8063765e5095f722f54aa4497a8a3a725f7d205c72938d8607db55e8c764d6d8ea2c6e2e8152f1e0dfae7f7875563cdcd22b102375cd044455d15d0c0587fb3c312dcd9fe32f3f8a78dc4c02111992412dab3e09c4dd8aa3d3ca78e34e2799e0c3f988a4b68ff4fd3be6a9679e507dd7d1cbb78e217a763956281c0ede8ef7b9b82f421b49ce6a96ca35b715d6c44d09dc99ee46054e250230a4d13ef968448bfdcc1dcd1e61e315f06137f29eaf3415b4ed90626aaad904f5ae84dc00ef161bbcf041bf2404b74b14359db9d797a27e3e6c7c557c327e1b34f7d1b35a5d54f2fb302510f68f690abdc0f0945199cb882f12fe8497381cd9e7a8ca1e420af206c70ccc41878eb2aedc914f84a550e06bfc388609a2e855d43d2689536ce5bb62db3a3b4e97127f1583145389f88ed90d9be569f29a4789fed24ba1cb29d512b0e1633af0f0c39ea1cf2e866682ec9a5359fb198b0145e8e790c52b0ef193884ba5ec17e3b57c2bd7e2deff9116aa012bd11645f387f0fe9c8c03b42a91eca0bbeb33ee0e649c66055daadf167ece2a364a797f5fef61f72028d1354aa13aa674c1b34fe858d26b5ce166a970981abbfe230b73915791de5dc6b6809a35d11dbf5de2ea28f614869eef4ca10c5ca20bde02c9526be11e0cc495ac91a80bfa5c87dcc0b3b367972a4fa31eea58fa3cefd68c6b1b797259dbd48b952c0ccd20da83f5544fea043c0a2f9fbd911065223c6b6b6264970346da40f7c2f117c5134647c443655f9b306254db1a6de607a2a5f8c1f4c2785e0b99cde40b1f72f5d55f06e2e25896fabadb430f853876326d78d8265e735f6cc8db2a72dbf3b2830322fee661ae5d2039fe0c6930d2f0330094a6caf919522f85194a0e6c4c52da41d93e64eefaffd19ece2fa750a919d9337039b7fb7a6784c3a78c2f58152107fecb50d4ad1f0811afe9dcb7fd3e5f83564badd5d8aea97c0a8c536a49dca9ffa5c9c38a86ad47c19513f2e042773b8239adfad4aa32ef5eeff5c73dfe3251cc1e695ce0b17cc51fc1b0649e57f96e0bc5c707a3bfefc4c519299c12ae0abd37c3876e6c556cd7afc0484873be31e7b1987cee06d430226c1c86ae03ec95cb1b7c91d321930ff83f33b090d6ef213cf40fd2fcc1b262c14a93fecaddafee35c882e10ba4706e0ef52ed0df518f7c3c842d4fd8192ee3b1c337b7dce8a07c102a7d2e5a3f8c1fd50d5b26dacc25968d1f84e97ae984e2143097ff36e35fd2b61ef7bfb306fe76408f6f644ca17f4b768a1b67b32e48cdcf598a30f19760741f06bd9b3f57d4a04326441095f4091c1c81249c60e8fc8770e3e113e30e46ce82664cc83b48500b0fb6833be4c772089a2135ec93a5172d367ce221c57088a16715f95c4a7cd4f90e156714b192859944305a0685d4e28065d8b38ae84420f862e3303ee38e8522e7023b3994f57b7f619ba96e8c944a7b32a95e31a01c228a8060d9884e39302d0b258ae94878e051c5538942de45e1150b78e430a8196b5dc2a00a516e54021e85a8a73e54269acb4cce9326f318e52e91370a531bbbe4b20664a0ed8c679406f38325a7710f10bb6a6e787cbd15a95ab048e1b01db5cdf7bfaf9acd4b5a71910f93ba9a059d5018ddaeb89e9e67874c36c948588593988d7b3fe5f7973d609a5760105106cfaa359ea6c0cc1119073098f40ab4fa7deebca376c156c65d763acf42e6ea4fed96d1d0ec90de09c5e82eb7cdaf437c5fbcacc5f1ae8bc8d39e4e434734fe439f5acbce2231e5d1925a90fc2818f627c3950f094be7351369491b7f86406996171838fa3f044e3624282cb7ced33f9dfd89c1fc102619c2ab8044721673dbec5da136b17f295c405fc30731e0da0377e139bb8883f1ee38cc931783ecf7c37f07b71698f601a9b5371dd3a18f70f2f97ff9748ce0f241371d4ebfd43c407f64c9402ffc2b97f73bd3568ea99ad61f1e99138794428553bcc12a96f0f0e018712aea15340d0fc4d6de2a6e9f8d86d15729b4314aa749934c5d01b560ffcb5a6fc09b25eeb06ff7d1834f93b01feeb89f6874971fcff75bc6671ac328eaddae4013f701f0869f3ff1d009df3dc6261e246d103636f35eea24f1ab6501e2bdd249803b9283634bc5e3c3f8afeab834d207b03fac3ba296b027893eb2f3b37709f8953cfe219a9e512079abea28f69ab29189bc306ff1d8801c6137023ea5cd18f0596f7e71e5af313703cc1981b79f8ab4e0cf8a5eeaf16e5fd7b8b330db3a1db1f234b48fb6102e24f62b54ea31db0354a81e2866426811fe0891fffc773dcaa4875ce3ae81c6d68d55bda0a415a7301c9ff0df27b494f04c725f128b6cb019fba23176d84a389f6f7043e098992ecae45fcc50fa275600b2345c348641f74c039d6759c54a4724961bcfe7d6876fc8a629fd8fe6860ed9ad925740bf72836f59dead725b1a9175c52c66ef5683dc2ce8b112737a98b58d2f583b1486cc20e4a758d869f78c16b9cf314e923de11dc42355703e982870df2f89c72f645c7c686d06ec00f17728e0bd44242d8ca1e697efe3635046b55900ad98105819043e32f11ff044de28b25e7813b1842d79a6cd136433cfda4abf3e3cce909753ac8f004a6ea756324070d0511c7eb3306c4ae45c9ddebf2b9a093e92ea29884a8c602ce4c774c304867efee452f726b1be492831e7b704b68585c29e1da4697fecb67384ba42ee27e01d00fa78739056e4600ef8d80e1acca7f551a9f6127f5c821d43a33978b8324ee26b016f1e530afc5a27d598030e143dc76f8fd2c60224c1108f38807b98a6a884497d23d8a78742852ab23b118534bfe68246ac05866066c39244fa8f1400223767ac62f2b1be3fe710493f036d86c6280098a51e9c8b9ec0491139a48e28903bb7aa9416db1e51e278d74f1bc7800af3a78ab4b65555ae2aee738f7e8a396c052356536826ffe03a08478eee6c84aa86d1904a8deb4f6d545c4b11e417aebe266656ba7786475540674cbfbd8d1af92d094a1a027a989a6bb937670f30eeb4d0cab81420eafff7055504896c64a915da9b8d896e649483c1e1c6bd92aec97faa027d087a63f5782365324eb5dddad77b07414d149990d59e49a754a833cb73f70be71952523738568950ccd66628c70218c1b859246be827541e884b9bc7391da90b2b977bb948f80a2cc0e3eef83ed99996391d64fa0d6b77c7046cba5de3f79043539941e7005351fc42db6d70503f0fd01495a12000368c298a5739cc857d45085089f424567a99058f3e33a41d001de085f69cc11ecdca80a9800800a92ed14a3600c25445c5bf46f66f774b38fb0ee20c9f0e4503aae704327170cddb9e3a1bbbccaa357a29cf678c2f16bde6901eb9b391108d3b01b5ff1a6baf621b2b3c3ff72c398364394c57bea71b26e626f0fd1c5210deb86fc0e41fe465358e699cb4dfc8ac6f3cc0b5d513a285122eed0824491bf4fa8a17636d02da07afaf93d44a99e7778ba08eda0117310419b86fc0243e28d816c334d4534bdb6e58f165811df5200a9ea49fa77e453d5a2e47a0b63ec32dc8784fc19ae8ffba43efa9955d33b21819442d0a30d08d049feaa071397878e7bd75e4717f1d221c98c39613466ee730c589c96ea29080016db0bceb988dc23786a893238847925a97f37f402451362c54af7f7fde04b8bb35469cfafddd3abc14645c6527833dcd803198ed315be89c28ded61b4aa1cf19864a0bd62ccaa84e8dc6864bb66561ce77eb12683cde5bb7554a93669c9434c452840257e3d5dbb74197ff6c0e18aad910445091f893b5a0ef504431ec7d0edc7193bac3ffa42258b7d289490339afa60bab08b5e851185252cd75bd9ae10b36275116aff33746ce7aa8f0d0d23445801824e8aac51f1fd8793f2ad99592d5dfd9f57201b990dc383c95c889862f0be3dd458871d7e582284e8f00db9039f6f480c29fa0e34e6dcfdd49839cedf2f27affa9d07dcda24a29afe8c8e24c75fff6582b734d9904ff6efe5e19a760618eed7fba1d8f2f2f26aa3b98485d183b8124da21b818f85e027da693a581481757095ef591a720a157a99f16d465395b80e834f9342ad572389a3702a7e1db31265afe02ad8b04ddbc1e3a3b96895e878260fbab231d028445b625d098a6fcb1de97f49ac37cc3b407deb638c2c07afbe36d78a0874b4d401039a47abf615c0d809d5cd20225a5f517d74e073fb7afec37ae62e9f1c42a0a9affbdd1caa3006943b361df7775de54813b0abd4d49455fb0b34086f006f7a04a5986138881a9cedd25026b24cec399ced697a99c92d7a751c62e8f835a0313a51eae6d36ed95c69640f38c4b3a95d3725d64945b547807c811a50e3482a55876889edefd0cb74bd5774359d6eb950a2966ce475bca859ba8219ecf4fca10bc196480055baf7af6c9bb55c215ff330f57a798cff30194ebe4ba06a858da34d48a68bf77380870e57bf54d575b523fcdb8e012cb9542d22c7116ece2105e8d12d6e3fd720df2eb653536e672972d16b0f21df03dd80210a54a65f8545135ad196765145b957965d4978831169a2b55bc532d6243eaecbb880afe71978adada566ac68ff10a8c4b1dabfea77b18e0d5625a9332ca332fceff45a864f633cc09ba0f6297b7a798e368eaf7ec3d89043499d32852969d18d2b209377e0c2a46c6e1685d0a628819b4e5f1f71f2020725c8c06cb9aa9596f1998c0dfd170de6122fea9d43a8644a6a54a7725ced87ff220a7095cdbea2fbbe3a6b7a89fbe4027ecb8fbad57f7991f6d59cce749dd90e78d2326b2cbe6eed13e83e6282e00525470c6d5532b53fde95b500b57448ef18a972d290f69e333bbe3036d85d2cbac015484040776b36fbc4f274c4253df3bde94b96e0aaa83ce54fd13bc6aedccfc229ad816b79a28ef965839ae49ebd0de048f4dfbfaf40f12b28ba84fbd467549150d2253a068f41c891970da5ff74720e41039b403c285267311882fa2f74b9fb72939efb420ded5a8702e2d626fbfc4beaf44b0d67f3f3415d276c0711b7548e5311d0de432016253527e2c3158273828b4b6c737529f651e1a5717496e0a4286774ec55ba631a500813de2836c1ef49d64ea7c33c4a75e920ecd424a75aa794bea30b8afaf29461a402521ad747350d70b0db8429c14576d3624346913417713b2c4defbac7cad46d389cea40a5b450a0e7aa6b91c5674c41dcd71dee7cd9a9d0e12bf5111ded594a27eb0a0014d54ca234d37bab680476ff64e09f237a3c91b999525dfec00c9e74a119733b8e09620f7ff35e74041f863c2a3a414dd9e6ee4aa485390fe063629788ba4855feea4626280a042295f5bd5e81018a0973164a589768ba4e0b5c037b9a132f346fb0157a71ceeaa2f787da030c8b8c29217b8dfe6aeff3d0c5cc70baa339e4d95f56e7748616132f3a9e7adc37172bd08164838f6ef69d919c95e5d4ef7951283f371a44af0c5dc9102a69b95bbb7fc2a886cd78e27524ee74b8d055327138f180cfa592cf5b2d67be9c271b9cf03908759959031ea1395fc3f02889d732e13b09bab010737ab9af8aa0cf8d64ed835f8e16c82a1ce1b91a5a439495e8fa8c582d9c9d483ffec0162355c8faa765f6f09602413bb2004b252113094e67fddcbb0a1ea855e9a2a25782215dc1d42cdd59310c0e244600c70d245f45971b7b49b4fb19b79392652d50c7a22d6e95452f1dde12313d2cdd15a99a1b04b87fea8bcb2cf80b7302faee5c678b5671036094c1afbf9252221cc255d414ea12c1d4b0c21d847aaf4315cd2c4fdea7fae548060fe8d7527cca44622c94e48d03b87628f7eda65c431315fa7f9e0dec483035519453993375716a148a2476fbf7f0e5aff925bbd0ce16512d97469150306d8982789b15efcd2236a54cf614faf085c461f249112540b849b273135f2aba8784e0264e8ca9c3840334eac0f6236208948ca15a966a97a060958a01088e0fa0f62a31a1ee8020d1303374b9ce97a12676613129fb4002d0fc33aa953d181cc141a323446c64cb72021bd4cb5f419fd0feffc03b08850733d996f070c07da8c9237ad4a6cfb4796d4791b43207d80908844182866630846c12f08c1c485d578479a5159d499074afaa904993e10b994a4bce1dbaa80fc20fc5726271565c260637727f2e4dca6ebb615ba8c3da4263c3063d777e075c29bbf4f5047489fd098d170bc357c2649fda67e63922c227759b0d0d198212d269ea3de80a3e1ece6489ca65488e87e9bcb6a151d94ae30489de7d1332c68d235b9927305a3e8504d68503173d5e8e53f126c47a8443768f8e5ab154ba1ad8d3a23001ecea6ae424631631ed828ccbee6a4428d7b449a02ff1309880757be03486e9a24c5cbf821870df1d9d5e3ea13b855a50e48a29a0126c13a30160f1baca4a629121de2c1549c49b48136ae45d024ee06b77a8495a17b9e1b605b7339c86b1053868717740b96839b45e4178b82410780af57d75963cf80dcf1febbcbded059f293cd6b77d4b31e04aaa67333dde15b01203a847c393c22224d61c1be95b7752009cd41f17ef3b890b006eaf018dad853181e5b6c1cf4d7dec15d0dbcd4c8c92aa06e786a8965ab5232404eeb8d101af0e9a44b786f68d2ea5a2f1a62d2a35ba2149b8664b9bee262a10c27d27f0dbc03ed7e68a89f880bb43064e2daf200d042ef6faef5f30e6fd1dd0bcd08272a72098eb5bb3c4315091e0ad5fe6112653bf45bdd3149780e6586366e24335685ffd1a137352ab615e58fa491411053f67548526d02c73b042a64960a8d96710845ba321575c934f868a81f69d297d1bf07dcb47603bf58936197010d014630d3167e2e62a172baa8e734bbade8dc1659002a037b6a223c28ecbf11fd63b45743371290280372081c111d5b37800a57c80da8817b6278e987da04dff2735fc8f09c4aa6a3e7cd96d0432f34c5a9200f056623e275872ff2090f231c8a2b8e91043fa7bf6243487f0141c4911ffbf0487e08676129cb2f6f7a5e3b07c91b815962d81f215a081d1a5a4ba316391af1302835808f65e27d73bc09be5cd60f58413c0775a4d4367c7ac7e29091abeaab300534390118e46d4338f1100d9f36bff4202c0091c3a38b029541417133446e48f15076c24d71f56ff6abcde3ea493a61e700811e528ecdfadecc6ec410c3425e01c27dcbdcec304af3a248868c8dc09382aecdf1ebe635b9abfd3d69c1e943d7a13cf78f9cd31f5ad06615fd850b144c9afcf05bcd217a2f88d59c448e9712930a79135811d841675775613ae06cbdf9db2839587f54bfc636512bc20597521f818cd37e156974aac122db39b32c44adcc4fb1c5a471261db2e93564e64d1db241081775da9ceaa5437fdf9f3aec9a7edd3724567f7be8586ed89ab0f2b7147646d97f13e1713434c41a8554631c252f456ba085792904699152d9142d0d5705fd670bc165cad21bae4246ed04063c3c0877e24ac949dc3fe21a98bab90da35eabd4dcb151e45d40317c9f0f467c38cc4e87c0caf1373eceffb5d62ee78445714465df8b8fef5c0b9d50dc2d34653cb2a71c0af9141569ce2ab1cd0fabe4cde8f4e56cee5c501806cb3d52312807ff60e6d2ffbe5518cf1dc6d00e8a39ec6f8bcd48e32161185d3accf282d2437487a74d50e96ab866e16916dbd9b8ac1dafe771855e5f61c2437ee93d12a9cafe16e863c47906d778e50fd62e7ac433077cf7051a8cef865065e0e53b770afd3864571774dcf442e875d4f136f2f0bfdbef0b405b9ede7355ee742765fcd802ef5b4beb2f983cf030b326f87846ca7f5561f3bc901e343a7fac2454a2d71ef4d79e493bae88d85c7b72c1b969735105be2ea5038ee69c016644b8c277de526ce03b18ec7f833577d52984adb3755359bfa699d6ebe37a0b66d3c2c300e526f2517dfbc60cadafd2ff4e2ea07c5fda9284a895a77d450c5b0448fdd527fd134b42b44580adf8cbc3d44763722581feb5f66d4159b9a7063889d392c50b2086d94c8e2e2daafbfc5dd36f40feeb440c8fc18630cb242096b37bd455d48abdb351efb72c8bec764f12b1d4f38a3221d95fb80e6b4ba78d1647d3c683056c05020e3fbc20217b1b1a0d171c8a04c9c7c896ad807b324f65d53ce92c80225a24eb9952d3c6243d9a4f6ef3d34cdc8a59262e84978fd7eeeed0ee995c35f55939c1008c7210be5c92c98bd8a9280a3fd8152965d43db817abf13b6ae39126b665629d74f07df538e794a3e97c7a1b15e4f09b5ceb2be40dd5a2bc976c9db252a39a68a361c902bb5f6d8b74ad8e162aaf903125b7f5cc93913c4dc65d59fc5d3d40c35514f04490bb6939b331d44cdc2d0151d3cf240105721d49d79a408a7cdb9b1a0c7907f952fbf4da1a530f9071b916d1a9a9db89e6f305eea6b37e4f864c0ec5fd257e760795dfe7004c3cf290fdd240d79049dc8c9330b3c1cee749827e16ca3239ccef69981226443c37053de1d0264ed70e4050c051706d68f7eb631385dbbe9e6d4b3c0e339fa44214e85e5b93c7e83cd8a144ffdaf45673b86ffdaf835021cd053d4b6ba70aee6788c7cbaa1a723cdc03a285a3009c35b6dcd1e3352182ad08bdcbc29016a55d777b973a97359bf94278fa7109fedfe8681807c8cdbab03770a90dab52b3bae3480715ce6badad6b3acec7e3b72ce028fe7e81385bc069878dde806371e3430ba97eada8f584a355bfcfcd912466118aa2a7a93a45632d7c78d9c031dfd2679fc3bb9ecd2a0ff77014f8b301fea4935dd5786c7cd34031ac96028a0569a6bb7f1840f4cce70661045a0b3a88beb3d4d86faba853b2f671c5493a8ad1969d666dfed00f0b9c3b85fa5e15f65f13b7ef5862e1d3ec3925f56f95880bac5f53b6e7424193206ed5beb63696aaf78f921a592406f13bffb01ca73dd9a973a0f6b16b999b696cd14669a2187d488d8d3c05c4a241c1920ad9ee90c92050c82fb5f76ce3f1a91c94e1ff464b401600fc52dde61691c5f33b0638d45478e5f089093676278990d7a59e09203067baa71b3166674cd3c9d5e4e06174da3d75a4f47e090b550e08ded4deb6f0e872da92e585b92d61f87c9d12027063cfd88762faf89e7703649108136a71bdb04ce231b4e5074cdc4d037c027cda73052e2d9c52a259fa7d5a3e2ef80d45af9957f08c523100233463f73b053b7eb96801c85ccd9a701c151fcd9b4b15be8278484ef41c6fbc1506e419082344071a4e1247dfaf009bbe18b148d7c784b240dd57ed907a541307cf789fc833e4aaa45ed470c9d20487b27df3fcca96b8c95de2ec133fb5f5282560d17027835a7c21a928927cd2c4745038b39e821953a5f19f4789070f792b8ec522f260111ead90194405474c8956c4e1509bc156528c0551f318d57627a43dccb9594cdd2e84eaaaaf4151797237a2af37bc55df3eb168cc292fbe3cd48944ad7e3dcea4f32464b24269b5114e82b3cab69e782bb686caffffa3765d33b931f2fc0b82caaadd5c5455c74c173ebc452cd7fcf81ad884c9ea01c58600c323bf54246848ac964624961f7812e0511b7e4872d3519b2d6aca018b7a82aa8d3331952a6472d5ab0a0e0979ba14d3f2674e1ee2e952a26ace287a5d16f7ba5fd51c8905e22e30621501c39d9828251a68c85770ac0fe076216585374e36fdb3eac76af15051eb9edfc81a395f5b7032e8c549ed8643328cee65b76cfa0813cbf895de8ef59a2faf2d29c1891bd3b3412b28e8fd79be2ae6b7dc9d6d01805af2eaca5ebec2753508526e89906d17d6f3f48473bb096b3f5e0d5fc5c6fe406a19c183ea6ba40794d93a9d7580185e7ec1f1130ae4eb8fa2e58773ef5642280867a1f67907429bb2df1207608941fd35cb4e92a6a671d8ff008690a2395b6423589e07a89486f92223ed5d357b2752357bc6e988bc20363b94eb9a625d70b7e7f7433226aadfaf3e34e35caff0d2d61e002574645e7d55ad4a81ca446f1f51148adf278078a34b73ec63b83473a1092c520fd7f25b43eca6c645a2b8af070ef28c02295d21280c797d6fa5f29f3aa87734f6fb333bb28c8decc98ed58314d945e77b4177f1558b1ac1f9b51ebdc4ea71169c80070812e9d89e7d32f5eac529c11dc4dfead32145f49bc4d8c3aece0190f67cdb2c84913942af189099213a60980178a3f288f5d71ebee91eb394a4070cbf7274de60e01e053305b2f6cf3dbed34174c11deffbe5de6a75ea2e32e376c2f51ae559a572fd3c3b57911b5264371f50bb5008c6e6648d87b89dbed2acc258c7a76c673e375b44111b34732c6b860ecdae9148e88c5b81931275cb398299211103a6d82c73c37d265099daa337c89c1746f04ff8c3484aa7c5a3fc781927079a5cd8d074f4e5176fe06928375a8d395265a024510103d42b19526a4f836c68a9ce5068017b8de2d7edebc8d8e468405664940c8618e9739dd9eb4e7eaf1004b55471f23a3ca17a74b7d3c214f76ed11f0923ad8da476c889b52e14a3319f4c88bc75a3c20ac9a783ae095e3a677781ca8a68fd62a2a125e2b8f57af304a3988bce6fbc3ef0ec0742be8ccc2cce5c263ee4a74d3da876e5d9066c47178565a09271371b7cb607de4965ad9796ed05608994002da5671dcea3010d50323111611830505f746259a783d0b6138bdfd680c8eb13a5c8da82cebb2dd558a95c28d28ec9992fee4ad52d83fc10a29de90723d5360d4b3a3952af125ee4a57e563c2856e457f553438713b5da9c6c392c90ba39b046985ce04d3539ac94a37453d52b8c56357655874a2f4260abdf07afec502401fae68934aa5035409b9a688c7fa93175638f71556537c4c7023f4af08322046146fa7dc130a7aa5f08d94f1a067f2327d329f32f7baf8e45ca58834d22a0f5fb9c08fb054ca7a42811b295ddc4b77326616fedd798228c0a56ce5c3ad952a4091e08e92de1b19fb2ca61207836b511b1334151714ea0530d86f0f0621d777d23e3c1471f8af7a38227647abd30b2576d1a3f2738ae2eb990283fe5d574d94f0805ec5c58f28f5f272ba457c817f4a499c9e13f148dff52b959889db6955a5a55360d6bb6bf5746914e94ff40a0a3215591185b752b8b0e70e3ad23fa400cff64c5e927e420056e927948a1e15ff2a3140f1bb5fad305c293be92b3ea2dc1b457a4df136ca3d3ce825fe98c2c57a4c104bdfee576c2c11bb63e5c45228d14bf3a0cc8c9f0e1468d957d91af96487aeea96d149e976caf6e4c1885ee233ef2e0a7836ba9455a2ddd84a2033a3508e9ec4969604287b15cacf7cde859b8201ddaed85e27af43bce205ae77c658183a101033b901dc869b6eea4fe8cc3a9b9d18f72c3a059386ed255a01c76acb5aa676de86beec53093e2fadb426912a9f75d7e7500b47207bff230538164718e71a81741cccc6c666898b13914884a9365c253130def7ad95b070eeaff0afe6727225b20ec772a5de8f9406c146f809b3b1b1e1373190a65242f6bee0d7f66c0484edbc6efeda1f97db7676b96d37ffdcb6f3a3dd6c5b0fcfce76ee6b1abf8992dc48dad28442edeee6f29e4e3ea8b342dbf34e2f0f0a6dc23de3dabe554afbd559eadb6cb5e5e6f9df59bcf94b8aeabd53ad3fcfb69beb3dabd4d77bb96d17694524e432199d6b2f1785cf3cb10cfff976bbcdc9e8a85dadd1fe95cea9761919118e00cbc6686d9fe1d9aa5e14968d58e2f6ffd53e4a46b5af3fa7ebdba6c2541bf7dbff479613fdec1c3efbb79f7d15ebeb6022150a8542b758eb6c5f9b7a8bdcf4decbb6ff8fac4ff12d82d1e1dc57735afbd7a11675458814dd8aa48ace145df50e37e1dc6fffdf1337d18c4468d03afb73bb9ef3fa5fad56faefdf592cfee96d603f94e3f6d4d018b8891b32d1e1a621b80e37dd4279702470b350de0bc1c14dbc5015dc249487101242584204f0416e3adc1cd4036e46e1e62032b8292852ef7053d0980e3705c9e81d6e0a920b14c845a77637d016a04070131092dee12620b5dea3ddfd63e74f21dcfc3343ff14abddf533c68f0cb8e9470f6efaeef649d47b87f6b90237e7eef691eb530537f918f2c97bef7c28f40e37a7ecec49b44745ef44bb6ecedecdd563c2d583951a20606a408028a80103060c8062517825b60ee8e4e776432bc2fdb262ebbd7705889405304485e87678e63b52eea8dd61d2f19b28138b68786ddf6171474a9c3ffcb1f614876b1a10f679d30f08fdf35ffbe77f1ffeb1dbbcd9b4a9f51c005f3a3ecfed3da97779f6ee67ad1e5a077aad8db5abf74c67f38fcb01a077fc6e4a5badfeed6d7be7f39fbf1c0e9d78f576b61d5e3d67dbd97a710cc5c911e8eb886851f8fe1efebbfdb53aadbf148680c31188f89cfbeaa78f80d7dba62691329afcffbcd5adce1e01613634d80808df769c87897fb8a76b7b2b3d9b83a7b29ca9eb7d7be7ff79f57633006e2c74fc265a7d5effb9fed3d97af7dccbffdf94d69ba3b04405b6e9d17bf7769b99d846ad5fb335bcb676cdd66c549c19d37b67c3a2c34d293536701d0e8e0d01a9db9a433b4feab806aef7be66c0f3e3598f0798e7d9e541edfb0b426bbbd60bcc0fd7d41caa59aa21b3efbf2150ef4ed3d170e99df8ef5f85f179f676301a0a0be63f07e7b6dd36ff73efffcfe7f86cb5e5da6e3b0ec7ffa6361deee97ceee1f08f7f3a900e9feb3fd380345cdf1d1ef5aebeb36e6fd89fe75d69bc2ec73d5d8e7b3a3cc7b3b7dedfd4a67b6bfb7f5e2f502fc73d1df5ae3ab5b1ce365b8fefaff64f1cfbf3bc1cf7747815f7721fdfd38be212b5450c053154bdc771c14c7bc7fa6bb319c644dffebfd96a37c3743085bccc44acbfa6dd76be9d7abf4f27a78777281dbdf76b77bf58ffd5ce83fad120fe0d4b28c2553c8b75bf9cf93f3beaf84d947a7950d3309d534e1743b80977997b97b52e5fbdf7332e857aff563f3f5b8fcb98de7b5e10abd55f71ffad6f5c027b879b760e7339f60e37c9b624ea1dbaa5ca1642b8b925dae126d91632b84956498b1d2d45b498e81d6e6ac12373b58869a193e50adc5c91a5dae166166596adde3b963e580c7b879b3019166ca01e16b5dee1264c864541a5dee1e6153586339dbd92f70e37c9ae54b87206b5f2c94aa12e851d6e5a01ecd0e1a695b30e3761b2fce75981c9aac8e91d86925579522507dcc476a8e92acb2a631d6e56f9e3a6772a4fa8f8e870138d4a022a04a664ea76f586e1297fa6cc99b2a39791c1300e08e775d6befba474921247ca974e2c2383cbc860dc6e80941caa40941f520ef4de719a4d2daffff5fb792cd6ff6a94d480a830ab8702abeabd4fea7d0af5f505691cda3b94175457efd47fd77bb54dcfdfd93b1497d5f70eb535a5f3dfd63b94d654fdff6cbd373cdbceafa69f77967783c29a7fef50575056bdfbd574ef50ef14ee730f47ace27fb6dad3cf178dc64bd801959a95c2fef6783ef5f112ce716fa5da3f0fd19339fbfe82f79f63ac7042677bbd66e1e6edbf80e3f39fe736dbae6dce495cef9d58dbd3cf079fe5b8d7da763faf6bc36bbace6efe82d3dbfe7f5e2fd0d7e539b7ff826cdcc3677aef4f6b3a6f6e9ecb7f15f77278f5a7c3add636dc7f2b96bef56cbdf9fb79fcfeb415fbe3f2c06f47c4add2ac3dc35f8ac3feefb671bb3a85efacad0126e27836f7b7c762bd99996d57e12c159b85ed1c0ec9c7912038c2a5fb2a8cbf59adfe8d787f6c6dcf1fedfe78b6ee4d0a2f684066e4aae33771fbffa0563fb569dc708bd0e847624c8cd1ac1e0d0dcd4a85ded06ba11e719ebdb5adf02cb0b07bb4fb1361430426f284088dde6136186ef62997c854ef1d41ef777779c01922a6f74ec46f620cd86c0a112424509f633e5befd7c135b6409a116410ec81839036bde39f86cb6d6b1ed143d4d6ea65e7db6bffa65eea57d3354da57ef8d3562b7d856b1abeb1811f3eabb3350d4b897b82c02da0fb40b95055bd777f67bd0b8409f1fbd5deaefde668b83b9a00a9f6686e5bf3a240e83adc44d1dd1f547ec4f831d8f19b98d66ce2b54de3f5cf03ff8f68879bf3c7f73ab93efcf4de7d30717d187d34e8bd13613b87cff4a6b4dbf463f3f2dbaebb6fe7df9d530f9a63bd769e3df4f6df3ae58175fdf91c140a37ff6c4ffdbfeb6cfde1a6bfb3dedf59bf23da7b5f11641004b2352805bd7728a804506cbdf710ddc5d1a8f70e17b13ec7af748edfc4294e5fd3a6387dcd3188ff2c8ed3d5e9cfb7397d7b6cdad59e12a5d96a4efba5a535716c9e57e1dc636109f3afff9d05a4f1fa53ff0c7b3747d4cd117507f97477f0b0bb835eba3bd8a4bb8341ba3b28a3bb8327ba3b387777104377072f747790adbb83c4ee0e727577704077451ceaae883cdd15c1a6bb22ae74574492ee8af0d15d112bba2be277570486ee8a6076574483ee8aa8eaae8800dd1584d45d413cdd1504d35d4126dd15f4d15dc119dd151cecae6088ee0a46bb2b88d75dc109dd1564d05dc103dd1584eaeeb65277b780babb85d3dded96ee6e8b7477dba2bb5bbbbb5b0eddddda7577fbd6ddadb1bbdb07dddd6a75773bd57bbf4280e08080aab7f7045957bd5f651dd8c2a23a0066006bab7704550a26d180f49cc1b581a203d233f4cfb4364e1ea5d4a34f33cac9e9329e934c25759e8f472adafc03692a1a5e46a6fdbae3264cf6ba414210973d8254e868a12e84a4d915a35cb5d4c131c89393279e6ca811b13fc7e1dadff0d69a4718897011a11b62139fe96c0fc2196acf841208af7aef67cdedff83926dff1fb446a2deac01d7b852238bdf896818d2c83b8d65ef1d6acf3414ccc83463ce8c2d507b9ee1a2f719783396bd37e719543264c890512763d97b6fce7f9e3df44ba1760e85dab30caa184262a888f1a1f74ee6ebf2f29f9797ffbc3cfb96ffbcfce7696dbc999eb379f9cfcb7f5e7d67ddf29f97ffbcfce7e178f9cfc3f39f97ffbcfce7e53f2fff79f9cfcb7f9e5d7de63f2fff7979f9cfcb7f5efef3feac5937fccf9a756b71edbdf7bcfe802d98bdf75e7f386a86c595055627c21ef644dc6373aa0dffdb33c019c0b887737fc57f558ff86703ea59adfe6dc5a315897a7ffe4d6dbaec5b16b7dffea6365d8edb531c6e6e0f6ed3da7879fda7f7c7ead574dd9fd783c3f3f0fe6d4ff1b736184febe9f23eddafb3771ef8e1e6f6e0405f07dbd5a75d7dde1f0ff7bbbd5e5b1d3ed7b65b1b5cd3351de8eb027ddd9d75abefacdb6dc7ddb53d9ff05ddbb3a66bba0e86037d1d110ef475305c9dfaaf07e3369dfba7b3ada6ebe82b713bc5dfe035b80c3ec39bdf8acde6b01f64434383cb72bb4a06e3b5d5c1b0f3fff93aad6dfd6e57dbae6d9eb3ed72db7ee27373f51c6e3f6f3b4e6bd3d9b65e7d8797db767776f84c67ad1e7086db0bd4b3b1d76ff53f6fa6f7667a2fe7b3ed7e9ead97df36dec76ef5ea3a89c0a9de7b19ac06cf7436d070a6b381257aeff01a5c06fb359b6c7a6acda65d5e601fbc06e33711b7d27916ea46a20e37f1fac04de79b9bb73170d3c93785af4602379d79da1ccebcda45879b709f7aef9eb451b859f65c2383e7f43adcd4d3cac14d403dad5a879b6fda2fedaf0139c14d1c3050879b3814d04e879b7980637aef306061879bde0d50463d0798e7b8a703ccd07b879b8013a218495d650d3b7e1343c0126a1a3ad3d92c5e76d9e126d4cea1339d85e2373ed3d9c21c473ed8e1e6200c43e76b35a76fef67d3e513f22f180f1e070f831fc1097115f8b6c34d186e9e9dc14de8594d5fe1b3dea78c7883dee77b4fef1d9fe92c14af6fecda02f8d6ebf9c7efe6fd05cd3f7e4f75b879fff9be0b0128c46173a6b3d0dcb69f217884200c919f35cfa0f6dc7bef21ea422c9b6721be7a879bda5f4373baa6434c75b839d37ed84670130e760cdc0cf4570370135bd87bc7aac0da586b879b7f30dcacb1721df753ec036c552f6b92d9cf4870d386631fda5b7aaf6dd8c66107f6decf60a83ddb7d502b9dd759286edb7528c24e6570198c06c730196c576ff8cc0cb6ab371a4c56db78f6cea1f3bfb3d79fa3a9bff40e37e1268e24ebac65f46ea0794cd2cec06ea0f93677034dbd1aaefe32d084ead504ba81e6b351d9f5b66bb23cdd40b3ef4c37d0ccbb32c1af2e0c346dbbab85debb81e61f11ffb96d67cd622dc46fdbbead35641830d0ac5d2bd65ab566e87019dc8cb31ea1f66c4d608daad4e1e60d9d7ec0bf2dbdf7e6df863f0c6f7fc7bf07eedf15dc849b6770f39aada1b83f839b674028994102840dc283c00042ae77b86900fae7a7d3ff670086cfe0e6f403423f0e4d22655fc5a1566b967a4c66a106e033b869c000080601ba0b020cc454ef70190c37673a4b46179a674fcba9b33796fe4053c06fa24b67d154f414a7426570f3ac49563dac5601abd1aa5c9542ef7013869bd01cf7d66a55eff8f5fe39d4f523e4b7c7f53bec11e026dcf4abe95a6bfb0571fd72c0cdedffb3fed9af0a376bdadf33d4cea1b05fd3afd87b8f003767b84943fd065003a0f6e91d6ec24db879db54ea15b8599ddad88fdf44ea1935abf70ec34deccf716817f0617cc1dee12651fbede024844422a1b93fc24730bb716734d1285a4dc338201c8dc268666670754adfde3afd330cd7d802a9f0c7a09fdb8075d69eb3f8fd6dfbaeed400f85e61f87a6e1d0bcfe8079fd01f1db9eb3b83cd3365fb36920fed339f84c0dbfed399b57a7c776a676db7156ab7f7b6b360d349bf9347b43a1f59f67ba0aa5b11e8ac59b4daaf5e3db66b3d9d4e3dbdbfb44a4fdd9ff54388aa5f328d586cfa2d97ceaa36dff53a156ff3f15fa3f954dedffb8b94f8562e99c2dcfc0d9cf6dc07fe3c167f35cb339cfe53f8fcd0e3e935373ba7a4cf44cd4ffaad7a607e3745ea0de7b5e91de3b841aa7d5026db73cbcde3b1bfe94d37b9fe9ec99de737bfbe71a3ed35928940d3e9be7b6da5f43a13834d05fa176769ae3f6145adfd99abedad5bba6afffcfe7f59d95426bfa0ab5fd7d7f2c140ff45728f4e7fe8606e6ff8fbe4203fd153aff407f8542efcadcb920e29f9efa3bdb46bb7708ecdc74dccecfaed83bb14e4f5d8f4ef4f8b74a3574b7ce015da0de89361edd201d1cf182a10b577a275eb0bb70d57b275a08632107f1cf4283b9467d0ec51c5dcfe51ac96de9bd13e5a07263c40a542a0476b8b9bd0a63719c8876f5aede714ae20689715fce4444e7d609d76bfa0a2708ceb07722dc1bdc5427be0171dfa2bd13dfa0dce4f44ebc6b7bbad16ec5de896e1b993613bd13dbbc2814ea9d48414b61d93b71429e094888f9974e704eb8ea9d58df59291b1536179d6d6c2dcf5a21716da9c689e8aaf1508bf64e54eb12dc1025d81228f44e749b7a9a86fdaebb4db7e654ef9dc82cc2a499c7de89cb334b13c425ac6cd47b276ee8ae52d0551e891fba9b0493d491ccd089b64dc4dd64f1ec6ae7b5afe2257bef10ee90637a27da5a3d6420928c86f39f7f5cef9888f83f0e1f76f76877c4e7d91fd5ba6bd464b4d33b6efcc632b992edb7ff4f6ee1ca50b9e8f3c06fe766b95d9be161bd362f3acf3e1aadb15e9b17238adfc481f9c7ff13eddfd8288ce3f98f936ebc35cf6dc53ac529bdf766532fbaf5754513c50fd8a29b66a96f3d9c36a6afb013d344e07f9b46412fadcbae89917ad7231e1265b844245a252cfe6fdcaee1f96fc972d8fbd534a0ff56f8cc45a38366221a2ddb4ac9e0f99755715f254393239e656a3bebd17b2762f19cbe6dbced6cd9effb4ba8ed999ee1b6b32ae20ccb81231076d88d20d789519c6a7b3702dc2310b8e2749d6b368678e69a159a617befae199e5902fbcad66cb2b1cda9916d314126477674c90e40c802c10504d940772190b90f023d90f1a0efc19b03470eb0f4de3174d7c1ec3a808be2697f0d47eda268b3d5b68323c07875d37a8bfb7ddc9aa5fedb4fb7751bd1c35b94c3afe653dacfb6faf9da5fa3687003221ec5037d5db4868bfebce895cef1bf874367eb95fe53ba86bf1b0cd5fe3a0aa311b17415823bb6c61d43e18e45ddb10d635378a0bfe2e191dd11e76f46ac2352edf9f67eff86cf68f80cae410db7c1b581b201ec36785d06891818f6dea351bc288cd6fc80c4bae882310b682c08b160cc8d0b9b81ff5cf8ca15fbe28ae1620bdcb0496e58a11b76012c53ef9d188d1ee1b535b88cacd9a4dad02f48e3d1e8ecff1df53420fc06c3d51c9bade67e1188333402f17f8f5b3d7ea56f6c1607f1efda967a1b10a7e7fa53e788d4adf4b6cf701ad0b6be815da7ba0b4683617d99f92a74bfe65ef73fd557a779fdb3213e119e897eebb77e76bdb078057a5570bdaadcae3c5d50ba7a74c9754170b914954565788d4d8ef1a6f5cf5aa9d3dadf523f34343c5a1785d160b86cfe68ff53d1c86ada2d2adf361c2d8bf1e008701d1c0176c366e13c8b856fbb2c2ac36a30191c8dfeaa16c6895f0adbb9769edbe6fae37febd97c1df8e77a0eaf2eafffd5ae6b36f5b476bdd5c7dd72b3a5dd8ae06e19c8e26a495dad584b2b4b8d9b75c3cd5acb2246f38f43ef6faded28fcff7cde6ceecd345c74fa677b4a0667af73ed6318ad0cb7fa68fef3eabb28191c2d8bc9eefcbff1acaf06fedb6b3dfcdd60e2f783731a5a0785711a86fedab6837a88d645396ca5feece3be8afd737056d46cb567ab8d25a7f7aefd3516dc1c16b67f3f7f7f402fc52a0662d5f9551e8fc5fa0bee55e19589debb168771fa0a8f4ab5f3ec14dee674edafe0de7bb78a845badfe5b6db1eabbc3b3caf0b74d675d86b938f7cdd4fbfbf6a8e9eb3bdd4eff0ddfb53ddfadeeba72dc1ebdbbd8407f7529f4de896eefbd6a4cef3dff781521d1af2aea5651e8ddae3edd2ab8f71ea9bb0ae4f4de3b4e7b05850aaabe8ab57a0545626d4f155411dd046e0217bdf704196afa9aa0d8bb8dbd7e0499885858ebad5317c198ec8d4560c24520d7bba78ae4524df978a0bf6a75978ad0a59273a9e03b2b0dd43bd1cd4e61f7800bed01b9dee9ebecd3b652d83d00772284ee1a88d489c4ee1ad8d2fbfdb1ae0117bd770378449c9ed30c90f5fe6f38c7eda95b205227d6f4d52d3026d05fdd02263a6ee71628e6d5745dedf3ac3451ef9dabbb04ecda2510b8fd5297801ced1290c203c6f4debb3d5f617b1e40d87b6dbb032874574020ef0a70912c3b02e2cd91c147aaed0a58ca69d0fcd77f4a6b733740a6def1e6dc00267a97d2f714976671f8b6cf7aef1cba1b60ab8af5b79fcfffb5b6b7ba3b95c99d92d3bb3b45d8fb540457cae77e9eb321de5ca931bdf734abee4a1576578aac6f6bef4af5debb9d1bc5a4f74ebcedda8d72a30804d277ee5d2839560f78d7b40b853785dd5edbb9db7bb8bddafb36a7ebecf54affdaf7defd7ad5a74c9df83f4de9d63ca7adb06ddb36884f380dcd3ffea9aa7b92d37bf734a5774f3d6e4f5122de2952ffb71d522a5544090ed039a303445659d70bafd88b0733f01c1a6ab25dce00b1e223547dc2eaf251098526b52639ba08c2fbf282c5b6c7530871444b8c3a9a14f940d26051170d424d8434a892d48799e68ee0ac50958f2e2001645083e8af01613341404dc19518ef96e99126416c33a212c0062e58714162e2d062b645038da29b0d26547ef0542153707a0a5a5166fa5306a40001034baedc0a6df2e38a06c0847505aa8d0504785c79439a14006d1990f35910c5f64588448cc98ac3395a4a0a3c5d456e6f8e5c7963b5264f088a286ad0d4b910af19c30243dff2c24405a10d5b2d72609ed48a4b0c51085b7443c957bce5a0cbc188366a73fe105a3d812c9933448a56b1af2622402a42d71604371b69046ce8c3e96a214e4d0a4b82c262aba4b285a41c125c04c9b39d296978ff18420dba72895312a474c005405b5b5a3bfaa238488f5ee0a0e8f222ecce1f3030118dca4c6a925954a6011d812a434792f78a6bc2337391b9f02df0026bf969a145404ea6ba354425fc9e38294b046647d1579b00c9e80c0f6ddb91e38ad4818506ae27426d9c3274e0e3c2d35724307d767c592482bc22eafcfd5b4372d608ca02465f616f5a5d165c2d0108102c21e40141756f287a84ad2d44991e92bd6d2172338185090908aa177e3470ea22e7015a60057b6567a8a861a8374544a23089ee28ea4be49605de7ada5c795417428b8105863b92b0f03b3508d98c94057a0380034487e8a074c97163cced2c5cd10065c1f68000e5a92a53a2906ccaa3295a0ae1ac10128111a22b4a622e643f661d0cbd88823005784850571a22101372e495c218b94d4193a3d04795874846fcbeacd9c29157208a88c142d1abacb50dd4934d1fb64070d3d5d5012c90eb869a4e65b202485263317021a5b13b6298b69de4205bcc7c0a434cb426edd101ab000cd92614a12458e28e1f0c23c05452b3a5a9af2e0e0cac0631373992f8410ba1494c0965c1db95caf613c3258e5e201cad150a3747366310d014e2b1b320479b1306b6a625da384189b51440b0a64c93275f1736087d45e42131d60683843c7084a6422b045efe66f8d9ddf9f4a2216b63f7654a6b8e591c960c031961f000de9e18fc05004393e7a192f497f668869e02304f02a47981d00308640dea64694befc51d18848268b9bdc9b1f90202e6fe401bd2a1054901f6dae9e274a48c219c4b535a50a6d49137c219423f8734184269284303480a23715959b060c18246d2829a6294dd661879bee629830d5a1a7d95f99ae0894e272834dc30602c0556a164431386259fdefec8d86611aff71d405300b54adc4f5777d2787875211047068f2039b06aec20b1e780974157cf7942cb1f327d666cc32890abb047c46ac237c8c19d3b6f4a1e341c5d1accb65e56863fa4d025482424c11253204859adaa46170241a9f10283948cd08f463a9aa46141f890270fa5bf245dac7c9d58e2c54ab02b44b28682625c8d322821236e933c1aaa5894e1a2499c716df93c725e30006179c5e42662c68f16b13c4f457784b8a122808b4e8d0a5700184304c70f099d73829f0a550d7cc89813405925a8a791f2a4c222baabb3129102c4a900808b42260e3bb80a01e252126924a0c70303501bc95b44e1072db1152d1011604b938129ab4241978bac102b2b79a4ffc0cf96ae26f70bac8e39145b85cf3312581d0f16e4c589e0a60b10426187542d43a8bad84d9894b92446911b1fab350a7219359556b029b0dda394b466cd1615e1047c2b69895a8c3c78681ea949085370e50e2f43ed1e880267c644b7b1f0ae9143e586128ecd923a0a9fba8c8825d01a84f373090d56270cb00d36411694d001e3c087950372184c52c542c387103c16af06ac37d5359ad010f9105b38eaa99705890385329cb45bcf7c83a71a7548d1d713b98a92171d7d5c5cb4d5b949151e71177db2d0636f8daf8e253239736e70d4ac2f068c0d840c431793f0290e370030e1f58958884680343c4fd214a0b9b53000b92546d8e531b376884d279a8f1f8c2c6eb000753042a31282e8882f679e6dd7b984579fb18d4ca56a8b900896a8730ec10c71b34c7cf814c5092e95b08dbe8101a6c0ea00038af9b157d564d3b725af909db12e2b64396c138bf4e6061d29a9fe2970562545530734536ee4501e5db9808281e6cb151f4c56307d6971f5d03e9c4039d246e87a2d15562254e8cedd997e85a26ac752d5053d2a7c24b00348da63826ace89155d571fe21812f334a0a6c6005705107428ca05980250da8319db3943d5ab011ba099c4ec8cdd092052114f900f65b80a14315db22ac44340873b612cc87861de2509f323802d3f5fd4543aa084ec361b70a406b16d8b1856044d9212d4a842e3ca0b19b7263a0facae1206934db8e2f8280280494d9f0619b6e4607080cb8bbe95187120cba5ce19316c83e124acea520fdac12e8fac0226e69bc950abce37387af1318592a6b300546865c1030673b1422d320156c414c87400864446a12a2235511f1e1b81e4ab50bf2cf2242043d8c7973866c169db6b94448b8cc61bc292d51610d4d789394ffce07c4da2c223c19d21031f99a991b8ac3632af56144ff400ad32b9fce3fc7ba3882b4bc88f3052737b01a4d460dd4943660afd72425d5578398983dbc2872e30c417a5fb042e74dbb0f0b788d20b056d2a6019c9c252045603294480a1297f7961b6f81cf002329d29494dc911f96241068588fbc66d0b13d3123408ca34441d3dd6147f30968dafc4cf1e0e19bed8c9c55183c499a8cb92982a1d7893888c3c1f292e33faa4557a7880f0f0e4e1210f8c6c505e26be21580a3ac1555ab2765c5208ef4a74c9eaeccae3b4239e4375628e9f1a828e1c07f055e523fc0062b0644e03b3ad23015dc58e2b1b42f6f8186140f36769ab5ac144122f5c59a69c182a79904c33e9030a0dd13866556e99454f10e119a4d627c2d5f63921e22acb98844fd09b3d6dae1a0000a04e113d5c5e636818fe68c340426eca850b7230eec4a453aaf48d9993c4cf9e3e1fc2ba0c095909896203e64931c00993355de8c8314cb0b5a2eb801e8d236b743c3995b55081c70d5312a5515685ce4b004bbc181551a9ee5841e094618f02dbd22013007a08408702b4246db2ab705c98c4a78e010a34faba0c007b2468c1ce96304837d4b89143c51193172f16aafa0c25ab3d2f5f0245d9c7177c5ad23b188069792298196e491d807af204ac49e86ae5050ed2525f98d49b32593a5e383863677b51415cf8ee32511f76615977a0a0284170e98260a8e0ce24a64892af1828b65638fda2547858dd65810423818b27becbbb100d527bb2ba74f6b2cc65d1753a4216b6340323cc80ac38460df878055a3b30c9419a4ad7ab0b3e799234a2e35a1f40d0f605c97066cebef0f3bb2285a5268dca1e5a8adad2881b8cc8b41599f25a6e12e224b090852a7d3029a172a380d39512e20623068d2852d8741d123739db60c1a9c08146bc3770f85244b0d9458bad4b47122d990413449af4644d9e35552108aa84b4b8b1896e8e8fc7930f10460892925d9d51a4ed22c6c1706d07928a070d5daa705d6a00009325320fba4d66c0ae4c29835631effc17d5124308c1344c227cc4c5e74aee8227466588b0388e4db19165854fae0d1f3c29b152c18f0c5a9f185139013fb12997c2e045b9daa86cf3a098710d98b082f32339494dc19a048cecd0f958a48470ab0c853351da5879792a59031df3f18e6193e458da33228f13087822b44c2181a4cdaaaf8c0f26349680c870a3ee09e7ee41932d342b14de2a18e01e6509b4e4c4a04879614cb84aeb83a11d66738f39520e86d597d015030980dc8dd84302100a3fdb0b64b48214a1bae1d6c00386301ed31c788650014bb1e62e0b1dc36312ea9a9a2002161ededbc31c3a6f4f0a11410f39ddc8e1016825b014176767c78b054a4078266c20d4f445a70a8f3c2fbe44a057e079a320462a5f29294310f1610159404949a0321264deb254006151240210a84558c21ec63f21707c3928539d033c51e6535d0943e10e824c2e0f1f27d016b95c252044ba9468c5a117ac4e25046d671dd03f921c1d8d2c692ef21a04a4070f982e5aee44a99e6883a10012977820d1833b39aa1c4283c220f62a1980b5a531a828830988c896b624543c772ebaf04cfaf1458a5c5f0b25cf046366340051950653211647339257d4509a5b664832b8ca84c505a16a24155e53242f16f5db93aee420465f6f67490403ad0caa05ececa892d6d191d46413226b8c371d27048cfdb9121454210a16970f1f3f6029513cc846402e49a4ac963df3e0cd9ee91d2f061601e77aef724c2ca2a1bd4141c9aae13771fa6707b99b3ccb9bebe81d5e5383e1668e7b2ce0344a6a6a8000013813ffe2192af41727e0abb07f6f39bd77229e95bef70d78968dd99baff7bed7df1b0af7f0d91c4cdce2df0d6f9bfff5e773d79fcfe139dd1742c422beba2de6c3ff138bec5d5e6693b16ccc1e9359db2fb02daa4914933cf595f7aaf75e973dcac56b5dd3dba6e0a6e4a698b3d5d6fe5aaa4e1d3a527ba44248fd75a93f29fab6a7b8949f5497928af2144588d09ca8393fa2e87ad485a80b510c0040f2242b98b587ce53cdfd4b6b98f3eb542b156f4f7f7f1984fece893a717ee72ec419a7e9b6f9c7a133defb3c47e8d316b9874b22e5ffefaade85bc2452b6b57affcf5bdd96b22ccbb22ccb721cc7711cc7711c178bc562b1582c16995aff5432b5fe99646afd13c9d4fae791a9f54f2353eb9f3253eb9f3153eb9f45a6d63f994bad7f2e975aff4c2eb5fe895c6afdf3b8d4faa771a9f54f79a9f5cf78a9f5cfe252eb9f4ca5d63f974aad7f2a955aff442ab5fe79546afdd3a8d4faa7acd4fa67acd4fa6751a9f54f6652eb9fcba4d63f9549ad7f26935aff3c26b5fe694c6afd534e6afd334e6afdb398d4fa2713a9f5cf2552eb9f4aa4d63f9348ad7f22915aff3422b5fe2923b5fe1923b5fe59446afd9379d4fae7f2a8f54fe551eb9fc9a3d63f9147ad7f1e8f5aff948f5aff8c8f5aff2c1eb5fec9346afd7369d4faa7d2a8f5cfa451eb9f48a3d63f8f46ad7f1a8d5aff8c8d5aff2c1ab5fec994b5feb994b5fea994b5fe9994b5fe8994b5fe7994b5fe6994b5fe29cb5aff2cca5aff64c65aff5cc65aff54c65aff4cc65aff44c65aff3cc65aff34c65aff9463ad7fc6b1d63f995aff5c6afd53a9f5cfa4d63f915aff3c6afdd3a8f54f59eb9fb1d63f8b5afffcb56df746af5ea809e8dcbba3a51c67df0f7e8ad375ffc7bd1ece74a287251e86ac0832089e3f7e13d3a03ef77387321db6f44e241271423dabf7c1fe76a0c26fa2bf7f5a003d1c5eccf3cf6dbef95737f84ec4a51ea6da1fc75a7fb56c2b2583e1f9f654d8c6611c26c24408395dc57db50d9e827b33345af06680f26628f166b0ce5febab7af5defcff5cd353fc3fe7e6679e5bddfcabb8b7e6fddcd377eeb1ffb9373ff39fe370f3d7da73edec9b7bf9cc74abcfd674a0af23cece05bfb6ffbcb7e1e0e6af692b7cb5f3dc7683e9acbdcde6df6febaff89db5b7733031cf86836f1b0436dbfcc3e91baeb5360e13e71fadfdf4ccbebfa0d9d66af5ff365b70f7746e783af5da9ccf0ab0d38d587fac0d1371389a162399729c66b566b151f8ff3c9898b5013d15aee9e9bfb17fa6dafedf6779b58d7b9cde5a6b3b1ac5b7b7bff3da9e46712ad5feb3bf3fed0647a3595bc30818f6b98783cfe033b52b5dcdc3faba3518866111300c7f2b8dbdda53bb8e46a3304cb5b3385d67f55ebb3aaf1d04087073a6a16738f5dff06b37bf76b19dc3f84d0cf0d6e1d5d9d515ebc6e0dcb3a1c130fce30791482f9da2de7bafe6b4d643ad560ffd80f49fa1b8a7eba067b5fa3722dea7365550f15e4873416deab560a7f74eacab395719d99f3d022e236b368944f84c04ec730f07c306ceecaa96acd97c2b5cbd16e0de6b1ab610608e70ce44efd08fe356ab87422bdc497be3d8f4f9e35928146ee6749d755695453f43a084fc79e1aea42241ea5352ac4879ddd47aef318cb6b646fc7ef30fd17b67d1df3615fdceeb9f86f557477d12148be3b59761aaadfd76138a2f1bdabbc6a71373bace96c16764543b027cac3fd6f6d22cee730fd796073aad56ff36ff7aaf49f4b54dfd70f355cf39dff6f4dbd49a89831906f52e6fbc4b14cac30ef52149e155fecd3f042c01f7abe9add57ac3784e4b612a5dc5a1d34ec928c4299298241ad1a67fb6a7686f7cd6df58acbfb182fec653fd2d7aea6f71527f8b87fa5bdcd3df229cfe16c3f4de0708a0a23a3bebef19dc5f32b7370292fe46a0d1df088305221478cd38f5d7ccda5f330dfd358bebaf59b2bf66c4fe9a7df5d74c417fcd02f4b7ec527fcb0cf5b7ac4fef1d81150103ee4ba08cabbf6503fa4b16892c108297ecaebf646efd253bf6de055051bd10dcbc10c6f4178296fe4290d25f0846fa0b61477f2110f61742547f1f50eaef8340fd7d40a7bf0fd4f4f781980786fd7dc0a3bf0f56f4f741dedf07d3fe3ed0ebef03382b5781032ffd75c0a4bf0e7ef4d7018dfe3a28d15f07797f1d78e8af03bcfe3a60ebaf8308fd7590d55f07047aef051228d0ea2fd601aa0360cdfe82a5f517ac417fc1bafa0ba6a0bf6003fafbf5a9bf5f99a004bcaf8cfebe22fafb46fbfbeaf5f775f6f795fbfb62f5d7ddd45fb7914b05a6a0bf31a778d16ba00a37add6eca4fb6f3d9d6df7ec1d0acbb043d9a9d3bf9fc7f17fed1d4a0ed49cf95b67ab2d57efd55fd0bee3f28fe36d5b6b7d87cf7536ae8c0c2a4eef7da63ddeff7144dcce712c4d5bb157ffb5d128f69a95fad97930114be7f89fd6341e8d46610965116009b0195c86a53f154a06afc1583a87e6df2aa10c4be76453ab9f42d7606b5a1a7c96e3d93b1a8dc244782b85cfcab0744e06a36dadb7b7d2573a7ba3e5b57d47adfe7ae773b0b7666b1b4be7b0f71e8e46a3b86d33c0d2f94d0332807f9ec546ad3efaa9701bfce94d00f7dedf330cbdeecbb4ed8da0d5fb8ed76c8b6fadb777fedce6abfb7bc19cbd77fce736dfdcbcf69685f99175e8bddf792f043a352028e8b69d6d57cfd9d976f3ef601c9cf1b9f5c3c1e1fec3f9d5f45c7f6ca073ee49d77b57d0b1fd1d73815badfead0769c0a937507487a5ab786ddb79b6ad77cde26f033a67a0afb3ceb5af966d6b0f5369b2dc67b1fe0a47a330b1fe81be8e88d370a0af8b46d132dcf5e9c144dc6bb567ffcff6f8fce9dc6b610f7f2d1a8ed7b635a7cdccda60224cb56106f9c71994e19fc66b7b4a5fedda9e7e2b5cd36430eeb55a62d90c9fe59e0c6ec25109de30aa1e55d57bb7fb7b40ab7728387d01dc8c1aebbd5ffbfb25f8fc562b7d41fbede6ff67fbedabbf5e9988af579cbe44e6e511b35abbfef31f8bc3dbfcfe0c96481c67b044e6e5c1f3ff33849af655291cd14f61dce77e9ec9ae304c7c4024c2b54d57a3b84dcded1aa6d2701919fc71ab8f838951d9988d46e1397bebc1575f47f16c3587bfb486ebfceaf128953e238bc2bf8afffbe79f0ae3dfdf7935ff56da3a45cbab7eb415c6a734b64d8d6afb323218f6585f0747d9f4d4aedfff9b6aa3f905da6e30f10bd2385a4dc3dfeff67c361e15269ec1443998188dc25b6999cfbd9dc33804acbf92c1384cc47ddd195e4646849babf76cbffa0e9fff5b6ddbe5535b0f9fffb7fb576f37fd5829ba01c4de7bdddf02997a877ae3a68afbaa9d0357811be5f6b7cad15b15e8add2f356c9a9f2f25671a9dad2b1365ce6800c6ea6c1650e60f8cc01dcc4daf09903d8eae1331cf6c0e1cff67445d51fdc2c23c3da775e7fe89dd774f3ad32feda86c3dbec399bf72fccf49ccd7b15187a158421da73366ffbfff28fbf0a888adaf46ecfd93c411ab7f17f43bdf5deadfda52ad0d17a801741fe22e0f0521d7aa9eebcd9f37b80cc0c8542ff6c4fa1f9c7a158ffabd0fce37316efbd9ff5b7c08c17a1b674e1d285cb162d59b05cb152c54a952a555e01673e0de2a0d27b9f9ad2bb112829bd774557fb8e7b0330e9bdbf01620cf64ebf01a267d1378092acf78edbf559b6f70ed5df005a6f0002d1283c5b3f4d85fdea776a6adb7a6e7d521428281d93e11328273d00a82f236b504db8b8819a0325e78db2532080370a8fc9d60a6fbdb577a825bd4329e91d2a0992def1edbf80b7cdf41e5edb81d43b3cc73d1d3e77c5be5050bd775c863a62a4f7dea0bffd49ef7191059fbef48eb5fe2af4fe50a842229d38ff10b09dd376fe29dae1e6102821413a69ea6e2749dded94a8f79ea0409400a84c5122da02ff3c0de8f6fd376cdde0eef6ba3a51f30e7787ba03b583b443870e0c3a1058d00910051cd8c409bf89f7c795714c2c1263b4dac64140ff7c7fbc77281427a04cf44b725048c16da016309be37708ac5d5fff40d0553fea9fa752bf4143863ebe3dbdbc27063cbb3aba0b16e42ac439e1dedcda3e45302b2383f0c0c15803060b3e7dfa446080800053525150bdf77ed53bd4870036d839767b4ff12b7d634b90986f5b8be31eaf9a7bbc409afaef6b16871a516bedfaafde9bbddb12f971ef367bb7dcb6e6f50e35f805254230009b8ba953efdda6d67370ffc7fda9cfe3b393fbb56d37ffda8fd6faa7de25217851968d5aff9ce702ff5cc72d91785e06a80d19acd0dbbeef6fe7506c16baa4e67bbd4369c8608909dcb4649deb6c1cc7301b1b9ba5b368c42c4222126e1cae49e09bc0e6a62a0098302f02ba342685454e709f3e966acedce36b905589dc780247911e46e804dd0dd8a0e5e5e6a6c32528374450ec8e20baad72ef20126be1835f954bdffdc5858caf100c870b2b4e8a49720e62be0220b367cca8d5a459a647490be1dc9f7208e44a9199d7d1e182aa329a2834b58c291cacf212153647e1886808071f9864f8f99d21b22164abe9c34c231252a2408fac68d4a0514ec24a7a15048cfcc001d7dd10be140d086731293db44d29b0123854d911690e1d1345b6e200c6480ba2614d1659e098257c7e7459e9896044c688abc23f2cd474167372586264008110f45d7e744212e207364b8101979fa1478776c441730a1a580fce18edaef2c23214b2c5488447b3699fc91a21aadc4840a1f374270f6ff1cfdad04ca0d125d569d0159b482b5624a9a12409fc2957713cd969098c0131078383be0fd7b007554afe811b57aa973d4b30bc54221562d475c40e203c2906d29825b1537187c88e21d69d9f12b8180973bc68b9a570313f7c2e1515b9cca76982343495e2d4a0a3f27a5538b1684e8f2123b8d4ba18aa726597028b0e9cbd5c706bbe2aea5041033049d2cd86f073e9d02ac5db063799e7c3221b5e90be76f4295931844e1996b119b313145919083dd93ea74a246871066c6d118328375016066a72393f09939ee2492f11d4d70f3053b79e0923452c651175d25342670d2acae100f8c60e11261b2ce6b72d7aafdd0c7c106a20090be892215982e00004b320825100b11323581f54f118da16305af59a17392ab9384109ca910d29fad2787ac50c28f276a90e90b23e2c83a20c89c4609e6e2044243d6df011f3821612c853162d4f65b2b866f05932e853910517bafe072bf9f84710cfa046587cd45d51c302331496a54b271b1afeaef6ca60393a7bb443c2d68db4b8ed6aafc99fe39fbe3e07709cac983820d3fdb87a54cc187a0dc1e4ac11c36d20c71c895aa0a843002c50da1540aeb20758669ce41101d2470009ba4997ce5cc18ce082b8703b943537a40db60c54aaaa6b4fce08669cb0c0a6217b46954e8acbcc1713871d48f07870c6081d166e38e72ac88e37d7ac36866252580a3829136949d5086788b157ed4515da4391bdea18165d52025804a4c8a120059f35510cda8e06b0bc9a667f4100ef3884061c131dcb8a540dcaf1e8cb880835a8b010f1c08270819dd7d48211017840172ab8f0c4c98009e41c5610443c369d28615baf3dd618e966455c0b4f409cfc7c3888d407a5f632eed579390933a2dd348e743918348726ec11a1ac0554cac02873004b14155806c8311423917b850652021cfb4c0c211e88ecc1a0d6e54b2fcbcb0d428706380f75b8213c118099ac264fd6b8dd31624e156aefec81d241bf0bf89a40700639a4ace078e5a0e0f4c0a21a1066daa2cc638a61c8a20748210bada3220a6934a1e9835665091ac14187e8bc845d7e2cd5cc1994c4810b88432c2bb260573c98a14185c2a338e3f0070124098fb4cc90481e584376c1794168eb80833531aca2da7cb067331179eabb381b435d200cc49f4e250438818e994202cf168a39265b7b2562f9cf4b89371a3ebd8250765858697b5422e34bf311e2ca4d824328403a620ec8b05012898eecca232b0b7a8048c2db6204b55c31a34017b30c0aecab413208ac201dd19448061c2e084495c14ff10756cc102ca741c0ad278e9b40348857ccecb85470d511fcab71a564cd448830975cb05dd151dc0ef9a8aa5478ea1b3e452894abf462540be1eee0427a7439370c0ed1e882012178d38cb485d303ea9e404a3c16ae106de1c123dd80b66385189689334309555b02191ada4581f1478e21276e22bd58d345c64f108a85297f623b3538115d8009b0fc566c0203c0860b1b907492d211e54c1e576c88d4139c9c9a5c8a4e41b462a402797d36ca4e4d046814eaa445c5f41060c46244e08c4d0e3c7d7e0a3474c981a62eb92eeaf411d0be86cf1b4a941a5c426c7c250893b4646c11143c2d831648d490a2c80a5165432330173094682a4ae8716341ba9568486960a18e1131b4316950c808317d7519612800dc0a39f1a0375c5808ae88c9dac4631108214a3d6450ac417112c2c37fa5801e7999a24904d4d1d3988b0d54c2c0407c2a043d51230272c18ec23d66573a69b97093a50a1c2a0684889e5811e4c54ca7b7ce9d4c350ea825c21bbde8706547720e130bb38144a0c71b41619243af018ce616d7c78a3521aa110986a337401476365955505155494d23fc010030827c8853b5262c4f1d3b3ddc8a51883d2738d81442c4640b4a36cf5b8d370664dcbd37025ac4ba5881c114284985c4e2d7e6465da17439c47668a07e09b407e900103b10723d045b7039af9e452bda49b694108f0ab79b885c29df724a65d27090218383833aa2f450d519125359758894234706c1f064b80be30ac497c18d42274374889c718a3186048f2b2b817140fc62154c4af415ed37f25b5503c79f941564928e64c30762f07070eb2af1741a3202278c1c06ab10f2a40842b06426ca4589927c014bdcc658a2f1c24295a53c282458051e1db1ea8f0f078a10f06210f6c950af7325c5cfcd8a2f100a58570cf950d19b78402e32a347c90deb8deb4185a09cde62c4192f71b465504f0c781dd6c164e57880d355d305497c907fb459cdb7b31a1dee4c63a0dde18075868a26f7100966c288c03b2331dc415a3934a25ff80b629b4d94aa0879722747cc152da8ac32761cd89cca58b2000947402d33847a91802a34f088f200808c0e06b62ce0f30363d0d7249324440a294e939331c8be035a7686c41610a8784d22426460f40048ed4dc21783c8b35216872a31ec6a90a02b8201d0e76ca3a551a41b5a9c164a14b788b4fc00fa2b008d34260b0551e493864d62565a862035ad40e81e0c3d42f449441a5d988c235b1e1885f89176e702559b4c17a06c61516c0b7dd92048cc1f23d8236805faac662089783ba4747d32643706058c2b2031b9bd2c447d246cf8a80bf929df067de212e02490cbdb6609944978cf1b41b0f4b80ab08716e573472c0c073ceb9685094ad514dc58dde013ba1e736566409c372471155e050cf2efd5033ed9aa4c3686135726fa9658baf23e8c069d41804346dbb18a6a88e6218a1942901205c1d364ad63ea5a0b24a7a39095c8210a014c62e2818c5d79aa13f0078fef1086373a6838ea1a94a2aa0d96ce053c704b5b08b8bb4f0e4bb20b50d7a2f7b9614c154b132fc612177c5825e4bcb4f111f10626dc841b69747d5db950079cb9343c7514d694dd358091f55271644088095d8c287012302141e4ed519654874459e035b518790e70f164288e24378885bc3387784c8f58a9e568c3888acc17da1b17090662d019b202ad0ba03f8271b26004c99126e1480243cabe432b5bd2092f81116f1938a1b8f1345909b004c5eb7fed9106e0802624c515325b0e308872434d0bcb4b393846220a13549440a2184c8aaf564e53112c0692e9cda12b8b3bf003b0184b2c711dde412b0d1e191482cf071e2d238dce5c154e287189cd1716088122acde446068275c6ea8500259989e690efb84b5a52900ac0105db834a520c2d48721c5b47074932dd921e0432b0e1ce590ac2ac5587458cd0c8c6303a544b71c124114408dbe406cab51d0d8f14ba70a7a3811cdcd6e19e348547b30659f0d426384151a8b4aa336869a2cccb1d1a2a4e9fbc00b10215e34257ea6e68e86a11c49f495398272ebf80b023411c89a1238c9600a2867a5cd55dc18d1e1e2952d3b649e311855955b195592a432586a3359aec39881a6d29e0eaa4009290448006f529439782ca9012dd151bfc8196a31289a600c156ef442a73a4aa88a52d5663d4bc31831a1c058e0192a52bc8170d5b9a6bcf3738cc60d1e89a1a605928564893a3131f3c4daa7f0e180340e1127840844e559bacb805301523353601f1a2b0e626859d0b660dea8da229ae1b37b0dc785a43e64950ec04e4002ce72aebe662dbcc11acd866f090a2d645a1ca031c2f444fea0486b1197460e8ec929b439c46643d21f5896e15e1c4080ccc8db5153bd8b87c2865598943d4c945211e4c62e51300be7084c1d812024f6bbb8ac14f4c327491d567abd654a983833792fe25281a91aeef1c140739cc0c323a0041c519380728c100738b62a4051122dc9f24459a84e29e5aad6a0c2c4c3a07528630d41d6299c3e7c6dba580073558b0205a72b6668404736e6097b2d23c56a4393270e954f667849b9456260f89a074b0f363a5a69397adf918c70a4dcb51df88038514d489a55b4566f4844591116592372ce4c29048488d3ed61a5b318e8821b36b60a542de454bc95ca4dbca88a2cf25cf570dab076fb86200251a627f0a0a9469507321900efa8a00d596425c0cee6b9728cc0226b42dde9847d4805d79d1084394a4a6f9e6cc8a54936559a82aeb409b0c64ac69065e448a202042340bd717404fc820b785fc34310177e7c99b48573cb8f88e666a165978d4956f830310aa0205b966f6ac5eec313799f8dca989757180ca12604f100d8922152addd88aca58583f324dc149953d4e08f0d006858b4cd51f2c1c49215e5028c7005a7e60a21cbb3841c21069d3874f2258d431f4a48d80b17838e00321ad84bc6699c10e34898d09d7a965d00a313d2c5dd3407950578300d5cb881839007ce2c0606e4dd09d4124703c595e6e96b83eb0b00c98af3c49f4cbb6ae943b8d125cb91e88a430f385cba21639bee86258cd71c122ed41878e9a1a7e9274c93a62246b27870d2f28d9ac15d7d272f87e9dc0e4e76dc95c9f0d33306480d230bf02a065e8601e6022c34bab23817ca78c16b1cb1d3f6ad458dc19843a0951c6597d631c3e2944644ac4edc4b507018e10476086795cb3079159510e4b7b5423d688d0025336e750900bac85130f7e8ef0b0237d3b7949c0dc54c1029d4754487c6d01b18449cf10aa91e976318c48b4460d1918485637dd82ea09a334dac208834312d81703cb26c106e9a222d8c12d36bab2e9ce56a10f6094a6606d389c5bb2810f53da1f2b45850a95a1042757d86c24e7bc21a38a589f22f5d4966b5bff10b787c022c12c5c23ea240989f6f9194910b9aaf3e8f0c6d5ccb6a150ddbbc59227434ede1c5cdbaaf0e241786b4c7060fa14b6200e86b163179722105c9c283412e36947101289988eae04b57071b5e60d0ca3fc66b569b469acea8ad5eaa766234056898fd38e74b8a8ab4b852b1d238a0812e8dd2060a58b4f1596a703e8a7d3180321fcb415d6909342c1f54a8086c4eca348252a507513ae1abad7071204d8346bd02d4e0089d2661059c73214171639bcbbd08193e5c04e04775705042b570a391c3241f24785061626fa9780248df48c6910ec29320bb084a4f7ac3f2d91de3a0c0921e20a5e001b78bdbb90d2688833e2c20c4e8414a6720abd7f55b97369eb3090109a151f855d2c059e095418c512a6ac8295c3defbeb21006517d7214c6df4981d0a7bef60d33249663a2011f3848b25af85a245a52016c0a80c36995d8153c72cab08953014521784615a5bdefa68af594ace1e135bafa6385b7850161a1fd4addcfcada60e458416351285c901b228cfa054609e4314fa9612420ce2d604894259d1bbd5162c5802d45956c24cf52e3603920b0253c69e6b0a7be762d3c02c94a1888f1d13fd2a0e14c0213c0b069df45e0501519ad87ba2e8a2772e3d210a795201858842bf8252498b2c75e4d27b550cb333b228c21cbd7705be6df508b902f78e8516a54690854b267a55a43802ea00b8d1bb5757a13b8320e1f58e25052c108b0c0addcd50286a63ad772f32573fbbc3deb38e7d2bf214f6ee9ad92a0399e85f7f961e1c7bcffa72268cb0f7b718c410850ed695c348ef5a7280897a7f0ba170077bf37bd7c2a3a277ab574eef5b207ab772d1bb1885ce75d57befbdf7de7beffd7d9225c38cd5504c810c9a2e1c55f428a2b5d727ad52053c8fda48510e814a12860d58843c099234bc594402488015281410075f09570100f3c0556ac084f01073231264add123c00e0d3240b2a22fbc3a207d307c0ddec9bda06225ebd391e9eca3ea7cf70d95197c0a143c82a6090bfb52e48c58561b58a42737ea28c2a42589923f3648085e73bef58ed645a16c921a5502be9409e14a01cd020c60a1b1a6c516c41452530b2c2f3cd606cc904e12a1a8efcc8a376d222fb3115473582f52ba0841c1a224c7dea0aa0068408072285b87854367c3c517962858cc988a8fe85bf8060a1096450d087175b52001f6698bd65c77eb3b321bf2015495230a1d317512cc282c034c13d6a8c0df15973d2d6c35746202463b5a254b0ea4e14a84a1ec029734602c5058a383100fce96aa58e61247ef2b69571dd149503e61bc5a2b517d2b6bf036284ac8601e310b4c70d10172cba364bdda9302ae4f82478a0089156abd892255e872c7b2ac5e2748faacce24f89bb3e30c6b21cb8c368c9c28d1b285e51580669316191ee698ed900ebc396c109f0bad60123b07b346a3b0896484551d209605c3259fc9a5b8edd89812385b709d1f42fae64cb032e6d1baa2c941115646e0041c143434f2743860725b3823af9e24786c1a01d956e826e8d45d6073488b3001924e4bcaf4f518534440a021608880e5afdd9a5bc51189486be47aa4b90a78ab31b0872228b063f38d78031d9c1ad38a8a522786a5ce9a18676014b4700880f665464320bf23725e1c611a233414a7097403d83aa390064136ef02b8a7c684af0359814394789808e9cc517465c398805082af2c34681c20b303584c3560294107c81c97860420ca367acc8aa72dd72654648a25890d8a00ae996ba04e43b0daf479f1c5ab5e63c082ef38a7612d0010b63a8611dcb143481c960241c193a6c1890170178060d562653251caa0a74e8ba19fc3fa70a26bcd122b5a8a690a8a38e0b105b2210b83aa3004e43c4980d167b4903084daa202c095a318537e6048ce200d7de883faf0c74217992334260c21b0f4f6014b23325974f8a9d2900308b60619170b5eb1154d2f98932b5b5319ba2a93100529e209c6c497048b2b4626191020294552b019d1047966b741ecd1a5093cf0007951080c98150aad8f64654903a23087c8248997e4b3188690e4d6a4293e4a6188145dac84d1b2e6082e85585a07c12eb919859a44a37c04551d48ac46f8708377cd1045511feb2732efa1c596873e617611650f923c176c93b6571285e514eed69cecb15157056127658b01032b024c6216300e7fc8f16e21d06c2c3e2d3674d612a1099251b1c5812090cd9e27606058bc912ef58430c403939c3b9d6cf0bd3b720a1ea62d10a5910860108b0f8277b4d45cbcfc0b1d68d3072e40205ce28a0176000b890d462a34349355284994883c7a1f3862c1c7286b39238582522edf2c654d6192c8c6a74f1f8be089b61502f4267d75a8c3204b894f1318e85960e350854544b78b94a52a0a3eb5c8aab9b229add1240f59642a2885e1f844e7318d3037252256f2aaa224edd0f2d31b1302060e050735a9b8774bfc40224404c65c000160e8decc52b08ed800e0af4f0b2b9f38396b6107b3c78b0ad0429a3a4de45ead3d2d0ebb230c5588d63cfa0237f7e6805da21c7e7a8e3cac055f40fced75a060c7c048972b0a5cfcba40445821c0cc0a9e7f72a1ea030f11992a141c8c0df64c79d70e285800a543a8e7ca88a44f8de674c87253474791163548055c6da2944814c0ca57095f0189032e51cf2ab13a0592a46a488a13c44d1a1e388ae45710e03c4770f8a3b7149f32ad05be98c3554c544da48350919df9d325ba3b864eb1110c5230e862696c8ec4044a81a8faf8aca2206d58baa22709e511a24cd60159766cf928730967a040850610452eb528804442d818e315058b707c1b8d859ccc0d020b564b18efc5a420629f8f9d0b1f255cd86d09209b0ded3708139e0cccc40002210d1b5065049e185692143c7082c5c60317c07b260e0d25591a01360934a3f20fc5f8d20294baf1e62539f2ee203d8889a21102cb53615768c49c6db54d192c694b6687574fa66207c7082341253450594bd1604f96a2091e8ca0b8a0440fa022980c428de47c1da9813cc0e00f21211fa7b1485f89a6dc43cc130f2cb5e9da90f4c023eb75a5b2a06a0461adac058a64a612273e3b74bc7961e2a2c74d20041ace2a4d527b079b395c413b64301581be2f5c5a3fc60c2442b0f4bc90c91418b83e11f3c0f6280482335e778c485479df14c04274a4e1040186a3eb524a4bbb30c601942926f498c93dc960f1d9016c0a9b92c6f5554441bec72f4497e1014d5c0e7568029aaec97bba5075554f5a0c5ea56942d26688073b56160ae55cdda1397049c884c0d30a4b735b6073535d54525400c1b8e492807003f93006c4595501c55d842c7ad83ccab3a448d71d4154571aa4832e21215c734263ce0b2fc3871d97ed05c895ba2b7558f20a465c20893122d6c6098a227e417443090854267f52605801b26003499f2b7d9635020bcbdeeab26ce1014b26b01a64156785efd09863c1981855a114367aece9b1153d13a4b02dbb5a5513d0697e724144819a979bea052e85b6dc5e166bc4804853e7000331283e30f110f6e4413698e60c6cf186912dbdf4cc5f4a43b6754262fce905b2e240881e4a2fb4a6b0d02a32f528ce6c0b10a40078d83fb0204b84bc882bc3738588d6a2344864b0784f242a936db3e7811c42f5a42f0ff0d8d16220a564c52667ca8a2f0b52fe8a330ebf166d929227818a3e4aa61e3838395169beaf9f3a4405ac0a20f2d4a5e100984768b278e428126dd3e7c6772a8464070504e0d7da76cd164f686204471488c020031a2b578935cc6a481f1e86341c74b1a41571965535c0410f1638c0f0a022a5ac0a001a3079e520f0c81393a561a7215d95c4604cc9ba6a2b7440cb1a58c350c8c983234b9439ac184a02c842c95ae141831509b620d1c0a7eb112197794a850c900ca94fea1becb30a802efccfa3331e3ada88a1648202d58865c057dd69a2058c08362991a27825c674d169daa3d27360b8270187468133912955582f00205ce12183809c26bc0d1b2138573218b00951048c6d8083524e980441ca7049893022818133366e260538e3e8c6dba42a042288646938781aa3f506e44a0408ed55951e4d55304df28405bb3aa1e787138b0bab2a500c0ba43054631a8ce0f53b1bc436e8ed8070e40f4a0d34ac814250072459f5c8fde449d3806e3b481500c7c412ed16891b5876980cc578f029e102053c472f6c48f287112c3c208ca0030561a4498026560c06c149a890088c72448491244d8ec0d062f483491cb03f597be836c4b8bba2b2821d3a911765682f0821a01044067a14b478a754d5111467efc49e184abe00a0a60916ad0e5804f6bc990dc24024b41e60e6600066ecba5055c7d20f4382c716090668327b2744aa17a9d89a88638ddaa99ed9d4252b4e2318491cf0102455615b00c5a56693af1488a0d8d59df4c071f55d2064654d9e4b07eb0643800f4bd8d4b853a3c6f36027ab02d5a71f97050318a31be35ca1ec9c571e3913d87a4c0f9d991043e1cbc30d20ae1f0a082dc4d86c3e72b42edc2e228a609109ff33fd745955c638d49e8f31f2cef1e4d6e98f726c44fa78e98f7391a9642aed3640a981ceff67a312c9fcd325f3583c4a9155653cd3d08fdde6caba8d48dcd63e69b4db00756a9df251294f8f49a68c9c1a8b54a40ce844328b4bd928cb4869b1e8e54fad2a63643c9775fe2f27ff542935fa647236c6d3aa322ec6cce4d6ef2fdd72e7f4fb63f22f95f29799d3b9e8a176be54c39d4a592a2b99cba3971e8fcc625269e7c8db995c7aa34c5d2e9149ef652475aa8c95d76c1dc2692c3293bf389da9466afc8f5e5955c6c9b9fed78f8ce5586901eb944e6325f538954ea553e33179f45565bca4e659269edf1fb0b6a7cb3bc78db673f6decb4aa32f1a95cbe4d138d7ce2933c94cca46668c9cfa69923aad2a63648ed3744ce6d5799cff9f97546f5c2e7f8ca4fe6fc566f58a56e757528f54cf4c4ea746aad427e7aa3246e6c5f132bf52ff9cc9e93f52934b6a91197f794a45d2209ccc6ffcff785422a772b138cfcb65d26e03d48fe6ab3a8b47efa5c7e592294f997e6a5c5291513fe771492d4e934979f64ca44c9da5b41f3d43add96b3156a33aa9d4a37c347ea3b2184ba5d278ae2a63596b63a1d6ec75593c06ca463fda6d99bc666be6771691f2927a44268fcce2f49844ce55659ce33fbfed2a2e1be5662773395526997291295d1667e4ff55659c4f7de087d6b6d55fe9e967cac8a973eaff3c237f721a33636a71e99912a44ee3918a54523dd268342e97c82f23bd538a3c1699d358191ba9cae5148f3ae5652c9d934526753e32934a39ae2a63e419d4b9948bc72253a9fc52247589948b734d6bebac5d439771f38393993c4e9745ff8fd2658cf453a95f4dff318b1e9cb354494d2693f33229238f49663c7bdbbaf578b61d9178db7353baf67844e2f2ceb1821d9c7f1a4be5af9cc6cc9979a4cecb63323b16f71c5bca6c1c9c48a49169f433359e65a46c544a8f731b9cb18c9491d269f2e88dcc2973fae50a1a9cd22513f98b3e9ec6b23419cfb3de58dc734cae90c1599467a6515aa42aa5543f1b8fc63ea71139278fd3695c943f3259442af99c53e65499542665a5723e16639fccf1a273cf3953e329f217e37969942ae7a9d26adb52393d27d5c8341e8bb194899cffd4f88ff2b762b339d299e7f433327994a55ef6463f1795735519438dd064dcd3499d8b5365729ee564114995e3692cb761701a915226323632a5465f947eb95855c6787e7b2c74fe3974f658663c01cf297ff9539354e592aa544a95c9655519cf1e6b24de398f73b22833957392a98c8bd2a4b4aa8ce5383b271529538dcad9284b3db5381f9555656cf5b7dfecb1727cff9cb9ac73ca48cf9c97f2722a2795b271665695b1f6019df3cf1fc954c6f271aaa41ea754631bd26e0334c305a7329652a7465f642e7f91a994c655659c077ea85f56fa6768d257651957debe3a3de65940ca7231693c168b4566b17894e31879f4caa3722935c63f599c915466f1e7583fb7cd1e8f48c491778eb5e79c46ead4cf4bd92f97466972995442e59cc56252464ea55fb98ce3657229c56f8fcdafd463052752ea8bd3631c2fbd9fce4aaab2aa8c97637a15c696729cb5a9779e77b5ef38229148bc73dc8abdd271f29aadab714ea4723ec6c77856267d2ccb466a55191fe36bb62e3a9dc6e34c8d8b54e352a994a931f3b6a5be015c3149f554e9b4b8944efd527a94c6b185b7cf9cfa29d31f91dec8341a7d55191b633a3765511a23fff13391c6d8384fbf1c5f687316a7f231999ca9f3d14f8df1cc9c679b192f2938a7546552ba344e95c522f2cf4a635519cf767382d37b24759e63a5f2c754a4a726e7d96673c646e9d128954aa952a3f168fccb2273cdc93c32954919e9a5733129a52ea955656cc55e69a8afe24ba59a9329454a63a5b1382b99d3a9916a946509129cb18fe523d33397b251f64523b38a2b934d2732a9f4532f4dc6f1f16834fea27db56f6c2c379945249219cbc96311191b8fcbe551b954c6c9788e974caaf77ea6fa24d6bee7d8c2d2392799d26f9c9346651189a432a9553b37ca4a67919994fae25c4c2aff7c9c2ee3aa32864ee9dce7b81c23ed3640e3a4f353632913f9ff521a2be7696c6426ed3640a548a7514e1e995f598ce5e972294d3289442b916844f61d9dccd817fd3ffe6471feff3895abcad8ce6b1a1ac7c92512971a9d48e9527a944e635ff472514a3d5695f1f2dff6dbedf9a4729cb4db0055ca57db865ae71b0a2d103b67647179a4ce54a62f4a6559294dce159d32b328fd1fc99c99c864d2c864569531156a8ce338194f3fa0f12ecd89645291df3827bf577a6a7159ac2ae32a9ec5426f9b9a8ce988c9e51219cbcca21c17934924535e329147a6ac949346652cc748d91ba55565acb56f3f687c01cd2923a771f2c85c329154a62c27e5aa329e6b0f85da732c2bc7f42a8cb58dbd8de98de9d18d4d3f9fd63f991ace9c32f523a93e191f8df137ced35f55c650653cfd8050adbf95cb084e999a9cfe2ffbe9742a5397d26355192f63a519b4cc03191d04675c642ae3e9ec8f4ce391298d93c8fc4a2d3e888fc82ffdd3a474ca2c4a99d4aa32be7d755a8c97810e64e631a934529354d928957d5519df390e65fe9cbefb9648bb0d50c031a78c4c26a5729169344a8f4af92babcaf8fe754d43e538995fa946a4dd0668b2c1d2489d2a3dd588542a95c525135955c6f9956af4cb4a3f1ceec78a72166a44da6d80fe3198a74b3959f453e99129277d3149241289f2f12f9099c918292365a652995c1a99c86251265e01ad56a2f3fb2553898c63a554964a7dacac2ae331bd0a6344627ea512c7f4e8c6a0350dc5daf7ac34de39d6f86f7b7ab4db0085e2d91b0aed12631046cdb36060f1af42a1539cbe7e7d41f0c2b9babab8ccb6fcbfbbb4c2b2e2efc785157f5dc564563294a67e066f7cfb6f9d7ab931f4ab4afed02452fef49d9b299013dc0e10c8577b0abd3fa03dfd37141aff25913276fa7125d5964adf1fb0c10128d48181407f152b10436d2bd4b67211b8860db8eddc7f093826c10204dada3c6cca57f130a9a82452868aa14b3986caffcf5ba550bf9aaee2be0acd033fdcc30cbd547481bae25e4bf4faeaffeaeb29af15340ef43663f2b4750454070c14203040408029a9a8fec953274e9b02d09409d3254b95284d92140952efddacea18042daaf0406f13664b5bef5d2a8dd87befef9feadcdf3fd2fefe89f6dee3a4d0a4cc7a6f8316e104b5f739b06817a5c5ba0a6baf9f391dbf89bd4b9d49459032ebbd4bbb0c08c5e27e8c7e1cf8b92a839bf019dc24fb397d6b67ffef6332db6744efd9e9e7c3696c1b4e63bd5f6dc55e692caea7e5e3dbf4e8e8af1ebdfeeab18a13eb0fba5667be7938f5374f96fee611d1df3c1dfa9b47ee6f1eaafee271d45f3c77fa8b474a7ff100f6178fd3eaa7365d3d9797d3b6dd3d7bb7daa667eff6f6c4abf94dbb516dfbc69bbddbb7fa3c2fa7e79aa65adffc689c38ffdce312e86d0d4bbdf56ae778765acd6f5a0a7bb89ebd142ed3da56fc7fead663e7aab897c343a177a9b1dea51af42ec5406a01dc7bef5d0aac77a9afdea5bca4bafcfdfded442291482412793c1e8fc7e3f1783c1a8d46a3d168341a8db22ccbb22ccbb21cc7711cc7711cc745b92817e5a25c948b72512eca45b92833994c2693c9643299cbe572b95c2e97cba552a9542a954aa552994c2693c96432994c229148241289442291c7e3f1783c1e8fc7a3d168341a8d46a3d128cbb22ccbb22ccb711cc7711cc7c562b1582c168bc562cc6432994c2693c9642e97cbe572b95c2e974aa552a9542a954a6532994c2693c964328944229148241289441e8fc7e3f1783c1e8f46a3d168341a8d46a32ccbb22ccbb22cc7711cc7711cc7c598b954269147a31cd75de7ba863729bad5ffbc7fe36dadf5dd6cd7797c9e3af39c1e9c1be6f2a0704eb8bb373b27f479f77c3aa14eba3db8bb3a6886b63a8fcfd34f07f8fd6adbcae6e7f5f0eaff67eb2dd9ae3f9f539b7e3edccfb6b22db373bfa6fd6ae79a1c7d4d552f2383ea518f7aff77ef518e981c0e4aa138eeb1534f6dc428af7d4d5fe97b8ad3337ec5bd16b6e5702cee730f8743adb62dddfa3f9bed4ccde77ee6bb80f575ffdf7a6e6ad6de345f7a1a6c271289bd47152234a8f7a8405180a2fe44f941e381b6f97af7703cf3854fd49e283d5179a2f044dd31e3a6f73ef72f349bff968d3d2acfcc9f993263bd8c482492c1ce6799b163328be7b615cf6d6b1e1915fd674378ec1d16eb97f31f73028ac5fa69b3c98c9148f9c6c544b9ebbda3e86f98409d962ee5188a87f9db9b7f201d076d36e1dba68699ea502c6ee7eda8358d46ade937bd47b9896af38239c36fa24d7f2a20c5042a8a02141eb6dea1e640bd813a843ad2e5accffedfbd43cfded46c9d4bb33d4ac181a8a84d5098de2d73b6de42b745adf71eddf2d5b578d212a9f78edde65adc6829d345cb95de7b19dcacaf59b87946a6c58616b8be66adf614867f4d5bb3d37fe3fe7ab5a7771ef8ab7ef67d67f15fdbd6326a4da3a545806f1bb6f376706efb91c11fc67f6e6743c0fe4bffcae2e26231db01ad582c16b31dc8a20c4678388b36a3f0f48390da70ed6f8f8dbb73024151567f2b54fb6bb2eded6f5f9d42719a48b5fe0402baaec0591913c5266a4dd461ef516a7a8f4a1385a68420379456303a2c2c6128424ccd303796003c34c4a601615909b726861a859e2e25109879159aaa4148028f1ea12f39f71e12469cdc59a0c0611089ab9f0b4e3a0e2912ca426a2e7a360809a9af4e4c1f98a68c8093e3b043990cba113db402a62c583330627ae36f4c170f0923d2f00ca98492320d6a42c0b705afa466f08c812769cc982d070909bcf88ba317c0a086256e715b2d2e0d8ead80334450005444a4bf0354362de9447481039422c28c38112ba40e45bd58a323022f0e236493071f115d879c0b3069f8206868c594d7598512825494c9c106d62f2822068ce8128a2d1857408209b43e19826e21272a0c43ecb6cf518d01ad60dd5609211109370ed7b63702ba342685f1566d905589dc88623bc0cbcd4d874b5081740691580b1ffc0285e07061c5493149a05f9366991ea52d81b2a3c305556534693dcd5138221ad2417bd8f461a61189295a1cd2ab2060e4075aa8941edaa614582d591cc0186941360052d213c1888c11588062c8000221e8bd00bef033f4e8d02e0d502f2f2c43219b0c40d88d04143a4f77b28ba43a0dba6223297b258e273b2d813159134afe811b57bfac85237600e1493990c5baf3530217a3960ba2a22297f934cd9f5438b1684e8f2179960e9cbd5c702b6fcb86f073e9f02a3f00e96b479f1216f89d0c849e6c9f537891405918a8c9e5e0d61f60a66ebd13787250510e07c0377894dd0c7c107ae07e634104a300e227378f7acd8b1c955edc5231038abc5db273a379ba81109194170293a732595c33fa8430231fff08e221148246962e9d6c68f80b91e1465adc76c517a201130764ba1f170b09b7811c7328c272297b8065c6891e5605cc082e888b372c1e96cbcc1713871d4ad88582ec7873cd72634f19e10c31f6aed98252025804a4c8613bbd9a667f4100edaa41391e7d197156f3995a3022000fa84e1204118f4d274ad4212c3c0171f2f3514b70126644bb6bd40216502903a30cd5750ef61a442fcbcb0d4287aed4264fd6b8dd31baca0bf89a40f006d64e510d08336d515ad5a4b1de20ecf263a9668ed5c3150f666850a1b04230432279600df94729aacd077b36fb0bf3e762af442cff79f9cbd3f6a844c657fc03918811d472c50c0320ac403aa22991100051c2102ca741000e620ec4151dc5ed908f8a0ea417a35a08778776020342f0a62989ce116de1c123dd4053d812c8d0d04e0a6d808c9f20140b54aa00f8add80406800dd5226243a49ee0e4aa7f55242302676c72e0a942b9a8d347406be5e7264198a425638cfc7684a8b2a111d80b3f5f8986940616ecf89d75196128001c0beaa54d3c168110b2a49691027ae4658a26ea0c109f0a414fd4a0f6b97093a50a1c2a2a833a7732d538b0f61f8985d94022d0ff2d5c1f2bd694e8a7a8a0a2aa929a46df2e4f1d3b3dfcea6f41c9e679abf1361302832950922a394bd9a181fa2510dfbc755e3d8b560267b8b9ea0c89a9ac4a64aa27105f06370a9ea648ac04c601f193a7d81a38fea4ac20336d96783a0d1989330d2033512e4a94442a470a8441d82743dd8ef45f31e443456f228dfda6c33a98ac1ca97c9ae6db598d0e77bc8d4324980923027d874afe41193b0e6c4e66a29390802a34f0888a8289b6b03324b6804025fa4cc21783c8b352140c803e671b2d8ea088fc00fa2b009504b5a2650852d30a0428091947b63c30baa1725814db425f38403f0092dbcb42d457e24313014e02b9bc6e3ee401f6d0a27cee7ca0f0a140e155c020ff7ab063a26f89a52beba1906a88e621ca190f20d602c9e92874f570ecf3d0db60e95cc0b71dd800ea5af43e3974d05142ce4b1b9fc10e5e2ed40167aed821421d874b521d126581d73890096221efcc211e1c64a0bd7191604006073e0e0c3634da230dc0016dc8062d585ecac131121b50c81bea3668196974e6aa708286411aa26808d4f04646430264863c198e64b03330ff324c41ea9323a3cf47a0bed9445f912f003e34168a15d2e4f0c467838fc3cbe7c08da735649e047b92b06de6085613f6bcecb17842ea13dd32b287810fa52c2b7189f6f40ef5d9aa3555eaa057650e8a831c6646e88dd0ab508d818549e740efed52c0831a6c589e9f4b59691e2bd3bc25777938551e5b1419512679287904c69e75c09e449ef4f3f8ec18d60862c87188217ac560c6012a4b803d117896f0c6e0c180e2ede12df071c7e82e4bd6dd893bba3bbb4176865476da353bb7d90e411d9e3a237575ddf24e4ad1044d96eaa46eba05d5dba08b03964d820de245d7836e4a977641d385335617089b5cd8d076610c8e854816ba585861018357023424e61f16e60ce173543acc0dcec5cdd1c9f5d9ca29f1723722b9b52472032ad0a930a442955005639ca7b8c3381c5a71d0b8b245ce4ace31ce17514e3da413b601b7080e0b9c09b80b706f82de9ebc01beb5bd51b9dd7133e2767553ba451542e1376f3e0f3c2aa6af9c36a20a1399409871518382060a637d42a4de7b3f26b3c938eb57fb2271c961ef1d3eb39b5409187a9918ea735c94ff7cff9c9ed2566ce0cfd61febafda5f6ffd7d7b267a1d66b2ec51f8fef9d4dfbe3a65b215f5ab694ebdf7e81245ef9240bd47a3bd4789e93d2a4cef5160bef41e65854acf235c82d795a8e8f78657c921366d9b475589a2823fe1abdfc7e16aeeb1b0d5dad66cf6dee04e729804aea0654100332f92ea1139bd7723d622753ab1b875c5805da3b7c167a0a0b88e224951656546c2cd17649a45335129431d5e758fd8103429c0a809e0420e4ede181156f65ce2ba3027195ba7ae030e001a779489c874a5b6e4c38c485230ac052274085c90164055718521360d41ea2f76184c8976c938e442a456a45307b41101389aaaa3120aa270b5a593dd3c07c693b42f89e489e044afc2d1290f5ed3d3f70acc9422c7f383dac5424ac98a0d1e0422541a43474f86d91ad6f2aeac431e5887cf835f022705bccc559af2382244186de2167ade0b8a48b3789571c85a22824a9042c0223c649ca93eac2e52e00278fab1c5597ac13f4c481aba5207720edb1ac913a23a2c15faf42192971cb51314e8ada24f1d12243b6dda74655128fa51bba879f47f6890e144cd8808d70da5158c0e89485a2448d09a5e27bb355f22c4d40c73e3d71329a84d5e8885f2ac43436c1a109211fa12e5c749871830b3b789a146a1a7cbdd1a202ca64e3e59700166e65568aa0661092699f004f8f3e11068e911fa9273ebf9d4256a38456551103caf933b0b143808f2e10f459222e362c416cccf05271d47540da9035c448220d04143ab909a8b9e0592240801417483789ce4b1faeac4f481498a962903ba8ef078215985e538ec5026834e0317124cd631465b625b5a015316ac150824080f4d24301781b8ac6efc8de9e221a1ab6e8f9292853a8704c5f00ca9849232996595510afb2386c78c0b01df16bc521a17ae173243244a00d2bb32f0248d19b3a5750f27584b0f2add5b1581177f71f434459252ec3adb32c226b996b8c56db5b8546788cb8c60872787c05cad80334450c007245a2ac4d1910589119baabf0354362d2f64d12460829340319000e882039422c20ca7241ad8ef67c6a7430cb0a40e45bd589b43e3c08c300b783e31b2ab8ac308d9e4b1274f81352a006c7dbc38d075c8b90093860f0fb2692820915962f262ad98f23aab406285998caa983c4c5c98b8cae46003eb57eeadc13e1468f2795e3160449750ea308f0e8f645c35a2c4b20a483081d617a3cd24a699bc0a4980d0b9859ca8300ced3b1c3cadc0aa6270edeba8c68056900e468438094a5c0d08a34ea874d1e826a222640a9911000002000000058311003040281c0e86c311a964389013001400025dae64aa4c9c0aa46992a33848198408218618203020203240a815e5b618143a94b9c6fad2489090da105617efbd55c4a7bf270f29e48042f429084a5150d270660f060f52ea8cc173fde12560a12e49dbc4a035224bf752ab533ff39e802bbe93360d3eca46f2acf5bc1140fe269793944238405a2ced57556b7db3ba3cf799e84de7b1720eecb13e4fcdc5261245760dd919f9c706fc4ff6a6239360277443e3ecde134fb0d3056eb11b281bb73819cc12de469d4060174f60b13c731c36969668ecdc31866acceaba1e03b100ca2782714e3c448468d24ca42e8456f1b85e5ccf18292fc77bcf4b112be1abb326eece396d343a2a80a1f1c79bbb87150f46418e2071854ac07de27ea468a9140221b8c6953a9e6748f54cd14b8e941e7b8f4d2c2ad3e8e036603e1a6a0eb78f14f8b0e2922118ae982abe11ca2ee9f56f17fa5c2db21d49d70a1167a36af0fb385477e190f35891fce65339f480052ff30543f0d495fdb90d600c9878723b80cb1b50a8f41e9e2197ddb3b81b66733297b14060c5b64cea4a236e4ea721f0b5a272a7a14787ed7971844a76f4531417c001cee12a73280ccde82ee576f91c43c6b1a18e4bd361261ef83612990fe783e6b7b802cfa3f459845475661e94a30fae1540a996461a8da975aaac46d349b0f198a4eb76aea5e69372a210f688f5c9efb0e7f88ea6da021ceb96b64efad47ecd15ffc3880ee19ea6655b1c34e34a8da3a1b8f18f59c93d1d5a484fc2863a9533de7c4e8a2ab490bc236d45dabffe4cf887cc0bada42231f69c29bbe1be8843285637aa3b5eabce7b9d07382a7446051e79342d83960e4ac419fd5ab744818634131d46b31dc570a6d134f8f9e7a29a4875c81a6b103ab44fea558a1f13da57e05d779b4e13dd517efed52b023852f7bcd5c30eeb5bcdc36b12cbf67f2272f8e08c7cdaddc43c2afdd2667e0d2487c6cf9556280b4038c156d52f547149a0ec67ed1af816a5283a5047627fb8a6fd38506df3b9ce597c4e4b58ee141d2764fb8c9be500f860cf8a64acdd1f4387f180a159ee21b8ce42fa47714a4505fd346200a9767a3c749778f245dc7a940802352b7399421ae30707ef075b1b78653551f36c6a2f40cac7359eafe4c17e5d6847351454458fa3055dc4bd1f73bcbdcdf482cbfd8ba2ea47eb700ccc785cac6cf0c890c8825961804e3fa70543f91dd22ec5594b434982c8b618a32031681128fd143028946f150a4eab0a5ee1d9f74a193de0b4d05ef8f4be29a5cc40a8b34e0eab89d749ae7e172d7c9af25d474bec4bf9fc3474fad0fe3285392fa7681b3fc20b53671b2cf63737425e49c0b60470a69dcf8e42af9280a322656334210545d3ca7552e18c0b52d1e52ebd317b8e7de84f159ee49daf6415a9c592938dc87c33f8db4b9be9723db5891261cfa47935869d52520f7d26fbb69eb00af1cfb9294254fd56d92c9be9b7d9b288711002dce4c049f5f9611604990dcce1ae4d45597a98834cb1d5c319c5349859705b0244ee6f001fdf2712f83803364b47efaba5b37ba909d394a719cf65504a2998f864919c4a7b2750705373f08599e5a053a071318651404d76ab364bf09065166c5b9c745f38c852fe6ab37cfd5b306c0b838035093ca3027679147e46667404a26538bd9f0fca48b86c88cce60481cf8a49861715e4f0ff500f187de40e4f3ad48b46fcc0d60be4a2eb4ffdc3c50816dfbde8dc0bbee09dcb4337ee5498b55e84db95f76ac8918d6a66f3678fc807a74f1989385917e2ca4c14105a8c67aa7e922f8e2cdcb727d8b33bedf5f340701f96319b4d08c8f2ea36fbafd2d04c818adffead56c5ea881b2a817ca91736580c3a7d204a68858301658015131f8332ac77c51661a0f67c4aaf13deeed6333b7496e24e7d3a8741ea26b4ba9bb4f23cc7362a7454759adc1b4a07f3a593e61c6a7dc16d77de49671bc6270d481893b5614bc11fa9fbb1301abfbb4084a1ff80b8d2c1e92b615e6da11885b8dc0cea882e1478b2315ed30267d8425ce16302f54884b7d90ba72a98b2ec26e5b8e8a4bf4b334799019a1149b1f1d79d091dea65e2e19a8f876fa58431dd22e5d7238fbc39eb73bc743ea1c06e2a02d67f692a440c3ac6bd2080be41ef34aa8ac1e42c83ebace1f4d9a1e57d48296229f5627e24d0acc67ef7ed056efd41a62e37c9482b3819a83022dcda56d16b545b936cbf2b629a3a5e5e371d4659810a152d607d4a37f609eb1a7c9f4b9dab2a4e80711cea7d0f37a9b136a1880aa9af9251e5a2ccc2d098fde5cc5c1e36985bf6a02657cff1015521f6e064c8b81f33a0ee64115967cef8003d7e6ed37f726d12f635586e056b4713c63df026bb3eb500299e25390e33f7a9ec7298add3f500b6203a9b0b78689ce9286e46439d1bdb6c009f8150c6436a19b16f782c43f099856d7936cc145086a0f99d1979522c5687eaefac90cf8d5dfb40b11d8c310e407b409dc7469a8ec40e38af83718f863105cbce34b00323dbc3ee3209dea0a06d43764c03690a3ebbb00dcf019f02c73254c7b341cf00b10bc6dea8d863a38c07e2321fd6c9886d03989905651a5a9391fde6c31904cf5064db13234676b45db6d5721837786e33a98dfd6c4262fb73cd2d6b93aa41929ac151e2332e62db43019f0a14fbb0753c37d6734031098f6793c29e3090ed91f8991dde2143b61b8393b110190c5b8b717b9b1f9451f0d914b1ed0903cc06913dd8f91d32e479985b02c7b141b19e18b72d784c1a05df4c119b8dc8f86c90cc87adddd3274b244773a09c3c3f72c86926c624bafc7960f63924fa50148380bca2e0fe5a34e6b5c07c4f80f7e25de8c5e0f5e01af9a606f1c434793a8e8e813c8745aaa2300c659e36d621a8ed9340fdc502e04331d9f8949569d8942f4949ca4295434562be3cdd38bdc103b0ecb1363602604f6ee0630bee81ad141f57c947cb4068a030307047231575673b1bc11b0cb13011e98b3dda584bb1c70242773bf601b0e74635641569e014fba72c317c2be3793bef40c1e29324ec8fe0192fe42e204e55c27ac81a128bc64c31e3c0c9f14b6fb2e9248388d6339181764468842f54045ccb5d1f3c9df503fc6d0bc6572dad434a0f93e973e50e0188be081aa3877bd76656b9d2616faf3ff78cda4eb1833f8b593ea3acee0dcb4f0280f2457d7971b2cf24fa0ee7ad238ad631a48b22c8533e187aa97998c9e62c977803c040ceb7bdf90825bf1c46dcb967a02c6b75caf2d7006100c5c00d0e9de1cbe7e6b8ca1bf43842eeee88c50dcf55c0123f7c856eed859dfc4bfa099da834a57e35103e4cc9582f544427fe1c1ec730595d14461c4969430969bfbd779d9065a45f4763fff12fe1d983fe9bca9c0f4d4c5f0fcebb6c311ffc43b5133e4ee28760653b673ff1ddf3e9224b4ad7526c4bba3b34e7cfeac8a4a62155b3662b116e2ec0af2364577d0479eb023da51d8b63bbe7351f832e18a27813fba3208b84282369e5dbf7a51aece7e967a0799c76c88534d3e87211e0deec78fac4f0a474826bd958b42e275c3950d80f6f0a141c7fe44cf92f4760329113fde4a8969818ec8d53c9ecbbbf80698a9621097dfc0a2ec9276bc3d9b5a8dcbce53b374e45920dfc567d9acc759c099bde7aa1ea580c5a6308c12be713768e0ed5ffcfa885b005307484d8963a0a91848e44bcf960ad2984af1f1c90dd11dd776063df630b34cf8d76fefd338c023630091a92be958ea020a7f538d1d5337adf510cc8881e7c4e973f7b00e9acf51d435a2d63e1c86749baf878cdf550ed27ae510ed17699f4f6e1fccb2c451c9c30adf92f5dc0fa7bf84a951f7202cf6183613ca53ae73c8ffc27ac0475e10f86cd59e379579f11ee27a005c0b115c0c609441f1a0ecb82e0f0bfdfd37fe2bde05eebc2ff3591cbfbe799d8eef1a4955bc666d6a1fc4cee1a370e0add3deb37192bdc96d261ed28650faabdd6ea238f65400f7a4407921a54c533fdf8739fa01c8a1a659b04351f05fe6c328fe522aed4d9a1d4b14add9f31b84368e556f3ce3422a4a8b615916308134707248b18c634642051c72c6e0ed9663b5d13b6deb9744e80b581840ec781b2fade84e5250a277a964ee8f7de2eb3d13fe9f06d47baa8d0ac7dfcf737817744bbec3e5972a5a401041862dc80ee1a7c2753acc9004ddfeccd1eeaa0c809c790010e1c0ceedfc66cb2b1e57e9f64713bb21255f2f4cd0e199f8b51ace4f245f2e26bc295a33f115bf7a764fdfbe50cca5f459bf30baa56d0d7c8db6dbe485e504ff9a81b8a9f9f5f0085375203d9fa6aa137bff450bc3f5124efaf8c7eaaa3004a1e592ba4375522e58924b12ae9954ccaa793b408a53fa5945d2a79b5d2316229b55a122797ceeba51004935f313dab9229a26812c9aae9f42a9c72fcb493dd503efd29a142b386b2a1a2bec9a8fc74944d485d51520152cab496ba28a6420835a5a1a78e08aa108aca4852bdd25429449597aafa20ab52e92a81c2ea9fb28a21adc468abb7e22a9fba32c8abcbfa2a705560891459172a2bbfccb2d6597f84567c4acb5f6a5dd05ae9c5965bb5f554722b5ac165adb85e48ae109a4b55741d525d09ca2e05dd75a7f08aa1bcbca4d7aff60a487cb9aaaf97f22b457f890bb05f0a2c850433d560578bb0282acc5386ddabc3f208313d25f621c5226b319f18bb4e8d4596632e7aec4790e557644a92ec9f264b23ca1caaeceab2aca38a88c2a833a415b8c6a68dd50b8c752dc0e3048df254e04f282fcea1fc3dd2440db5ab23eb437bc0b6cea2ee7256312320bc61cf596cb3405ca89ae4c62603e482764afa4a22b0a59c60e1cda8903b4ab56970c17e48ea08f726b8a3d373b6e2fd29d2a7f7a6f25952766d538411dff8e748c21188e9dc234933f13768700bee32cab62bc13752a770854e88d92074e530f8cb9b4bb02c542afb9acb146203012b83352facf05d2729716affc2d303a79869d4607c6dda9426841edba0cef311c2b59e83883eb64aaa4b0515096e08bd37547401be50162eca3a1e8d9decb8e1b3ae8596bb741f978ffff77735e2c58d05a74732aeeea6d80d0b58f89e1f1313aa0605f23147bd06d5b3dc0de2f1fbe982fb882f3e13955d566047719be9cbd95c38029e8691b68c3703fe806a0753fae986c2e049cf4ccbdf5320ae590a4427c2678cbad88ca1a058ae499787dfc4ece71bf9ab21fb00fde43add60889e01f45337e2fbe80540cf067a33440fdc4637d4cd5e41d11df4011df8199570b16d024dcc643e8134e60752317a63face3adfb1cbf8826cc3b64747890b6616148a68e474a9d80fbba73cc034e0c026bc457f5d68f48f60ac73d7989dad7a68c8908185d64b742512fd2e98620a136fa7060e148256554b5864f23e98408373ed9fcb5176a344d70ef33afcfb18a2c02b4c37ba362ff2d4c6c37914ffbd12d1ecc58facf56e62215871fafe699c697a76d000f678326ed21efde19265795c073f80fa1fcc5b671e2d92223ce69f4ac44438e361d3d4cd6bce9e039efe51ed7b1dce7bc78f3ede2f3f37580ca6191a2e8924a2eae54f5c9681fc2abf11b0b7fa067afa7a4719a3d0e25254d589380d5ed3464670e2ad6c0b5b62e425c8f7052a4f8f51eb2751aa11ce70c2948eb5884cee36dc3d41946195d7e145448fa884867f0e2a224e14579218a3550ef9ed0bf59d830c8c1f834fa4a651a18be05231ec5783fe1089e49c7fcb17e8ce821b88709ae5cb8a98a39f6d99e795cc38d5b9746b9a2a6e69f056d0e49a222e3270499be9c637a37afd78ce75c20cd841e36847edd749a7608759c8d05daf2ee847606942067a4c25b4b0985e5e1cdae066fb1847c79c281f85fdaa06ffcdf51b3a70be9e5fae1986ec10db249ac08cc04c788ef0d26e0cb99ea7dd702f2385533ecefe5cbdf8d4e95cb5c24a8842af700f00f29bf5ec867cb9f88443be0ac6967bbd1acc23793c2bf6c13a598e2e3b9c27d8857fa22fdfde58cccbc5afdc448f7064ac1632bce1f98bb584faca48d8b9af9a16a25129fdf010f7dd5c15627d5a2930db316c9b08c7e8de3ec88d14adf643106ed2986b5791c4499a3b3aeada09321aca703cf35f1e4dfa37ad4ae0133cd539649c5add88e7d84e5982b26f1ca294e6960477d7d7052a7e049f228f1c4cf78719dfe53c57bf06189c1595049c9df798e01c40db92acf74f09f8fd7d238799f72e2099c9dd6965871059d64d7f93ee40303b3f33de7df0f38717a1a28053649be86f8c38ac0ec9d97df4d2d1c6ecb1ec2e8f2d5cb483ff342922ddf964a94049b7cd3e1e2044166661a054aa728e351f2f0e9d0192624bb46693763d3bd1d31093a180a0068f5765cb13bfd8288bd7ae02c26948e8d1e18dc2d89a05721e4cfbe03eb3fa4f397b6c961cb3cb65292abb4f9614d9cdb134637fb1143a2176ea4ba4647df172eacb8ab4bee0ddf5a5d8af2f92a5be7c90f581615706db1b7a2fbcd0ac4e3fd294d4fc372ba4125edcbe8c717dc08d17afce23a8e6cf616d98acbf628bae0da2f59c745cd95a0cc39d8a2cc178e6c4f554064b98d92326031f252fcdd808377f1f73dd317f103d441abd5d5233e71e0864e0566ace1e9cde541bc63a843f0139541b2eda1797181cc63e4deee0a0bea44ba7bababe4b9350f2f4f770834caa40b8a72658b66461fa3992e5ec445c01a00a6d3b088a3108346e8630d4180c1c3f5ee0d55325c2f7ac25c5bb157343c5a469ca1d51d49cc2637a055d1a8260c92ea1eb1ed43d359b54dd8dac9d04f5ad8747e91ccae405cc5fb6ce316bf29233464c4281525546302a9796e1a8b88abb9fe7b935e19e614fa6e35e59733d6c82981471b3f193fb488df86c5e250ee48a5c160e9d017012b7dc3977d8bcad4b14f8a31a5f7cb3e07282baa494892b4c47c17dcca254b8174e8524064b9d74741c6f944a66664a10c21b352f0942f1b68d3937943befc27ebff84e251ad8f26aa40cac666e81ac682e6f8bdb3a94e2b610be6384e4ae50fc9f6f845b0a1d0bae85917e09b477b92330f8753c51b897263f7fb70cf932995fd444b4d0bccb5808bc64a1eef26efa6d4788d81b25b0907881703859f51740a597e22db6622227b454d7b620095757cdfaa29f3ab797efd0e194478618a2ef4974f30b5be7c49b96f8ae85a828d8b19092fb754b9c3c3808cd5377b0a11980045ced28bb1c41f61446b30e5dc2f3a8d7162152c43b6fd1cd009d7c5ab3143346beaeacd1c05505d6fbf51419af0c30673d76420db1ea93c88b6a83d925f259fd8dc980e235887e5deab625596fc63963b941ecf22ca8ce3341b27957336df0fb1fb22125aebd08753c8b3b169a701a5f4868516e13b8fc26185767dc3eae51f1e606bc943160eeb559b7cd0a72f23fc167f07efb200caec9212fb74c61400b24be5e5328cc5f69317bdfa4d79319205715fbe7a77e327dd005e27390b3935c7c7fff72c2b542a8164f07d1de12ee5d95f9cfe115a9d6a6f2de9cfbe718fadddc4c92893a56f7ec4d200f58322bf67f891ee89c03629534d1971f5b5df58b4b169395b5c12a4d3629f5c0cadcd7f982cf13923db111a0ef2cb21ae4b0d96caeda8d1714a49a8d03c6a614d264c53afcd986a4a32e8d49e18b1422e655ffd88f467f132a817e46d89c09ca8d33ec513ce69364870ea0276b6aa5302b283344225eae3316a52f5e0b5a153a41fad6e66423dc116b93c0cbafb8d3e66ad9ce9273d7436ca6db11a730024ee24d83c454644dbb0a2695694b88cf155769c450e1f7ac1397002e3c6580ddb467f20240d356883068dd78f292705bb55cd36bd966cb7b3adfc2f348b7af15bea8cbfb9152cefde2aa6ff80689101278b165c794056e6d526919ed5d7fe895f52883c10e3a072eb7a6432d7c80944db7649c9296f3c5165ebd1fc21444d0105ac9750201824f64ebb6c6a1f3df28406d81885e44e29db8026d28ad4f75a1fd3c3be87eef207457b2ab18fb6658870696281b7acb4ae8e908a24c48f4a9cdbe88ed067c1e448596cfab92f67a48f527f4436ca5fac40381d4aed9386df3f770c5e033370a4a0cad0b8d0134ee6be89f2bacb1d1e93be6c91cf6667d554efe85798ed53656a99ddb68b8d1a2c655b54e30fe57a654d30bc09255c60bda3d02647f29dc01de661d446c03822dc761035215799fe5c72947b82ec6991f498bf8b52c39d2d9af7a0d333a7a9a4db8a7d01efbe55f3ca6fc6184205770241dc0d4cccf1e58282b786fd253b5f8678970422c1f2845762dfaf42f53a0cdc87a006c88800155188d4f53b12ed639b2821f9ce3d16d0f307a3d019f8b6897d157d4aaeebdf9ca2104d5027d2e628f99efd47780f41ad1790a3424952af21be6d8c71db322f3b2aa085f03e3f141ad03fddba306dd5d98f8985978e371499743d8489e6cbb788342a449076f1cc08906ddb5987b8fc16b7764b91f941591bec86ba1bb0c84a46216e33c43f3df110ed9365adc68c74f2249cf7f61ae106250a998a09bafe01dedfc9e2886af67b8d74f3a06656b0ae13c11f5bbe606c01a41f4c3ea6d8a74dd8d6a9def0299adb74a35203686175774f4500c74706395e3f78039d8f069a89fbf040a9141fdbe0f8ae85e10139d2131ddd628d031a917e4856f9da030eddfe5951594c3c73521771b5a2ca8b4f46c3da7a77cfd818398e472f6055273b5714473eb5072c7710bb3c0b31cbaabc6e78cb62223f1a1fa7bc15eb594220ea0849c4068f490106aca11a94dff7c7ccab9a149076c2a0368b71902f2eb9d271f009d8b7e9c3ab43c8288742d4a7f0d074464fcf91e25f3486b60f43982494de4cc601b1edbecce825e5fe2867d94cb5acca213a28a278834f2051d4acef203a927a49bff9941543a23deb91642c34aa214568418d67ec1de7097a43fac7d580c201f01102e7f431113eaa699917531a1194523663ce8482e20e045a65deccdbded21723481a7b1f2c4d61953ca13001ab9999483e4f9c2d9bae92c1f63c15924ace722bf9e1d055842dab8b27235ccde97b2f947f4d2b802d610b4c38817b290af8fe8d7a1b99eb2b3b73035277dd0cfa1af6c9a55389033fac0bfae9b2f4d309f8dda0c42cf8e6b42dc8f46f113e83cf0942c306854604daf5747df05fc3db6379e3c1c5d644b2214947bf7c694244c80f981ee84f8c1c701fd8cd86fd7895a3bf438faaf50736e2971f8256bcedf7204e86f993d95a08c0d3d263c183ebe373fab9f913ce6b105fdc4c391707a526f467bf143dfbfb22f1107d3cc9a7d629ec118a2b91331369ec2d3ecd4d1705382fc7cefb66f707f82bd74ea098dee1e68686e5da7af2dbeaf5ced3ba7d744f127ccde98b71a5aee7c48389239b3be2391a1ae8c74cfb5db8fb2f948a0e31098f3baf79682b878297a1b7c8c6d69d77e334e566c27e3f9cf829a0c16eeb212baf60bfadc6bb78d5cab29bd371166d360a7f3d7bc13eb21584908688807fe393f8e38db6e8af7c8e9a651c255354695fdd0923d873ff4efd94a3f0cbe0bceec577e6d55a6dc19e18717ab674d9c2c4aeccd704a1cf6cfa5d1fdc893d1164763b9f7a036a3029ea8a0efef4cc76cc45e8596c40da2fd9fa173cfd7d13df7099b7a2d7502444d05ee1c7a6de135d211833cb089553d6e9adbc0bd99a47197940f76b12fbd208e25ed3eaa4c4970f51962399130b30f69fe8483f596dafb3b57348f597e2ac987d99e66fa0262735488856d8541661f8365a35d94ac80bf692a0b287e2018a1de2e39aebcb28b4c8752d808e8cf82d595eade70d54bd2e4cf4b62d78dfdcacf54fc534986078f143c55e4bae4836450c6508c83ad9785228d3fe15c0aab87c24def4582dd8e14c0fa721031e2b9b6f25fed0ce03f1b3c8238a1a8876e6ed96d91ea895c1ea60caf1e8c9551a6f9d60fb314925e2d74ad893d633157f5ffcf6e96e7277cc9f550634422fba2f8a609569a477da091765879f0b3bc388c51d1cc08b2e6be077af81403890d15812054f4ef8025d483a61df568eabc74c1efd6d0729d80f0a680cf978dbcbfb0df5f433820ea086296bd0cb10cb1e90bf66ad79ff71cdd0832658a68d30ef72403804a3b9668095bb2db2c954f8eb48af2cca9c297bcbf9d3fea5e8aa0542b09d3491017f347674260043fcb49c1a8f4eee1793a08b057e9fee8834a3cb9b5b89c2f6395bf39ce06e68d0ef4c1c01676ec1829018ef1a586e0fe1f1ce8bcc99f93a5dfa6229fb41690ba0c23f279564a25034f0617faa5a82a4a9af1e262fb79552cc1e4d188ab28df71fab16963bc6ba83b94a8c05a023a3d696a21227c2e782d75172b089ca866821683cb040a0df8841db59959ebd48db47f846235dedf4183e379595a808f7c478b1a669f2dad68ba0a60da90f442450a2e77a86a0809f7551529509190005fa9d6824253cbd731ba97055a2c095ad48c37e3e5c2e8d4999531c40f77740dd2c7d01d3e583742716d938b78a678d77b45d7ef57bef89982e9ae7765fa44306d2eb5582b9b2253e8ea2d1427eb06929546471324ff70b45439d4f63e006ed782b3212705a0ee21145759e7a4fdfb0318ee1218e54c79dd49578259165da32991ad11ee6d052d221b34ca3cb9ebb1fd70dcdfd40bff9564b9c8d9f88f90e4be3c0869f84cce48cedf42c8e4822288456369f4dbccbbec1813c876860f17627af072417817370541f73ee3fa2098940242f6191ae647dc3a1513601adf4bb3bcb1d9339554e62869f9b16e4e2ffecf77f0312cada8410071331e059d24ab5b68b86b2dd5d4baf7e309bbd38c3fe58ee9e4828632c5f1af6260ed12f4f5ff432d175aacd9321100543b5b3ea854efac124aa5188f4d9f0d44c4ba8aa6e4cd383b68703e73842b781750add9b7c5cd5f99aca586dd6d4d4da635b0767f4b525ab0b0b37761c39ab257cc66cad3835c68a2f11740a04b4829a04bdbc398b1f1cd995f9bd68886caa0a27b73a0f470728cd98940b29770e2f7675f0febb5f47715a1b3575e233fffae9ef5b355bedb7a8eca33b774edc15c137f4247caffc17f2921afac79e9609018c19b9320949cbf70123311eb90c7299b9c18c6b26ea4ba8e5b89421df0cb919635f5b755621e4fef5f1948b11cc83363d367e6bcd53dc312421da68f6b543c49cc38e4b94fa1d9e5118b06a7a24507cb279c2e3e5b7a13594ee5ea12fb393e6cb9ea2bc9aa59148dcf90b119bb89aeb0e8c542676a4bfa689dc8d210c22be6e231fe91b1218379c121b3d93d9bc02e8ab7a0d4cf44424111acc3a06ed9725f226aad1e1c5022c82155aa0a8589657e4170d14d046e3968d754f52de66d3bca71ae908faa41e1667363aa469945681f90c056c1a1a88cbeccfd6900f8a5d8810656935b133e9d793dfed61a0fb5ed6dc89cff070e51a8391064c19ddd7db008d42d5ae31850be391e12f5bb8ab07b24dc57992131d3b2769088a0171b944acd889d5b8e5d6034032575ec363571f08171e1382d63a68aaa34e34e4dba6a235c5282e86ccd152a310bc6fda46f0b832391a00d346661625dbf2ec947552f0b60805f4e241bd8da27ca947d1360a7ed93a0154b8a1df862b956582da496bbbb9b40eaf6cbd8aa850a34e93a2a28f198ddfc6531b6608d31db647e58461d119a4965bb775e78730d84e34f66493d6713bbb3bdeaa76f00cb329d60cf3ed0e72d96cd87a96e03ed84f1d0331a9d834231d73ba33c5bc907e45cbb53d1d68467cb1642b0e2e17e241da46fc6ab929a6ccd93bbe0402777d73bec4ece166a12ec7ac3ddc07de215cbf07d04b72b7ce126a49ff1ad8f99a4959c09621112e22c40aee7ebda34385a13c4a98584dc113f76e7285c8a67fd3a9d02cbc538cdf3d9258e1decbb2fd557f5dc848cf2bfb5895eae2b41bb2bf82ba40a5bb7da04b3b0ce78798f315bd5a20557781d8099176e6055c5bfab0d209c8e66684c55f72762dd105695e30ffb2188df56c6f762255db64201605f029af0609c2a34a916c3dc846552d63b8b9bdf406b05d4cff4bebcff848edfedb46c53572501839f55df0a1da955ac321234646b1df46f3a3115774873e660425a4a6da626a85de9790fa4e1dc45713b1e4e6e963ed3d4b0d7f19a9e9833e76cdf742b710febaa9d82396f6c3650215492357f1a5adc2e32d085b638c1083df91a56a88bdda492be29bba523ae333e2cbff18ba81638fb3f53c3e3ccf3667e2072db2c2f1b203da49760652edc0358f4ec0a4c4e897871c94be2a2207e666c0374b4b7dece309cb7f5e9f1b77066bd63ffce669c42e20752859d2496f1251e48290aecc12cad22123b3d285e5e1de1068df6455e8f6b936a504110a80c737005a5c83f7e171a863a8e5fd6c2bffd770f9d52fa46235a85333b90b32a5a0d2f5eb347983d37b25d4c085f3845cf435c3ef0b2e73d6eace1d6af317f97921d538c92273014c1accb17c457838963b1fe5ca442ba9aac261448f761a3e5bac7b72d319b2293b43f4b0515e9cd9e2b3c469826dff94d4f187d4410f1b0d8c729ad7c6b13db089a7b6023d680c757acb445c90021b6a5ee041a7c6d62803bdd25ac7a5f72db11441549071f00a57d74ea5c857db84b79a67b510ae61205f1a8da57c9bf366ec5487c15aea5c1bd249a5c155ec4aac759fec30a0ea47053a395790d230d34e0c62b9997bf4773d214d5b6e1e70d07772373a1c1feab46fd5560e262ff94d83633c5ad2da52d4894fa01ffc80b23fe86547c8593ec72b41f597db364a4c8c3e6eeb193622f463dc632d24c275a24af691ec0d04b6e05ef9e91ca338ec567bea3ce546aab50691f7b1c43cb60d985a4430efb8d839c4b1509f1ec140a6ff3f57a6ef996c35d757bb44081d2cb7bf2235bb9f4b3cc7dd8c60629d1b4674d242b481127b6f589113a0c51fcd412f98333452572c270f4c1e81886613382711bcf1081fab107be3d8001f0f104ee103b3dd5bc1bd7e8f9dbe881b7b0eed3b1c7f4ece6c8ffedd0f1fa2e81bd3863c6c132c4db4e18f7c7fc417b05d0ff434f51f16a799638549bcd27e6d95d686d65f532d66f91cfc325df2da24bb3e67cde3d929a94dfd68c23bfaa5bf8e163349abfe9ccc9dd624fdecfc855c66e72e06e3751942916329d2a38852af78e096bbbd6c6566c80d85c861e142602979810be8054393f434ea569ef3f27d3e40560b5bfe42da80b00fe367e4f42cc35d8f2d8ac55a136f14501a191017418447dcb526fb1857acca78bb473b1b9c47bc7ffaf5e374ec59991b7be346a9590013b11fdc7e021ffe42a6023c66e371afc5b0ebc73f386c5f575972018290575e4d5d467dbfed252f25bab5c6be00e40438806be8a282c2cb3a29dd2be18077f88ec320cf60c37cc3687b724e1d07f5ca0b480af1c31051036a32226243860eb2df662ff24a70a0fab3ccc41282645a469d6caaadd1672511d6d017ed4ded0a7a4d2e7b94798c75a61381ea3f1b3304a06bb2fe648c312611daed6832f5509eea4fc89f3c6b5d76c0fdf594c8c7ac079433bf1105dc9a919351efbe2dd0e3061f76a26e98bc02a9cd881a53d77df390ff3dc8b6f17733b205bddbded023916f7ec179f8c4e0ab197b843ce84990b6fff69b521f989fccc0ee5c1a57baf854905e1c80d5fc40fb88d343f43db4988e7be96bc3ea01b9adbaf9cc2145eb65ff9937e2afe655b8b0f749a16a5ff55f463f16f8e61c0a3524d06dabc0293eb51e4de36ba108179913d028f32be20756a8dd815694dae0b9c20ce2b40a504d72c39960c391d72160e78efa1acde387df41a7b19eec275f3ffee0085ae485bce25f057d0e073cc0ce80fa26388cd74d61c377797b8b91a496f9cab7544562a0d320e84d8621f237226f4deb2ece7e41becd375f7aae7a790b040154cb5414ebb88d4141061215d7adcce7e230a760cc58a80ab6b081f45800a4400a3dfb5f8ae7fb5b52f0a139664f3e133d2ff73b04e8074ed5ecb2c3d01a15bc8260e6a027311ccf77a19fc544129b626b5ae37483f7912847dc9de79e2d33140fefa619311b3f946ccb0ab7e8c1268e611ae7cbfbca1a4fc721c81f92fe0b6e4639b08eea0ce17c07a47b9b5e2fddb23d8efc6f4bca9d70177d35f7ba87f8ad47fb2e181a4837a040f27ae5bba43d11a3a09e726289986c5589e2eb8301fc740f121c9e625e1ae16c9d8812c1e3f16e5f126d3e54937b1188481cedc491a4f20f0ab53e9a3fdf3e889a95d27fce2c306441a3145dfe4235caa7aca0f84aae9b0b645ac3f8c5ea57639ac900baa6534575766c41e47f01d0447e7261cc3e2fa03507eeb1271ab88084156ebccc1da8f57a2336823dd492a6ef5b58e0f9e705c54e8e375137c4f3ac470eb06d32b8645dbffc30d60648abbb6b05cfd42f8971a61323131a28dfbef0e142a4ec3849eba6a23bfadcc43e2c8f899394eb64db32e2fbbf84b8bf382320bd5fcf02f332e799b0cb7190a229d2b7d4da03a3b607a641e0591417fcc238a2e43ea6f9aa4f12c26b9dabc15d49676257b84bc9ae629caec63434a48dcc808a9b44ca8961f6c279a2b7c051fed5c662a3edc2fb8a5b5dc2855ff89f1bcd20a59d9689e7e454af4e53dd392aeb62e2454b5ef95851f36ff373d9af87583d2647531e3c20dc79b66aaffd14e752bb36980e3b05718b345724c6d30999cea43b1ed3ec0f26f07394c1b630b930f07cda2e955485cda93695285bd04eecf7ac06bf3503b61517713b0426ae73bd101ea41ee1e312be171705e492af9498533baf43796ee746074de1e6201e229b06d894ecc79188d0981744cb02ef8697c9e39da2393c9266cb4c03138d5d512d9c2287bafc626c384047504564988c0768274403e79f704785a057584eabcaaf64cb71ecf7fb7aa77eca82b873283ae706042b422d1490b8ae3d981a0e980f14b632b463596170c0c03b36f926c85605912c6754a7bf0783162815fa52ede6e5d20ec7e4b2696827810a53e41d8614b9e42d14062b3f0e46e3d85d5dde7d4c6d75e5381e02e1b43451af171928ef097b2d75d1ac60933edb2507a7684b5ff01af065a666b003dd707375fb06b5bc8f94d013eb4aafff266430c15ec17bee57c4ccbdbd8982dabd4d974c8f5e3a56a88c7861561af906ae845b001464c6a14b72a562453b53598d93c32187bd9902ab2f88b9f7510772ab329ad4bfb253625efb6bfe8345e1eb6963162335272f9d80a423621618daf67c952aef643c1038f1ad14677fc8d1e1f61e49e18a75cd5503dc78513d9652288c3a1f4a7f1c0211b0de78206f6249f6593f746c05384de2e4db38afee13c90d806f14222f3dbe5d4c43d700b624d7fa06f41fba7096ebe913dbc8e26f34ea4871af20c7cef5242735e4013bc7103bea6547c133c43d536c0786570dd608754d0f8524c043e6e72c32a51de52a6cb25cec3fbf1fa9644b0df8206743945b6448e904b0bb6f96443561fe092d49d1ffa3b88da9622267c320719e5c425576c184325ef9af33de387be8e3b25276b4f37a2e9075b22713a85558ec683bb637da4395327a8ceff9ff7b9e9a902e4512a49486545ffda3e0de233aa1173fca41c043a87b2434d49e8b09efdffd787ffd8493bb85ce498758a34963ccbea576af51545c525e2efd1938f3d993250416981ffeaff8ae10390a851d67607445245438e7c54c44a3a92507c84fe15d4332e6e81a117eda373e25752bf2bdef85f14266b4437dd96fc640c301bd923e7cba4b506334b2f78306fee80fd81b200949baff737b7c2073945738e24f707e99f597c3d5cee26aef008a40dd6350e03ee460caafc5c4d48a5ddfce7b8349f956cf7f052f2e49e8827aed54612b0eb9bd21bfadb7aa1687ebd0648ac79a1b83c86226c3e161fa6d5d02608ffec357e400fabe3ba204bd7bc3e133a2ef3d97e6ee4b69703bb3163f01c3c723cb7465b06b7bd5ec732c7436b6ac21e2f282b2fbe931d53167ddd9ab8ba192a6f1e962a495ea61dfed91d9cc836eb6723074b9a1e6dac96171d9fa44ae668fa77b4de43c1e16f84d8a034267229369ff9fb2efce5ad0667baf9ba2bb7eaac153ce8c7e040528087ec4c8a75817caac8067fab8787eabca41ced3406cb9ff80b85e238f16c7152c223f8e4280a11571532916d57166fd862383b33984fe3b1e2f92b0b124acd4e9a27f64ddbae42fbb745b0cc974d94953f5031f627073d400437ee5cd3d6354b9a01141ba4189807f8a361923ef92f3022c8328293df4c5765294161fd23ddc8f3760d765730101f631348101a40fee4fa8253fe24bdae81a5cd1036a13c13454c95d1296b119e56a130557071fb82eb68e21184ab3c68901c7f5c69fd02ac0ba8bf374b70254d7281fa78e9b283e893e3f20229c07ccf61f91f9e3fd974a205070bec5ae5420254f11b3bae2e37608b6323310e9597d7caaa982562e7872c46c3e8e04825c4caf586950730a1ae84bc23789519c98a4e3433bd35500699b839d82184e78a20de12d08c82045f98503201300169fe021767e9ffc5d111d9422d06feb7043fb01890cde1c672787b3533bc9760e39899c6500435e9e9c1550ad122c4c85320bbc7f9a2b307338cfbd8c8a1621cc9c5c7072854aec95c70c5b59689e941dc5891621180851d73c28d660688e2083914e5afd69729368a174d630514956ca1d39e1eb8f01ef8f3db4ac832680dfd1d37913729825b8a4b15cb567566d48e4ad7ca0ee70949d6c793616340870c57f2380db0baea043e40689f4e6a1a5d60f5df0b36623d2e95df9cbc003db4021ab095fd51b398131bbaba639c5e07c63a04cf6b68efca4857047ad8abaf5b39bc1707dd28f8a51bfa08104a25d7ec90bd47d08dd9c1974f606e8e5e55678685c165ad564a38b04468c405c721c6de47a105b65376b5b20ea8df6036cc5d7eedf47c6af4bf7466a5b84f803476feb9fe56ad0baf8a8f3cf82a1a74d1c08a56bdd1debee69abc13e060fb2d7d57ab439add909400ae475529b82bf560ef3f3691732feb69e8e6db756a7e5edb9ce6f9c5db39b24f2455cc9d17c9e998c3ab0ef447c358757e10e6b8a062024767963e689a22b954d62c05ead368df855fbfe20f04b0f0df5babab360c9b33fbaa5ca7904b2c90118c629306bc6097ace3fdaa1aed01d3d3f50dce4e0a22627de6b3b0c41e39594f580fb23df64fba7409133f2da663ac2071b1df332f1f2bbf41098e8149121b8270e9a9d208ce2612c9fae200b9fbaf6ef73d8270b4cf169885a4fdaf35a2a589a6e4696b01ccd6d97ea7c4026aadccd6602e143aa56b0b3732fa02f669caebc45f2c5bb7d3e5f28814ff2fa22b6baf68be1e9f9f563af921a6ddfdc805591cb5821305229d6cc404225da07e14deff88434a2e29daf73ee2e7d982840ea13ac4fee9578e746847b4ad5a16880e30b2c218041967403a64eed59d2b17085d4011640d98bc110e71761c3affccf5b9c0c2b77e6cab473520f4b80e5bb4cb36200e79280907527e62b18cc651970b1848dfb282b3c3148bc4e600bd14d2dc48b77f10efc228094e19ed576298183f25e03986d287188876bc2f582294f80d33524b6c1025a754ea78c4329c5879937d6c1a264f6abb9e52773600547468daecad946e47e4e4232f09eb0705cdbb102380ecf50d38b4350791e6565b090cd6528698cd40da3dfa6d4952ccb2aa44f81e13402df111e0835c833eef193b3e72fd0592b22bd0e2dfbdaf781399cfe19dfed3eb8034d9db54437fcb881770e3e3f160148d5ac0cfbceaf1769da8f19a24a0eb92f53e931649c05e0f10d9164beb6419e07503c0ac9c8a0d709e3d5ec654d922996bc01eca9281f1e2072709c6ffb02a50b8cba467d7f2f7a408f8f7b482533e93ff2e05877d80b12aeae5462c6d6e4804773c19d5357377e2512b0ee0a8a2e6571fb37f0a163bf2f4a172b1fab6de166b455e0f53ef43c27b0995272fb6ea9d1ce6c8a807d93c7b4e240a5b990f446cd4588f04792bd497c278d4bd1d52ecb612323b85ea26157957d02e42380eb4a8a131a2b3ecee8f142b0908166c74bf89e0df4f81864d507d297207cb736b65ad5d2b71dcb8e5ded681f2a79d2cc632a14c21ab73c5e5aeff322ed440038b20d491270a8720c63e9cdcd77dc61979787df489f6287db54c5126bf40c7b000bd3c854a3694c9057f1d78fdaf193478124ef9b7b47906ea53506ade3757055b9e1c5dba74f4757e43a3ebcf22dd210e3ce6c3409bcf14ad7d0ef6d6f03476770a33ed4b8e647bb680ad49065501e658de95fbaf95dd88adcd8eb3c29657e97271508fdbdf64350fed98cbb721a8c282b62f9046a0434833c1229dec7294eb3d88da464b0063007634e39477ec6b777c0c687d2b997e2561e5f89ca582f081f0fd68b8cdcb1eae88e8f6e6c2a6eeea21f704103f0e77bc68543e9b046f7d43c36c51b35cc8323397ed3fd9ede34aaca4ff9ead45d04fe619f3dd0cadb284364fa4b9798a61c5346316a9fa20bc92027c4de6e98a0f9a819ea6bef46743e76b94b18f505c4612a233d1be297b40ea5e4b67bff3135471f3cd41907c35e1ed1475fd27885fae7e18e44a422d973fb2a41246c12f2170f1c75065c27616f739ef0cb47bf8c173a7ca502ae31b8c96471b76e17e549805ffe42ac4e628b73f143a03b55ada5368753ea6ae59e5a9b063b5cf8a5812da2209613ad8d38a66d3e243111d494efae77fc74e196d9db1b59cfcb3180606492c8bcbc8a9d8fb1b3f30d1ce5085b04acf4f8f875a8ca20002cfc6a51ff7aa6d817b199ef3e1f7fc1488441c5130196a035da2db93ca3b32cf8f6221096f76d7a621b6b530c3a4db880a123db4a89a2afecb2b10579a6dd3d3736ce4e1bcb133ad105488c8a41aa49f1950f14f240705437b37aab45a6c1f8099376308dc0d5f10005c439dd6a5f23998781bdef02e0d07af9d92c0e220c8249a200c2298c8fc0774472cc7bd318e66859a85151a9a1fe7140392e1e78e9d35ccf62839eb670640d141abb5fd5bdbde5bd2043f2a23c591298bd617417a672024b9d0d38523d84441595fe113ba24923f0824e7f82bfd502494eda9ce4aa72808b8152f6da327af39207cb6a1c36ef3b29ef7644fe9bc80f191647ffb9a3e237c917a37e4f464271b939c435319a9a74afb1f8ab879260d061cde37589e20b610d0544a468d64ddcc53d1e5c43571324e9c5056520cea7da0d2abb0d6ff0c08219defa71f32e68114ee41ce78d41aa53ca41cc5a379492562584f61be32fb2953ddde0a9eda3988272e57860ce6e517132422249dc51f1335ee4db3cbda75064afc01b132c052c6b616964d68fd72500e3e20b647537a5186555703a3cd2ba9d89b60e93ea17781baa02293e32a7cb68e974c789331b467a3f8070b2271fde356c57764192080525d8ba47f2a861d43941cddc40005958522bb58f722c8ef687de42425ea5e3f474a5f31ead4cfecddff91143eabbd60d49fcf6ff30529df1abb39269919144f7daab86eb2c1f652c1e1ec36fc8a0a1e565e6551f8fb808674ecaf21ba3d298e8bb286b6e04c9b9af4faa9505839f8ce218534a80a7441810a06bc9e6a6352d4483f66132e517de0422f4322123df7668f2316c528675d91d59bf0c25620ae1a9141f9804a643923e8a05f2631d1a37f60e947de223b71579922a9c15872eed7adc329b3938789377a3780df7677c793e983faa7cdc09a682794238c77ce6444cf8594cf1be37e05535b6a1742feadfd6f93f08088493036536fed4e16bdbaa889db5c8e4b00aae121669d8916369b9721f3e065eb31a5688f686afd372e6946005140f104ca0690d879f2ac1418514d41a055a1474b67b4cf7d6818ecb8a9c4f3dd9caffd5fbf3ac75f4498f27e683c6de14b41e19187e403143b07ef73a3f026f26ec9558c847ffd6bb8461baa76390540dfd3230154425ed20be333c138c4faff5ca4070325948310cebf521cab9e246e1a0fd5f08094f7b0880f27a5192ea6dfac598158d83a8f2b92a1790ce91e1a00dbfd6e68d645be92f5836dfb488a8b4fa7c83479ac437a08c9261211cc3305a614ecb17452515b9eb16ec841268a51df72008c086030db09f83fa5809526b327ddba7df2c4292511f739a021acf644429434541c1bf4aaf8adcfbd66e107a3252c9234d2222318bcffa86fc7cfccaeeabd2454986c1358b3dc5033380145719bca58a1218d2f0d9b592298164ebb5da0a963dc90634ba69d6ced77ed4de61479303f60271cb1d8a29797af95117efcf9b892278781b93f4f90aa6a21b4c9dcf77edb61dd73123a71f1ab6f18b59f6eca265df06494d08dd1544a3df34cd0079b54bc44c3860c0dda6d119623294bfff953ca3a0dccc8d65530b7b139ead8d8ceff41f495f515e19da8f3ca33bba07bc12f965efbab71049942575b8f67fe53049ecc40e35de044b9c3596f4d6e7509db4acd93a49a9543c7c9d6b3681195aaba1f827c267d89b6d4270150ae8992fcffc332dd9140edcb37f38e7de8fc749c222c8e069bb730a37d3f282b37d8fd70461f08f5543323af7ca1df97b11e61bd1b7f2ee0da1a7a2273d895243924268673ddfb441494dae9b0bea97f790e0b11b1d0cf10fbf5142efcc38abda52c4222cd0f6d68b3cb5766652fbc4dc74d233617f6caa438bede6f8e6fcfee75bbb0770bbdddf75b62b5a7f5c886324643a4d0d8d30a87fdae4af920b87f256b3c638ff8513701498e0ff57841230b2af326eaab51ffadc7178333e6406e42e46ee5234774a7c2211f9b1a3d1a718742b1cdf410f8e8e7d0f69748440b28150709bcb1234943641d4c254c83c2fbc45639f76028378db8e6a3c1430edb77adddbece43552ec318ebdd374454fa3b9e07d307e7444d05881a145572c61cd12be281de4629e1feb2f0644f2658913da1f7a640624d5e7cdfd9b1a29c40809f38938095e0e486c7287f4edad96f066deae93cc66bf5f444647cfbdf3ca959444740d14c780d7fdf5bea8389d5b3cece7d21b65c282bc0b26c911af5c8e4082515c6dcc48da98f9cb8d2dbd795edede41a2318f3aee4466a7988797ee4c51ad63956b431db2143329a45b0eadec0cc41220b770621fc287758795bf9cced49a0b401627455b29c6c0160d1d0486f22bbc12c3ea593a32cadd8f8052945c8cc35622ccdb0e954f784a4c1da556ce8e0c36422a16f225a87acdf46204cd5c53813bc59ff74833857807ba3b49306d23d16ed6f93dee4414c38d0288da45c72d6575ffac21403e00c43127c8cb7d5e4871ef7eef1ac52a10289b5d062081b6352089ea55760ddb14c44bf1935b4244ccda2568a68b4db55de58055ec0ecb80df12c6b9586e65fac439913d66bed6f9994d98aa54d42357cbf7ed8ed6fb2d2e1c4740f2dfe084fdbc27fca336f3b16e42be138ed7ff4c39b98538fcb9b8ee73ddaa0e356d7a5214608bddb9823e8c2037ecc7b7b4ae0e728a2ed17bf062f8ef16d1e08f47489ab86f4cf73ed09c607de1f83dabce998cce409737bc36dc4104d41d717bc4e559973df7d4b0684523ea0e76e5af50ff4b4ff7429d9d8a76717fc1ee0d986f2a7e57ed7c369f93dce329015e3ad309871c6b2a75df3beb7e6c9851cf26d3285370bf65e98dfde5e506f3dc5f06221827528284c43fb0957d16facb0d3330254bff36968fe2067196472a6f9bc37353f9a2197c999087c81d4880e0dcd4a0a794f2da3730dcb98973daba9f2416e9530f96d07d80b8a07ec873670954f54ef8794874bf6dc8afff935408f063a05821d369f3799152c7e2c8438489b9c7dd6e10fdb8062cfa9e14f35ed01f5bfb2511d774f038e887434184c7213c8ebad3e99ae8896b1790251e59e1cb80bfe6ef9a0ea4ede3f4f9c1ba1b779d8a99a2d02ab7c351054e2c7885b5fb6b9fd4e0aba1afb807968c5525d0b3947763620815ba3fa20f9c25eb96fa8ac562c93595e17a8b6ffeab1d23aaa071984f2df310e5c7d66d980544b46bcc9cda7a24f2d639b802fe63a10628b13dac811517bad9075c00eb0589b989d907774905dff4fb5bbb9aba43a2026113089a576c9f2166fae7253b3bfad2bfd626169cb665fe528ee582904215f6070803642eac9233464244e0fe40b67104e644c62ca2e6d0b5536d0cb24d7c3ed6f1e4ff52206b7c20b0807693f673272e50ecc437465a0fc66a0b3d80881a858bed8c660557c1448294e429acf35ee73b0db4874c7faafd569327d3c08d20889f39859708ad3bc7dee0ae344893d02cb6f07391dac61d3d25e0105b06a10b46952ee42f54d720b439614469dd42a4ea47e57a39a290a47b99d8e22018f311d8c4b0e12f13fe490ee2c776b2e6259644bb62925a5483be119a0222ea0cd800faf6c1022493da37c5d938ccabc9be25581a0d5040ef5509cf954851574aa44d5279c5b712e06e0c42d06b3b972f02bcaf83680843ec7c5a9a797986ee27fc8f138e37a9307428c850e7605991d5e978a4b880201cfa5530ad145509b0b9a2668f7952fb518470200cf111ee61082fb384c20aa41437878b8e148403844ff2717932ab04dfc12ea94a4b9e10c4386746f3186184d9b3c8702e3fba2c15661f6eea0cf0c13d889d39b02770e289656ad1e8814d19484435d38f801e421041de86da13a865d6743f557180970ef3a7dbe6520c338161c06b82f4094bed04253d3cbd142a627e281194b75861129b162f3743a6a3370fb2e11dbb15d3bcc8e3e6aea848accfb2d4e385460f83df28e53716bebe6aa47df65393390ec4d2168bf5e6d5a1c2be47fed69e54badde7669937aa96b58cdd59778282b6df1f0adfb89f15133ff844ebe3c8d7be3b0bd2c1f5ffeb5a5f72d07259de2e39505b2c46ed9485bf09181e20a7f320911b6895cd3eababc22ec56760c8196bceda2a8c93535030f08c08388a64d433df68a7ad32c0764d199e4f914f4b073c0ab59602047410fd8ae0dbc02a40376ca1282e99d0847190bb2fc2c6455f04f106f712f897e841a1ad5b8b56c98d540724d0fd3b188f400b1dadb5cabbfe4cd2526c316d7b0f625a3198973972e6006ea9297ed2064f3ab30b3960f11dc5761a712e5055f36857931d2ecc669d00196a5d9a7e389c3c4e72f8f059df7fdc47d80f6e1aedb3485cd5cac32b85c50f801d3f044cbd3e91b67aad89620e55d92aa5351f5da9b1efeef4d169592ff577031ba36fee08f5212f0ad251490e4a1ea0eb9d1065039e4ce69ce594c7c45e335dd40a9151d4d16a36d5ff7155ebd30a21785f43adbc0051d238442eac7801656eee7cfbd91a96c13f58a5fd880daba2964df6dfcc4675b54793bd93d1ecc5e6bfeb5ceaa9b729960941feae58277dcd8c7028b93c2becd2235b23ae1a33586d00591504e84c9eb88ab6cce05c3c3b9d9fd52fbda6974633a7a1501809f0546c100b52082c4bed0e83571e5dac848ac26142c6966e1363e1b56270ae429ac61497fd5400aa45916af4499d401420ba2071835c79e265c23a3e841fc2274d0838dfc91a0752c33c44257a53512e1216e31bc2d35fbfc3ac779cc0cd8feb0faf9dde7b3e5dbf04f05839b94f1bf4f980ffd6abdf6ac4dabc3ad2bffca0618c06d9c39bbf34a2f2707c545e2a7b70238cfe40ef65f37228705cdabf5ff5224f767a043eae5079e7d6e022980d176cd1c7e8c832fe1e582645e48c63fddaabe469fe8c4f32cd53fa9ae483fdaf9881835173110b114aada27bdfd32abebfedeaaecade6ccfa88f216f008a807a3a05e5c237071569e9ce10846ad8d39668abbc87f1d26c46dd125523fbbe54a296be241eaefeada289ca89e42d623ae5343d13359220f0ca3c00186c1f2f5fa4ce62bdbfa0bc0bede6d79fd7048ee56f1a7036c9e31ade2a9f165071008b259b2a6ec51014b9819e28926a6f754929e8d7c03a8a5943f55a65764d637ba2736330a45c3c2d68d450c674e850759536b415dbf21229fb6b5e6fbfcbaf23152dc677f576bf7ab2b3069b4bafefbe518a0bb08f73bb5d8d07961f911efa459d00fd7d46f8007874abdd41bdd1beeed82440b15997055ce0cfab4cea143a63c4779a043b1a6ce25eabcc40cfec7ce6cf4d82a53362af0bc36323303a02b7d5a08f97276991a6f9315a78b13037e22c16a1026b7b8a27c2be3d5e07fb504f696dffff208aaef634603993cbe15e477a81f870b0ffe7bdf404cd9721064953ab5a7fdf4a003beccc669cdcc0d39523f66b16af541806f0b7373a22105ddfbc568bcb7a748d0c0d5ec59e454be6ca7ae3be5e647e6f0b3e8273a22b7bc499aa5e4de00636c5e1398f083edb563ea176ef804dac728489bf64f74c691e51275dcd3f077ab6f0d6f7f3e00f777e94020371353d77c8946185821e4dbe95bebc6533908f669e2ef0332ac72bd7b66d923ded61cdfee6f556627167a21ceb934c564e10a4e9650d4bbe49803bc34a138308765cd1b5656a01d37e705c9dffc520e9f0f073e6bb7b1512c865068b108c704511fad9f0b9da3abc8262b5a14b204e0f4699e4cf2f12e4ee1e3b04b8cfa193cdf1dd6644b1a76ebe97ef9d42b5a4e2f10afb93230ff8e323c79670ee2dcdc363a1a7a00fe996712304b0dbd3991a9073907efec5489dfecf7053da6c2387357b247b8bf1a7843787cf35b20e00f93f81b17cf74656110f9ed8156cd7dfa69b9165cc1e3d80e4afd8abbf045e5e88e311ac60982d2c6fe260705b6f2b2ce6c95cae469ea607dcb1693f0ef353864881b358ad69cb1a02d6e3a074a313e61e85b2123a7d9b47a317bbe2adee20707365deb11cf8b163b8875529fbf6ea49f32ed72b900bf4dfcd5f7fffa94d5357ff6b108b7f7e903925aae9abb60cb6a4971bc0d894a82514fa450bf4cebb1bfa1ed97a4bab071b157fd59d0d9172054fe9f5884116fab3ce6dd1c13f3909709f3519578c2cd12dc821f06dff380a35257f08e728e31e121052432e464f655167eb2f43109a8be991f93285d077d09187c2803d07082f8d29e08106378aa970d084c800faf4babebd70dfbdcc80ef7af2b610377e6b0bc551c7ac53a67093d2277c3776d4bc8890edf9919c10fd41843f71e9c94b1840494752dd09e5c31588f254197ea02b35c67e9d451874829b97b76aa73548b9824603e25d87f5300f53dc9be76af1c450c2567eaf803b27ded279713f7a71054e7ca65c34a58a0e9214d40c3ec72499e668ee4f5cb64fb970be219269f4cc7666dbd87e43405f9cc21798bd52ff123c6f830a10654197852f55fa468d7c77b5cec7542217e977560664b991fcabf6d31274063c334a1dae7d522fd1c4c4ca4c250122e8d285c3365184960d3cda5f0de115f6a852e62883f7b9f201de530320eab0447b132023903ab0ff353609ef89e20f01afc47340efcc0058e006b4f331f3bbf1b27bd1535f24f25d1fd44f6a42514c9fea85849860a1a617a4022a98172dd3f5cae06fc8101c3400d4bea69add08cb1424db8cfe756fe50c7aed46d14a8521710c69e9b6800e22f1c416a83812d0ccdc38571049ea14d96197e65f33d2fc89f09a683ad9095a263d54787ce7895e30cfb2db6642755e35d01c106752682d2421e55c7b0018af95a845a490173830b9345b498c7d81f16710f53d9ace25f17615601ff0eab9a2582a51bf1aea4116690a8ffca42287ca04b799767a4cdd33f166ca0b85f350557fba1130b388b32c859c4cbef2e18af8841e17c1f20ba0bf70586293601ccb1aafc904aac9461a29941dfeb274420ce27604ecb5920fdfea5016c66101b5791f4edb7b7597ece638f004f54ea1192c4154600688577b24d85e68713f6d2f7ac1679737f9a42b0f86a8893341326a0f7781c6b9a2a08a026936bbc420f51b009eeebc1ca65fce50e079a1b19d531e8c9c7aa441f65de45b1054b0a82a5c38332a060d8e390e0c72d208cda109ff98c1682831630d6d332c6e9f7ea77cb08175cf0273d0378c52214ecf795b71d7d9be3f4bde1db57c5b7ad8de416be583d62a2413c93f7a5d10f3a786640212ed391b0eb5c9acaa96e1d773898c20d9aa7f4cb477b5fb4650c5382e25655235dbd817e0bd0ec830362ae74ea4eed0a0e9f4bcd668021daa5f376a90a77693b2c95bb5376ca4843bd0e11c6b7d5bb67c125b88da3c88a9013c47e87c71575918e919d3a53e58751c307c15fbbb619d6664465404fbde6986774495086982e307a550ae6efbfafc4eb06a44079cadc7bbb4fa5072664e45688a16ad160fab40b55181e5300fdfc98f74e19299b0c7943788d13e13c771f26e8ad3d3a7d0fde6701d903babb01e083f61c1e539eb0270600cf80ec81e5a918c7de9e43aca9abf46be0399ff3bf5c203138c778a1e3615209daeb25d83a5b595a828e597f4876a0225d80be07cc2497d3cf13491f5fa3f8f1bc0d9eef06b2b6333070f5b671b0cffc20c57fb3cd480ec36ed7b9b175612f37617f017d036f061562dcecea863d7e2a896d6b37690b744fc1ae6d281f25c801d68e275c5552781100743121a644be5c9c7387161c6348bfa0ec16b0a2843a4d3f6101f2b2722a660b5b6ccb5fcff73b5e7fee0b4a709775575b840556bc18a5c6d584e328d13f862dbb6bfc9138725ed9f3fcace5e1a46c73fc2ed434d19a40373660fe8c8f0dde0ecc0522ecd67566662cd8157d2e827e6ce967e4779473dd38ec3d205d7ee07b0283f20a7c8d5f65eaa2a3120a74903dc3ae5846965d4983dbcddd87946c7a656ea18f7a918ae053b571284a1a00e61cdb81ea157a5e35fcdde6907ab698a167f3e3f548ef56d7db539f022df5608cd0dd2f5d57c0b1646918bc30cb2dfd1e09312ce88acfcbaf918fc54c32a875ba1c64fb5f7516bd4273c66677de86a63adfafa1b93ffb5849eaaa42d6107e5806b1dcd6c61c0b137ab9a6a2ed9991cf70c2ad90b8a1cbfa375b7fa74b6aead2958a48e49f7e5bfe61c96fe1ae7641932eae07fdf8ed0b248e0c3006a9ad3b8eb2aa5b6d464a7d4c21c63ef2f973e8e792f7a4494a53756320325e14a455700fb9b5a5ad10967308f8afda1768f38e316dcda33255c67d2fa1469ef2cccfb7d536570a7ebbadb064e276313d1a37729e38299c9c79a06286c6715708078729d2d7168f6eb0e575c30685ed26731802a74b9de26d84d6d77095df099dc6c28b42bffceed74b52a178baf799b0bbfd921c092dccefe167b8fc61203d05f21cc30c36136b36fb23e5c862c00ecd0aa821348e059a1f49f994b16d6166565e2e2bc21165e35b17c3c7371683770df6c9659c26070d977a17b50dd5e5852cadf1693383df9e7c9ecfd32733c045b69d7b57230655cddea70ffe92257adb93a47b7436eaf3498c2e235e9380d84174ba0566828440a756a70f956b2470c803888c4d135e6c37b280a2f15d7b086a8adae9d41e6f9befcde5d347d4a287a84d151f395d157812d4c6a7fe042a0b7b17bdbe1a4fb1ff67b30a87479f60b32caabcdc4b3b4cd6aecdabba4a0bdcc7682edeaa2dbc0663937aa0f843a0ef289798b3ac09b8040001a702eec33d63096337a317077d50b0f317cff0e9249dc64414a50ad346b4914a70f8a5c3c44698f360fa7ad60d71d048fc96e05d380879ea44d36664b048c3ddca789431821f64876fe8464107c26368d3677548b817f38a71c2429c00fa2e1c5f142dbdd080e0d30ec48af53f3697cb5b9bcc4301fdd19a330064828d2866d7d5f6080fa83185b9fdc80dcfce3e183bc09c22e42a47cae0997841cc21e9b9ef9781311a5c12f898da8dd189bba3c67d2cb1ef1c3c6f332a4e6748241fc1edf3f0c5241126abf69401d0329742b13cf8eeff2d34e50d9dedfe85754a4d987aa9a8a582468c3e7c134be0b626eb4123d1fd0bb15842e399a3d36fac08a748c7da85b5404c6715f6d2b8c22a8b51749291e33f7914cc3aead314f694918c5fd5c322feeb7fbac2d1fe761dd0359a3f12c4d984561a2ed4b0871fd469f25ada2161305601fb800f1309abf4c0298dadf48ea864fb84e94cb63a70f6b924fff7a9361e834d3ec24a8a9e809aba2567176d370e8d089d20162e4d6f8e1f9c1162320f300eac01768deb6bc4f367dd28efffe1b0f319e2a8b743845fce0c421986c74f165adc21cff64f8083a3afbaa0f1e811eaf22e03abf50ae632d2166bbdd9f0f82b58f3adad83939b832a43743c319095740ca242cdb8153b9b03a8ed09271f9854b260a50d62749700a2adb04f59d1fd6a8f39f5ffb5e547eea98b159732320b5ed840afff3ca5cbc8d6a531ad634a5205b26f4e66c90d32ed6f22be7df9bc378ece613d5b02347d1619c87eb809ae252aa6294628f9d9801a28c8b90fbd67eb7855227194d483c21a471743bbe688d383a4075c295115a0739efce41b151b2edb18f5947e6098fa02d9f8d450139c0db9f1cf0140ca899693af7c10c50a56df6a4f9998b411bb74c558f372de993f5dd3b9fbc66feaab7a64ea68afff84a661015a40c982108d05f4de40bf230ef81dc2fd12a6c63c7d48b1dc683d835c917e5831ce5ea03886314b98042ff8913f0dce3e26e280967226b775d2a30bc1ab65dfa9f1047c14cee4d0306c56df8569a9bff0f204f548e358b208f1dd7858a92821628225a850ae20b16f8ca779a2541585db427063e60a01159099203fc898267f07dad4cf5b83f9aa04368053b3e8819da2c5859fbc601bcc7759c83f4d54f9bf1d8500d092c808d20c82e261d9c1f79303b0f350a8c4a3327f248c87a97cd8263aee3f9fa59141e9fdd97499f338d37170d6e68fe0d0d444f7fd6a164772e70708316fcadf79cbcc3304f1ad14ec3080e16dfbf3b4ed8b9c9c9d2a09147d185b3374c1403879096791ad6aeb489c82fe0b7faa5224cc5e89028b9c862f42207113b331777bcb43971dcb2d755af731dd122770cb3a570d1865a52904abb523ddceae5edbf531626756292606c681d4bab55dbb3e001756b7092dde95c044492df4d3ac5f80b9b3e32d36881ba0d7f50e211725f352424d78c951d82288bff02f924466de8927b24879da198c426689473a7128c9b085c8503b1e57be90e4287a9ea9a5c3650f5bdfa914ede9a34d1135696d98f2216c3a92bede8f5b8f269d12121b5a734e5159c8294f506e2acf2094527790c248aab137feec69edf235fb58de86ddb64b1c650e16f5388d67daeda7050482f1687b8e869ed1b18781851d1a2469a097d042515776529a5825ce321333137169f85deb90a1a272e435fcc314671fc372acebf0f2bc37057e2698ed0d85fc5c95db01fa5d7eb9a7076572f408c5427e98a5821e3235fe5ba8f442d10d0c85b3b2bd1d82d2b12328e9f142535211cd1d65edcba05aee17c43e47fbc6c140d84f5bd0c0af1beb073d7e8eb33065c7b357b9847e0178f7839b6f269b062cfd6dd2da52852d10e00fb968ec4e1e77b551dde9b0fe0bc99c02cd05475a2b34cf60b17ea722216e6727e1850494ab143cf672475d4c773269d62fc7c924699de06a369de48672e41adee91f523ad0c7e1097f4730f90faf542e315033eec6bf0f35841de85742296f23b17a03d75ff1f9fb2c112e3c8d301774192a52f6c11c1ba3670c25afe8780f8a780196d9e9390002148277e2e4b2caf58924083c6ec6ea31211d7d720b75858d547a0fd0e1e041ee35d939da38c76f82b917f12a05166ef92b927aefd64999d5acc71ab26bd582b27fdfa24af1a3ca81a0f103130164bd2fa53ae3e765561d24b7ed10e0689bef5c46df1cadeecd306e8215b2839fa969c5c20366be14e5ed5982311a0be752fe92f942fb01feca2783a0728451fd7f01697bf29e68f01c6c212919be9cab7a9b916da16ab4089c1ef9801a8cd1593799ed97cb3bead9b4d01fdcecb7cb9976c43e6b6a4eadbf61388ee4fbba0450d5c1727d989febe62242ad88ffa7ca0831e1cd7bf1f86c6ec013a63dde5765b462c081603328d2df29819fdbb0dfc0053761259aa44f3d1f03199cd1d2102616d1f5926059190edc657f04c211fc0de0fd65aadbe7c7e928cd4308b7b399acc289851d6c9bd24910877f096483582a4ab6baec0f9c3e9052edba3b493b74308faa8edf36ed0884b0819831d3a6da52f6f0671a7b9b12a055628dbe6212ec3ae4d42e6d89ac54fab55d5d2d9728fe98621778294bf1deddcadc376f083753250d0ec71e968cea09de0553810e927b1b41cd07df012bc1efe76182fbf58da4a5e19da4cdc1d6c36b10f0b3e8471397e51515663d693f96a5c8d3dd0e7a7d4ce41f1e6b0ef4ef2e1cabcae61007355a4a2e66be214f6b34ddaa2bb7a0f09ce48917ff8b600f1a8e87ebb63674fcb13cad349dbb2668a05245598c842eec2de51574639b2fe20cddc032e3a1b384c1aabcc5a93dd5623ab9630343c078f1d0f0a31997f28b312c6950fbf65895291a5606c5fcf21c7aa65e1282d44e073a2645b980ccfd084f6c4f65b3cb254b6ea6a09520f32eed0efcf450da972f15a4ed059ccc9262fbe648e9860d087d09c51fc4e7c7b88a313b30be2f1c84ea2a7c20a3058c86797958e5d9c6bff28ae88dc8a544487864b9c6bb3fec4262a9872c1f4fcf3a88a3c9031cc2a15292f9fcade7b5cb4810911590cf76e13a7a60ef4cb3eab3b5be8ce8e2b2e2867fce393f0faa1a5031916e6836bc0299d7b0752ae6af6f2320ecbfdefa3fc0cf3294b86aba5663ddac2beca6a4bb62db4df7e1f21cdea3b5cd532784b2be97ac30376528ac3abcfce7f0292f063543aad0d409439103a4cb03067a0ca8a3bc371708e45840864619c0f286b51ade042561d3b95efed4bb581d32e5ec85350dcd463977fcea977334f38ee85376c76a18bcb5f088082fe147a7c1764582ec7ed4bc19a3c77c24bcdc0f6cd8eeef9b141cc43328b8ca7fb0df4ce084052364ab09b01fed11f099ed6dc5b159b36ccfd756b54b7fe52aeb2cab35dd5b1a96f40ba6d11d1577f22dcf5c8a11644334a33340b80e5259fc2a42d6860ee4db9aa36e7b571006b5c2e9adaa044724a4b16a696918ce55cdf957b16baadca8feee71f82536b7e6cfd1c1cb1257db612e87c86a862500dea69fe3b8c0ddf1fe25c43094e3e73a0adb9826c27d0bd011cd51f3eef90ae7c127c1009042ea93791d2025e9e31a4c7e1522cd8017b050f6d6dcb64007346bbbb6ef067d22480e02240f36af31e2e389e85674463b586b7d75f249cb72012a5a3967c9d50dd9691c6ccca9ac7b553e33015eaa824d76ef7a3dcd6a183c8193941ae9f09dd0f040174b686a97229b959c3fce4074ca26e66bc2c68bc350c3ccfa6156f786093b0e1781175a0923e290d03b266a9be78adaf0868c99355cdca2413eb21db91f5c7ee6698961a43a9eb4a8d82205f65612564908e7a13d7d030e3f302d4d9fe70ef8aac48f01f17a98f8915c1157a435674371b04fb1219ed4e17ad9cd567c83e098ff9ec4cc356ab16ea1d33f73f0b583b130ced4fbc49eceb68131a67a37f0cb2a053c32413deffde92f253bbc4475f2af218001476abf87085332660bad14ca419753efb0f2014055da54dfd94033941bf6e2cf0e740202143693a188e4a1563c5294656e80d3c03f10e63e2a155e004ee918db41a1c6f9c3edcc86a95f68b99fb60807d93280311cc47baadc992b73fb56c4b74d762be4e81ba0b9813388ed3af4c2fab4f66be5ad24e0a3fd0888fb23a5dc08967bf47b3adfdf15b262696a5ba2f50486007e9a62a6fee1667a2d362d8ba73cebf82f255c3dc3c7f42164babfa31e5adc957b7cfef35d90ab018c55fa6d40321b4447b329568d3745b09884145226aa54fb97b968a41ffdbabf544f6fe43917caf8907767114b90ece2f0935822b8b435067530905e7feb6a86679543ae43b0cdb27bbb51a339629e0eab8f858b7ae70a1bfb83567cebde3c7a1d1ad80e1328bf2b032df80d256a4b636ffd89c64f27d492b27c1a8597876747874131a60b30ce82135ab371760d623003ee0ae6e7a8f688b08ea7d471946f6024bba0513d69aed496a335f702d1b10527a37335b9c4fe2dbb1ae514a15b1d12f696d9dee9559321069ecdf607758c3308e393a75a7b5e509ce4cfc6aaace997ed3fbab109fd8a41b4ef8d15a0eaaa0d1a85a93e5098fedeb4bee8b3fb2ce3a4385143368908c9ebb689c74f6e40c8202f8cbb173727ae2d0dbab412aaf776984f3cfb1ecb04b1710bc125270bc783e00c62801f990623123ee1f693deed4d977bb6e6dbf24bcca6a4aafb28ce225895885638ebb5880295e6deeda410993596a49229e55e625a04ce0fe5e57e9dcbd5f3a167afeb447fa462196005a03ff9ccabbad2a27b99448e6abec50efc0c848806656778c1d81088bc1a5ca25e373e7d15f62b0094cab88be26abdac45283d5ae0ee730f983dce186faddef4ddd3c4fdfac8733076bbbdb02ae0980e1a0498d14fcc20d21f19c5ee46fb19af8791c1785b9c58e55cd067da04828200f9037ca9524494df7711b763c613d00cc17cca533276fdfa27a5a445b327c619d8adec8a7ff30ebd8b143fa9c6e672c6980e9f50897c83b6c62d89f2de753e6782c3182e4757cb4c10be3fc1478d77d7247afd87d32e465de21e02a0c863b5096d326e28274bdb98bd52ddd3027397336b5d457b335575ceb51b5abd622b4eaf6510cc33eb0e4ccc51155d9fe5fc8be9b9ba94e540b3d08f4a01f8429a8245030f7c9e84ecc30807f12c205b3b4993acde89a2973a18d809cf05d0b402d93d4135ffee7f36931028920603b46640799b7b74da3c0d683bc86c457ec1c58b1b07f2ddb58030ce19040504c702ee98c5260e3860f26439ff00000000000000000000654d5b34f50ab0b1943225cd220881d0e1bd29a594924c91ec0ede05ce4c7c3a33f1e96a3c4a2c080f270f5a0d020e7534615eb37039ea4f52fa67c224ed2788fbad0feac784b13b4ab49074fc56fd12c6891275f5444e50dd12e692dbf1838cb822f34a18f2251929f2a3236d4a98f2c3425790a036ed4918d5a34576cb3969d6923099dee8127512bbe64818fde4696b49f6a331248ca62fc748a1d6230c9f1744e46c2a878896230c2abb7ae2585f97ae1a61ee6e910fa16384d1939ab6f58927f6220cd9a3ff586fe91015610a7695434e32520829893075070b615c27ce081186a452c4513998e8ac1dc2a45377ae5421a708933284b145bf9c78b59a3415c2a0ef4ea558b952ce0e210c7a5566fdaf4389fc200c4a44ff52249a12ba200c5a4bf9b925f1e207c2743226d1b6c498dc80302969b254b89427e73f984c45f1fd8af325f583d12abfcc868d67d507f3a86d7bce913f12e683694e2b85e439e5cdf760908b60497afaa473aa07831893e4f1dc5427e5c174d622ea4124d3111e4cdada29d7f49208dfc1b89efd56f6f48532ed60f0a4e3fc4a8abd15eb60d6f299e855f71fa28341a91def30f7bf6f0e2695f4d6975e6db69383f92587ce29c89b2cc7c194fdd242e74e2694050ea6bb90cf295ce7f8bfc1d4a523e3163ca5d0c80c3798e3c78995fa90272164461bccea6f327fdfe4a645d960c81a4a7e5c7c93bd1129cc5883494652f6b33c9e792535983a9a7f124ad6ae677b238c1b27601b5a3c20c78d306e70c0c3a3a303757434c0836b1233d2604cfd8bff8e64b1661366a0c19cdb3e4f27c93f4bf3780933ce60ae0aeeb2a62e4c5b879330c30c86646a1ec3d4459dcf1f5ac41033ca603c53972e9fbda5faf0432b8c3ac40c321854ac1461e9c7e4b8b888196330a911effe19b25cc7fdd0ca220653f253176d2e29dfc6881961309abcbb042d79fa24a53870e38bfe020c0f0fdd46cc008331c2e8e0978329fd937c68554707fa8e1c1d1d1d1d0cb071810cd8b071010ad8b0c1800a2860031d1d0cd082023620d0d1d1911ce0e2d1e9e8e0c3ca620b8f02a461c6178c2745e7928abf9fb57d682130beb0b2a1c5036cbc6086170c294e8a2abf30a324fca1552c2b05a6011d1d4a98d105734e42de7d5cbd8965b1a1c5033a3ac228010e1c1f555c30cc7b597757c7d9896fc19432aa934ed2bfa4c24a84195a30fd65865c9a1c791e643f9891854208117752047debdcf0a85211ccc082f12a3d92fb678410641f5a63b88799171be8e83835e30a861ba194c448f22cb3fc50c485f766b185870a6658c1dc1f79462fa72dbd592b077a40154c15765290a4ef1552c83431830a7d124951dd5f6494b2ec0f33a66012f1645c979e2ed1b996a162861408c974945341ffc4bb44c1284a759b48ea818239c2fee77cbafb21593eb47830e309e6cf2949faa01a42ce81485022e0811e00c60c6638c15cdd7144a569c49d3708339a609aed4a1247ce844880b8b8f145175f3a3a3e8c1b5d7cd105032eb0d786194c30a5d23b734a7ebed9e7432b0c9403c7093c8c0136120d021d1d3618108195c38c25183ff42b4e69e9432b0c75c20c2598a2499c1366d9b2cb640a3392600c955e7ef4a8d1e1181ce8e8f00275d1d14182f6a22b60596ce131430a339060709bf86eefd15446ce114c793d2e67427ed85d8d60aa8a1fb2969785a09345305e10ed6427f71961238261e48590e4268908bb8660cabe61be32ea3f49e4430b35d0012fc4c001060aa3a3638610ccfa796478875356391604f3554ffeb4a1bf3e54528063011d1d07a50087d702c18b35a947cf2549118c1c5ffc00a5733f07c92d3adcc50517edd1c1a198e103820ada9216cfa366c1713a3a3a3ac648010e1b5a50c04647c792320314337a507ac5dac57fb4a3c386160fb0613a3a520b8c1c5fc8e0c40c1e28298ff8d292efe42130c408030717efb1e6714e931c371a0c2de63063078553764a99fd24f1b40e30c97a9767d23af8978335e2c91161e7fad0b271540c1b5ddcf808a3e304365cc5b0412e8c1938484394ba7db9acefc4e862738851012f1c801898710353c75291277afaa6c77474a0d3d1810e18288c1936b83cb4b2a27555981355519f2e28d5eeeb9ef6c08c1a989332935632a22dc73430582e7db2e3d9a8d8a519184352ca9f98beb91cf4a1753c48e0c58d30c428f580193230ff491e5315235abe130343ba14eb262e4d7a555098010353a73c714a7b04a5447c85315f444b0c952913e40d485798435a4eeb71ca53d0ea09325a61b0fff82113ecf652e443b909325861ec10745e0a7ae1828b66c07a94d92a4cc952ca3125864e7f990438b8d81b5fb4475145724d448e9ffb4389b848980aed448f0e22f447793fb44880838b820a446eae35be63e9280e0a2419a748bb2a5b4a196231b92c57a8e457da52ea1082674940021c14f80247161d1d24c0c1051630727c21c3146631ebd92f7d66b22e85b1840a77a334b7cc3b1fea005218df72c7fbe93c7fd2330aa37bc8b51a222b3ae488c2b8ba39737f79b94da13048ebab529bcb78394151d0ecaa2473b19242085e31dbc3e5eeb258fa274ce74937ccc6b5e43cfc810c4f18d44f2e6ead43041175c2907a7c4d9e6e479085208313a6f750c9498fbcbc71a1206313a62de55133fee37a84a066b185c7870c4d9823da8585d44e9194ad870f6464c2246f7fd5b379bc104f1f5ab800c684495990cf176a1f529c3fb43ccc2e61dc5e177133712b21e9436badd22ca1e40cef4a33eb50f74829f4c55289be53a9eae8e840818c4a98746c390f63937a3e871206d5f755ba3f4499a74cc260e97482eea89c728eebcad0810c4998abb7bd6ef2a714ceeee8508fb2ca620b8f316444c2d429e8afecb752fa7490305e5985f533cbdfc98e8e29c8788469af4a8ff567952895644718747678ce4194f8200b838b2fbab8818d30280f32c9f72ddfe49911a652426a7d12312148cb22cca15e2746ba77dd0b51451884ab988d5c1f9b381f305a8c07c04046226a95afcc7675d716936c22eb59758a5d673afad0422428e3a24ba9173210618a53351dc3cd22a5500792710893b08a27469f56b70b3284498b87b414d3cbfbef43cb2329a080055880020fc81c29f0c82a84d1248ac41429a264ff0fad14a00fe3aa2cb6f0e890410883ecc812b267ee63591d1d1da43ceac3b8d1c5657641c6204cdabb67c4c7ab569871242f22b04590210883b65136f134cbed726c041981306ae90aebb13b49bf7e68e1485e8431465fa0a3a3a3034722eb515b00613aaf889d54fd5296fd07b375e414e53a7b49c9fac1a04d2cf4dfae75baa40fa63d7d17a37129dee9f9604a9753e50575899dca3d18c4eecc071d7408a9a21eb82c16da1e2221b7569ac5a52ba14cf6a710a294910783255715f390f1ee9a6941061e8cfe21eba59b0e22a71cc43b982fc6470997920e7d273b185c268f2419b3a2a746c43a18740ecb0fbf8fe3c1a283495fce2a9fe52c5b8c490f64ccc13c93f2a91331ba15ce8e0e948329e7e6ae4775887130c5eb8f3eeb26d9c2080743940f296a2bd15f2be618c87883c982474b3a699d68c974707ce44015b8f18502b04e50e5515827286090e1068304753517768476091e14c38616361cc5b081d90663ad075313f16be3b35ed41064b0c1f4af61a782a80a42e7c58d0ff62822c8588331ceb7c66286f7aee9432b130132d46048712ee44f2de5f7f8176368c11ecb04196930ed4b0ab65b412c3fde11464a41061a4c55356f29eaf55254f4c5185a78d418398c2c41c6190cd927a7e7fc53bbd2e9203c906106f3e76c974d854e4b7e194caa73a4f8254b16e616120519643098968884d92cf131fcd02a9cc5161e326420630ca60e1d7a25ae3afd28af38b06230fc8a1c0d5d93cbd46130c9dba5f1e8e597c7d2d1b1596ce171021960306a4a0af6a5b6e5f4985e90f10593a49c60bf9de5e2c4c600238717a6a3e3ea041d1d57e5515727285e30c9de9ca03b6f4770bfa3a3a3638c1c1d1da6a3a3a3034979948e91c3ac20a30bc64e2afdaa7d1811b6e5826956823ebd65ea3fbb2f7080d1808e8e2f708071148023871711f0c091c38b1bb9596ce19143c616cc419597d6bb8c4eb9ffd0ca916e7c84e181a60583854a256eda2ec4087ea807220118a80b5239c0c011c6c9c882294a48c2d44d69a81e0ba655fbb9dffc5092423eb40e173822d060a01c371c608301362260430b0ad8f8a22bd0d1f14577d1d111467774808172dc30525730b987dc3e21675cb7e543cb0bc485070e2f3c3cb8d0638c1c37c0e82fb6b2d8c2c30132ac6058bd1f8f5fcd0ba12f0117623873d15e582035a200036c70c006036c4cc006036c1ce4050a2cd0d101062a0118dd454219400747161d1d1d1d1d5a89617881a3ca1432aa60f61221ba74d2d6f2aa0c2adc1e1b6ed12b2e8a569ca9724bb2824e42459004644cc1204412a973a9f8bc7e7f68d9d0e201360eeae8b0a105056cd455166448c1287779e49f6adfd125ae818c2818b5824ae27d54585a12148c91cbdcbff3c4323d7a8239c8f8b01d7664c57a27986d2e7bc841549e4e7613cce9fcb2cf465cf0ab9960d6b2385e16c44b30c9ced97bb13333db2ac19072c96ecc276df92b1f5a6c438b0744000c9423025de000c3018fbed040474747c7a3132c290f195c90910483f00b29b8aea49c8279818e0ec485777478b0086420c19ca2a8cefb6b27ab2f1b5a3cc0460a4e0448e04567a0a3a3a3238c2f709466b185c7917104b38ed9d7a64e0c912f1f5a1e6370714630e4882592d0c9c272524a194530c552ca2bf29d926aff87568e2f7078708911c60d30488014904104d5bd246904d7b2285ba23e42b66da990d97b81c3830b2efa19bd1716f0c201b9617c81a36440c6108ca1ce4627a5105e3e0819204308e68866d9aa7eb46b4a2c01328260d293e2de5c50d1dd69353280608ea6638724ddd475f278816e01327e604cfbb8b5e3bb3b29cb0f90e103a345c911e653723ebd405c7818620364f4c0a0c352486db1d425d73c3027cdcb0fb370b1941d984f07ef115b41d427450786782a49adc8fa51ba529903f3e588eaadca29580471e19d438c2e4891810393aee8f13b88cfeab33eb43c3cccb8e002fdddc0a8997121f765e8eca90299c5161e21906103f3092139857998ce764707175ca02799c5161e1f905103834efb21fbe714d513fad0f208e386950164d020d30cb1942d468c51d14aae93baa487d63b95225740c60c8ca212c44f82278d94f360193230575c0857f954475cdce89405468e304c460c4c1e933c040d25f3d5fbd04201f2a280813400460e0d54291839c2900103538c94b2596a16c35f60fc6cbae6632aab5bbbe1027374ffaa3c415d50ab5b6981f9fdd3757e34d32c912c7316182c9df0a423c8aba8fe62af606d95d5788b9ea55a2a1ab6173d787cd091c50fad4b313c727491f48b2e6e141518c2259dcf4119dbb90891f208df05900673a5a04576129159bd0b000dc66e196d4205a5afbb0be00ca6eeab10c278ea92b80bc00c661b9537824a9ebcb70ba00cc62bf59e92e4d5c8ed02208341f75adc6e7879785d00633088777b9220cd3f5d1780188c252aded39e3217d5051006a3e4beb36baf155dba00c060defe512b71724b0eba00bea0863449a594e85e304ab49be8612efa82de0543ba5bcf614ba80a9f73c164a1163241eb74b4f8168c7db12f8e8c0ea564ae05f39e4a3ebe9d2b3de55930fc9decc785efbc9563c174256a24d6e79cc2c4af6092ddfb0fa74a66246e05d3ce4e2efb4beb29e255306c7e85743172b809712a98440ae1423c53597fea2918efe25e4c6895d4a29682398b5fce139383ada8a3601015a162b5fce5f734144cf1bb1dcb64d77fa79f60902d265294ac9aebdb0906596d2d7eb14aeade4d3089acfe798e9472d49b09c6bfb259111fbcfeee25983d7546875813ceea568249df6b65cb25c1fca52c66e5fc25374682e94478166bad514a4730a91c9f6839da997a8d60b04f3b718ba5d517c1dc41e2b8de754d9208266f112bd9f72366390483b2abb0d9499b654230dfc99568f3f4e10a82f923c95d33b79c900382313efca67d3611453f30a8e9f1a44da772d17c60187927777d3af6a707a6149be79aaaa25d1e184e8b48426d55c4523b30b56796d01dc4469ab40ecc71524ce74bd1a3cf8179ffbc544ef1b3741c98736cfbbe7b7394e90626f93d112e4fa5f06d60f4dc536143671f6d0dcc63da22a9143f217868608a203d789a4b4a3c333065114b7eb5af63791998e4780e6944f2c489c7c09c6e7bc3cd4f95580030308bbe5c12df8386aa5f610cf1e3ee21a416df15e65275a2ced289b6b815a6a0a342cec91741cd0a93c808792727e45d7715a6eca2533c347452525598536a4f22498e33752a4c31fea6b7947c191315861915314af5e9bb4f61f888bf6a22929c104d61ac64aac2de2769bf14068d1122f85790778f14a64c09b9434aa6b43d0a430cdf70d3a373cda230eee5864acbe2490d852186d80821cbe8a50a288c1641dc7a1abd58fa84219c9035f97946ace60973246159164fe4f6d50983bca52f9d7c43c40953a898f57b2194be09c369a6d75babbf49581306cb1017649b92aba54c9823859c253febc518136673dd8916637127ba84b95355eed239a5b3254c7925ba4e6ad35225cc9d841e2d711692a484398c92f21e391b804998d3a91c938f7be1f90d80244cf926a8b8f88e277f0310099357cab13d05153bf70d0024cc372ae8a4762fa8ac6f001e6112f62b9eac3c54e91b004718745d3c25a7c747de1b8046987fccd5353c8a4ef7068011e58b8b6b692fc22817a26bec3efbd6ab0893be99f0a94c9918f126c27421c4c9f9bc0e222f220c22dfd5aa470fd6f11ec214ec6368d3191725bc86302891fd6c17b53b69b710a690d95a93b74d86760961d44ec9b444b2ea78771086a482aa143fe75aab2b08837e481e3a5ee7a5ba8130898d5ed3724fa6930b08833ae12924f9d7f172ff60be9053dae7f73c92eb0793b9955f7f6cc927dc3e18b4c5a760dadb4387cb07d3e95bd4889d214ab77b308a5296e30553a5fc5b3d1874fc52fead252b95cd83e1545cdcfa0f22766af1603251bfb174cfdbd7dec19cc3dfa9f8d2dac130b6a243d486e87caa83c9cd83ce7e297e94101d0c7e26d45e65bb90477330dd8ea7a79098e122391844f2ab7852429588e2609225adfbfe729220828359ced32995438bf2d01bcce61155d4ce64a5901b4c4296e696cef2a374da6092f241d77b6ff9e7d960f8305fd32d59d4f73598fc3eea8a88eee1693598549c7a8e6fa3bbef3418bf4b928b8e49a56e34186247bfcfa33baecc67308f473a3735717f643398dfe468b87fac895b06f37672d1395c825d960ca68adadd7271a2a83a06936e67579d0e9f51c5600816e44de854c36018d339e7ca675d972a184cd983f8143d5dc84eea178cf2d142f0bb51614cf58229fce8dfad244d9c50bb6088113545e4f5c9252a178c9e4c97757874133add827174e9fa522972eb532d98e487f6f1b4d9df9e66c1ec79de65c249bdf3140be6d32b26db74928a9d5ec15452dee497971ed5a9150c6af672e57c234e2b5a0573ffb85a8b68a59129154c5f214ef96a85d1974ec16c39f2d2e4a552304c0c33ad1446be5e1a0573189df4f7ed49bf9442c1f41f534d4c321dabd22718df538e7c32fa3452ea045310abb61d7e233ca909c69914efdb4c725f8909a61cd3d5b5f2c4dbd1124c29f664dda9d68a2225184d7ce5a8b16942889260bcfc9f3e4548f96308098618b92e8e6696d039473009ed79458a7ef1fb18c11ccb54d8cf325a625e0453e71dd12d924b049908468b95bcc3ded3321e826123b8b985bc5cd30ac124f24f4308b5f9d206c15ca9a25dec1273f902c1a4f48d7035519e63fb0343d612d9d80e9693f58129e475faf11cedd2d903b3241da66c92de559307a60f93b5bd72777a7107c6ec1129f9e59ceb431d98523e35a72dae2e04736056b98fb6271c984a08bd54156ebebc1b982ee6b5883c422495b381e1dce4cb662bbda506e6fd90be734a13442b343048f4f02b216506866bb3f477a6727f1998f6f2a5be7c1680189827fcaaea7bb893900c000c8cb39f3f0415cc279f5e613833a91d8229a147e40a43ccf41bdf1ea5b2a7152675d24f07fde6dd3e2b4ca1a4ce8458dd29c857618efc71210851263aae0aa3c95e24f1bb92c29e0aa3ac9f95dae9124a4785b14d74c6d73a3bd2a730a910420a29a25be86c0a53990e1f9b6817342e85c12ecee598a43d3a4b0a43b2ec30e33fdacf1d85f947a791aa16e28c5414862092c6f25e5ed069288cdf6f5a74d46c352528ccd143fb6e890b62cb4f9876a25dd6a89b96113d618aac9fc65ffb3a8bd809c35bf7a72795f2b8879c30aa569cf9a4e3c356701346efdfd51bcf58db5013c6af88e31772f6aa61260c2344645d3fcd101562c260a174ce59744ed5165ec214ded52687279122859630c5bf7e91773f5e225809a37b899820f6a4de042961588995ca738f9220c149183d09b99c28c13a465012862492f697f33d6d53240cb75915c463e72e11240ce7594eb678d4b1ce234caa9df2ac750851721c61ba78294c899432d2dd0873f0a06325ad8c906c46986a45c743fcaed17a11a6ca613f7faa1561c8a2d52f5d26050f27c2a05521be84904ee88c0843fc4f6963525eccf910c6cbfbb09e447873d91006b73625ebd92d4bb810664f29be2e47937a2f214c154de4902b6bc7640761ee0e17d79e2b458f0ac224e22b3443c949bd06c2707a591b41e4cd5a01610a17b75752e5506bfec1dc3a73319eee7b4c3f98ee3b892829f6c154f952523a272547857c30c67b4c512f764a04f76016e52917b7b4dda9e8c154379e3b9a7bd04fc983e9b3c7cf342b95c48207b35c8a5ef152ee0e86242271249b851cb6b38341fff2478dbd27a1ba3a98f3e8a4b4c9bffc5d4707b3bf053d1354ec9debe660ce915e6bbf84acb34e0ea624c4c5d0665d1c4c5f393b29df99d1d5c1c12c2acd3afba4d021b93718747d8e16d265b9859c1b4c21a47cc92fc4789e4a1b4cca429b8a27bbc24c850dc63b9719a1274ab6a4b206d39608494c7f890a49450d261d29f4f66cce7a50498369b77e44079584d851418341d5b729713a67309fc8176cddd358d09bc17c3966c514b730bfcb60f2526ac9e45476b8c9609e18a392893a25293d06534af899937b663a158339c44b8ceda04444340c663fd5652a476e3d25184cf245fb3cc8510fca2f98824e4f7d923bf29d5e30ec5d55b86855a5845d30ad28295bc1db5f3d2e187ee47d2d699116de164c3a3492e494edde2d450b26957695528a234e574a16cc9e21fc4feed3aa56b06034d92b3a43cfd7b47205531ea1e39d799f4aab58c1582179552fdde81c52aa60189f9b371d299a9a142a98abc53bc799a41249998269255e8aac8fca21a448c12c9fc25f9c9a10dc140563dd97eef211b12f41c19cdb62d6c8899a557a82314c0459dff0207ee404c327cb9d73f8fcf751134ce2ff3a9a0eadb6212698447bbe3d49119d9f259882f058f99f2ac158a35ed2ccb597789260fa902f879c171adf418241e54b5335ab97d43982c1276c75988c07fd8d60feec1ca15f6257f08b600afdb6bd6efff93d110c7b22a88890d30ff92118dd5e823e89f5317621988294305ada20987ed465edbbbb5b81604849f69cd9769e89ffc07c7f633a9afacef9f681f9b3e44f483d25443d30b6a4514a5ea59c9b07c61dbd904f6df55a76608caf149694f24915ebc0203afa749f889ea31c182c76dc4a32549e6b7160d0e1e63cdb8627a5bc8151c6d4f7e27c5d6c605cef78b97204400d0c6af5a445d2a3cb4403000d8c23ce4d88e6b904d1003003f359ec9024e2e2426700908149e32e2bc9d652f262008881a94df6d228ed9f74c50000034358cbc99fa9a7ab62af3047dc132be255e59bb9c22056f9e2267d236fd60a83f8a04c243d32179bb1c264e371a7bb356f9aadc2a04364b7e4a74b3d335598c3d78b855d52afcc5261dad2318249b1adb70c150675c1f2dde4a3ad65a730b9cdd9e6b756c8ca4c61fa8fd79fe394087262a5304cea0f228418b99718294c3b4954fe733fe1111b8559fdb7e268b54f761285793bb4dd4fa130a9c939f7ec75e712280c3a4794cfa9ef92843e619c74958287f9af1579c2ec2772bef956d025ea8449891353da84c7d10f270caaab73909fa329cbd984497ccca55c95db0f8f4e6c13a6be4b5a748eb524dcd584d9adacbfcd635b9c18e74023134657db4f1544ddc28a3061d23542c5d74ed9e9534870238c93038d4b98d35f444fd1beb24a360e342ca1031a9530482cb5bfee55d1020d4a9843de33117a347bfc340953eedd5d0da1db69b637d09084c1f7a4a84e3169d6741ca7dc402312a6b2f09642f88b2aaddb60808d2a8fc2bf41bc40031266cba52ae54a93f408d1a3d60f341e610e1e92abd3e457d4acf2286b030d47982b77869cedbde8cf3c8a941d6834c268e15267eb206784e94d63e4dd9ef624c145985ffb7444906b95d45784414cdcc8297c7c9d10920843728b22f3e673ae2023a29e8b7a5f253542e31006d911b4d2eeff95951f5a18041a8630eea5747ea1ca2dbd8e0e20d02884b177f544dcca22526a1f5a6c438b0734c0741042145e9a15529c47d0d2933a364947dedf328b2d3c72d0188449f6e8db1122871cd9168479ed743537be45293510e6efbd1961294c106503c2e096c32b68fbada8933f983e4bcbe711292e2fc80f660f2ea64e89ad0f069d1149e96436f262c7075370f9e8af7afa12db3d985a25f55a36d1bd19a1a107433e6176d92c7c1429ca8349cacba9945e912a48f0603221b23d7e8b9af0d31d0cb65b91773ea95c3ed9c1a022585ff8f4a3d592ea602aa124b9ec891c4ce7d0c134f16f828eb9a6427fe660109f4cfda988ecfe5f0ea6d866734a484ea3f7c7c1d83955faaa7c0411f27030bc68ef503ae427f5f41b8c659647ac6551a67fbbc16456793ba7d00fcf761b724f112476459a0d26e5f6794c97c6ea87d7602ab12a77515d6c7b568321e7f0b21d6ae9737cd360d048e5312567c434291acce53b3f175723ceaf67305b644b3146c7f512a519cc2632f3f5135d479e6530b9454a9faf440673274bd115fec13a88633079e44f954fa7a46c1683c15310978d71ad515e18cc7ec2445a8b106c9260306728b14cd3ef9d625f3027f99084677ff6b58a170c72e9e6d6a2b3eea90b668922d4b89dfe9f665c30991699cbf399b9a02d1835ae44eacfe5a4a2a505836e8f6c6b2af5443a0b66fdebaa9b8f3d63914727408706162ecf13fb27c70434ae6098378b6ee923c7f70034ac603a93a7d921b625c97b0b1a5530b8a81051f9ff65b18587046850c1de929f4e5cc9694cc110c3daf5446a49dfef43ab541611f0c20268071a5230b7c773f7e8b96358088d2818af6ffc45feccfb50305ab46a3761cadaa345e30926c9fd7931d1e752d08b86138c55fe9f42dcbcfa373fb48c46134c1d17eb65440ad12cf8a175349860cea31d6fc288f4bb7481c30b8f62349660d8d069e9dd4d82766540430906f9d993369558d2fe940463e8524267ffeb432b6920c1d4913afafee8f049d90fad17d038827194d65e84cb0ff5bdc041ce08861817bb449cb39e101a4530980a217c24a1c29c443fb49806114c57493fa4ec6971c2f7a1554a690cc17c7eb23ee8ffb00ab185020d21985e42b624438d6f8e290846d113235876db6b0f73126800c1983f716c467b548a112381c60fcceb36aeda254727ac3e30869e38396a699bcfb107e6d2925afd633243728e060f0c579f6392da1d982e244f349b0f1b42a803838d77893ca7b2028d1c98b2599a0cd93629fac141758841e306a6ac4fba935dbcd8c0d4fa17475eb890824ef198028d1a982d8ffabc250fcba212068680060d4c67b5a274aa8d12ad7e688180c60c0c3a22cffae6a494cd420dd09081292ce4d25f3515460da3f3ea013462602ef713a55773427e0b060e0fa4460306662fffecdeddbbedda87561837b05e6198b0fe1fb2e8b34bf5c7e3f802a12b4c418fb6c92958aae9bb15862bf5c14fb542cf231e3950188515a6feb89f214f6f5c8487c52acc37e1520731391f6e548579bb8338257e438ac6022c5261da0fadd6a1f388b5a8305b249bd4653f314bfdd0ca53987fc73e2fef238b8e9d1b6298c218bf32f2945d98a4d687969696c2f031e2b8669a12932485b1f4f55e44549b34ef438b4761524246de9494b77a826e88c2a052c558195d937310fad0f2900116a13048d6aa24423835db150c148618a03028cbfd6cd39694ddf3a1f509831269679692a424be89910379e1099310d66127de8f9630f9d0ca1660d1894524983453fde571c2a0425abb957cf1bec381030c0f9403c7093c701cab1c387080716360b10963e7bcea8634359935618ae5a322daa7904ae83fb44ea94ce01de2c99d55f8ae90c08b1b63b8472915062c30614ae9c26cd6466c7601169730c71f2533d652b4548696b833bf73f29bdc8b7e9671042c2a614a37f5b9d4f7b342c88796078e63c6032c28610a42eb5aa89b5cc93a2c26612ab9924d5aec0a5b9524ccd7962ea2d6896cbafdd02a2ac0221246f31fede12b7cbd993eb4ae568005244c671652249fb3190bfad0f2c0912307583cc21cc3bdac647bfa30ff87961728c0c135032c1c71c78d302ad8e906698469afde2ba774a1cd4e1f5a5936c08211263d2186b430dba20f2307425d942dc22c29cbd552a99d6cfb87162ac290da23567ae9241fd68796870e018b4498523caca50adb41640c2fdac30b1c1e0779788471034b18e7861807042c1061b6acbe9e7455d657fb43cb03c7b94398c6f284f5f6fcb5a1c691c3e3d109ca0c6116cb9222a8cd0a61aa7b773f15f6123d240c42984de510d53ffb1f5a288306580cc22c61ccc26cc4f5b72905919674df974dd55f685c3017b008843144895437f3094a4b608005200e792de4ceabae65df87d6d515b0f88329c552af16b5dc8c8fda0fb0f003712d779c8be039e4b15ac0a20f0695ef55a3929a4f37fad0321f60c1079396c715912fe8b46c3fb40edf008b3dd8e91912e525d8b927c0420fa6b54eb751d99110609107f3e8e7893d4fa2aac40f2dad01167830859127575daa3af55d20303c4e70e374813270821b0d40e746073a3a3a3cd64a0ccd620b0f136071075388dda3834f14bf9c5236b4780092cac2c20e269d475fcdc5ad90a05407f347b08ebfa46bb2253a983cabbadf9d6855ffccc1f01f4f2fb6b7a3ed470ee6abfb6c519e5d44280e46d17557372a8d990d076305f14d3b65bfc194fccbc594946d49b61b0ca67bddbb94db06a38f1491c77f3c96e7d860587def4afaabe6936a0d66ddf3ad142f2199aa3f3c0a3580851a0ceaa3e3c7923f69a25d70c1457b385b06b8e042010bd82f609106936d789653f96081866435bbad65b3dbcbadf4892b8b1325676f07589cc1dc7ea284299d77e4431f5a627881632da005166630a967d12cd370f508e2828bc6a20ce6a094181db5637b502283a9d43d4e4dbb9d2e8dc1687336aaff218d2589c1902a4bce9582fd8850188c3f1e4fcfa970ed2030186f4652bc4a6fa6fc2f187654d5979ebc6036191d964f94beae53170c1f2ad7885f947ce1c40553e78d4f8e192957386dc170da947df2fed77e93160caf11a248ba178b6fca82614debcdc3f87e5c13160c49be5a0a228490764d5730ad9f52f71c6ab4cf64059356a77aae68aa75a62a1824e79f8aedcac865a282499eff7ecf9a8709d3144c9193e8a70e269289490a66b79c554b48d24eba140583901b55f12c52f4588282b943d2138c934ea59a20e2fa0939c1a4c3fa44911451a2a809a6b2cd5e8f7871e7c304b377ae17f9de75e95f82d9f2ac9d5d96a0c557823995d945db90b7ba27c1e0bf9bba91ae34732498d4f586a720278b521fc168ba646b4dfc4bb93682d1ae935bd0b2f6242e8249fa27f9b5d2553213c17c713b8585ba4cd00ec1aca2b4c812b3a33e1582498752d750e1e12d0d82d9c4e285ff5c27e3048241a5ecf55db51c2f7f609aa8e795fb830e3afac09cf7633997ea9034f6c0e426a32627f17c2ef2c09c72f474addb81298510954fd352aa4f070651b9cbc6dc947f4a0eccb12a2485d804170b0e0cf2c7f472b89437643730e8ed18b12de852b6d9c03c29b5ffa7560353cacf49f52cf4298d0686ff54e954667c2ed50c4ca94285b58bfdc5856460b070c93996eace98202c62607693946e9daf3e272c6060fc9cc4e9b9a0f42ee915a6ee10725d0ab9c21c232b252576298adf0a93be34e1c4775618ac84bc0ca14f54b85761102288d8b5eef90aabc26477a673286d2a0c96b123d4d7ac9a161526f59df362b19f4b7b0ab369dff3bcd0312e6a0a73fcac8b39b96e394b617e0fa6ffea2d3e43529844bb3f5469c8aa701426fd781db5c37b2e9d288c55691ef6d2fade170ab3fc8fc7c7eb8cb980c2aca6d492aa0e1752ca270c4a95fa3ea1e4df553c61521e3b9efdb4fdb54e183ce4bbdecdb05139614e53173be58797e826cc292ca757e753ea2b4d985ec7f435fcd5baca8449fc571e51d5c184b1d248f7a47b26a5c9b98461b404cb97dbdc5d722c61949c723e4991530973c74b5a136159f3440963c989db2128bde6a64998e5e3fd59f8b2209224617c8b924898946607a52aef723a90309fb220efbda498f63cc2604a757ff4bd16e57184a93a5cdbde865eef34c238a3b3f558ae1c949e1126cf6e2123f2c79a7e1186391f156d2647b7af08536993e67f7b7f914e8479267549cab54e724684e15a5646a8a589163e8451549fd2216e7bbcd810a653c95d1ec45488ec17c2741de165c45eca379f10c60f96520e592bc1cc1f84f1e34bc4125110065529ac890bead30e8449a94e1f2c2e841e10860f41ed477642bcee0fe66417fadd267dc5fd60def96d19b5fbfa953e1843e5f8dcfae9539e0f464bba64e5786f3a650fc69066be1e2fe6c94c0fe61413723271cef33c98a4c88c4e6aedafc58369553dc4ee7015acba83396ee255509deb3f76309e281d82ee60f37b1dcc39a457cf31ae2ca683d9545633737f3b84fc1c8c76954524e7f1fdc8c130fac308f7f19b608a8331c485f95f082a82e0609215c228252217c01b4cf24dc8d38e67fa432e003798665b26e59a49bf1d17401b8c97db22498fa621f42e003698d3d6e524fc74d6fe5d006b30e6fff947c872727d17801a4c391a6430dc7c5dcd6c9d9a34ea17dd4521c018d0392adf939efae82431982e26e3af3d95f0a430e4d97e6d6282f5d5090c9909a5a44dfe90534d5fe0728e7abf242f943e41e70b616f3f5dd82fa68e8828e31e2ee49ab695be44d6b3854524252efbaf85c6e7464f18b36056d32b654abe2de88f05455b27a1e4853115ff2bf84904f191e02142762b5ca25289987815dcac8d3c21c96e0f6a2af89fe20979576927dc533898d949df5c31b1140e7a2b6e761c05827f12f29584ce170a7def69091f26dd7d827541caa854373a05d7094fb2997c395dbf6d02b9adeffce52b5ccb044e7d25d33955c76909241dc7b3944af892d8921cf497584f2601cfda6d298666c93a91e028cdb9b8e511d2d73fe96bbc436884656476b98feafb0b16c1489343555d6ee4d21141ad4fd5adbf6cdfb921904e6edac7bf53f23d21204405b111a226774140db9467ee8914d458809049f11862d4fd8382e4bbacedfa4aa70ff0d86a0d0f4a6d9d3d68b27c69abb6ecb0f180a046a8869a1435db4115bf3e8eaccf95e9c0b160da5494aea41c142d7c3d54b612215438a82f89919fd384929eba81d9e5e46b4ef011a953364847b9f57876b5db550d1069d96249151565d380605144504ad797840033309bb9cb4e88e53217f120800cd2a946a5c75d0b02c4c0acdfab59937a36100006862dd30da13d27939e41a0a3230cfec2005e6148e95b2e2fa490f2a8a5c2005c51ac309611b2c6558be5aeb0a0f6535a458ee4f9a2bb2823f5457751c618402bccf91b9e27e31592526a300056d80056611413f1d876d96c4f4915a6492926498efbd9f6940a83aeb9be94d7c25a3ca1c290b2c5e994bc47989c4e614efae12ac80d2d124ea630291b21976e39cfc4540aa34a9e119120c27d4ba43088ad893342664dab340ad37689e0f9234914e617a5a743bc8950a35018b25d96af1c721825028579626d07952f7da2f309f385699de689af527bc27c29e1db6c2fe48451278c914486bfe8f6470d71c2343a7ffe2ebf9c3dda844165a89c15bbc54aa409d309c929f9d98ec62713c654d12126071346bb3991f2677890f625cc59ff5b54ab6d09531021e718214da77c9e4a984d59cf9538d197e7a18441a8493a294b9f4918454450eac297aafcbc240c23b277142192aaa93f12262526b7aeac2b86f6216174b9bb9ce4297f64ff11e61391f74649df11a6cc7cf73bd97192f21b611acfdef77bf5f1e033c268c945093b4fe731fc4598bd538857c8f2a1ac5784417a360b6a744a96459e08638cf2d04a9ed297de11615af18a1f24c4b110fb210caa4c450561f64963378439574c379d83d4b4d50b61f4f4d7729f544e9a3a218cf77992a910fa204ca3ecb782bfdcc5e78230fee5e9cde74a66390f8441bef3a8eb759f4f714098e249cab95e3d9c67fe07e35cde678db89aa76f3f1894a77829b3723cd7bb0fc68aa7d7d52357d96e3e18fb42f0e816c25cb27b0f2661a3841053a315d9d683d14ba968498df6f067e7a13b2da942ca231eccb2ed226269ef2edd1d0c9aa7365f41ab4bd77630b688a90b1394fc1cf40fc59122503f18401d0cf28378939da38650693a9883d0f732ba3d9e88cec1e4236de498520e06cbbfedd371b2922e0e26b112215ea7f000e060ce5b6d1329b9a45e3c8037780cc00d262197d64ded8e88561bcca23e5b8b981bf921cc06d39fdb89cf63f934b406a388d856fd4b41e5bc1a0cd2431c91af5cf3e36930b98bcaa52a3dfa830653d2b83af5c9fb217c06839eac5b97c499af680643cabe7949b5a2f96530ed9ad2267e72e4cb91c11c2fb9dd6a47c760f2e0298cda5fc5603c7dad7f5dc3603631edbaa257b5b682c1ec419efefc96d2abab5f30f8c4cf9bf914425ed50b2617f75357116ee969170cba745eb1f9e41224ca0553a58f9d0b1f5ee4680be6b04b0f5d3d495ba405c366494ea243cfaa280bc68f6d21ae58a5f51016ecef18a552d6f30ae694a03a76f66d764d2b989356917392f3e7c3ac82b94d275d65e5a8774905434aa7c447fa306f2a3905d387de6857e7d07aa514cc92839b4eb9320a460bfa27554212510f140cf23cab68f720c16c7c82b1cee4b6c725a582149d6050228f38531f2ae48a4d3084d329e80ea7efb22213cc364add82b7ee5d0a2ec1d4f94f8468e215da42259873990e9a6726e727980473796ae74a5ee121478251e28c9daafc8e608e9a6227174ef9db67048308af99122d43a87d4530e6082154eb461e9d3b2218e3836409f26654c86e08e65437226f17da569d104c2e4ad44398536f21170483da9ad5d00f10cc394e54b868b3f6ce0f8c163e7c4a9262ee3a3e30e6c44f21582c71b9ef8121490f094a784aa2e23c308c99d80bff24baf30ecc7ae93a8488b8f36dd181b9f44eb60873600e1fbfe32fefbba538306b6804fb8891f2873730e9b8fd375da2be3e1b984c5608ae7115825a0393888e1f4a58a528d2c014d1720791d76d19293330d9774eccd830ef930c8c292f61278d62600a899223a89c0d0006860d79a24c7d44096a7b85d1df2629b72416246cae30a4fa1233b55a2b8ce6aa9d467d853d95b1c2f0922e053df52d655a85e97f72b0a453ea4949aa305f7f7bfe5ce521e553611a37f5c14204fddc5161d24df5b3b1f0aabc4e61ea94773bcfe78917295398e454f25b0f69694ea5307cdeb628a974486d2285297a2971a64ca330a7b4125248f7d1ea8bc254a792a7ba0c155f0f85514dadecdc4ddcd141f109d3dd054ff9f1d73b3d61c8417a45d21629b64e183fa84af2ace3845152e88997e1e182651362d4d084419f10c2c2a4504acf04392dbe928c4552ebb2b00626cc59df5792dc5437cb02352e61d0b24a352112a4c48f258c2f7216454ef5b7b42aa85189ea3835286158d18fe8d951941e918e0e8f1a933079e8def41809b9ae2309937aeb8f337ad2b8c51f5a5c70d16a36b478800d8f8f1c5fa0a34566b185470a6a44a22e55d736b312ad4bcc620b0f2f6a4022f9f55933fd6f70e1625ca0a3a3a3c30119b061db831a8fa8e108b4a8cc29bba4840995dcd76884e9627bc5e5a4fde29fae0623aaa3c622cc25ee23c8ca1e4d08d7baa8a108c398cef1f4edbfd8af46224cc2cafbe642d259ff972cb6f09801891a8830b788394f7a2b757687c4a1c6218cab67975a4d3ba79a0d61502a584ad96796656d210c933a4daffa65f4086b10a29465e477959026e93408b544388979521e0395c0a3d8ce90410d4118d353086a2772b1b50b84b182dd6de98595fc08204ce2be72f670a23bb6ff8329ab754f68a9aec8329f50c30f063dcba62aa4cc5699fa600ab1aa3893ed38ba3ba1061fcced91634f65fd3ed3eec1a47ef24c4b44b8b5560fe6a82366174e85689dc2851a79306ff869adacffbef98b07c3e7b47a42d7ef4b50d93b985379e56412f46e85931d8ce2937364469abf9db1461d8c3a7eeacbe3a44e51a2834977f6a42d2e5d16997379a0c61c4c9f845e4f23936c6f3998b489e426635ebebc8b832984ee60f9a66647a76e8c1c5f7461bcb0800d06d8385edc98c01860203130608301361860a3a3e31035e0602cf7d0704f327ccb9335de600a22df7d9e3341e72f0435dc6030914597927dd9c39c6ab4c1a0275ece4a43f723870d86d4b1eb73497a841a6b304bf41bdd591e4f7a148d50430de69c63ac76ddf94c9650a1461a0c229830b5b6b510442f230a35d060aea42f87a81ec11a673049cb79695ff1422d7279a86106434a5733912aa93251cb6050f11cc182f04d999f0c8668694d894bf6eb798ec1ec9ea747cb67751a7571038c2faa6c68f180d41a6230c8257b8d1c4df2274b188c33c1746adbbb7e100183d14268fb1c82a7a4317dc1b07797e3e2a9e2eefd41841a5e307d8d054b797e4238a52e1c663c5e3b489f0ba61c347ded3d8ac2d8822169e8b86aa34eb52969c1243f87bf88bd63a19f2c98b296846c953b89121f2c18f7445095f4ef74c87e05e369d1e1c344dc0aa690fbf78285a7949e56c1546ac4eeb27f8c0e15158c5b5ab796e729479a88f1c5144cb5e2616492d20bb7144c1b425d90939310a1a62898944e6239928e45f611140c49ef8c2c3b1d9f25e709a6ada04d4c7fb58bf69d60109152c82eb16676134c256e438636ed24462618e2ce89abb10ba2b35d827942beb849fa3f4cad0453aa2cb1134bfc5d5693600e26948c689f749e4e4182419ba5941ed3d264c48e604eaab3a48f9d34135241a8610473fc78324e58b827790e307290072031b868456270d127404e428d2298544b6fc59525352d11c1b897e331f49aaa509f21987a7e726c4a76cbef856072f9f9b6b7f5b5a807c11c748e7fd7f67423b440307b48b14ee46e7f603ed12f61a1f3bd9fd20726a1c24ece21a917f1660f4c1e443c2d79f3c0a0b4de2297ce15f2c41d18befe5c3e3be67bd3813978a7b5e7c4113529393068c4fcff6cabf289e1c03c9ed2782995f583f606c69a5cf359b1b45c6a03737a0eb1e784f7de563530c748131654a5698a72dc40c18d8126a0c5a5b2d8c2030235686014d98f61a5af521cd10c0c2b2159ae546abb735dc8504306e635f19e576269b3e4d688815163628b5239964871d680814954f3c478b40e97995e81c62bccdd513ccc841cefebd2d15127e8e87085a92e25212267eaa7c75b61f48fde96245e45d28a1526c9763ace2e05913b864e6078a0b10ab3e41c9394524faf15972a4c79c429f3b31cb1a6531da0910a7330cb163f215b760867410315c66a8f9e3ac24cca95bd61760aa3c7cfea29e85d7cf06e786cd9d0e201f8050d5398cc3abd7398a815b6b35fa0510ae3ad5ef6baf8314ad43048611032d408d5ef6f3aa447619a3311fd77449867511d6888c2785ab62d173f028d502466326b649750d58716280aadf4d395fc44758c8086278c1ed6f5adfa952e773a61acbee816230c03c717594da0c109546ee42822e5f5028c86a8044dc6e2a148140c8641614018100ac330bd0a831500000010168f06a311418ef358071400033a40304630241a2216141210120c100e8442c140302408830241301010060342a130e655744d00402a73b6e3e6a18ad30757aba1f619b858c691d8e2bacbb082cf764309d12c666eef0f4b175dd91dac9a5747334629d61fb51c29a27b62d8f8fb55ddad5d37e58fbac9b4423dbca83f1b76766105c28a530d225a633a0c642bafc68936f52629ca4efb7a725111ebeffca7eff244f33988bacdf40b185eea5fc3863d3fe3d082b95fcfe00f1a4b77c499d4ea23789174ba49e37aefbe5fe0d09dbf5ce3819d176235bde302445be2f9669f7bded71aa95963f95d10caacbbe96e517fc997768733ad6fcd5b4709c68bd31062a2f72353b4d6ab75a3a079efbf337ad13872fa1e2b7e01e16973733d83ff476ed21d0de20f7e2bed533d1b7335e7366b8eea6c59cbdd3a4b63e9ffa8e582e9505ece535fdd783abb351ec9ced8ed3a506dd9a2892ec088afc0a7eb4ff98639a9e95a9655c5a4d638366c3c559f1b0dc9116d93dc22f11a1aa432987d7d32d8251ded4a756541d7c0589c78e6ba609ff446a7922e4ee89292de9a09f42d7d9019ecf01ffdd3949f32849a49722afb3e34ec83f642a1df9e47179ebfeffa8adf82630c23b54521ac37a1ac234d501a73eb457b22c829f15e69b3d2d0046da4651aa8d77f7b934bbb2509adea966f01cd9fef29629b74a90e587d821763d870f59287f34ef5785f079460483b45ecd5d31050674a52b37aaf9b180c4c053ca40f9450c9f55bb750248da5e93aa11720dd4e97863ba4155d1ba99c0e295fada551f4a0671540d5955c28e93e41318e551d4f46049cdf1714b0aaec9012aab2965ed7aa1f75311926db5149a025a2ef77844fc03fd34374e9df558ce15ce712d3c9ad61696b50419118a0adc8c3d76953ee7c7efaa45d82fb7fd84357c43ff2864d138bb2ae0dadaff0d8a41ed54a93345e29f4c48276de5dbb83ec775c1d65945a43757fddd2490ab3bd6982f18fe56de6aca3126aa8a71544f3d29a1b843808cc52f5282930eda9b78aae0ef452d420806a4b06f494c668543deb41cc1eab937a33e7867f55cbf540e6ebb51d65efc05c590c5a31e39aab618ced14e604e5913a09333562c52ac3add569ddb0cb72889ed79eeaf410ea33668daf6abd8734afbec748ddbcfd64db61a7ec32be1ac9620139d81fd6ed8ccd0fdb320110e4f0d1c7f265f523d3b65df1ca99343da0e0bf7e9f949fde4483464be19a20df5c18c00d5b9744dbfa19dc257e560dc4df93f5990fec168cd8435417f4b222caa49d92118e62d8a0cb69c5fd7ebe5c2a6e96763535b5c6a7fc236b1b42ce6e0aebf804ceb8d10c0edd8daf8c1ff83bb8755ed36021fd6ec1a6d4fc086077ec01ed1009bbd37ac41d7ee17a2b9a3b14d24be2d6fded6a7f97ab9ba33c46ec366d2c19fe2de70454726d21bd22279bb62d8f1d2c8c99353a71f60527a248ca91959313638c843b09f176b6dd51382149631b6c590da7cbae8e8f368ce7f6d45b81f30570ffe98633fecf20ebda9db05b2e2ca3faa59d9ad0a2e025b3f3ea21e496c8e4519912d54644ba8c8ab15c3096cb4a846213e4e66b5d25d8ab2c4ec4fb4443c7d7c4c2871dae82407088c3eef8aa41a945e0bdf9a6db88e3b2ee3367527c0c392a3906913e623d85c344ca48a99192a6eeb97f972f7ad42889e86617e46b2248209aa5b8473a88188d6f3d25ec097bbc0e9b19f59f9326399b1c64cae62cb0dc0a6e7609061e68d682c86c11d09c16b6e6c02aade2e0f2beb23f0cec638a3f5f751f6ac1d9153280c236abaa2da70c73c34c483c619ecb0c01bdc033d2badce43215c639e295d12b75535db888329bc0c8467b822ddc3ddcbc4d003dc2310b0e763255f4cf6984474cccb2bef8fe4b82781571e5419d1bea5315c9d324fd8e58467de9474806293ab312a3d8e34d6abed7e176977229802df2b86bfec4ef712e9db8b084d320ecdc572c0934d2847e69f3df959e940bf02a1f25d87dc9bc2e8d46370c51498e438167e3aaac109ea4ff6d23e327a715b10b8f0ae357b94071fc7861dcee0834371dceac661a363e41f367b50297d3eec8aaa89152f49a1e0341d1a5a987a66be735bf0d3627cae0827b6624499ba0acdd69df1d4f8e7d402abe472707262a407a98f0da0db94ccf241f7e7c696975b051842348915cc80ac01c6f846546316a4769767051c95a904e426f0f2006c0b400d85f69d5a9a7f21369d33813603f802e00f55e43f50c02d2027405103dc05500962e782da0de807d025e00d403a0fd00307ddd66089480fc7fb885be65d223a7bbff42326e589d7418be72132310f560cfac2e6a876560a77b9eca309d3150a1953f572513ae6582af789355eacd0e62158b39de622f13b2b58eed911fbcd0eaebfad576c809c6b86d959f5f2d518bfad4b6e4402fdb1c94d10e0ed9a5f98ec3918d0b98dc5d74871c600293144b44acb1aa55ebf6731eac273c27dee56c67092f860a037c03617727261dc271b2854a3781ecd76fcc6bce2f092972004e43f2af6290f4e656520843bafdd4b94682b61508f63986b244fff17a33baa95fc82bde11739e64e1982d379b284039c93335a02d5a64f7967a64e720e02b2de0ada97920cb0bad16fbc6f7f65317dea41b420a86a02a41b7a7e99a1705831db1b513df1e3b8673d180e07dd056112a211a85bc34ded3dbc6378ac4a678b54190c3ae61868978229e856d0d8fa413c449932ce6f8a52a82ec458d3d40844087b33f637966d9c8304bf24a738a2caa99871c521f2972342dac8aa4eb706c703db0e1a10d14c62623a6c2b3a130073c5c0012e65b031dd7e3ab1247831ff4624c6a14d4fd166f1154c71613912c25ccb2fddba5fc44ef190911fa7feceb8f94dd4bcc555c14b29c5d06fea721ecd0016909ef62004f3df3011a5385d0f0f83b4cadcd104e5c528d3f30b2e3a8c989a121e70aa01255c26291287293239137a8d49c54639745e294426dcba070f642513e7539a41b0589a6b4f020126328a965511a83623e9cf722465610b0d594c902fc74800dda515bac5d51f5d452124fc1e73505c45c5e2263f35c1831aa57b940b10e782ab4b4b54444fb22314eb7ad94cf6e8485e45af7303e4421786ab631e0d0d2e967d37c0aca6b4dbe1859c8f16862df53a0b327696f1401c6a60f2789c66668642575842a51a1226c7acc66241e0178f34caf244142f019685902f19cf50bf46052eea93378debc13f2d5a4fed6ac2e5b9887528dd2b453663ac17e2f60b1ea58203910903cf27dc85e60044e1933e5bed82b65250b74b51be8069583709db1bfd054cf2d2a7806982dc29099dc4349a5508e0308cfb8270158688d50dedd31ed0656a103b45a8a040325192ac44173c3aa3c181c6c29b14b0dd6d326fa02f53a86f57e014fd907ebb2ed85a317347f89dc52a130a8c592aff731c0bc1b201a950706026977f77f7474f5060e57958520450fa9187f5a260aa240f90569fa68b57a6525d89cbcb57af0f52a34b13d44f05e74058741707edb0e6ce0172088efb03053f70479eb22a5688162545851ae07f710cbb51a55425410429aa9428a780cd34c46e42d4813597a794be4118125fc50897dcc611277b49c4b80d2dd0c2396b8461b2fd0c214062e7ccb8a858b685c0a7a4cc4b60acd9d0259abb10caf0cac6ba41b99698b5740e832cac51c96d45438a6ce9f09c3e637534a435615ea98e12384b3d2d9e488cd7fb635be02a6974302940023d45d7fcb6450f02d4c59f1d1f51f94361a0da5f11a91d834378342510083266605fc0110ea68247b6d19ed17073782e85c7f317d3e60ffb1c7e90e4b5f5c94cdc5d1e749d4f5c2e78b850b36ec8507be408af5e37301f8b037f227f6817cb096a1215cd64116162302d74ff86866931f301d238ff8d423e453b51242d67af9140680daf1355048b39fd4c2308d008d189c038a56bb2dd662a5e7463629cc37654d3cb88677f49c78097528e327cb02cf77592fa3dfc21112d1f296488976c572a53b52533f5e242251d84075aded1fe40d66291050e315a331a849c2cf40834a1a2330806af080cfa4d573452cb0e2e98101e0ec8661bbcd3902a521fa03909380891753366b27c49f28be9d8f81ef38264e8230c76491fcf8681c697cc5aa429f2eecd6f1c036915f4c376b7abd69658f7d02292cfcfb92b751209c18f912408b7df061801313ace5c0fa08e4fc8a7edad74db8333a8438a14a6ee50c5887f9be0501dad594ee7e592e4ce112513896744a6c858e5304033cbee3a609dc8d1d681540c17a9e239d110e0909e8b12aadfd7d7f18dab8842f8b411a6b7fb74d0850f5dd4b443cf63ceadd4848943b0b583b7628a88b193a5cb66a2c142c9063b12b49829fd78151a1e7d49631f1a54777405be4f05176348da681d726233011c4f371d88da1807301083c9b1772695fa0fb8587f90bb9a2d0648ecdab3ac5cce28f783f4f792d1c2db063f179629b266c407bd68768ce773289b32a28f68066a3da3b82fdf31a2e07084e41d3853d4f1bfc88f8f31146afcfe4ee8e7668fd0ca59900f34c314e9a0671db968ca39e1c256b23681b50dce66e5268d57e63b784cf4a235461093f50d0580025d46ba2187c61b1cb3322468c205d8783a9da876273e8a441a8062098b60a0d8fccdcc93fb2e50df6b6e70026b8b83e4e64d2426526d0b244307ba26b9f8001075c62d5a7843d9175f838a56c2847c544d8594606ceb275056e3b2c3e19d5479ceddfe9f7b8ce9146dd82616e098cd114a0fc1e5dca24743e5c307d7ee3f60cc798649e3647409f50880aedb23888e3c730211674500d6783878f4ada83d2fc0eb81f0a294e73b76dc6c06b7087ad95288c6d5041de786c01c4660d562400fcee3c27ba26da869f25a4aa5e2167925f8fc517f116c3320be2789fc404de542386bcc8c77fded516603e92e6702251fcf681cfaff985115f3440983aac3624df29a34d50e1a0e866b5ac9b5692becbd52048daf2f2cbbf286753886a86d050c05055867ba7adf2ed16b77fd4121e39d969389f81cdf29565b4e7189439dfc4f15b82c9e56dac14c4555dbd15f0a720dd3ae275a85652062fa68d403ff4f64fd330592a2ab9b76342d77b085664170056fc61b0e2e22cc54d276cb066567a003a3c0ad4e3e6a6cabf9a17c90e749e24a56a5c12ef4d82a56456fa8ae9189a764e05b5157bf9445b1bf54f5dd5fec6dec2992ae543657a742de7da7dd480216501249b4bd22f078ffb829092cc1b162532bbc4d7e8a0209a0b75c48d61f420a23906856e489fcdc671e56102f19f1c8609fc6720f08eea49f08d2082326c8c89d0e0da5df8468e8074a20c006e1da503056ada1bc458d140a7771b82edec01ee5ca3f55ac17b7fd96d68ee43dc371c95f6d85ed294cbe0a1f208a5b9c83543e84ca0ae00f2fc99b3648b0bd1be1db78bc311ab7da045b49d826915743b4b65b633cd7313320dda6e3bcc02846157aa72f8ba9790a6155c39bdae6887eba6e85e8a9d2f75e8d24722d9e30119fb668799990381900ad8c4b1f5a379adbb8fc0292efea63bde0b6de8252bff4d6b09a78a2e977a0c3ec87f0e11d9e16eafe21f5a26b21cdfbf8d40737504d2d8dbacd824a849f510838dbb66558032218b1c12fe1cf83c944f4b56ee58b74436e1c2712b80a8f02ed0124be397c21ae5e53dbbc57026b6a7468184396f9262ad58d591e54d443030f53e2192a52bb2afceb61c4ff23a8f3a06b71fb7338d24d1042765bbe83af07db032ae77f385b932842420e064b9e420ac8ad603090f07f135820131e449401485d0f83a4280c83b8cb7ee4687da2f1f43a8076fd1c82c993d0ef575aecabd876e0feed6ead6ef658b0255c09b6de5b98995f0c137fd65971971c967f9398b4696da0e80ae52753a18a93700586bfa5c0d74c2e171823bacf40984b983dd96a97f9d243673e66d4a3f63515e90f4250f7be9ab5ff08e850186a7aba63e352822198de44f1b39a927311da44413a9971eb3942f90139d14e0386fbdf7f14f7effa9df7efa379de61ae7ba754a979de3a5a78fad95eabedaf54087bbe2f55e34ce0c2f772490afe4824d132021326a17f1bcbff8b8f77fd88a5101ed9ee37272baacaf9608badb2f71fdeb5ffdea373fd349ee38a55ba6855b2aef5c0c8b0ff2171962d044d4c79ecd59230b7efa251dc6028bfa17dc63f2d497bceeb92f3ee99bcfe786f35f6b523a4835165236c69a90350662be57e6646238dca4647118ccac8d1144599cc82707d35fa9804b94b6cf7852139b38b1539fd79cc68fc604e39a6a8cd31f1b39f38631261dc9a7360dc82225daa44103a9a82327eda44621b92926079548d394b335a0da6413315856ac85bd1c9a8bca399a6ecea6c676ba6d25150ce96609bab266c6ec9ed94ad3b23b2d5648f99d4c928729e532addc4c895df4e568aa199f3b2ffc3ab55206eba7dd2aa4bede4a85fab4c18d1b679aa94e61326699a5989dc798ca00a4a49ed294a0154924a780242822899264a71f19e9933605a4eb649dd5002d3105bfd45dce71a573b775d8352ff5b6db3cf5d4d73fc7eda77ef9e9deb160012ca37ca2a0886e44519640742143b914a0835648909aaa9c6d868920223ed2d4a7ec0aef7be4b35fffecd79ffefd67baca09ee74d25da776e3e9de76ca3b976686a7d92332fb373227afc0221abfc69033b5732a8e1501ec64a475cd495c7536579ceaaa73ddee9cd79edc9567bdf4c92d4932c524411379d126073548448f14692fdd9b4f7fddf3de705a9ff3cc606e21e54c0f3ef9c36f7ef8ab5fff4df739c629b2567a985d88a883ef78d453dfc15f2b86ad5b07a49096d4d306c142c90c184c6c69fa89a009a2a82224cd094709970300847f86c8e35f7ff3c75ffd503739c4852ebad4ddcc4126fa484729b9a8420675cb76e569dd77c6ab9ec6638278776286131cfee487dfd429d771216957f99a80d3f130a597b621a2289db379e77c9edff9af42d073b25f550d1ec31446351119e9273d0ac9a73219a84526eaa4414769f5056455dc5cc239e12f3ff9cb4f7ef933dde70c779deea2f35df1ac771ec362cc543b401e9a4055413fad3f954d8241e62c9221cbd7f5dc67bfdff433373fd6d1941d3364653abcd096c593da0d85f99a72eea60d54c4293ac494d8dbefe75148b1de962397585e40e605980a3d0d1655fe940bdebee99f8dd28c873c333e34621b96f777c3c936001af223b6fdbf54945bc04852e079b6daa52763a73c00138329efb3d4a34c246b704ca2329a7ecbef4dfd9e19f7855ed0168d111b443eed52b8ecceb4be4010b87d3df4963b52625bc6db5f3a94239c1a7bd973dd5c63f8c4acf62dc56b1c537d338f36aa93e20cbd3360ba9fdb489a09532a2989e5809d6f4cb2364e47faab3992a9fe1ecae1aa829b8360661e8f7b5b235f1955e0a211dd678e3f4c061e4edee2763aa307941aaee49d75ff0f0bed6cadbe505b20331a7f69fe782f3332eb73033ee9cdd4a3a4662a1caefc4b91a4ce682caf20cc63c22b9b288c7d6a812b2960d5b8dd31406b4e67de07ca2920a15277ccc93954def52f8684b1099ad3747b293e01d902552f2327ea1e119d985b133cdca97edd522e2930cfe286b8f555b7d2abb4c6fa115908f0e06e1ad51060f97a6531b5937dfa8413f7b872087fa5618a0abd41ac5e3fb1d03e24d3f28be346d66baff9af45c6781533fe23360a402dd925dcb011a0a20c013f9369cb52e58fa3b92436870a480af7fb4a456a8144e103eba587e01ad47441bc22d69fd436d16a4598e0b3036fc870257f35b9cc2039f2589ee9605999587f1ad0327152af0a021a3d1ca0e3bd02ed2e719b2e7d07cd27161eb647cf56fe513261f0063d859fd8ddb31e0cecc7ad5cc1c4faf378713a533bf545490a4308eeca724283679ec8f94b67c5433135ad166f14ae11d38873c7ba5ec60001668067f42f6bc33dc70602c31cd116859ae31c07307d3397440adda5fa1d74faa2f295ac238de0eaa3fc6e59c583864d021a6a40aa93e16f7cecebe6151d6b155a75840c80682fa2cd8f32352c6a1d57c45e9bad4560a70446086ebe0a127b30ffa13872270c0e71f4ee0cafbb7a9a6e2a3fa4b802b36f42ff5be16a9e11205d004d241656740c2b11e9d4a463c951b24aba4d6e28469859e0d714ff44c5e75595edafbc90cc38fb4ce21cab306aa5402355db7679f76dc5907291e1d12d95288be597ce12b890181134d51d9e6a485c6c88684da61f2a7683b831764f989bee47f26d1906e0acef0769149f9419957f80ee52af077a7893821418c94197506bd85d9f09084d35725c810dcf3e6098062cc16a8af4e6ad5f28d720504deacee18bd15192d1c910163da8d72165ad116f9702474d96e4674c4db8149628c4a701b8d53400789e5eb69b9c0b3557333c64515c86dc14bae5240541055a7d82d65b95d219889aefdb37df46705026262239498292182a01f847e54b5238804d404a3cb5a7c246700b4f5a9f6f4d3464b4df773e83e3398229e3b538e6cb626c0bee3dafce63a025b400c3ed1ef211d37e6bed7f39cbbcd52508b451012b72b99d411aee48894294ad3189840d4c8190c744de8fde1c9e41e97740e3301d48be51ab86c90c66bbc27f132844b696531a965a4e6881da9fbbfd9d54b1ae96b8d84ede632d5dfb18cfa17977c5c0b3ae10d35d797c07a4e082eacaa53bede6de60d7ae320a8c394f38de7f122c5a5a4768ab77017ab9362475a2c24de5e95dfd078fdc657ecc4bc8c426e45df9f5f831ce84f973f51c921afa38fa5bdebe7be19b872297c6907c7a1f4518ddb0fa5c9139021c4b21228ff0ec389949a10c3402255554bc66fa64722d80666eb15ad576e40ca4ac51ccdc67014fefd89d946520608d7dbf6d98a85b6c362bef0fa8acbbddfa77746d268e6bbcff930e5c71fae00cdec4b327a78210cb6ca3013dcf22cf07023f78ff450a620cbf9828bf3794cb7b1dc7234f6f6582fabfda9f61e1b33b66ee1d6b7b2ddf83c87f3ac62012ec0bd4840e2752bebf3db171d8fc50ce2fdac0ad1eed41d25ed130907df1728353acdb571ae6a91ea12a30b62bd389f178e83cfcec6268f541832d7513f105cc712ba5e23f396834b98f7991f02a770e96132a9c89c6534e98b3f95059f93405dbe6b2c55d6e66c45ca9998cdc9dd4978582e1417277a78c164616ce5e13d593ec68bfdaa7df930ce3a5a81ae7a9e4fc473b4ce9dd0bf35c7ffdb03ad02d24f986504fd618a3d42f22f7dd1bac580a45cebc2c1446f5ea63644abe476606d6205ba6f45e1f2f942e3a54f046af7c6a05d33cd12af93872bcee48603d8b95d622ca66a71ef3b311b2c55d99a2022d879b748537d509b6657692910e21f465538f66a68aa49ddd4115e514ed63080054432f7face02b85753568d469e7528a5818800d60c5760696c282c2b425f47dc7c4942e3c0a0640f2385a5e4c7f74a375ed5a665f63a6ce3b7cfa68269b5253c86da981da86e6ecb08bddd0ca18689ea59062eaa78fcb9ca4175e3269ac05923f979bfcb418726252552c724b5fb94d882ae6ca9178413e6ae55cbdd21f0b9b2642c472a4a7daf4d4380d4541eb1ecf2761905a0acbd0aa33609e15e6a5a41072e9dcf1131f654621719d2aa9372a59145d038456d4f9bcf851f6242bac402cbb2122e6c03cc0258362b6c1dbe3e3c9a2a9bfd72655a3b6848b66c44927f829608082f6d9e1d02066c66d921a4d2e3fc1433710fac34f0a91fe420e187d1bb6b512ce84086771a7eb4d3d2816e488f781072f9f4c773b19a3e85fcd57c2ad3ff8fee197fd9128e24034388ca45d823a797e1bc7ccd98b530f06850fec8e2e48a0fe91ba24566e8a71473dd0bb2f9d8e4aa499d9b53466d30bde5555fbf3ab9236893e937475a7ad4a446a92a5a932109af42f6dea6719fff2b13180e548883c1cfc9d4c72c68e4fdd338305cdced2eb809437170faf54227dd55c938963bfc7edbc55f0d547ed15317b022fc69bb4d5ea1814ec4edd7dfee4048a46ee48527b6f19af964afe90fd0902e57cf8c2f96275bcb1176f549835eda34089d0b50ea344e589eaf3500001a59aa3124c2d89211a01141834c2f10d2d34b0325db065470f61948a40ca0558fc8220255cf68076a314aceb7f00d4d44f420a782524397a6e44683e6320d51e9f2236016d325b8008e2dde8332336ba5d4f8467ed61e09089dc20b9b2dc654e4d6fa2e8077a61085a127c5ec664c95e574a6c2ea76e250d6e144dbf817ff9c14628d97ff3c1668bd6f2b942263be2a84298d98d3daae4b4001d775421f83abde944592a9db93a45d82a25218775c96b67cb5347e939dda71ea25fe77760eb623123edc0236b5211fde5f5d2ff708638d0c8340e333b3db2e2144204474944252f6c002c182169dc2185f01a77c0818b1b312a070cf0b182b1121f11e4da6c989ec99183db178004497c1ce64870808fd3401ab6ed78dc5e903142e5a956490d095d7fb9f8279a9e70fa213c1543039aa54267e233372bd6bd038c58e17be24d4ba79035d83d1b905442d8b3c421be09a784a2d6526526b1531c5373ae57b8cd3074f4525af5b6c6b26c8744c568c1918c6e4c38903365b2d198a3a179b35278a84a3630325548d8376e11af4ac04bec04c93f2e37cd7636cba0def24be867d145c1cb6f77cc1c7fa4c7b84c409eac186a2cfe634366217a32e844d7b183b987f4e78d158bc666e25e0ef0bec1d7bfa05406723cc6c8faa25cf4034e0054bd93ff2aaab11127527d0be716c68b28c9ee0c2d141e0094140f5eb28428908a921fb8381fa16c5d3195ac035f65fd13db5e39101c7c10c2620f74559b9830660f317d754103e6dca9aa28ad920abe64612526d7e41291d9c8a77a5cb365a44f413ac275ad47513378fdeaf071f3f1916ac8b329823468ce78c11bde3139ee4b1e278d6b98c6546d1ede795243ae88dec042f3539f8cef838de6ba3aae30186952b28dd53696b271697375ba19cb2e44d0aa8d2ce966a687ffd6584033d80d9162f866074805374fdfdb4e3db5efc198c06cf6929b2d856ec26718a3091e8414084f39e4d50bf98cb50300011c794d9c0dc9b74dd0a2a7c106bac8aba54f21089d75e8232cc3f90d43dc58f1ed6365107e089788e8522adaeb05a24a5c98eb7f63caef40761ca2cd04fa308771060d92d457ac8e631642a38de981452008f38e9019fa40b484b61935b5185a4d3f31a272ba3f1cdf2eac5c08b0eedbfee319a1ca2e8b8861004cbb84355a159ee0fbc2ea6752aa5e4e23e925b3375ccc7cae3f7c5c305da4fc547f4b3269564b3a7a2c383491f0bfda5bf0999b7adc9539923653358184fdae2152a595fe7cff34ecdfb1307aed180832f35b8df34a242cb0ec434d35b93b62060fe00b1af36be8fcb0168e82ef8f1a15b415c697ce7848b80032f39e8efd6a82340941de33d42240744f5766a707a80aae726eb77c149e6b28c01b0cc1389fb076f94cd18ae06e9ce4e30ea2b8bb78a2edc901c48ef97ef7b21036cc0cc389ac2502ce1d048a0a3440b2a4d001ffffffffffffff7ffa0cd5b66f5bcb6846a69424bd94157229555ea69464da29698fe89b743af0a135426600fb9ab9160a030b7a0a231f18b971466e8c74e0c60807466e8c6c60e404618c5ce1c30d87135b3f13fb84c3d20d1f6d386a6ab24a3feaaed2596ef0c186c3996aaef1bff62f3d143ed670505193b67ada1f6a38775d3225e5560f3bb1a6e178b277992b7aed5bbf2a7ca0e17cb289f99565479b745253f83843f2618693e6ac4b6549e76c5486f38dca24f762fa3291e1bcb6962e95e027ce9cc67016df4a728a290b1f89e1242921543c4cd06e52c2701ea11f5a53aa788860386e496a32daa8a0b5fd170e429a92c426db0bc75022372ee62e9ce64bbace7a9d0ba70c32463687be857398897e99ac3616ba164e6792f80f11efd7cab370b070caa26f4cf94bdd5838a9f2b9b9f7d8dfbbaf705282495a5a632b49a3b6c249876fba2e4d158e71a3bd292b9a0ccaa6c231f9e7564a1af376494fe198645e8a8b0c6f5b4be1986e3f7349e849f21c85b35d126b1b2efda4140aa73021546a7cd1f096271cc3ad96a035f7c74e9013ce274a16a1dea2bf62a8090795f5d69be4cb4a79269c52f0513f193e74ad4b38c98c2f5d16259c4bac2b96dc25625912ce33af57299eec0309a724fd557e9d7dabb8f938c249592c9342764444643e8c704c5265459e497d169b8f229cb3c4fed8ff17514af3418493c9cb9c5ef934fbbc1f433805e973955eaf47cafb2184f3ea7dfcebee09f56e304e6a53f82ec104c6c9337f959676cbaffde25c39453e643a294c6a7d71f8322563cf663cf97b71521354d09a2989a8342f8e27cfbcefc56f9bbc8b8388b0d24b4a2c71ad2e8e7523bb34a98b9b7271cafe31192db2ababe2e21cba4dfec4cbcf4bb7385818933749556cd26d718c2b49dee09fa5d5aec5c9829a60a52994a4515a9c5234dd693f26c65c6671fe0d22e4a918e2952465718e6d93328919af62502c4e77c2e88dd655a3322c8ea554b5e852d19bcd2bce96c3545a1cb5a0b5e28ab3aa495295c514b2a41567576b517a7ece3667c5d12ae5d44aaae252781547abacd179e237bb55c5e143598a61317f932515a75416d65aa2679c878a73499a5adbc42c890d4f7112535142b5aaa98c298e7d5ac9c29ead85a91447fd5242fe872a696348711267f4a228f9b48d4671cc70674a92636f9615c54909afd427bd89f25f128a93064b97ef4ba0388931fff4251f55dd3f717039fdd874b27aee79e2b81a776472b1249fec75e26049fe32b18bb5a91d278e9725f2e16f6d2adac4310815ebfb38994e581327bde13c4eaf89a7b165e2b4294c8e79d7cd6f629838d88bde8e25eda9965de2a87b4ad6eaf92b95b7c4b14c89a39945c61679254e92a9291d6925bcde9438a81bad97ea9ec4e9ac04cfd4a8e9b495c4d14386894167799a301247519abfa784eb4b4aaa070f98042337cef8118cdc18e1f1397a30080c2c06008993647297d8e8192fbc6ec1001e710e2dbf31a341effc260c0370049a31376eacca77233e51fec470d2995818613c7177ff4f6a3ddb1691501abd5489125a52a488e47451febda2514b9588eb6f5d36c858491222be954be2c7e91065a524949a7b3f593186f82cb3a5f1dd540da0102719bf742689276792d61e67bc0df0c940671800210e4ad2fb1659f2253488938a774a4c9231e6a9200e7b61574cec3669ce401c436f9272a5629a767d850100e27c1bc26cf48c1e65a63f1cd3a8d7fd932b465ef6c359541a25f3e8134455b40fa7b4cc223e4b795830f9702ea157476a5a33297b38c991ad8d1ebf1b93490fa7d8644a26d15e344c9f8763f434d9ac263f667c3c9c2cf44509e24aa6b0fb1d4ef26c5db58893ec3bb7c349bd09a6a45b9594ccaec339bb2c67c3ef5d55101d0ea66297beb59394d8a1391c46c808d374f97a632c87839f5ce25e6a1aa1721b8763ba86d3ba967209420a877399bc6a9119d13ce51b0ed6aa61554ef9d59b6e389e24c325258c490d7769c3c96eb39edac973a743361c4de6a5ce2d256b389eae13a3993eb78c266a38a9b33bf9c6772bfd349c4e2a8ddd7acd68361a4e7b1953121153a9e33bc3d1b4052597a49d194e3a2a891e531a7db3329c04bfd7f9320d198e5df11cc349479b8c7fb793ee2b319c3594182f94a484097e0ac341aa7ec92cf683e118c39864826aca522aff8593646619544c500bbb7be1fc591643ffc6fe8b7b178ec15b84fe0a9b0ba7241bc2b44bac242adac24966f13eb9620e25f35a38d6860b9b47f4620a67e130a72656da68260963e16cc284357144655093af7012d5de7283c99661b6c21a0650856369a87217b91d6d0d154e624a2a935495291c735ca7be061162a291c2a9ef825dd25549d35138bb265372b7a7263941e124c574dac9a93ee1543a7ba2a87c3ae1b05d25944a72db096e69c24184e5ca0b35166b62c2d12b4ed291513fce5e02dac47a339a90124eaf492aab6c254b32310907cda3bb3126241cffd2b465e84738fd5a9fa60c35ba4a231ccc55f387972449722c82190320c241bc5fe936299e8c493284e36e8c97a452dd008470ca3531fd7a86c6178371f69051e664e6d5e82a875a4100c03885124ef8488bebcc9b5f9c5ec7040b37eac2dd452a08c017a71a953b429524460ba75e9ce3f4e41b6925e2c3c48b93fc06b94a7e6fc94abb386670f1d166255dea5f17477b0d75edbfe7e298339455d2ca30a1775c9cd4d488f9960b6bb5dfe2f4265c8b658ddbe2242397ceaf4f3a77bd1627e9b62999740f252d4e8be3575f7a788c7ab57c1607115f23ad646c0de296c5b145f8796d9f7cad742c8ea2a6640cf7ad934cb038aea9f10e7982cc09a3571cd6645397ac37e6cb22579ca4b29e3bc9475b3a41ad38a88f1bb52e3b4935c48ae3afc8fe4a6939eae7551c9378b1212acdaa388909f78a5943ad9d702a4e82676c090d16debf41c5e9425ac50afe27e68c39c5d992a7fe8b698ab3e5a8a0c20525a6c94c298e3316472bb30925a9a43888d50f3729a79ed58ee29ce1d3848b7f1b4c92280e6f496e8d0c6eb90dc5d9f7d64bdc5a41718c260825f688fa89631056b2e95a90b312f5c441777dbd45d7989567270eb24f54499513d6a1e4c4d9e22f3346771307317d7726624bd4333571923a9aa471b592c7cc4c1cd4a9b64cf26fdedc25264e31e5ca94c664b2e45fe2dc5f2ac5baed8693b7c4295ddf76e39230b2a9c4498a279a2cdaff4d6e0b254ed1e4d292e992cc986512a7fc27ef43eef8da582471b02498182a76891d371287935db536637d9722248e2705fd5d62a4c5bee023ceffb51b83169d493f74c42953eccb16e35f794f1a71d0b3f14f126525ef33e2a4de3328a1441dfb781127b1a41053dba352d653c4f104ada49212fa44cb4bc449053159a6ad5252a943c4c13277e532d1848ec80e711059b7611733439c2be53df7124c55ca17e2e4f657e294b9e956008438e5caa14ff44bf225c112c0208e69d34afc9f24a65435050108e224959422b2e7a4b27c0ac449bf6e4ecab4bc363f208ef974bc82b8742373e60f072da533c8912958e9d30fe79274d8c5ae68a6aad2876312c2f6d45d2a0601f0e17c79def49ee85582bb7b38b8e8cca79228dea7cdeb8200f47010ffcbf562a7fa269f87a35cb04d7a43d66996f17012947cd9f0a33b1cc49fd767d797d4a5e911beda9f294d13369c4266dadc186737e94a6f0a216b38893b3152438637e99d1442d470b8d158b51b4f9c59fdc2109286f36899cb6825ab0971cf05216838998c7ae2871255229b628290339c7daf6b4c3ae91c6a4b8310339cfa2a96c9157284f65586538dfda5923acfa1c62307651c192164389bbaa0a2c617a5f2336338b7a6a692b57975543a879aeb1823958d88f18172060f76d420440c87d1ad76278e8bdd57d602216138c6ecad8c7e090c47b7cd61794e92997effc2e1b7429c9ee07951732f1cd34e497d366a4efedd85b3b899fa9a4a61b96a2e1c5e37569efabb859385b01b11a7b245ac5a386a960c6ae42c7a6d998563368b77f1a4cf935ec1c2312d7c9d9aba8fa77785a39cbcd8a2b394ced5c8601d2618b97185102b9c842ccbd427d389ab18528553c5e652726cf81acb43a880db8490299c847d7b3f9dcd920db621440a2749ec9f28153d53330887d12011444814ce5af2bc95249cf0d726215038a9d1165cacce734b5cc78790279c464993c5bc0475a576821a93694aea1935530e93343f0869c2b1c2a524f48ac8b7119ff1233015c2849398969230aaa14208939025e0a84088127a50202409364290308190234420c4083846428ad0801022f47040c8104642841001906038302000f20b1c2320be28905eec483ac6c0c18b5d80e8420220b9c03146191b3881034070b100905b4800c4160b528b0380d0820120b36800882c1e00128b0280c0028701405e81e30120aec0310190562400841538464056d143150e00494502405081430120a7400088291400528a1a20a43000c8280800228a0f90501cf76d2de5ed6d6b3581e26c1723e72fdb2a9afc274eff7227fc29a5e450419e3869ccea567675e218febbb25257843639714c73a14156ec8fb0781307db74b1449d65d8d368e2d4f3d617d4a91ad566e2a0ad24d1a941c593b7c5c4415f93183dab4e1261b9c45944de2ec33777e92d713e25b7a24962be1a79254e49989333a8d27ef9424a9ce22cf749428f74ff2771f0d53a933bd784a5242f0091c4419e67a8afaf5259932271589f935a9a3f244e82dad99396468f9cff8883bc2073f95dee37933be22483ca6ae659a6e5f4461cbbc7efbe649a11279399243d77b7a1d28b385bdab893b4f247a928e26432c5cc25b44689262811473579f7849111818828b14e548c39c4694b7cb3dfcf18e220dec3d35d2ed33e2dc449f96e7de97f9d3511e2982dc813e59454f2c9e720cee9195365fb934dfc057150d286135f326ff6409c7ee6bb4ac6b3be1401719227db86b8ff0c9ff9c3c9a468919927ebc830f1c3b942a598566a8396a80f0725a5125b1945349a7c38c67ed1dcadb77126b787f35bbc660da6445f540f07191d9347939687631615845a8ca941be058287530a355eab22e73b2d903b9c3fee4efe7dcfdea4eca0a6a46e6ae29959b389e5bf98de4b3829c5280c903a1c5c93302177371d8e7362eaa4c6e97a1fcde1a04abdea2ba8dddcacac1c10240e6603040e279b0bdd5ce3edf6eb9ad52c989cdd18a9f364949103312c00420079c3f1b28f90754a4280b8e19875972c4b4611eb9fe100481b4e522ad5ae553d1b4e416f29bbd51bb7f140d6701ca1ea37d5b2852d21881ace5fd9921a5132a91c13240dc71ce39ba694beb698540a466e8c140a466e8cd409466e8c9409466e8c5409466e8c1409466e8c54182337466a042337464a042337462a0423270863c478bc0e1d63a42140d07018dda14c1c57b97c92a02440ce706a13b604998f7b8811c688255b0810339c2d892732322fb88671448c300a1c40ca70d8d4bb9b7bb4497629329c6c33bee4b2662a5192982f808ce160e2ac7f8c690dd7ae1740c470127df355652541c5fec37092a26509dd556eaa3e368080e124462f1bdb9073fdfa17ceb61a27dcadc971a9c40be78d161ade6c939865d38593129488d8124df6b5940bc7f6dea4c97ad30571d9c241f499649d23a485a3892526348da5a0abcfc271844ab22841432c9c4fca962bb59885b2f90a474d7b270923949bdec50a27714e56924763c614f62a9cfec3929a122a1c833471cb945a6fb1790a27f94e5cefbc4f0ac733cda2254c5241882a0a4713fce2a4599c4b2382c241f32ce93d399494c2e409a72ad5a6625cd609a7f4e273e26d86693d9b709029ffa924e69109a7b61127689fd11027b38483cc1564f8bf92fe2754c249cf32ebda8249923a9370122e6d33636d30613a249ce289a9d495b839323247386a3a61e36f521be124f243f3e7474d544c114ee2a6c42a69345c6e37875a1a40887050d2ac9a8f92db72cc219c5ccb54bdd70d2284f3a889cd93bf66c2c7609cbf73f4af0825300ed24c3a259f20fcc549894b25f64cde249bee8bf3a52ef994924a687bda8bb3262905d72093d8248fbc488c27269d298929bb3865b52e2943575e88ac8ba35c3e5df272fee6b47271b6ef92bdf40851526c5c9ca458c9c3c4b8645aa2b738953457d26917b7bdcb1627133a2a449c381b94682d4e5b42cc85bcca95f6a5c5f14c84d40bb59694aa66714c9b84a8127a49f0f96471ac24888b26f905b514c5e27cfea725325eb038588790237abd571c4bcc596a9953579c4375cbc9df250515de561c84d624c3a9b4277e36561cd46fa6d5acdc4b515ac5e1f24bccba49528278af8a638dae8eba9c92e28272e81ee2231507517772c7bd45299945c54126d9f28d293b6595720a2e97e8f9618a93d0b3490e19669d5ef928c5b147658f1487d59079aeccfd18c5b331bb4eba1a4571aa34f92e6a4a9b82ce84e2786a44c9a2c4f6018ad38c2a39d2a44926b5fdc431540591b12e26abfb3e3c71ec18db30794e09e373c6e0a31387b3ec1a939422275ca9820f4e1c5384bc6896c2998929e36313c724cc4a547a51e228f58c0f4d9cdc62256da723c3c7b1c3cb0e3e3271506210276a8f9f8d4ac9a1c638cac8810e7e321a75f0818993d20d7b5234e7fb9939d476b8f5f8b8c4294663de4a31fb3aba1c6a36e8c166148f0f4b9ce4ea529b5ddd31068f3fc18818618cd8b0f151898312d66d744ce7d6ec92f8a0c4f1eb4db2fd92bb27db8ff89884491022e744a8ca8d91911b237f032e810d1b89e1b0427c48e220d4ee8fccfc717ee11c6a47831d6420063e2281ca2fa976a6af27e750c3a18331fc74304607729831060f1e2349217c40e21c2a7c89776ea9cae0c12768382ef0f1885378f35399d2e288cde215397c38e220a71e4ad966491f191da711e70b694a0639fefe96c48853eeae6a1ad770000d1f8b3867905bd22ab6ed4463c6dba0c71063e4c68818618cd8b0a188c3768ab29264b8d052799851c6181f8938f98997e9a493cba156b7860f449c43eed49879d8a5987c1ce2f8267f95b133884b291f8638ae08d998bfc44d96e847214eed27c5c41cbfe275e65023c4c7200e1626b79f24d49f1ccbf02108d66487ce55cf5ce650c3a182f808c4498ad91b5e1774e9099d8c1ddd2333f10188a3e5d765d8ab8a7a31c3c71fcebaa5ed63368d8c92e650cb337cf8e1b41d2b523fb3895f42868f3e9447a67e68ed3269e550b3c18e1d39703c193e060e1d3bee460e33c668410f32c8d8c0c88d91911b2366f0e0cdd0b1e3c6c88d911b232362843172b0acf4e1830f879d0da6ff94d20c3643054ef8d8c349a8cbe5262cf3949eed430f67d5f74fd37e51810d1b366ca419427ce4e164e72197a7526b52f22337464a3022461823685ff8c0c379762e5438afacdf780e1f772868586ba7c55c964c8ad10f3b9cf53d44ae5f345327bb71f8a8c3492cb1e392e0afe79fe2a191e0830e0753d18b63ea6ede3437876392944e8d96b1c4e63f15f12187c3a9a62959b7bff1f01187b396d8ece7e1a1623f307cc0e124cab58ff7edc8093ac3617687898f371c7bc4425e5a92574d4a04233746423072630404233702fc8e5a0cfa80c6148e769745690525c8e4a9144e9b7ff3f956cc860d337a3c0dc6f012c00007106844e198ada667eb7bb9c29c43cd4c0834a0708a49f8f79d122cc7f312c000c70f683ce1249b4a90a6524c26ee33a0e1849329494611972b1a4d38d79d29d9360513c274269ccbf62c89269bec287b09c7db0d524ee64396565c500218e0c0414309c7374198a8fb3609a753f2a96e5fd9deac151a48385812c6664f904986d11ee12c7e422bc534e9dbc48d70b8a0c3ec465f28932ec2616b4dbf52de89b721229ca4a09ddf6fa24c260d8d211c4e95966d253b3bb5718086108c673b427b0825c138a6145c47569e92f7c400e37832649986978bbbb95f1cb36b3ae14d92fbe23c5e49c5f1dafc4bb15e9c33e83a41a4e539d4bec720a34711e1c5e146450975e2b786e973a8192088ecc26ca4882ecc06e6c26c88e0e26e7110a77753491394ca56d9e2746293b0e3fbf1b6772d8e7dc2623ef1ab4d9ad2e2342605215f92f4cc2e6791d05ffd15941894c5b1b408253de35990ad627190e627ae63da9a412a028bd3c80af9bbf924952fde82911be61621f28ad36c524d212d4593d22671c5498a498f36a5d29c8dee5a71163d51a4693b89b0e2fc1a4365ce0ce33883871965c9ade2a0e6b2c62f9d20fb4baa38c8cebd0a26f809d2e2a93859bcc9169baeb1ee46c5498f0cea4edebc142f3ac54953b5a42b6531c5b93596945aa62ac5c1d5e2c9ad55163e24c52953dcb4e8c9b292e446719241cf3cac2f37bf268ad398ff66a6ddcca1f6501c9449196fb35776091914c73c51ef2c9ecc278e66f5e7967fb399bcf1c4e9b7d4f9ef959d38c5e5beffb80d5e25e4c439e63d5c9374a944eebcdbc4295f8a6f66beaa133e4d9c8230f94b641017d52d13c7f02e9d65a2df6e4961e2d89b466fb8b52e71dcacb98d39eb46cf8603229638f88d9efcf22616635f8993cc32df6e26a52d35a2c429ceee6655094fe2204ab68c248ed62a26fa060bafa546e2bc9a75e3c95cd36441903885cb1eadda248f387b89dd3119bf88234ede6f7248ddf9d32726d28853bad25523e2b684ce4418710a424e0adafdf4ca881771b6b870fb6b1611451cd62fc74b8b9688a38ffe12264931e557ca09c21841c441096f7a2575e813a91fe28d9fb5f9475be8d710c7e46aa3d59bec8248214c29a8182649624c3722c4f1a498bebd46b68d4c27426410875127534a262ce50d13411cbbb2bcca8e83ef67815a4224106777915ae15b6662c96cd8b061230f2280389828d2f7d57b9492dc3f9c64a67f8a0e2196aae382881f4e4a0957429c942dd5ce7d38ca860e152b9e7ee6a902b761c3ec0c227c38599ba8261b55562eddc351f4956c1c0b1935e5f57092269fc7580911bafd09c2180183481e4e5fe1a458fab9b15b5207113c9cdc2ea5b4ee36a7277c8783bca53e59567454ae4ac40ec768591b43c6d9a51c953988d441afca2429e12d480e2274385e9f729117c452f64f640ec7771131a63129417e79661091c341c95632d65d2a5430e370f012f366704d4268db6c1944e070ee10253366cc8c15cb3215183381c81b56135564ca85d6985b371c6dd3a7c5bfd1f472f206540c226d38a5a4a2668e28315caa70d8e851923b88b0e1ac6b325396934f6799d670fa8d6b62467bd57032419dfa9bafd6947b1a4e95ab65bd82b08ca346c3e9478ec851a3339c94a05b72c26b86836f9f5afdc7de9ba80cc7d319f47ffb34bf25c3e94d5becfd8d217b9a319c4c2e8d63266a4de58b188e5632c6132e9649cb62184e41962cdd167c5bdd040c873739ca2abe7689a67de1f0a304dbf4ee4cd9a38817f64b6ffa6ed2aa05912e9cd64c4bd2a254d63d495c38ad67fd8e959f55f746640b47b3135254d4fc64aae450238375f03822c607c8e0316eb043c71964ec38c1bf07f67a7840440b27d55562666d9cabfd3141844816cef61a1b6795b2bb5e3c78d77186c3cef620828573684ad1150b96478d573866497236a9d01593262b1cb4469ca585b16065bf0e6cd8e8a16347bf0e4ca40ae7de3b930dd3a6a45ca2c2c14b434c99a07285ff0d1544a6708a932a8a25d1c24cf95238b9855b13936dd3ef1d85c3c88d6ed1f90b4a7f5038a892d32d57558c5aa50462843162c3468a3ce1a032a508d119be6d544e48d06cb2586a7596c9ee2599901925bb4459c964130ed2f6f747af4999af34511061c249640cfa359758e2b525b28493dc54a736abf4aec8449450449270da8a293a972c35264590708cfd65e2f889aa2725f1400e6e30e281148c98910312e8f0800d1b366cf45882c8114e1f5e962673e68ed1f5608c1e37031123e840a408e7b0efd00aedaeba1b8640840827a93474caa8d634fa3484d3ef969859d6a418a31611c2714b4d1c374969ca888371d0632342fc7b6598061847b1d4606b7137baff8bc36ecc8be29aa23bf7c5316a8ed1ab2284e56e7b7150f3fdb24988cc9a9517a764e3a761ecae35dfc5714c6ccfd9b03267a52e4e42b65606d39471ffcbc5c14a8a6131a977bb19b98e1cec289441082e4e25985f5293710eb5bbc5c97285cbe0a59249a1e232be070ed381256284d8e224a8873e0d5fd208b5e909426a712aa9e66bef1bd52a3a768c514a10428bb39cda397d5ba596dc1c6a76488290599c339a503fff527225c919591c5c672f5ecbb4468989c5f92c5fd025940a71f29c851058a8fd159ba47968b110f28ae329f16149bbfc6787ae387b681e2509231a5a9484b4e22406199b15a7de50653d428ed88a0959c5299d8c16e4595a3c2d5310a28ad3e691967d1e37c0c163075e10425271d8a0d49970ba2a28d1e6505b1e84a0e2a04945996849ff4bcae5503367849ce21cb24f9d4975bf495232c55173f642d948b1cb92529c4e1a2549bac154d858170821c54994944c0a2a77bce2348a83bf6cb8ab929498b4248a6310316bd1622914a7d4136b1d665e6525509ce48cfcba88490de2ffc4d1edc27bc5c97739f2c4416f6ace4e113e22f54e1cd594d455551f2589ce89c328d94d8cf71b1d9f6fe22447acc36e35a379ad8973c99bc2ebb3cec449ea288bed109617838993a4ef3329d56c164e74895312bf4c3c69664b1c46a6d15b9ae34a9c644b9dcb1c6766b6a1c449d0f71451d2499c24d5dc5e15794109ab24cea725afcc922468b61a89533a59a255c789252d0a89c35bb4acd313d4e54c1f71b824bd6ae90d19ed4e479cef2d997c296bd413b311075517b95fbf27ed4932e26ce925bf89f323b3ca451c46d58b3a6983dcec8b224e52bef6b50625e2b4264f7cb6c4171b0b220ea2fb96d6ba5ec23fc451cdd4595d7745511be298640d51b2a687f2100b71d8ca19d19784db9e248438fd6d50d7e1a70469728338a5cef64c0bfa44591027bdd69fa6e42641c907e2ac1737378693cd9703e2a437e849abe926c918fbc3c933976552a93de3c90f67537e72fa57f5a147081fcc46c81e8e5fe1757e2ee68dbf193b74949511a287b38df4529699e3e46b39d44a1821793887323132cfa91884ca78385c8cbfc92335565052ee70cab357b99011d7961d84d8e1f425f9e5f04ab22afe5f06262308a9c3e1a4bbbbe668b1f62a871a8e1d6e577c104207ed467ae64b5d79eb92430d078f1d38cc781aa071c81c0e577f256376d1d9aaa4c0868dc470d84222440e07751a430955f1df368ec3c1fee29abe4d5bd3361c4e5258fd677fc923c7fb42c81b906bda4a4e0bdb0d678baa9b6b55a7dc452e84b4e1b49f767ca8a18b9396bbb0a44eca5f499f8bfe9414c39db6545e395c60fd771ebfb92abac54928395354886f2b296d8bc3986eb9ce533a4e8d6a919fae1fa5c94a56b438b6e613453ff4f72a380bb35b8a8db62ed9448c1ab2385652316931b9d2ac3c3378a8118bb3a66c3899d568620cc3e2f45acae54c8aada1c62b4e1d974e34cd98a77576c5c9cf454d6ecc6f27485b714a1115bd1baa4d5a931527494cf5cd922c85b6b78ab3765d5493da44ffb6557112d10d6271762a4e3542d7bf585d089341c5f1bd2ba9bd3d4f711e1d27c57f93ae349be298b43689184b16f2528a8316b17a5b626bf209298eed9542091f6b2aad328a63cf7565566acbb28be23c23abab52a8b87672a138e9ca3cb62699946283e2a092ed7857be20d5b554438d4f1cfc779497925df4c5ac278eb932cf4533954e9cb4a9d8cb5227c5ab911327311643aa7f5d74f10c3536711ecff0fa753add52d00e3534714ae17d318c29512d2f1367b5d26afabe7f49d498385e7987d61a533d11bac451f467acee339638c66fae11a5a2a25eb61267b7798b53265f77062971caaa29cf4d7e39d4ee46307263c4e25063125f68f0133f65b424895499e6a6a5d4a68944c144c69e5862af90702fe34f6354f0d22314d1b33198d2cb961dc15e768fd498d2c61bc1dcc9f9fd25260525cc0883f03b41938b92479b8bb85e6497186d3a6c5314f177494a949b0a258a30118d664a1ba67b5347c4e6bd765aa25d12b3c9219a53a16e27d5e7c5ce10b8bbaca618c4870a9110e2944e096152729fc5d1175b71ed95c124c83228d418c4d144e7a88dfe7af7690e353b411c5dbe52f85dd222ca2a592310c760a229532989a64a6b23627c00004ca80188f39e2819637d9e43edecaec61f36252b6c5cbd24a82f879ea1630367b89fa18313e361461987a8e187833a35290591fd2b15f7e1ac2949928693e4fad4ae061fcefa27e436c5d7e6caeee19c75b967cc32f806385cc7eba9a10735caf9e5672591b1a3d18e3c1cbaea543ae925a830871a0e1e8c91ce0a8f1d3c787c69410d3c20c67bf56fcdb532ce30c306ff65680d6adce1bc26b3dd9ac62e134d8e0535ec70927d646c0942b4774f1ae8d841c6a2a0461d0eae1ac64b29316334391d4ea574b3f2eb6b9bb0ee5650630ec7301a5b4f52327238865e1395fd25fb56c24c48821a71387805f13ae1f459094b0e35381c44f8d649b3aca1bd11d478c34163e4c528fe9eb9b4e371f0d8e1868316f3ab64aef57e2539d478f0491835da7032f1dfb79a174b361d387470f760c34930e1f6625c12ddba24875a0aec4450630de77c13f75ae96bf249e6502b3d78f009cedeaf0235d470b459b9bbf8a7e178ee56d716a22c0821341c93aa3f494ec81883109600258906a1c619daf21272c1f45586dc0ce759d3cca05d214c636538e8b324dd82ef9952fa1a64282db3862513f70a9a56ed5e72ca68dbe4e3a5313063f209f799b228d410c3b9a48afe2394a91ef10fa146188ea2542d75c92efe277582304612ab018693555e6e5082ee841a5f386b0537398d25fb6cda0bc7ef0fb10aa649d90675e1184d98865cd35b1a365c3868f41016f4ab05d5cc164ebe6df1527eaa85536fc64a154f6949d9ccc2e95783f03f595b928d85a3c926354afc4cba165ee12466859284346562d556407d7c56f66ead46150ebf1b4d3ec42c472651e1b8979fb326f23edc3485e39910597935cdec95a470d09757612e57d07dea281cfbdd648a4cf2063142503809d718e4e284d5d7fc84e3e6761367b3224266279c2d7d5775e94b35df34e12486cf28f282091b6bc38453f6e54abfdc113dcd124e71cec299942be19433954c9292e92e559b84538cafa9a046f5a80909876d7d2ba9fbf19e1fe1ec614109fb0fd5f9a9114efa164fdc6638f516e1e05fc2d676a3491f27110efa84cf3e21cf369dca10ce9b7b6f374a544308c7987e27c8dc5e30ce72299f5c450d18276922b7c412c3bad4bf3867b092adc41fa515f2c541ef5a8e8b6a96096b7b71facd76b9f26473703a68f0e230af29ebfbb66e4949bb38c5bedc1a44e80fed27ba3899ec7a97cfbaa46e2e1707d7de3051354d3a29868bd397ca501666d2ce986e71589327e929253e94c96c71d4b72433dd4e55b28b8e1d64dcb0614393c434a692ec680c0d5a9cfc4e339c147306ad54f280c62ccea1356df6e7a89d2e8bc3a6e85ba9de172f8762712cf523b48b578a278861712a9919d684f75578fa8ab3c677a81346251dbf2b8ef77fd69974c95a99ad38e59b1e5319c40db0e2bc56a5f7ab6bc3fb9843ed064fc6dfe0c9383778329e69ace25492a86ecfec719296063c580c1b36b6f44062201aaa38c5384aeb9c20de4b4a4ac571a369ab387a4cccf8a3e29841558a164b68bcf64f71caf55e92e45972e573531c45d6dba658d2a538598d9ee5eb937b5c448a9309174d69edd3af9c47713851359a0e59829a0d8be2249c6097c4922f6932371427db2e7172ddab68aea0388f90c975734fced2f313272d15a6e5b29eccac78e294157754598a79494d3a71cad94c593b4e9ce2527783e88c1267dbc429f709a7265d9894cb72a869d1c4d13f557ff40495eab44c9c6aeec466c4eb8e8989936cea4a9428f2eb2c9738a8d9fab5933bef6295c124380dd0b0c4f1cf92b039e396382586870aaa12a75ecfd3306f2a52f3342871141b7d9b41335ce3e8061a933856f5c68d1b54fa7b5112a70a6bc2f264bf306592432d2b402312e73e6949b5ef45bae939d470b87a8006244e5232990493151d63b019cfa32c03341e7110573b49fdefc34575c451c4c29f786bd28873c59f90b373a7e4bd60408311e7af53a73195694d52c8288d45a48d55c4a6a14932d1355b34336824e2a484cfd5fbf6c5383e220e42c3e5edd0162e8af810e759dd947d935a7d439c6413ff0d6552bf62b210a7af13e395c55c1671428893904be2f4f625d9c71bc4e97574852b88f36651f11f0b75e5178d409cc24962e4fb469f3a478f1c94616800e26823c24f2ca5a3f187735feccbb253f2c33196744a4c7294d02d691fce2676dcbd85daa094c9876357ac1495614b4eadec212f255d58903145430f27b9e43aa67f631e7b16021b36d6b50934f2703e394e4927b65e2c65c2c3d93668d0f3cdf01f3f8d3b1cf356a692ff42c7afff061a7638d65ecd65bee7584c85a0043a705481461dce7b6a5ab93549532a87c30cbe018f1d698dc7f7488a061d0efbd7194fca24062b4973389be6b9aabea7e9e87238e653e94228494a1cceb91e6a2c87c56ca8e17030992dc92af51bce25e77b49d6febdc96e389c59c6937c4d5e8b4d1b4e3ab3974c4ad0d2312f1bce1aab64f779cd69c15dc3b9324f4925d4e7eeae6a380699f65296b8a4e1d8b39af444d13193a2e1a0625062977b79865349a32d29c1c34bab34c349455cca707e13351744fdc8ac15329c73453ed4d6449c8e6338da492b42ec15c3415c2853a1e66cb74cc270f8bb2b17134d0ae21d188ea54789766810194a5f385bbce8a6a4c7d3375e3877a89592ef5a174ea7b349aa142e1c4d123eeb6f4a74e42d9c64ada98ecdd422dcd2c239eca2c7fbb75938859269625d305dfb12c5c24978ef92456e8c49e84be30ac714ce56afb2b689a16185634e4b2a89f1abde279f430dc70e98078e1d66e818a3ee0534aa70dabccd9d952d6bb623c3a04185b3db9fdafe028971a8b42ce6a2c27140180a88c2c160200840e14c2803150000001018918502814898a7d9f0071480034634223a2a241c1e1a1018140e0e161006c2a030181c06028261301810088382c4e1503414993f1ebde4a53505c7ead142a0c4647d0babd47b618942897298b86a205689021a6f354f098118e7fb7c6c1b6661aa2ba7eabf0d209d69da1236a30fbaf68f1b4da7bd437cd9185843c52c2464f4b4758bda457109c98b18c7d66153a7728ecf78d912b6b903bd0b4f7119cbb8e78afb2f5b31d0314e98202f198cc64ba0302fe361aac32c4ede942a153b4188a0b02c85059e54f332b37b0188f1daf9ef283c7c687f1e0789f378c7c381d8439105f3f43c8291c756da5fb5fb6661004772c414e6be38647c7a533cbe7a36e7294b2144b5f10d7373a2df916795430cb81c7f3e81aca5d6e6c405372c3457945c0e15e54077a198bd37092262d34f1df08868d8971049deffd29b79c8d521831d100fd8a495a193d88f3aeb9c137257a0615f48466c865becb85d22f59527bf9cae5b5ab879592a01194642d744e0476e1aa691e94abcd174df7eb8c7accb012e9a4cf8ef0147c3a51b75bbf1f31e8896b79176c3e803834b3608165d62f098eb6b875585b4380bed78fb90f9cdc7c1962c1270d958d0d5175b139109fc59f84a884cf2b2cb12f7cd87721d4395e5df52213406a76cdc21ca52096103b2deec4c18c9e4bfa8f349e73f035748fe8df4a9c96b9aa2c284eb56cf699090b5285480a53096eca0b59c2a364db508b4d8d22357a16da5e024b974010b28e6d32d3e165a1978ce06776d92a2344eeeb6d045fb493c2b33084126bdf1e67bf384f06cf1073b80cad9f2fc277672c95643b072f101b12a29f373839226e9129f96dba0210c137b6a9009d8985d747d4e128888bf06fa4e87a64baafa72bff310aeb2fd7d4545be2c2ca0f8e5426c4515b1a0ff9149f597924ae5c3caa723585d68a13f0719d7c567add606aad90d13f387206204aa9226dd58725f88b2733d9a9e12493d1acb1861fcdfc8af9d8ba0e30219da1c52f3387c85503262a8ecc64e48c1923ae7cedf30b63c1496518dffec66c9a22d70026b01590dd85748b1fb1f929e8b0fd26dab5e20656b30171bc9ff1baf511c121656986f1257aa247b2d093d8d8f2a26ae46014325c0eea5d7f54eaab7bcf606fb051bed4059a20d451416387970e0a329a62ed53652495486eb8b0d32e359a6db6d7c06471adb867bc69fe2e0e0e178354e33c58bc5a6a4dfde9a27f9d336b05ae81825de2c2692c7b49a33ddb99f2d8f7f93eddf3f5b2d658d90c1cfcfb29f4cd3ab3dd83a7769c7c14c3c8cbbc415a986b4a5dc06c6650301d05c3ba080f4846402cd20e967cab4313184e84df20c5109638f9cf06532d3682c0854c337d0300514018ee6143632567d960b6ad0e6f74d83659306285b28842a81d4938200e8656792a0b8a3d8827398496b9e5a43b8147f23c7580fa830c99af7d7b0f6a686c5244c137cb5043f34b7b62a863a50c98fc058ecd64693a4a3c95c106670cf27bd62c003479998f24287c5eee4e4e23b9649d7d2ba442208c5f850007c23331b450508bdc8853df208517934f2224a12cd5e89468e8026f6636aac3708941a65a3b92c107e6aec48faa6b208909e5af5ebdfab9c53f54ae8b1fe416dd86ad3aea62d693162de006eee01860d0a7a6db14d4629f5f1aa2604506e4d2401695af4635710f359be0b80c846865833dc3f12ebca5ad77cfb28aa45be4924e6b338791fecb96ea7d25d4e9c3919331947d0fe3f70d01408668c7ed26208d24f21314e643e2de4ab15d33c4654d9542b7d450e2df8e97859c4085351739dee293f82aab49b381d43bcac001d5d12348882ac7abc563da53e036d0c71f4a751deac293237340cfa4860c57954a751ea114ffefab1cbce7219211e3955f5896283824e914b2182c604e4cf34d116bd5734a035a7d7b69fb579de1d09aec7f2f53eb82f2a93c2539351b18a9475c154ca627819001cdaf7c6b6f4cb3dc3e069cbcc81d8f7ec36fa1ac498d9fc707e76cf01e5ca70e69615325035fb942503df0f49d37692af1b7c7fbecc07a28007cff916bc7beaa53c18d3db8886286c779eaf97d12bf030f048e4b7b0b7bea9db6f57001784144e43def97e8fe0a97fa9dc64819ebdef9e1cea5d42ac0dd22ff0b247e1fb5698db8307a48ccd4ee0f31694bdbc517763b281870df2fdd5f14f26d9f8c74872b946548437e359d58525d4bed6aa58547bbcbec9e8070ea778d13ce4e763aeb4f948cb9b4524eaca630281c9415d9b6d38471ea5b2e7cfcb06c4afe17e1f390424ca177709044f7d891eb235f030597244c66321305b4da6316cc187bbaaaade69d5e27ea8f4becc4fe813c0b73fc8683cc9b232707f8f320c3c8c3f449d624bb720b49b68fc0b9e5edf98f54bc2e8ad331a54e06cd57ff68dc3b8711df766cd71ba74c5f169c30d37ec7f408e3b8bbcf24af303c18c1cc87cc604cbdd036409b2dca7de59147c542cc411437852d5f9cf7347cb65a94403a39cfadc519b21c8fbef7a9ac1fb06a653df53cc825d69ea7f5a144c6bb9f5f833b2aeb6a87a0179ded48271aca7395f8a36effde814e95e6915aede001ef9d729daeb0ab82170a776cb22925b3c0702d6a0f64b7b69c63aa6dd9174d687475ddf808fed77e8a03ec45ec6f2dce224dd152dd4dd73ecd82748010a8f49fdcfd1907719197e739ac6bf775809b849b7106f02b74ffce9d7a76dfef8e1ce4e99b2821bbd4574b0953a7ad5dec0a1e8a385580ed22f5e073e51ce28201d692dee741710358f15c2ea66aee58a0a5717a903db18098d8c46651fed0e9568c160395a815da0313d4a44f232da01dc887f700aa8ee906167e71755f7eba0dedfc288a63aa6280104043fafe85020e63e10aa99132527490da6ca07c855ab11e5f1da17fda600c0330e44292a5c44cd88fe4f99e82b171fa41711efabda739b701e9571656ee3e57709a4a8d18cb5664da867d4633eaefdf47c6a94b6ce95276746307d62cc8e075bc40f60293f65e8acd5381946ca5ae1b5fbbcae73224dc2e0bf273c7e9c79306f90043160a9e1a907ad426c52fa5ac8243a9d33027024e7e37133a5b4e134de0d7c2c2c550974d7f8ce1644384e6ce8b8dd7722719a913fdceabc2e2b3f21bd004cccc5ad83a1a7a00f3eae57ddf9f6cbc94d87b96956e6666a971bc32655037c2bd2032ef860f492c0be2ee7814dbe01f790950e8114a52009bfbf698980022c3c122144142214e5e8d08da832cc20d684fd62f381c2f2681aa21fed47a8b6bdad75ae920aae46ad9791e65c80abdc5de36fd637e4945ec0d929fee5bace9a92426227ac441ed59088cb2ee6a2f3a4e7ceb48c989103192ea758f329b7645979014a0e511d39d57fe9f5db1b7c6b99ac1c1c230fde4c63e430cd9a7fdeaeb57cad9cc060861949dc08c6743e1b9ea1e97b2a7709e4961de02e1bba4997cd5b04ea6695f94e8ea88841abe4b852727acf5d10fb120300b8e3b0c51d89715481e60beb579f94bfed712eb65f6c9478df55371494a3ecccc440d895a8d31fdbf1e76ed5a9055591b1ee81e261812a1b054986010b17a6011d92ddb66a511b2fd578892cbe9285435756c3bc907ec6c345178e2e9e92b40221e3d3419af4e0fcff0939e14cc66335d31e65020a3f7aa778d13e01aa17e2cf4b7c396a38412b70432e8561edef3d5740fd62fb2960f3451218f93c24b0e2819c3e772327ec9b779d85e5d802502936fe6f1b59c2d397d9df50fe05664bef8a5dff03e9c5b8f213a0eb7f0360e18b7cccfd16fd8bff08c4655de8589f02fa5ccff0ca68d8991f6819c960ba9d4ca3e724c66485d9e54a4759572cf9247485c0c174ad88b9ae53a65e6ec1960023e2e565993a48e70d6b63d5ce53156f4fda522d7e274acce7161d38b1b9997d15cbb371014cebc0a3917a5f335b7c1ea8af0c4f4e532fc55c02d5ab469fb417c0056d34f3fd1db9220fe967697fa3d8d3e84de26cd8eca31b2821f5ebb9272af7de9595493fb78fdf308026dcbec6c0887201700033b738f14ea5a179ff410c27197bf91a0fc21e5254f2e4a3058ed903376950155ff47c4f6471ca6744e15ea9d858e17d6093b17f5dd14fb5459c870e8cbb9d50510beed9a082dd4766101d004ae98738cd678b4474c087f42a1751f3e97573be4254303df572e97cd47c142b4e19c58cf4b1e9d9a5d2523a04c2d015c36b726accef04aa4c81e05a5a2fc33a5a468defb7084f237d840c6e9bf116ff7b9b9c4d2dac25436b31e5993a2c7e1004c05755d929e647706b081cf8c86311ed18d60229a4f6b2b6eb2679be0a69f373366b43a7b4e034cde20c4bdf2ea6d21312b7fa9f2dd06268c8e715fc2cfd1ffc40988a85120ded9aff130670df4185b82e82480d39cdbc4830348680d512980ff0e631986afba16d62ff71d5b17413d4378b90dca63551c8370483f2e174a5b4bb2433c3bc7999a094c7240062eb25aa3301214f5d4660cefeceb083aac76bcf564192565a7192405dc0e5190a14f43a64a6c89859895440266498ac72b4712d35ab6407178f577fd9a440933c10fc20a81f1156c3605300f15c9155aa4933887461a09509bb8f3a27acf82f04cf7b5f6f484f326908882dd9be1dbcc3a26307c6e1ddede719214aedf95752b2a762fd650f3a8d24a2205bc2e26de29ec0f7372fe078988088d482b9cd045d508d1a2beae581a91811038e21e0029442c26e4ef58392c7fb67b256bda95d4ac979563c52566d69a95f89551955919fddbad326faff99b4586be597219217caaa19c7a594589b91751be833a1c78d850de1e3aa37b2ca86d272ef7c0957a9b05f63ef24890d71586f0a476dff6d748700c17ab424c04c81b05a54e13aef5b5f8725bad4abd4cdd37bb83055a89f038c0535cfdce4eba5d6cc36816e5beeb79e4a8935e0121fb08f1f8040f24a8a1826732e54c268725e410271bebb9412861a86cfc1d957023f3f0920cab1bf96fd0f5d7871571516160a365971da8fbdadf53a031661d80fa79d2aec0e808997e3bd8a07402d18244d16c58872597dced94d28bd28432253220477128b10390343173b0194bc100ff058c02e6009ccd0323bbe8a612ec9f5eb6207035af1cdd063e2d06adebe4cef2a61977d9eb4b4eac6ebd3c91aedd9fb1d35bdc18c0e6fba5a6b6345bc2362501d323e641d573ffbcf56ec8cf16ff6ad3fe7686ec717ace5cde46280807fbce1b239d7b00ea69019984bb1df0f261b335716ad4cd1816747849f05d970e296bfd4d11a10439822c808e408343201e00422504d11e808218210611a0227056f71ae5db32c6b3617f4548866fefdf3cee05eaee94fd9b6bcee7c0d9605703a56f90c168e2282d5c193450cdd5c5b3bbcd798502b1ced5d1bf63d31eab61b772eb5dd780fc370670bc28af9ceafa1f49a8b8ba52d2d9ea1f8b788e83745f5afb7b6225abfc6ae7a890811736270a43feed8498f5728a6fdc062d533a28bb4644385454ca73e9b1bd8d671b8846233734d12c1c680e86cbcdb7a1245400abc0ed978ebb88b68699517324837c5a5493b155ff96c92143093841caea8e356032713e33b08ca7c3e5e45e85c82a7f382e5ef01b58aee721e3de6c50bac363d90cb0ab614afe11e1e083ad736cd442455e9aade73ced58fba296a1df9aec8cacd0b72061e85ce9a5975f8d5b87ed11169afb7f096ddc1b2e14697cca9b30997f1b7fe84afb5406da0760834f3084a83e61a5c576b26e9bb3668673008f17409ed63b8f48ad3f31315e3b925f3b6419f817c89273f57ef6dd09deffb786de82efdc8ee51d15946eba6e2e4ce5d62eb0deece679e4611d194fdee1c6bd67356e0b9382b0a27707b6f63385c94afb9f3d9d3ad124fe6771457229330b0daba68f1c4e1f2aa9a3249b6d3883dc62ec6b4dda6e6b8f3aa17e86bb9b0d7d088d3dbc03cd1c2f7bb9de0bd6bd2de1c16e7279a6e9d035dffae69423dc813bf37771a6ff00ffb5fec99ec49cf4a766c555cb82e549bbb9f7475d0bee81acee402f05686275c06bef2e37718736f80e0c72a4a278d9bb661f5d34c068350a35629171ae5a21f38116a2fdb0b1a77c4528492c221751c577b925d046af5b6cb80a3e70d063d255ea56b975ab9613f7014aa582b6a4dc755625da8f19549c686096e34492a3ad18e4ab329b75290a2295d9623d828df40e5abb9b4fb16bc463418fb0b6bb8b69fc9e921ad8032492633e2f43c3b3f29fd3a5966432bc83a8045626f8c6f4996d5831a78564f01713cb30e1d212f90941fa961d588df9453b7fa6de93daba0ecacca0f0328bb7a7d6e4baa1036465aa3856824e584a2a26ed40cef12d6d4f879bd6ceb045425361491d8419123f8d609f3a0188a2fb28043bc35e38997476c70ae8f63376cfbabcf1225c72d14b918b6adf9f4503e65ee204a233fc1f325c11cecc16d29a940f230520fa90ee005cf3f980e8d1a94d3e986357ec85f14564b41c35e5732e306ce2a518b7fdcdc5748cd51a676245443391bfc6edbf73b87e348a9e572ca7cb348ac38da80201af44c3a85ced6d0a2ffd58608181153da6b8769822613d3c0ed909c36701dfa321ad184d120680c1a038756791aacc01b4d87a59d8c099b89049a8576464bd16895928c19155f8d33d34efe6b50b6271a19ed45638a6995af4e309583d677a5e5b253e2b98e7642bba211687934f1a0313d451fc62e34e67ba7ddc912b93f8dc94070779533cb4e636a70068a6fa59dec56487227340b4d8056219a29c2036d90112d8c46a079a3556866b4205a8366466ba325541a131ad408df318de9acf1142b8f06ffe49217031a0eda8c06a3b5281ad3d78350ffd965324ab771e5fccf443c89af5b9dfab4fd0699d97e5a74b301e6c908217efe43451b0a943a0770e3a30cc5450b0dcf1ba97295779f69567db9002546c3c487f0f954e31e47218bb7285c5aa35a86408c2242930dd4362955ec6c231e995d7cdd7f0d844428acb4d238f3c51d2c0cb177ef15c4dd88464854d3a35119fe5bd010f2c177ab1c13ebb3d6e732196af107ef5e687366bb20ccfc2e0800b91249e9b08e61632d362d7c5df8ffb7376f6bd889c56c0a10f4d4ef70726c93022ccc12f8af9ee3003e6642befb466cfc3be0bedfceb498f4bb3380fb99110a08c2df07dbbd82f8dacff801701d936c3e8a1355de329397c58422b2551a302ca8f1933679e2c989e5ca0e09fa2e6559c2941e673b9f0a41152492b41c01532f794ba003f479adf6ced923ca121ce0ca46d8cb83fd394a79fccebdbb4cb52c7241d94f67008f1251df08f4b6080b5e4688d8c1e05c14a02c85c45b9bcd9945b07ab4566039fb3caaf9955dfdb9e80572c7c9b653b5e3b743902906089a32430108aee18a2ef98fc4d7b86d9690e97def710b076079aabba8293f3e2dcf921fa445af0bf3d6ca7699d2c4ca17d9fc992b69b095b754eac5c939f8e3532ce58f9c0e21edca2f944189b1bfc712da274ead8e5d11b8a2718e9310cc517c427259a2181afdeb32c1317916c88b6abbe955a8f4b7d22e111b0d85fa1b4c7d55bc18f59dd77681332ef6acc524516797e806e412d5cce61eb080d37bfaae03f76aa8c12e3711e8c6ee5ef3c79bb99313ebf8175255aca2581001bc171b22af357751186521c5c30e9ef8953e089885e86dc73fe859c39e475bdc2784613c9afe2119cfdf8aae390b494a6106ec5dfd13ecdc7f79588180d3a8c49addc26d422d68d6221eca2a0a7e6f24ec4d27850cfe2481099f85fa4c3830281829b882ed0babcbb52d5cb0d73b6b1f8cd78092baa776ed66eb8c9fab66cd6205f5d96a21bc7335143956c70b6ad87fb99bfb203267d5571c283e18022ef4aaff0c8931a082524e1b2bcd492470e36956e9b1e118f6083a8b05fcb31c802ff12b9db9f6de5fc2e93383be5f0b3feec920139891253482fa847cf9adc1612da8e61e06b30aeea03dd9339ee22dc0ddfdad9d914f36ffad40b0983e39319d440eb7c24e49a58029b447696c1979d60154e261242587f9b8801f51b5a67273cf3418b3d8ef8ceb2cb314555a8e20d2dcdc87a989573223f244d64d5c09a995a06b828bb87f4aeca65ecc378a71dd13eb8c6d3969ea4851b833e300f30c40e9c4749743511b2fe891b87f075cf148c93d84286fad6906d76f977b0fc8de586625054877014be93117b0ca011dd7e523a3d0cc30aa338f335d86b425a2f4a15094136218c16da67a232c705b3c99f6b1e60bd0e27163d9d3f69c41036f83ff813da6f70ed34b432277b65f8ba0107af317ccbc237a624ad8e07486975454d0d85f9537a26f0d4c814606d7ab29c5f2226ce00a780263b71f9bcdc21fec9d48fc62272fabef7897646f662fc4cb1abbf5dd8df9f8596ffd4676357fefadd73757de79bbaf316da757ea52759fba9dee4a3741eaa609c73cb269bc05ddef5d14bd8dbd84bd086f80ae6717446f23ee3d8fbb5fd55daf60efad9f98b7b172e1dc7aee961b9e7b7387b989dbee90cf87dd42eb5de645ed8aecadec9decd5e40df9d6ec9af706efadf71aef6de60ded2ae9cdec8d787d7483ffa6f7aaf706ef8df70af306e9befc9aecede48dfcb57823e36edd32d05e2c7b0779295dbf6e92dd66af88b7a31bea4adc4deb8deef5346fb6e3e576a1626f74ef3edefa2ee314bc0f2bfdc5610e020ff2fc9de33f0247bd638c15430e44322bf7e2da02433f8fec3b12839b8a1bf1ac4c5a41bd1c506df7f534c3966203502210068263a2c12c5f3004de80dd0a841bb50691e0eec333cb4eec0b650ef4e61944ea63b5549157800f9a873e6188a308429ba48267666031247f4851aad23d48966a47482c0e9f0d710b890a9cc1d900b8356f6e70c3068741d160c68621a2075321dd02a86e20988635a80dee064183c2e06cd06e900cd60d5283d0e0671032481a0c07837dc7b4c9181b301e042510115ae4c14c04ac84627e1088099bd4c2e0ae061b33acfb8b9ec168fc2688e819bedb56eb69d80cc6f42421852d036c20625061069377ee62f530501c744b508db02a0cf860c30c01093219e5fb0083a5bb3020ed77850ec6f8efd26e4010357858c84084cdbed155bf3018d3a5436f1ac00f96240443981120f0872b047e071bdc60edfa0a27cc086f040e4b905bc2e66c82c4cc08909b51de39d3edccf87c834db294fc0202b6206cd0dcfe28d5bd2590d1893ddef3bb0680016006605200e157e1df5702e003d427c0bf621ae15f028c01540018801880368016e8072001b80009006a1a706560e4a2ae003c400780620404d6852c7b0828027e05d006080518b800b3f629d3c9097065d1adbf6f0070802080a203e0213e7047600994013e00e4015503d0034881228009002c2025400180001a0098013006520108000a1000204e00e1f973b5771b2017a8d76220cd188420bfa8f26f881798a96b3dca3d6c8f92c7488f131bc022438848beee69fb7f06be4f21c29b997152d49996b017c447237a38ad276f4ae8ca2fefc806fca802becb84690c3660b0a67230333333333333333333d3acf67b8bb7f6182da4dc5b3299593ba42a333333538866a7f34e1bfe52bffd30e305efe09da1947b0c950cc70b7cd56a8cd794df809cf31f8ae7f6e16c6f8c0d085d9a16d7d35303b27cf4ec34625321431a3420ff5c575cfd918757b320eb59f864257dcc9005d92faaf451ce77c9b7cc214643806a0b336241b456cff8b7901eb57b182ee0000e2a58906bcb4266f7e80af774c1010a68a0500d335e41ccaed85cb7c1423fb57305a1366676913e8a99ee8f14981d14206c05b1d3ddcb531f851584faf21c71275bf2b119ab60fbc825cc0f6623fdf8f8b83be6c9bc4a397f19d00503128d304315a40c79f98fdfa3e7c3b652419eb8f01cd5b3b53f8f0af2618a99965ef6c2d7334e41de53bbe87a1bc3dc360521737c674e359582e4f9684bd4a472857d48413ef0e3a8316a96a32044885e7a8a868fce872808ba6f3e79d7e2993320cc0805e1f27ed4ca3186e730f10c509093fb6f0a5baa8e316ec627481a15659d731f7e30558c1d18c8d1c38b0fa427c81f63be94050d625fe904593a2ae604614793a69d4a61dfe72688f1d39f82a7bafd669a20b99ba518a6cf0471abfb28a57c1946fa204c10ed35caea32ecedf77109d2c5ba9bc5f0c312a43e8cb1681bdbbf36a612e4b7bf0eaf3edee0332508d271295fac0bf9e52488ab1f978ffda862de54910471c5fad08f2fa891208964b8110fd235ab18332041e8e33893f5967f04594a3cf58f624a61657104c99298c7ef863c4fe1462c91d15b63efe550c2a1e371802146b300c78e1e66ce432d20021c0b98c10818cc5804f9305bec34c576d7ba9c198ad01989281ffa86496a6af26620c298323c7498a6db9783eb1006986108f287fd78a59fc3749ead78f40863462148e6513ac65fecec3f9e6f04330861660c8294a377be14bfe9337e5c046608825859b3d36fd690e1358120cd68f63c9d0504a14c74e37ef654a3e51f8899d2fa0f4f77376ee80752e78a7e5829c69fd83e66f481dc7ed08759639c66f08120565d39e5c75b7e78e650227a8103745c00f530630f2a98a10752df6d3eaa76f31cbda644ccc803398c5db8cb9a36c6e7b380087004800e33f040fab6d3a8553994b9964375ec20222222224d3c2bfa60b380087004a00c33eec01f6f65cdfb29533994d4bf3811d07181d340ccb003492c1f5fee83fed4f5f9b8aa03a18fe365b414cd37f97328f10c3a10d5c7b5ef365ea5182431cc9803f92864c894924ce790dbcf9003f983bf1f9b46939cef830433e24088ad1872692e9f0f1dcc8003a1fbb2a7380b96635cb198f106f2ab1f58faf1f1617d8cdf0da4d8ca47313bac196d20f551fe4a35998cbb1a3690ffa0d396acbbce46bc06c2c70f3f7e58f938ec573590e3f2b23f7936795fd340ea6cdfabcccab0b8a281a095396e5b4c9e81506661eaa3eb3da5ce0ca4c8b9da0eded9a34c6520ffd1783e0e329a6efbf82003992e8eb8a6e8877f8d81a05d1bf37cd0c4401ed5ade4614cdc30902774476ecd533efe63c140d02cff47e57f5c1f57fc02d15bbf8f0fbbbbd536ccf00229d4ec72cab23963f51186195d20f85bb87b67a5661fea85195c206d5d8fbf9ec63df3c60dbdc28c2d105a633eca48cf9dfeda0ab4404e3f96fa30fae05ad6ce0221e22a7ff843bf871714d837ccc0024936f7ec6ea5b688ce8d1b6b98710582546e99adf2e4aec9ca33ccb002e953e7d98f19b3d665ab402a0fa9defef92868cca8403aad7c7ca4295619664c811c2277a60f8389de4f378619522007cd77759f4cb48ff595c28c281034ffb168f63f92cbb569c20c2810234b63ca18ce24cc780239a9f5e1e575fbd4122d126638817ca136464ff9ed8388ac30a309e44c9634a86fbfa6dd308168213c279554bb9c5b022946edfbe8c3c949550433944050bd349af36ae5e03149205e6587ca9c73d218eb0ccc400231336f0e9df43fb8a739948c48d11e8164ea3367e73f96638e11c887e9fe38baafd3b72f4520f7d1e69dedd13ef2b48940b6f88ca177637a0a6f08a4b9d8cc8721a319422026b3986fcb8f8fe35e4a185d81c31f2681194120e5a3749be6615d42a72fcc0002516475b3796a9093cd0f4819ffd8d6fc2beb55340a337c40cc4a9bec3d2f337a40283373d9bb2c37d1cee001612afd514cc54b154d9eb10372c86eea833a0d7dd3ccd00139fde570b6c1bc8f2722ccc80171263f8c0362ceda7efb62152afc19372076cd8a747a12d9f74030c30644a95ff1e3988fd23ac3336a400c4b6bdd31853ea8385f60060d88166b36565b2da7d47328ed0964cc827cf831a3767cfc838ece0b5cb0e3e40b64c882201e3baea5d43b3fce552ceaa3043260418c29997792fef9e37465bc82bcfb239536f5d6d49943a96a05325cf1daeeac7cea7be8f015388f5610bc3b851bd5fa7c58e31764b082a069636b2b93e9e2cda18443479b5a0531b4ab45774fb9f21f840219aa205f50b1fbefec9410ab202315c4cdf9f5ad927625ef5141ac1ce5651a931f7cd04f41da1c569d2fa357bb630aa2fb416ebf751f7a87a514840f9d8b7ee4b9d92f2605d12d34dc99e756ce70a541c62848b56dd3471f2ac6fa15053947baafc79817efb650903a47d2d4dd2e4e5e0c388ee30a006490010a828cd494d85e3e3e940f4341c627086299f3fbd187103f3e8a27c8ebb3d9f5fe72d1bd4e14f3e975a6507d3c41062748aab1b39992f91ededd840c4d900f935a3eec3053930abd019b09421f9b57fe710a191ffd404c10467379ca6a61b38b770952c730a5ed471a4b908fe31f9567664e2588657e9ce25547eafa228312e4e8f16c8993bafc1983769c31c488808c49902dec631ed1985a2464820c499453b1cd44c397a8c357e038fc908c4810fe5df48fd25bdefc47a9146440c2d8b3cc5cf3fb58d03cbcc7186180b1c3606241c623889f34c2b3e3474f9a8b820c4790326c737cf81c41462388c1fd0fa2f251dc14df653042edd0703f0eb5a86a73ad9009cffac7c77d988f1c4a5a4890b108821f65121b1d334911e451c9fc414f533c6fcc202311e418f5eb438e8f0862a7fdeb30bd5933f887207c10cf9693889d6d6f0872ce87d6296beb7dd0974290a3bf4df37bae3c4d2104c1fde4f3b41d04f9d673738c9df938ff5041ec7916daa50682ec956cab5a3b54760041d4cf14ddcd7d3ca2dd1fc895fcf8a0d5f27ef02be5e9e3e9cbfa40b2143bad520a1f88a7eb331afa8f63fda83d900f45f3451ff9c7d698f440fa8b1a5da13f97a73ff240f0e4079fb68f829b031978206fecd807f79ba40fff38772065affac33ece0bbbe1710d64d8817c30766b2966cc8721e7185643905107f2c15bca12592e1d089bed4226fdc034e31f732064d874e39dba62432607f2819876be2b310ea45c9b7354aede3f66e1408ea81593ada419e30da4abed38918e1b489e31dbaa5dbe2b75da40ea7e4d0f7eb8970fea650369f434fc1f6df4cdcdad813cde95423ffe68735303a992a774dc10f651b23410d364f5b16ace47357da181d85e7f3119f6d19f30c2e81b3774c83803a9eb3cecac346620c86ebca8eb6396422c03f938e7fb303ae7ec5529642025ebe89b6576263ee20e648c817c707e9c331f3b68d62b06f2711f6b3eaab3ca395dc3408eafef8be5399239070329322bcae7ef6e4ccdc5c0a1811b37fce817c896fb388dabc78dafb8066edc303c568617e886096474c11afffdc36eefdacd600b647081a46fd6aeb75df1c7fd16f69453f7e3ce4820430b644da163b6bc2e9e0fe35920e5bcb23b1a25f3328f05b2d67496da1f1f1fc5f50a846f370ddf291b7358ad40da0c7e1ad3be6cd95405d2e78c41d2371f46fd1c1588ffc7d91b35f3d148cb32a640b68ce1be9a62bf1249812ca6331d958ff3c1a6b86f60a3401cfd2b978bf92852816f6065408118d6b937fb3f525d31c4706314104657804dc613483a9bf7a68fcbfb204495e1045294bd7b905dfb4bf1a58c2610d263ac427fce07f2930e16ecd091021d6330a11cbdca8f921f4c1f3b7a883186c92510e3d3357ac687d69cc9a184c3fc14ca50020b64246103eb021948b0c2367deae30dbdf90e1947f8428611d4ef14377aacd7c860c82802d92fa5b2db7cdc29a37717904184fc8f62e335fd5df3973104a37bc7e76873283940035d68c910c2e1827784a58e59c9a144dda31b00c68e1e3ac4f8220c30bcf8f8a8828c207c9c7fac29a987b1d807ca00023986d6f58cb98f2e77021d5ef0e821068e1d3d747841aa64fc80b8fdc9376e95e103821f6930d90d66f968f71e90362ce8d5ad4485e83c20e8458d864dd8dbe63b209a485e564ee13eb84707640ddac7f6a22936a54b0e081d2343b4fc38d78f6d1c90c362ff66a57d0392a7d0f1a39c8f93a7d50644f9ff983b1217b20fae01c90f2aa58a9e3b8d9f95410392581f6eac457116a490163ce74b2d9ecb9205697365e60af97339522c48d21b7ed81653452ef005801004000bf281c5efa785a694ca0f01bc829d7f994a2157647ff8a3e9abad72db0ae2c6aa48d9502da9af0b3c05d845f41feae7587d9c3402295d27f5d8397527b308e403ad8ca72b1281e8f52a968f3eae546e8740746bede33e4c492e762b0472b6558a4c1fadb46d10089a6b9307eb6381408c996739ceaaccfe01212a68d058f1724e1d1f90325432d1ed63bfadf48094d7377bc8a80e8007843e1ef53fdcf421ced401ec809846da8f421f4a1fdba803d001aab5a3f9f8381d400e48a18fa3eb25c916937400382089557de66cc96c3c03b801397775fa034fd992ac39001b10332d563e8c7d793b9903a80131de6a7778b1d40be600684096393d75ddaff82e67417e4b3957863fecdd58ca82942d87cbbceec71fab8c05697cfa486395b0201f5fca73f28729573e2a5f41ca16f94c77b3dc1857904e4ef42ccf63f24b2b083232e5e22aba95c20af2a6cbc7152e5afa93ab20cd9bee6ef9518ae143559023afffd83c870c19c25450b29e19ab6250418e392eae65e5a9509f82d4a9bba43c6b0a52380fed62b2be962d05792d472f1fbaa420ad1f87e73e08b5bd7214e499ea2ca669262c1405f10f676da6fc68fd0fbc50908fdddf72f575a020c69877e5abc1a2a5ee13e4cc616ce5f4b533749e205f72179733dbbcf9b84e107306ef1cdf3c4ffa9c201fac85be8d6713e437bd79ef705b39a30952ceca3479f938e4339920686cc73ffcf4777ec10421febdbbb246472c97205cbeab4e7f7ca0f5b625c8961b13125e25c88729c41fe71bddb89012c43eca315ad81d3faedc24c872317b9a7df803d724414c31917e107eec729a4582f0655d9a39192488f1b21f1f9407f7589d471073f2645379e30882dee774d5bc963da511a4f1edc3b3728b1184cc712a574aa7efc95a0431a7fc07f2fd9f6378a508b2a67839f8915689201f1f55b9584a153b6b8508528cdc6acfd387d5f32108319d536e673eb86cc910040f9a5297d6795e498520fea157beb4ec47be2111829cf36be99edbf3663408525bede5ec07912088b1e2313db69a9d4090ec0f62ef633a05b90141c814774a4e4235c87f2074f09eab3f8cd963e70752cff8d17b671f35fa4054912e977cc9aee9a30135f840fee383cb15b35de84c6b0f643f8c69db7a6b2c420d3d10d2d77a6afb30f63ebf79201fddc788b9a4a98f34a6061e48412ca42ea7669d8a35eeb0f961cca57cac75a4795a6fe6fcff3eaabe3e4c0d3b90b3c52d45869ef6cad550a30ec40aeb6fdf9cebabcf15420d3a90ce46fad862f28c56f61cc897aab2fa287fcab0cb81649ae67ca35ddcaa701c08d5d5f1874133e7ec210fc3051ce0e16184d13c3e80831a7020a7098b1a7f18d36b1fdc3cc88d1bcdc36bbc8198e2666b4ad938331e379023fec287878adbbadb40fae3e3f9084b56ef616303e93d8dc45df8036bac816ba8c16aa4817c79fdc8341f8c35d04054918fd25b7ed4bbd738034937c6ed5c2c7cf3c70ce4c34e2f599afa537ab9461988b1ca2ff371f0cd7d1c6795420d3290de47dcdf3d8e8515390c35c640084d9f0f3fede6e394a318082a6d5123d39ee7980c0339bc73757bec030c35c0403ef495ebe3a3b17c341afc02c9d26b9fdef981aee763bd40b68d7e20d6e80279c2bc633e0a7b9693e102c137a7fc3ca64fcdc5d8f185c1b1e3ec1835b640acd6130dd587f9b3677328a91608d65d2bbd52c9a1747434d60e6a64819c5bd1cefafa68d3e6b1403ecae8a12b8ac5caadf2e01ad4b802b97ed62d5c65b38a9c43096350c30aa4abfbad940ff3f181962787e25822ad0239de85b798f39435ca54206be7dda6eff87676f3136a4c816cff5ffd16a5921fc84ea82105e2e750a9a25d4c6f49a35da81105d2b55bf8f9d15020e7e6e3b4cc8d61dfde2710a36ecbd688faa537b950c30924cf7f1ce299324d208bdf455ff71415932599408e96e737dc3b99b95a6309e46acf19dff1513c2bc61807c7961a4a2067fe719e4dc6b8bb70d4480239868a1ff41f6ccafac90335904070394d4b91b9bc59e6501a839d50e30864d3cee1ab37865c08732869804731a18611c88716e25b3ab7fb29e606358a40cc8752d90f37ec400d229082f49ebb5dc62431e0c60d2a428d21d410022956c8b89e34f5dee85d3040878e0830a00b1c5d7080025d18eea14610085395c6c2591f6b695f0308a44de5417e327cd4196bfc80d89bb2c3dde5bcd13235cecd98d6236af680f49dedddfb50e501291f56daa092e647b75d8d1d90373ee63c579f82774707357240fc034db2dad1155ac31a382005fbe358bf9654c78f53e306c42096a2ef2aa61ec31a36201f65fdf161bece996386aa0b0e3c806ad48050f26262fd56c04841508306a4ec2a7f281fdffd008d5990f78f9274fc8a3994f4ac0768c882547dd817e2d4ffa27861c638ce4393402316448ddef8394f99370b7a4480083460414e3f1ef37cac2e8d57908ff2fe51fc3e9e3e4f570e251e9a011aae2074f751aef2f0479acdc7a163070e3e5fecc8f1018025d068c5e6397dcae8e8c08d1b3cfa8b314ee03c8c0020061aac207ea64bf2f974aec3caa1d4a37b8c51813c5fecc87116a0b10af29be714ef30f9d85105a145ed2bd65e1d17f0302ed00503ba0863078f062ce0c68db52ed04805f948e732563e8a9e4b4205d1d6bfb2c7183f94eb14e43cfa476d92bfb12ba5cc40c31484cbd3d3394e93a6d430814629885ef9f8f4e3857e65b5811e2e469182c628c8b9731f8e1f481c061aa220a7acc9821f44c66871434112c90b9ba3b52c7730021600c38b1b375c60be08030c2f8e400314e4a3d690588da97cf5f20952e8c8920d9b3d4148cd477f18fd72fe618a768298b27f9fcd1fc509721a499938f7c306343651a47bccb4561ffca1fd51d49c29faeed304f1fe289467ad4f16ca0f1a9920f5e6be99a88b041a9820c74bf67d185fe63f738640e31265c99a0b9d2e93342c410abbd155ff0f4db73260d0a80459cee70f4593a7afda655ed0a00431b6a289aca5fd81cc9320a77431ff7f0a650b6848a268448298734cffec9a4ada8704f1eb376e8ea12696398f2087ad14abe2fdf82fbaa80a1a8e201f6692dbe85d72e37af14518627860023dc6a8808e864051f9d9a1e30060041a8d20555477eb681ee91eeba1a34d7b60cb053c7ae8700ca3c1301c3418b1341651341461d6f6e695b3d157e0450f2fc0f0820706b0da402311e408cf8cfec378173dd34004e967efa36f7cf0e995c6210872e99d8f43eb86208ca7ada57c7c1cb3342e0461423346f44deefb8184209c478deffb25517b1044550d5b49237753880441f498da471275fec7fa078d40146c4f773dee0808426e3ed296fced0cb5fd8e1d3c30f0517f20f7911fc8c6b16097553f10e3ff71a8de493fb4b30fa47ca031e666fec3d1e8f94012a9f4b7f92bc91f65f640ccdc9b3ff2f0d4ffb51e085f29593e4d3fd13f360fb97dfa9472bde28150318c57be86fab16708a0710762b8fa87ccb21197bd1d0893eac7f952e563fb5ca90351e58fb32d68af474bd381f0b172faffe4399082e7ac28daa1932195c3972dee8f07d0880359f3c7d0dde818634cd380033e7faa3f7e38d17803b192a57cd8c739e60652688b958ed5269d521468b4212df7a8d1f92c0b051a6c2096dd6af5c7ac76da73bf40630de473cb153dcf6dcee90f2fd05003e1924a75f85c19970f9306520c4b1e2763fa91abbd5ba0810662aaccc7f5dd8795421f25a07106f2ef1fcdf995aad668a50d8f31766c80d40c79be4e69aea83aa05106c2678eb28b0f71ddc7dfb871e30619c8412a8515f5dbca591e03f9fb38e5b3643931903c75b536feb1c7fef5071a6120765fa6ccdd060d710103f1f2c9e9c4a6eb9cf1b334be407c4ff239ce7c778a190d2f9072eefa48343ab6e5bb041a5d2057ecfe5bdb9bc8bab940d06fcfe17cc552c5ac6581c61648b3972296331ffd7a5c0b44eb1df183305bd73f0c8d2c1047fec842e5b3bbea95061608fd7d9841cd2f2a069bc615885a71666341fc483249c30a8458fd4b9ebb8f804615b0b49f32d38375d0a00229864c62b5e71f11151c3892a6403e3eccde1f7a45cfd29243c9f50b1a5220aeec27d7145b1c4747e338de83c70e94018d2810ef2f3da64d198f3f325740030a444d8b59b3731fc469860f349e40befdba5052692f2a46c309c48d3217ffc787e982015d1c231cf4061a4d204a1fe7cf1afd07975ba2c104527bcce539a97228e5126828816825697d5f97ad2e18071a4920fd61eaeff9e38d06128823be9bfdf838642fc561801101c715ac81c611c8c7fe16bba40f3438d03002f930d66f9cecdcd0995f34d02802b1b6d24a73f836f9b30a408308c48d7b96821f75b6eece432079b8ed986b7ea839ce40a021045286f6a54dcd602f7f7c58814610c8d6f18ffcf2d6fd668a1b1d3b2c604fa00104f251d0a8f4dd2a9646067441bae00005ba2827d0f801296d880a65f938c4b8ea03426f6e1fd7e4e766c9cb40a3073ea0c10372f5b1e75b0db3f617a4b103b2f61f873a20cfaff9684a1fffda1c907674eaffe87cbb921f347040ea0335c4bc25c581fcf93ae3eb88a63eaae040f043d98ae1d2d21fe76f2087abf4e37cf4955f3a720349e54cd37287cc7f1b8897bc6d2f66f6bed9407cf1c33ee8b31b7d7b0d84ff90797f57032157efa54b4d0349faa48f8f0fc6bafdb08f2dd040cedb63612ac7cf29e6cf40baada4f97a376620c868b43ff40b6d510642bf95fc8597b72003f9e06f93a9881f8a65700c969bab6b59c769b81f4468fed9249adb2d670b3110fa4063cc4796aeca3a97638b3010ea2d55fae7e9631f9fc7166020af567c6c0ce2165f20a81f6b8e1708172e1f4a4dd7b4077b8b2e102e75b0f27c9c62caf95c206e0ae57a2bf387391fbf0592e78d7facc1d7024173fe4a68b43eac4b1688ffc707b6db079dc1462c10df43e595befc0a84f4cd199e0f752b90f3273bab7cd07e18f62a90b4e5fffe283ba6aaa940cad107957de27e6a9e29105e35e65be5e3c31ce391022957ec8a9e74e4b58f0231a5fd7c9f3b4daf8702492aa54b1fabba227c024956fbf8301f544e20ac885bc4461f88dc04a28cbffc1ffb619840ce3ecc071ef3f1619640363f0cda29fec184c62881a0f1839a06cd7c5c6d120895afa28ae78fa3211208a7f1fb0f7c83c779e50884c8983cc666773c6d04721fc6ca55d399b3c745208a695abffbcf8a3e9a08a47c24950f22a4d57f3304d269a67c651d5d230452d0b6c8d8c78721b61204e2666d8cfc2391931b08c4b6954b29fec13f20f7c45a686fe503624ad9dcd632f88146dc03a2f4edc718f48f2e58960764cb3095b3e9a3fbde1d102ce4fdc2ab03b27b99eda68f2a1ada1c10566eaa67bbfe23c60171e4721fee64e5ec77037214d7dcaab86e6103f29e89e745ad8e95748b1a905aa3bd35e6cd369bdc8206c43b933c0d1666299cb320c6654e75e3e9fbad940531d53ade9e95b1204e47da8fc8c6710f2c4895accf0fd52a9e5bf01564ff964d152ffda0a3e80a726e567a143fcc8a7e2b08f225bb1eca42756505c10f4c73f203bf94efbc5510f34ba528b36c3946a70a72efddb9e4a920fdca6fce192d5f6f0c15a4f8c976e7bc539062bced3f98d3ca749b8260f30795ea53e7775929c839f9278b1dfc283d64a420a7f6e3c3f98ac9ee37a320653f4cd1e3eb120551d5a672cc9472acb842410cba1fdf66152808ff5ed1d6738ed2399f20f451ce31a7fcf1fdf1613c41b28fe287e992f9515f3a410efab999f291e58f152748eb7dfc7512d1260866e1c71ff50f4d902b9a86ce775d29c49920a7da8b3bfd7d68810952e71fe9fe14ad21fec82368710992c5644a69bf32abdc9620de8e5bf0a38acdb1d3a54525c812b2a1a2adbdb7db3d2068410952e6d0980fdcb623ff305e7c81c3053d4eeff8820957501f9330c432e23ab28ffa3064fb38f3c15f8afd1c7b5cd24212648d3fb77f7c206b110952a65f8f9a1396f7a30524089f7e247b59b2168f20945a7ebe302931d13b827c50c18f74fe6364ff458b4610b7d2b47b58c67670b560047dd426ee5a12a215ae5997e28a4e79741fcb2e82b4a1dede6bc61468a108d24ff6e166daf04776a71689208d7ae5cd0ebd168820991f26d9fefdb53804c98f474a3dc58ba3fa1a827ce89b32517ef4376308b42804513e6b8cc9afb52004c1c65efffef8b2b4a6b418c4de561652dd61e9c7c7a18f7b5a35e8460b41f4f1e99ff9301e08624c7cce7bdadc9a0208722737e9aff5e34dc13f10f3a7f823cf7db771bd1f081ffef836f243e5e6e3fbc0b8668bc92fce07f26165967e1f48a6b1f81ec8c7876be9bed10349b64d67374b8cbf792054fa183ddf8ea718c50351a28f2c6474475ff40ec4e03f5ef39da32a3c7620771f6ff4f551aeeaefd4819c6b3266ced6a10331a6b26afa2cf2713a73204ba9bc65b90f4fa12307527e6aed3fb494f9f8a01307824a868c796e935c0c1c48a94c3a681fe7e3c30fbf815ca1f26c44760329f46e508da37f306f1b88595da272c8ed6d8d0d04fbee943d2c6dfa6c0d643facd807d9369dd7326a20fdf1711ff7e1671df7caa481501a7fac19460329e61fc59cea3e3acdcf40903f8e9d5e8b19887dd87f7fb99681541dd44de22403f10f2cc9e6fe1f860a96319056b2bc44eb4387b08881fc7b5bad391f250ca4ddf314f3b17f6feac1400edfcdf94463faa0f3054275ceac7cea05b2aae5f0b3b9fb39d705a2774a481f1f5f74d09a0b448df84ef57d0bc44ef1f0e3e38f16887af97d3375b240d08c29a87689564ac10239a5303afbc75e81786f9e3af6c75620c6bb4af13da657fab80aa4f0a933d94c754a29a60239568cf51448b2119bd77f37bc9702b1c3641fe45e963e7aa340caf6ef8a8c7fe829080592fd618c8e96d58fbcdb2790c4c7e43a2527906bbab5b3fec61e699b40dc989b4b3fee3ded6399400ee1c7f671fec0fbff25908f43346d4aaa4a201f5e4aebfaf171ba1faa49f8f8e23cd8dba64820e5c5cffa07b65729a547208d7628d7ae249f7f23102ea337fb61da9c2b5f04e26da7cd797f7ce4394d04821f56a8e59d39046269a5147f8befb94b211076a62ca5fc95eb0fca2090fc584efef2355aca470281a467b6fad9ff80381f9ee3dd8717abfb803c1a173e5c5895f8f480d8e5fa07d3e19fa3e101a15f5d73ef6fd4a5ec80ec9fbfa7957375ae03b2a5263f3e88ec2bb3734008abdbd4a262ff07e28018d73be53ef8b6a0de801c76f275615183763620f9f1cf460b196a5103a29486deb0d91bfc0fd48206440fa99697d1de3b1f380b72fa41a8e5cb9105396f4c397b3f53fd1b0b426acb54fecf8aa3c182acb9fe0fdeeaa22ef50ae2dbde96f8e11fc6ef0af244c7eb7cd4d3c7355d2b88b796f2eac77be17c56905e725eef5c05a9caaa75255705c93aec8fb2755241b6fb687fe21e372da820ea653e0efb87d30756390521d76c34af0fdfa3620a621a713fcae1fad03a2e05a9437908c953eb8f928258bb97a16c2d2fa7a32077f8fae3a3d3ec5993a2207bb8d8d3475a2848f90f3ac69c2fffe18d060a925bf4415794db749f7d82f81615e44b5f7e37f30439899b25b1d9decf8775a230f59e54efc33841acecc1f26a6e7f3b9b20ce743eca9e32ae868e2648b1b364b385f39c9b4c10cb0f564379c7f25cc104f9a8ac36eda51fa8dc7509f265cda6c1b604297b3e9d975b4a1fae0479274b2ae8bab48729413e4c92f9f864dfced549909387e7db32f33e4e4a8210ba395b1099fb832f12e429d16c7e34ab665541827051e634ed53fcf88f7a04e95d2aab522a19df11e4333ff21dbb1b41fc982ccdc41f77e8a31941a8eb9f0b112f82d051ff386e77cce95b45903ba67c33781241be4a9e73d5d9a68d2182f4a3296716890e41eafbc318822855393bdd4d2e5a0a4190cbd0e6b1b963cf8420f64d4c9c253f06300872f683c9f87e793f941f03100429ec66aeb4a16eff7dc86000812086991f59db7788e501413cb74cbd2ea329fe3f903d4dbbdbcfc7cec60fe44ea739d56288d6b70fe43cd16ad3f72ebff2815816b30593f9f65a7f0fa4768d7e59613d2c7a3d104af3452b1f7ffdfd7920cd549a0df10797eac203b98f63ea7ccbf30e847dd39a2cf5b0d087db81e8b98fe3d41fa60ee452b5b8d73aab984207d2c8ccfb86586f9fe740549d4d59df341fd52c0782f9f1b1aef57120a6d03f5c3fbe7ff3120e843e3ee96e89ed8fe31b48959fff263f8d78eeb881e85d79b9b4d306e255dae815990de4c3d3547e58e3c79ddc3590c37fa79ce1aa81246d15358ed44b9e067292fb3e162d1f97120d0489ef23ed639bcd11cf40acf99fdff8ec395cc60ce4d8cae8fc9632104cbc3325e99081d0dfbe259272da9e3190f5b26773df18a22a6220f49f7dc7cd8f4d6118c8395ecab7df313385050ce48db26c67d2adef952f90bec332cb7cfaa5ab7881f879836db4fcfb35952e902f88f5e6a70ed3c77381d42972c3d467d4346f81a06966c7d4d40f55d60231a6ca76f0630b3d726781201f3f75cc5933456e2c104efdc072b4952535fb0ac49069e73b2f697bd45620e58dfef8ff5781ac7fd0366d39fc71ce5381982b8497b55d7ce6a740be14338bed6bd27129903ab78fc2473d0aa4970c4b2ef5ef31870231788cd4a6bff81bf304a2eb75eb26d558713b81a065fb232f51f6596e02d993d4b8966d96509909c40be9038d2ddbf0242f816cfa8766b2495602297dda86cf9dd7fc404e02692dc624df7fd4e93f4602f9ee32d36e6cd5e51c81d8c7095cbc817cd89f2d69a8f015ce8f1b379ec0851b8851fcb88ff2cbcbad3baa042eda40a83d9d7b93c9dcf90f238cb62370c10672b6942ac58ab993715e0359a3af3cf2fe603ba40662aa9093e2c7a5e1f4e3d2388b3f9608d532f7cb6ca3ef87e17f1c34e8c77d7d547e94c24d7b0664bbb434fad0bda25bc573d8744a9149021766201f74eecf31d4c6ed83b90ce48e25a39725190871e91a73b80cde6166c08d1b30e0620ce4364d21cbb41403b9ff58c253caac1fce1806425d9ac63fcc2e188c3e14f3943e48db4db5ecc7927ff03f73f1055278efbbe8e3e81a7d89b4798cd13a062ebc4092907aafd473e9cfe5505a8117c71ac05be45f9431761cbe2e90e2651ebd7c9b8fde63b840f8a4391fc6d8ebb176de0279767393568a7e50d9d302392ba76af1e3118f216781eca5b6967dbcdee98358304a3ea30fbbadb4e25a347e4a25c652c3c5c51588d9c1ceb26546e5e075809ac08515c871919febdd57811c36a78fc366de2efb5081289faa2e5df6c1c6b7b89802e12c353545656fdc581c64c485142a0a0505ba61012e9e708ab659f2825c3881e452e1b3aaaa7bda390c30bcb8716387175c3481d0b97cd34dfe51d89ce5820944dbd861cd7fcbf48fe2620984b2fc0ef759a3df3e9112c83772313a2b8737b84802d17269a9e61f54ade939945ae0397870810472aab0dfd1634afde1c55c1c81f4f341b28f529c02f7308c74706104b24edbee7c6b27adb70b0e3ce0b46bc08d175f6ce0c68dd3cee3c68d1c5c14816411e2763a9ebfb17341045284fc518ceeab7e647d70318424fc6062feb0d3d4e5442dfc0f3a2ae7ad2a7fb91002d9ae93a7f56349b9080229f5acd4ba5c14d10808e4e3c3bbc92077f68739ad63871812702e7e40acfcbfbacfad3132455cf880dcbaed91f1369826050dc60771d103c48f3afa38a3a2cd453456ed6f73a74ae517e68207640bffb378fb95cb9344c0c50e08bf9b8f432cdc6e5de44207e4f11a39d7351960022e72409a8d2e6b5969f2392faab8c001e1e0e206d45cd8806e84808b1a68800b1a908f3dfef828a6e46329331bb320446d8a2b9597bdfb209505b93aedf981e8675dcc16c5821c2d1f0e0be2541f465d3eb644c0c62bc8c7f12ff9139be376c515e4518beffdddea1e632dd86805f18fa376a37238ef706db082ec072b97ddf67201d771010ed85805c17a3b6f862d55354d4f15c4bf146306bf541f19b2910a725a5c392b51414a7fd47153ff85c70e07a460c70e0af4d0e1c50e0c3420470f2f3e40740af26fc8ede318379b8f5b1ba6207bfac3201eafd1b183157081529033b38f7acd2d98a60a0e17f0e8b1450aa2dd858ba74641d63ff2c3ce0e6ec9f3911c860d51904279c59fc97c9831fd110a625f572a8f7d68e98f72a020dd64fea3781d6d6d939f2067edb4794965ba14d8f00479bc0f5a22b60f23cf3214d8e804f950fac75394f0d02d7f61831375aee6cf9761f96076818d4d1036e6b7bf0fb5bc7df07b035660431384f8b08b1a6f367c77c6f8c27984a16b2313e4ebeff0a63139949c070e16b88e244c90e2a77fd9ff7328b1c075588e1e8d81cbd1a3c33817f4a8b3710946aa2ac6f4b8548fc6c08d1b397a741885962079cc7f592ac50e366d25ccae0a33cf323f1495eeb1ca2976f4b8c5200e1b9420b81fcee6f28ac9a164b43b0942e8ce263f3e8ca15d735ebc173dc41883070e31bc589204c14e357bcca7995fd94810be35ecaaef1f362041ee83f1488d8bf1976cac301a0cf3808d4720a195d5f272dd0715f434a95c923ffae3e3030c1e3b1c00068f1daf8e20a68aeb23bfb831ba5313b0d108f281e689acd18ec70e1c3a7878049478f85ac0062388d34777f182e5b0e9831741cef152663bddee6945d8a167361f7cab8920e95baacaa11dcd224384b1d9ee71a115326762761f42ada3fd7d08f249c585a5cc86201f1f7def05e93fd08f6721484953a50841fa8ce9ac252e3d621f04294a8f6bbc68360441cc3f3eae547a078250e7e10fc7530e08c2975e8ce9531fe7a8191b7f20c5d8d3eda8d9ba2cdaf003413fa7dc173c85fee323fb40b872714d9770015d30a00b0578d139187023f940d43feeb8bdb44f2173f640c858f2c7c1e31ffba1dd7a201f6baf67bafd6ce48194e7d2c77e730ea5318cf3c0718243be9d021f50b08107c2586eb748eb1c3d0d016cdc8154b962bb796a31c4f0a2878e06635dd0a387f30823c770010fb303399a4c1f6b0ea5faefd7815021cbf34e6feed8c7d381509ff7ad99f2617299e660a8e73eaed837c98158196b3167e5dee8ae8d3854a13b6a7657f8710f1c1e3f0e3f8a7d91efbc8198f3bdd2471b738362d691251b2e9aed157b31c7fc03cb8b291fe936da404a1fbfe3c61f860e9b521c24031b6c20dda6d4793f0e9ff3aa105803d2b57eda877ea9819463d33de2fa48ac0edcb861230d644d95fcf8c2ff5188cb0e3070acc08ba389d58113230c2434a8ea2dee871ad987e2f2f12985ff660c011ece821d14b07106e286e5b77c9bed58d163c30c84d91c32f6e15cb40c0437ab28f2c7f93897decee3c840b49ecfdef0181683464b4704c4e0310603c4f01e2e5840116c8c81d807b39becb2ae4f683994d886183efe3f9d8ecf47daf3b0118625d5b5b3331fb4fa1f59c05036be40564b973b1f668c7c36bc40f2b2fedc9a45638a7e1788f930f58f3358d6d9b6b9a0764bc6575f5cf55d9e34011b5b20c9563e98d198d634a407041b5a20f71f7f10cb9f835fc7d8c802a92ffa602eed68d8e85820d985d158af671dfcb27105525bac743f1a1997d735c0041b5620ee75f4df0ff331486ba30ae4a3a4e556e9a5efecb44105b2870b1f3b054f7d14341b5320f5aea4cf778986b79a60430a04e9dab839f9f1868d7e40200d36a2404cd9a1353bb3010552759ecb707ebda92d0ed040171f96001b4f20670d7a7136b4e626b3e10442c5ecb3e89eb10f636ba309e48d0df17ef4a95e7ea8d9600251e552e475fef0e2c62c817c743d23a96526162425902f7766e3053f42602309c49c44352745af8fd28304a27a4ecb8fd78731ae62e308a40c5db5ef9d5aaa4246d80f5b5554fa30446622adfa28cc33fc3f76ea6c1481f417d256664afb605d221056331f4c1f793a0462a899f8742d97fc7321907b2aad56d3e24d7d8240ae199b9ef000811832e7aef1e887715efe01f9d8e259fea30de307b6f980a0d36933b7a4cf5bce460f48b12f84b7c7906afae101f18f34fe8f773a1f851f6b630744cf351d46af0fdbc26a4307649bada89aa894328f0d86e3e8d160dc016ce48018f3a79493fb51ac76cc060ec89a0f2a6fd686f7908ef6e23818388edf80f8d7496cf3a555c69430bcf8c2e0f862874104d8b001b163b07c60e125317684510fb05103a29cfcf14ad8ac4bdf4606b04103d2ff66b1718b132f971c4a9738be18038c1e0d06ef16b320b8653fd8beeff4118e1488210b72fe8a7ed4e1593158b083078e1488d1602425608b58900fef2a1f05f3f5c3b68005e976fb30c386b6b08ee550120387bfc00b1c5fec303abcd82d5e4108b5a8d3f928fc85287328a5208c1d3d7088e185e616ae209b1f1f1f1fe68b77a913d9a215a4f58cabf3dea504b6600539c65419e6f28f3ee7640ea5a43170ece811c618c6575095a34783710ed86215c6cc1f944c49bbfc518a39832d54419efb033fbc59df4e9fb6480529a5098bd9bb2aca7f5490c25f9d1f9fdea49b7f0a92c58c3bfe9dfc68bc3705e1336bbe6f5d0ab299e79883aaa77c6839294829f458fbe696917b1424fdb2cba9ddabca1305313c8b9aaba75cf9a8130a92cffc51f7416f4041da69ddd07ce82748e1c7a9ed4a4eb22ee3099279faab4e161aff0fd30982598c79bfcae931ce09b21f870ebdb3956eed4d103ef6f1911f881ff5775a344190bef0923eea3e8aa864822019cdcc3e774ae98309d2e6fd6aa9d47f183b9720c9e6105fb1e2a6642c4138bf4bf17d34c69e2b413c3f8b39053fd60c325382e80775ea59d755d2e24990f463d6a81ddf32c7254138b17c162d58cd7422418a2556ddf9aeb616481072435ddbaffa3efc08b2fa7af6fab1eb08b2b97cdad5b47c1adb465cc9c22463ce514610cc8fd5cd0f233e5f8e2e829c51ac43375345103e3dfc42f7bcacd64490f72f1f7b0829b7fc2722c8a77eb8169fb5aee63c04a1af3bb84f464a996908e27adc594ef1c3eb5c1682aca331fcbe8976754908d2cb4585ca6a675f711004f95c5f89fbaa1c4341903389f5d6da1fc5b46120887e143572df87f930f20304f18f43c53f0a0b1e33e7fe40f268bb31fed16a3e3ef6fc40f46bcd1b52f557d5f5813c95827d58d0ee2c1d1fc813b7fb9eebcafdb73d900ff447daf269be1f6e7a20a6bba02beea5b1399607f2575b66856a7820feb146590e7ab291da1dc839e6434b1773e733d3ec4054fbc3db3faa607de887d5815029b5b337fbd0525f7420faf5e155ea3ecac791a93990ffe8c4ae2dade65d4b0e018c92a8b42e8522c250201407842171180c062171260013140000000c1c918622d16830ceb3551e148003522a2a44282e1c2a18161a1c148745a260280c06850361401808060402815028245c8863cc3db11ee020ffa08e198ff44caea15a2bbc00bf43718cc9a4d74b0356d840e8b20910a251e1ed7be3824f7afde4d06bcd9d160474282fd016d780484dd2b29fd6d2d12400099903a79a2f96bf24501cbfd048ef844a5d9d9bdcf775253300701c5a9757ae553570b075ff6a98935f74a9f0ebe62c06cdac2250a8996060df2f099315913c8b4d0df1593afed46d1938dd9dd216e816b4961ba0c1eb44a7d02b1dbc8e8f28abe439fb2a836a3bc2e817735e4f9f022dfff5e73b6c5cff4edf34256d0e2cdca7685d3b463c490461f204792bed0889fd1db5a466c99fcca727df40ef64d50e5e1389ce48636e253f9d2e22d87f388c8a437bdadb1802f55a85967de12041bf7a134622e40e57667b61810a4a46ebf3e49cb07190bf1b75c8648c20394fbf4caa9299c67d77984a2203cb714b248e2675a96683d0d1dc87a1969e01c49e40460702a3043bf77ebec9c5979ae5d7283d3257944948f41e7ca404fbda7ee508b1f9cefbad32334d4a87b88b767f5885428d2ea3014f8102ca78aa71bbc8207e57dad929a5b7e48c96e8477034cb5aaef498351cb44072975dd09fb5a644dab186e4a612ac571943e4a34fb993fcd611591928d260bcea91abe8bd1e1041a220f88665c6cfc400d09e67e75a7856fbc20f891ed568e698e0754a6276eb5e7594a78948d4803d210628e66ba55f5eb4569da28214e0ee43ba66abd0490ed76a808bfacbe1caa550f452524178e961b11712c002ba232256fcf43b4ffb3d5267d65a78fad5ea7dd5633f2e5ec09a9ccf50bf8868b6dd8c063af6bfd4f61dc13fa2aefe9d9d65033b66c0c2dec3be0a15a45e0e8cb94bb43a3809effe378855872a39503dbcf780d18e3f8c25f1023775697886027a290378a3a75a08abd330a13328a249e12474331d3a1423571a57354cf8a8cf4d1921b0de7add7fe80f1fe73576e590163eaa427ddca357146a7b0c9659e6d1db5d1069e264d21852e9d6dadf8ade25c9d97ed4d55930110484a66fdb4d749c47aaebf403b1c1df84be6c21464f46de174f1a64d0f1a481bd148cbabb022f26e085c22ff256322d8f34be3627f425f7912495930a5951de19ec9798d82927ad10d940a10cb515a436a72ec6b2e481cf8175fa9ea3034baab13e9763588a25ed1a8aa1b47910ed4842abd6d6c645ac4be06eead10ddd0be1558ab99f8351ecb163334aa3e2552d66e8a9106ccbd0171b21cae070eb2103fcb92d0c6239589028caf596c1df4060089c4982ba399b2903f00a66f36776b7f43cc6272ec3634dd94ba80b168d2bc5c57fc4e21bc028c9ed47074108f30fc1504c862d501241f08911b874c16af1695a4012e8d9b64d15d58020aa151615f4feb31ff6353702bb7b9fbfa89a90a90fd6dc9d4c4f1d337385a3612a14b5c0c0c2f92f9a11e42acb0d8765db75a3233fcef6cd28f0ce942f596d840be035532127f670ae2ca81a86082b186fb28e0f23569a758bd79e020533ed55bca055a49e05c451778e692556a69ba3375d73bb4b8b00cc0f677444c5134f8c560f93a4661fbab4d48c6e7cdd4ae23a6398347083a362c40e577ce02ec42dc6b85e38d1fa370aaf7a333e25144f74bf23a6102d88d75dc6cf00709df670302d57943ad5959ff3a7e298096baafd078b5d143d2883075044f3497c593b3aeba790007dc785a338fdc52fb02856fc673dce4c48d8d38196cd6cda35b9a841088145cca1c31afc0a0010b26c049ddb9b7328b6111479748b4ebd7a6377f0206bb1dadea24d7cdc8419f4550a70bdde420ee86299b82930807002f695f79c23925398136e8294201cc0129e08349220533b5169154548c1d56be550c4781af137f099c71096699797b0d3caead8c2c057615b7d6a9db99dcd4cee1d821a870cfdbae758da70d559cc9cf268a254a354cb592920ecd6e6e6dd27e14b7399c278e39016de8fca73c1773bb166f3713bde98aab17863e94d9ce142c912e51850903b146d6bf0af52dbae3650e10ecdf73b4463e7aa9825d9f7c593e1580c3c2ec1b668bae7d64667bf982f021fd11257c0417fa457aab90380bcf5ffda18889e739a6a0780d440ea23e088c593b8c95a00c21c8df121a464118b06fb8a72b619d2395d315e2b02be1b3c24ed327b5002046e8ff4f73e382a2c3d86c4374f054422f7b01af9ec50150a0c80edc8b58c02d98315da5014a75941619a070e41e2d85f38ff8d7a32acfab1d58a25e0effd89a5544c8ac61457cc4c10699592226f1bf5d28f2e0e94521718ce3e40f1195e063b047c47a6bb0c0700e6312ed81c494951ba77e00420ac34b8b7e041845d891604cf00789d43b7bc1a4d1440908e91ec40e369f3e39ac0ff30d749798641bb2b9bd2711a03f36a2a318dfe6cf0b67d31f90f189d80e01fc54dcdb5233a3ee27c4e17a480588e8992388b9ab0ac6247438908e75185bc67604de1a0af4eb22041b426342bc2844fff8c974447c2845f9ac29379119964c35bb838e28263932408ac29c804827fd29745b658bc1662e4cf2a4d07f30c2639a85fcb1d7d39addf7f17f59b2e6fbc4e26b96f21d0ccb4e077c63170f19184b23948b9ed3793747110651a9530b11e4731288a32c24681094ba2dfa491de5ba6b2b8b1c9333a8b504f88e75803594d44134219903cb5d566fb534b74bbfd98b819561a21535ce039750e20f88bf4448dbedb84bd82f157d6148ae4c314e8d886ebc8d6c1d654f28ab0873b6038fe2a0c537cd09bcf216fd1ef4791f9ea28bec289c2fea6d006e4f25d4cd7307ae87e97f2516ee21aeb4c8a1f04c399fc2a6133c1a0fe1dbdd6cd31d1f0f74eb9cef0c016e2faf2865e478fefa389c73a686887025ea080046246517aadaee76c4c290fb731c82fe5a6c3a95b62b704952e2964336a4d3acb60ec953220260cdb6c0cd105ab7d33a6819ad5dbd035bc9111bea848fc2b314a3c8c083cb0b54b4cb18ceac6a48d62d1b3441b4f1ba58da0468da1cfb8da686d4c6df8aa15f48a215844582f5941437a20470f6b80b38a40e877b9c424b035180fc6829dc132b1340c2806899161941833060283c010307e18ebcc1443cef253272c30568bb1633830080c72648a291dd69e9e976f686664fb5a122c000e6287f934c2e78097eadc11dc8d7a179535c29bd75a50b5ef7be74c22623defc313f7cf2807a6eef67e4a62e84621a9bb6d28c9a24e2734d847a3942cdb8e143d30c126540aca127d54a712cea1b833bde6ca5ae8d802c5274658251cdadfdce86942420dc2728f55f6f99cbdf135c5b20c65c211b52362ce49e12a7416ed98a42f5ec7d6fdab453c7edee057bb82a9dc673353717435d57ad3f9ade7eedfa9373fa5def99b3ae591a7c2fa38a9d8947f05550843d707fc8e9030cda301a1b6f581b8440c016be294d393a64db9959765cea04ec501116bb676405e038a84d5d15208cc6276980d89e02445b0aabf131a2d429459f82514025cdbb213b2e2eb2c325fb7ac69f2f0ca0cfa3e3262393a8e0ed13192a6e05ee2aef8ae087725060a5c63a7f0c04c6e9f33a4a02a699d9d93f3803116cb07a38876a275cedc353e89acf273b0037a4912160320bc0ae86d2d40f282426e446a8bb709ab65ab2c7f7f4394bdb991816b08eec3a697a1094ca7823ed2400878ac5b8e9460443ed1f7e76cd1683ae13e39c03efb37816a4212440625660072d2c59a0a53a9672ce0bddeaab4399e3e3e5401307f37c1efd16549072b2a4346bc5ea8825395415e8a5947cccccfbb0c420af3263019afbf2fc53e81718a2454245cc214bc48d084507f980271e7680f1ed2f97633408dffdeffa5e35d573e3743b6a9868a913f5680868ad490c6fe5296f0506df96736e0b7f81b798d0ac371967082a0308705c62eb006b35e1b5bd51222f035577d1ba85bd40d49e3c5583d2b488ed501c875015a2350145c2b556523540aa0ae77d90cb32adeb9d264b0d7cd0cfd0e0d142bb32a5b4e6a8645ab8d94671bac6d058c20037a464df4466055e4ef38bf15787419ac039b816a840dd311a1b534c391c792700bb3c3fcc80c51fcee082e427e073322b79a1b8a8667d881a9368ad85a93c4d4c9eada0a64e672381136f70c910222316161c065953686363ca91d983d3ca00598032602ab84584328298be3c386f6d67b63bd91ade1ee506f406bb03bccae11de1c88c5ce8577918998e22336a03b6c636fb3b7b4b55e8e65c66937c254e6576fe40888c36ff831da02eadd8a77659bbcadbc71de186f276f99b726a62102b8d53b088c656271180106349690046306da315363f3b1bdd8cc68d43b63448a0cbc60b9a9b879dc1c6e266e1a9a1226302699b80284b2b912b52586ad40022515d3db94d70aea6ae1e0db2ad8085fdd6588ab6086c87c75efed33967b336573cb4670592145c4abe0b27d315d3124ddbd7ac2313fcc0ff9713626e2b5d01ddaf922efe05ad884b2eb0334bfdb77aa0fecc3b5fb68f7be37c7d4f6d626eb2ae5bc589622c922fb8e0ea4a3537766c617ba25406e43d3d62332285acaa63c9f653c8b05ddc84c1377c10d3cfa464417a98ca22eaec7ea71192b71130b624ff59115cd4ef87e49afd363d3469f4784505ecd77f8281a014da0785cad99d70c8127a55137c5f0f83fa6671ff198663bb1082440c44b1f15ca19d903fa359f5e9b3685253906c29ec4a92c00179f1f71135e1a0ac3a00da761247ec4d46a07588350388d62aa8207e1713c16c645b054046fdf0cd11c5b6791f7a428cd7d22b88f2a4fdbe5d33d7edfd6aac9ac1f9af01e491f3d51cfd594af35a692953175515c8883e3481ca37066790604d45fd697fab81a2f2b321fe13c4a57d4d1228fd61ac8a2bb438655dd76e6cc84485993e83ba0228598c2554be32136c443b899cc7a6f7625116d97eb8ebb23bb53eccbdfd2073a1b69a69f2974391caac581d26ab7d741613033e2a4af26081c9de35159eb796ef41311950b167bb05fc8e986464d3d8c77042b2d094ef6efa1c1ecfdc9a57b183200f008dfe8f3d004580b6674f744bc8efaea130143a33d54aa7ebb69a700d812976d190b7026dce0af3383c20442c783de7edf22faa8e23da9519c9a8be3e67dd17980995f2611a6fc0e187587af420df39e5509325432497a7ec1ce02e25ec421a9dd68cada9c2842bdafff62e42ddf561df607cdceb40a3fa339dcd5330f542c27d9bf8b1665dbd20959e34052434dd605a7ae5536446db55e6aba09afcc8457f26dfb883663336226f3a962b3921c61698b824a555ac43a3404852653e26116309bd558dd2e1a2ae382dd0f778d42ea00300d8b85842e41cb254ca41efd8f9b990cd84c0f013f22c294fe6568126960602d0a09fb9ee077e3b1eb5ee16431310c588d4c9ab41b252ff532b304e541a76b5e29c6ef0171f1ba79aa8b12ac1aa89cfdc6480b83f9dc10d0d277b404706efed22b3d66575e6535581b079660663e146b443ea94a45b30600c19d270bc9cba4a0cb38044afc1c210d04dbe30ed1cb8ac9b44debe78251e5d8f06a13b04f838c763cdc1a3d771dd9684c00ec44f063fcfec428847d66564b59fca8a83cb2045fb0336f777c4a90c2992676c9052b257e3924d25cc3ba0155b3afac1e4244e1bdf70aa7ea068f4214bf8adbca628b1da22b22676e1c080851ab853471f6cb0ea2b72a25d5dab091e9c422d6babccee5e58d2881b79c331ecb82805c8083c2e255de6baa86247ba49702f1f180ec59baeb94209c77f4c3c2d19b1045d1eb19eda330aae00e2fc2414c818406e0f3aefb76ca83e21a471e98544aaaddd392d06605e99ae20e2d9bfb329c1551ef19b54ef1581b5efd87775a755b181a59babac3096ff6074d65c38e34fd659e55706965f51dc9707f1b4cc25d8d80205af1eef2c122388dd10ae44f6be54c5153b72cc1cf65eb6353cb856d295a83ea39231b1de9f2e09cab36d0715b6cda7b1e19f8e769d0c4989be97af5e50e2af9225e6e20188b2fe75a3dced1805551b7f7dc5f222eb08e136d231c0451f9fe4a2c2a4abcfc435628dbc76608efbc4e1a53e75d29a50256ce0471f3d48dbaac4f8e4e13cebb5e5bbd2c222cfc67831f60625b89081552ce30eb99654552c794491a8604b889e310e62d8e0ee0442f3f3e7e8c406167333db1b5ecef873d06c584f80a137c6d03e0f1688abb97605ea9888631bb9fd3e406aa241806eea064628154dc278627335275a4ed371335f8c72761d9b66153bb522545684269f57e6cdb95033a7c0e9d412601c66f9e61e27394597283176d8e16acbea51b51600ce2a6697811826b113873da17602685e90c0bf812bef1cf3f9f34a07d048edf41e52aafc1104037c5060ea037161d3efb0b0e14a5cac0102c50a450efe17b6a591999429d9ca0e42b406328570b996579726bd89e5acc914ca0283fda1e0ca200492b76e825a5ae4921310d69ab0907cf3c2c60459092c9dc3925478b4c343334748dd06518ec07089fa7e8c1f6fa63dac97fe28d90f5bfbfb68a424157fcddca1918f91ec90e6d9e8b4e8e2d901618b24ee7cc6c0556221269f1c26db740e8656cc25dd46052b6eeac6c86908b4b229b4e1d852bb33ba0abfed867b79e64795b24bc4e871a934b4086fcf06e627cb46561a53a585b3aaf9677b280e262ae02b980b6f7f66c45f2e6b215c2259bc9054bdd009f597ceffafd2169fa06041b2c58491ea3278a96f75a693d54585ee4d6e51492c9c5ba565a6dc7da8df130ccaf5bb25cc3e0254cb3234a799a84b77d2b29e8d743329f5d34d5acb2c64aebd6e740346a793695c50703e8785588f7604c6c69960e78ac98f0e10e38a57ea35907125b193b0a65721672578eac60618414a7ddc9517c8ea21c0b9f92ce1dea57476cb3cb4b5c452b1262d9f2a71b8b10e3a045ac13c034e0c670cdc2249d0778f211390d9a7703bdd8f369a04e21ff2ad9bf3c5ac27125b71b768f67f6a4881725c73623e48112b7b754633d57b3b9cffbeb71ffa20e80868291526dd4b78ec9efc1f01bab57142cd8cb8cef000682846493e140caa64559949a1cf6cfb4c5ca5ecc4947b9dfb771601613f3f5822a5d967d7a32a3bbe38e31cb1682b21cbbd2e73bf49cdfb1b4e594c7f2fc792c694ea5c9168e40ed7ecdfda12bd02f15347985bd809b95291463316c8738805c120e90d79e66e986d2e7a3e6ff5b75b277f3860612821369807d0a4d3e0bcd0cd5e55b82ffa4c12dcd63e02f68c91f141f4a722d009f3105b34912851e3295dad43075eeb7014982482a7e14176b03b424159501f3320f1ead23c84ef359580c2708e833290b0ed78ea82e71696c115fc4d0c75bc1062de96a5785d160e81d0b5b15ba66f7d2d484491c85609b57c19cb812551652f4ea51a52de2116ca12695d04173c9a077b8841cc6da4e74119f2c479a0ee0c3572374bd32ea396709a6acb21e23ca1d7cbc67a429b72d9755818f59903c4a257609c1e680ceaf32bcf9036bc6c4a8b33efe53cecae282671f27bde8a84118a94b72209bffaf7a96a65265a53998a937b857c1b1be3b2b80c8855d92ff4aa6b39efd464b5240fa46800011c5d2baf3e908323f52fb92efe2ad0899a27347b60375c39b65ca0cfc63fdf900764bb0bd83ec4b962ac2821a37ee5a5171745972a5481f62b4a50526f1fdb74398dffd4b02143012ca48d97dfc3aa992874123417452c65b7c1a09f1c0f5f84aaf638bf119c428d0606b31ac06b06a17035cf977bb49ae1284e6138c026413fc6cc34644e2ca4ea82220f506340173cfa1ab9a437f8ae5969965db71fc47c3d1d91f84f96d1472aa78a62f20937e69fec426f197e573598e5b05093a5315cc9e418cc38ad857689e380745efdda4d43eb1cd519db861634d8f634539a794471a3eff9521ae4851e6f561c7f77b158ed188e7999f159e6e7315a75d97d0a6f9931dc881bf91c1e911e52e1a87f35f2f69c9f18b82c3fa88528fe6548cfd95ee1b1192dd79d8b765abc706159e55674356c2f783abe179f1b050fc33d7119487b8790ae75b14b34b69cfdacdb0d278323b66c492db5ce7d04bf52c5ff89cedacf305a1eb813d0461e9cfd0ab1d390e28cb8d6196a2eb650e30751a13ab5e63019984c252ac210352f2f8f7f76ca65f803c844286bdc68e64f0f3ad3cbe65b72daa931b446cd46b0a639bd5df75835951c6c5e8648c0ba9686f2e931ebd6d4e0b4decf949d2e0ed4829fcfc333364704058848b926b29c4562db775a7b0b02b7394d413d38e0c1169aa27a90d029309b3e78e80ba26336c0d35a9221d3204ee1963870e9f89c2977126be44e334079dd746e85df55277fdba6970ebdf75cb948e154438074eaf712589585399f0faf05de37ad800de8e636c67a161d9845ac441b8874ec00542fd72326d4270ef1454f9afee467302c5f9f6cd3e68ad4d2c4c265a05b7540a155307808d2b445a71dcd1ea57cc5fd54ada67c23faec811863f45ca6c663550a8480689cf6fe8dfde521a60dda42d526b6484541636de1f20c623cb4f24615481a3b69d5698ecb093cb1c154f75e6e1d04c772c8946246879050ebf0c4bc3e4b5f96d937b748c53f698ef33e1d736f8881847f626f903e01757008c7870e53bd3c0f82a22542474cabf0d754e41b1d2870cb29860175dd9b8555dc1e5f7f9300e3aec54e4d28511a33fc8e81727cc2ec153554541da5efebfa554fb821d390591abb0c193049c9f2dd1a7e8872f2554806860e9c24c7e8a86ae468e86671c0054da09a1e5e0cf5be0db22c42f573ba67083d079c45d53e01464bb6dc7aa27e2a163529395fd944f977d62ab890808955299c6e6f8c64cd284e461ae9e0a23c2976a35aa92871b91a88927aa0783b218b6d6f3b8a11c5b32c0e3fe434edc5e9e694e92af9159d836f884d778a0c3373fb19d682ab015b8ffe650811b33192f7254311e32e8510914419d5a1bcdf132dd556d50e23038bd321c62c9e482cd27d5b585ae14c7cd5d278c4d1cd2b9b0869d4162486f7b02d91ba65ce8c638d2d45178eece632a8e2f7fa3c6c3ed58a1c6d8423d9de195a254cfce2907ca2a4599c98695c9eefe40088081af9778b815eeae9671bb8ae882113355de50e43a1201d30bd06233719b34ae1d7af4df2564129918487d39f98083626b84bf0125d8a7cb6c2a08f687c7054882101b720bdbe5105e436e1a92705c783d09460bf5ae413ba843206e60c45b86dcb54a3e93af648d5b9bc91b811d4f405500d3660063b0a910c277ec508ee874ac8784e45f19266519e4c1824b7f8195e30d7b4a09af44ce38f50548cd6a87a0b18d1f4ebfc352d6cea219ed6f82fc082a6b19750ca0b1a3f4126c203edd43df4d1f2c4534293f244ebe6a7ebd0577739563d72641c89ab401373bafa593157884bed469c6a9016d78e019d90ff28d7eac0de99af0cdd1a8518f031644afd8dba6a35675419284b1bd3578f27b41632889e2ccac7cda8fe209c267db1d235dd1d500b5be1a040fd7faea050fad7efed44c8012eeab272820e12c98aa8d82b85d6f964f587598aaff4e7579544f9d3a90a97fa52e4c6aba4ea3ecda3069a91b6c7b58c046327ac0326bcb2544852c4338a04d2821b172d9bdb9862125082d7fae6befa308d776e6574696cbcfe7c1fd78b945e383134d5a12b5685f15cad78c443969aef94bf3691b7a7fd8b6779a95d3d28840236fa388296c7d28095da5b978ec0a1bc0acfa6b7b22daa66c6c35831e612171037656ac1f1ae488618a65381cdf4dfa8753bbbd4a90113ac0cfa419a5224831e3253acb5e6d980b6cb53a7e9b917d93d881e35d3b83cef15fbaf26d47aef939d140442263a065c3faf8d0b0223e0a9d422b500ad1aae4c99bc14c17e24544a83071d256251e721e93a50ca8c89c88daf2e8b0fd1e8dd5ba46ae77266237afbf617c6a5f5acdb424b67beee25fba887e082cbf1adb6a5a6e0c12730b2aeee7357c4b698ed83f01487660d473dc0dc60d6537c7423c74ef48127b8ae82312e3efe0605da67f1a0bac532c4e02701b5993c10aeeb01cab024d1094cc8d10de423441c9cf576a27c253af9fd1334831b1220b6e216c57cd1f521fba5720d006af991d704edc7d6f88022eb9fb19855dfc1c812ad6afed6b75d6ad43b8194f88aba64186fb32678bda2296901d51e4415f6f75982aa5452ee6e452d1f68bcc092103d2867a0ad122ff5e465bdd9a82e1bf46dccb38601cb004b923ee4b2bd8670d877d296476ec405fda3846481fae4434e2fd1f644a1e1774f9c8d755f25eb861ef06ffd8fc854eaf11eb066a254df22e38d8b3172e67f2bc5794836117d7979a56790609bd7a40d907045ace8753504577fd64c31afe01b3ae39a3a93cd27ce4b48255baf246237e8ace1ef251f047c044781ffb2879f0b6d7e4ef9751c5a01deacd4025cd0ad50ed33a8666612382ac28ee8d7e26084a3f2752d42133e4f3c5c48b51c8a454c8688380a1b204bb004cce3dcd45d1c6cb8e9b510101d3a8c9f364d15850c2f85409433c21ca10792f9131eedc843687ba9bc2bcff5c911d64070adc48b571c1bcf829e614ec625c3f6f6088887d27884605a793883048ecbe9e8db1b0eb0d1e4dc8217a236c91d88a4a9c38524e3cd8ac30824f1aaca50a26ed7348523968d04a8a43138dcf9275d991bbd52320664dadbaf3ef935987a2ac05401298fcc0e1e5b2625661710794191107e7f207a3f0d457da0ec7e33635adbd6c5bbfc60d60cd0198ba5293d436359f0fba81a2ffa70020e428d0d217c0d3136c132dbd0699822a8e9bd76af2f13f7321b10817622ea759c1311222f80a07f8c9383578a57248ca72546097db6c0858dce2cd048b3e384d67686216de05ad5c45afd7377bd317b75a3da5a6fef4935887ad8a95fb3e72b82e0362199433965b79686b27eedc7a04bc03f5e263bdf8907af1b146bdf8707af14112b4f80ca7c98a10ff9729d22f68c802892c31f2c4d043701e041738e81e307dcce8bc2a143973b9d76c25701fd45b1f37d6ebc763e975741c00ead7192ee963e3c3e5c54278b42efb2ed79d8bf24eef788506c0b885aa3c387f833e4e770fed267b98df28ff6a631c9eae32ee77bf598353c2d09cd7860a515f65f148db9011107718abfb91d8ffda0a742c2b16b8a103302a8a14ece2879c9ecf1bb7716d1f2b57750bb59873a3e32390e12a385fe43e15eb12dd3c13db5edaefd0c9214f3a7a9024615eee816551477d75d80e7d4a629f1795ec2227fbe0ffd367c2a685cd59cd01d6a802055e31eb6f1e5a119c92f7bd3000a242b0c479eb7d7fa4b078c166107304f664ae3fa97ac15039018141254d4816f3cb6abbe1b0fd2e1e6daf31f734af749fe8edbf6ccc7b10858825a2a2ee08d31b3f74bd224de3d1ee7fae628c5282ad05360e126761cc8403d686401b38fadb045014d6cf65239ad0d42ee6ec49930c49e4749f16a4e96e30c4084bb0dfa8015230ae61d12a2c0edc087e36e49856cf1900da374512cf1026e7459b0d7132f1633153f1ab4405bf5300ed847552c7197893da95617486c135680ab624d19f17616db2a204ac289844dcecf5bbeef6fa52c27e411a25862b2405d3a3c015a48703626b7a71c9008245832ce9b48a4257dcd8d9d04746a7fad05caf39bd010f158fcd6c77fd32fd8dd8e8b4278932a32228b1492b4a5c7a7f2fe82450cf2a13f3f18e76affeae9461c47654f7ca002806e700253d913bf0a9d66a3fd4826e3494d12d663e788e83fc0fb16cf3d08045820eb0128325c18188b21325b5ce5c60af5b6e0ae43743ae56e12beeba7f045af1907b82bf1c56768ef963c8ec24e2f2666d8ebc683a7e566d2615eca75967979a6dc0f26c595dceb08ee96c03811a1a4821d3c8df10e0c05ab41605c28b2ce9dedf1019f981b290d2ced36e728fb2c2bf0fb1453752132e0555c5a7f2b5d233e44eaa06193a816844b3f1138d5e6bbcce3c74f69c1c9cd3c791b65a619fb7b25ac875e127f207f461be3893d646665495e980686e86c6351006702f79f01f2bc03bc64a2ffb9c80def4249b90a869ec028d0cf5c144341ede9220b869470c6b4fe98089f4d73e336a7aa78963b7bd9f2cc071a664116799f61f415467eaf860d327e6a594c717699f150b83c8bf031605ce0494419fc1e1f01e15cb3edd5892d893cc5fae394087844e0a14eeb8b7f35e5dc68d491455b366e0fcd29e7204e1d62691d57d434cf57d5f1fa80e2c80de16395888fd0cdfff59282b2823820175a02bd888c295aa055f2372fb7eb8ea611cd4e4d4c21007a69a01d86284b993b3bbc856609dc5d03ca9b83cc38e4c50f0951e630b0155050a2ca2bae770be5a9d7286adc4d43cc262195a001c0a2e1eefee7b12af30d47ef7969e4dd1d9bb780eb307053be2a014a2c68d7588ed81663b258048d4f65314660640eb7b00910058788960d46dadcbbfb2b4a631b8b9d509432623044ed2696b5fb3a7fde4ffe8c49c2395b51d166f1614b0ebb67e3f8d30df6c0488d5a8cb4f2320463f2efadde9274abf92fae95b7f09be2bb45398fd7ff959ad8feec5af6820f4b64b1f577d85be7ec5891fb03667821375e36fa202694dd463f65a2511f592d0f5b4b85a51851fba6a6d1f9c5ecc3c7299a92c0eb87881ecbd8a500b214593e1fd8097bd205b6363880130bd0b012a218e563150b46439fcffffffffffff7ffa561012407e6921542629955cbac562bdc02b534a32a59454eddd0202d874fb1beda0328a750526051405e47cd2e49945dd030d8dc6c7e7e78c7a9ca113d2847b99555ff0d7c30c6d8a24475bacb80a0bf12843739e420effd025bb821e6468f49f4e901f49a804798ca14b22e88a9ebe1e6268b464f3d21b93e74ad60dc1230c6d6f36ef9892ce659f3dc0d0cc0719e932c2194bbed076951c1db92a78ab5fe6853e269155f368cad7295de82aa79c9b8953cbaeadc0830b8d50ebcd213dc96049c5b185aed3e2b35f2edd1e492d74527447125f95196b7559e84dd683ee99907773e6010f2c74a2629aba8faa70f22b346ba259bb5258b43659a1dfcc1ce654cc5476ac022636caf978c8ce5863167850a149dd92e287c9102cb826f098425741e774939b64294d99b176c31f8c433ee021854e9664ed98a134230acd5b78a8784ffa440c29010c64dcc0030aed68dc99aba41b4a784fe3468e7481c7131a912f68097fb9be41ea84366c9f12f9839efd313d9ad09b85551393440f267429dc7b338699f86f96d09696f6e83eefb0ce2ba1cd1e1992649f1852c467ac25228f24b4a3c3e51849554f63833c810712fa144e08f5dc7954a896028f233442375b673644f8cb083c8cd0a669d4702995f80add8c3519d80003b73d8ad06b6a79063f9dbaa9a14468cbf465c971f205116dc6daff8d9405041e43e882ae189a75e753de6c43e02184ded74fef778510e34866ac05a18d94933b689838327266acb1083c80d0a725cf0ddaafb4fa41a3533e991584b895eccc5853721e3ee862bc9454c382e8c678c65a990c193970d8988183d75b1274f442060d68c8e00d033a78d1b18b0e5dece5ddba2512e73d3376031db928a4946c31932b725750cbfcf84b19afd4810bbb45f39b5bb297acf9ba050c30688ce08b2f6cd09011060e628b2ec794a23b49a8ec13921681157c20071bc081c34fc0858e5a7422aaf9ac4fa691920c1b39684023ad0660780b42e0010fd4c0e137f8e28b937155e8a0459f43d490202e97e5592374cca2eb8ded977232ef1c3e8e93456fb9c5c3bf8f8e18532c9aa4736a12b23958c40e169d790ccf21e5e777b9af5082b665586b25cb1ac935af755b3f5eccdf15ed59e8fcac5fff87bc157cb8954a2a4b252f29bcc9de507a2e8598ddebd0c18af6435ed6dc245f456b21c91052ec974fda54451fd552bce42b5515f254b4124789ce99544b8b5a830e54f4396450222815bdbf298e8e53b49bbfbde14d844a49ee30459b74523e2969e61e594bd1e5868896d990a2cdab8c982495523a9a46d187ac2a4bda6351f439ef46d0ab64e6a785a2513245d1b173357770f020f8e20b84839f713a40d1064dea13244a2ed0f109ecf0447fa5944861c2075132a5138de637dd229f37458b72a20d9aca4fa9bc322b5dc7263a34c157eea0b35ad6bf8c6626eaf876919c595a1d57ad5f9e8449491e2cd28109940a59e6f227edb844df79fc25043d32b2263b2cd1e8f6e04929a5a7c52f9568c333e9e88c98217e28d1f678e54c9ee4269bec984413840c3e9b625c4775100d1b2dd01a1d92685210a6f9c486d822d1956191688486edbcbe14489047f46d21e9105a3bf4524c87239a8f1a51644adec881c303298840472398750b13b3bb2d8bb9ca580eb93da798a7542c607430a23f939b61627ea7f8df093a16d1ef574893302af2a6d2a1883e6e6cfbff873fe848441f84054995247e89d0d9207420a28da53f5ac256ac9cf387e8a3474cb24af85f88abcf6082030757a0c3107d12619ea4c6a49b37a5105d9864d9cdf39f4b5342b4495f2bec88866953221363c8d2eff204d1e7c89ca94c74ce433e10c858980929c4d32dab4afb54528f7ffa490888beb25c9b5b79cb6aaee30f6d75d229df1a933825e9f0436322cb07b14e13b32cb2123afad0c57f10d9123e6ebb96c306182af8e20b198623870d3070b0103af8d08bc9e8c78fa1c394f6d059fca4d7b13299f41c3d34fe22f28e92e961b3a311a8586d62a171f53c38344aa594b5b8797cb437f411652f54de0d5d5226f47a38912f5bdb863e89f777102236343967ff18ccb3865633e8d4f1115743937a65adf78376ad681aea2dd9cc574143675ae73728dd3f2a7c86ce43fca493d2dc94ac19da3fb1c8f9dd4b8ecad0c4aa4c59e4e77e56c9d05feecf5f95a66243c6d06895f293e661bd11435725d4d367e4853086a1fd9e4d0b3a676e070ced5a9edd3ce1acd32ff43def6ac1f36fa4ce0b5d503a7468c489d1ef42273c7e107fd14b698c0b5d58d52f113d6773a55b68849e121f84bc14455a68de435eadf495cc4d161ad74af5d5ce1216da8d9daf4cc99d7db942a374354cd26ab1648566c564d0d26a393f57a10fa9543f930815faeb8e1cb7cb29f42659363735e9ca4129b41d2f7f258498b9228942bf95412fc6ed985447a0d0f5e75441a518794297b3e6b0de57cf7b112734315cd0129fbd4c4a4de84b9abca4d14592d033a133b50e7d5ab484ce7479a86ab21c4f47094d8ac194a78e49c2394533eb383148e8cf34e94e9a2e6e9a23f49ab4c78c65ecfb6e84f6c4a9f5886c25522e429b8292112d9e2445970897c7e8103a55213773b29461a342e8f537e83cad06a14b32637f63a6be100284ae5d2d5426a13a8e7ed0c8b4ec314643c4e5013e60c3d98bc6238809274c5e24f1a28dbd78bae2f387c57217bdc5bcde2985d07f5aeaa2d94c15532969ece673e1588861cdc4c745a7794314af144b2ce8168caa36e939638b4672498f542ddaa4b5e8fa534c91b777c6a4451b82d857edcc2cfa52299bb81097459ff3e9eccf792c7a53d58fcf9e9fc9028b4e4fe8043d231ac4fb8a2efbf37a75d415cde7383ae58c395b9cd88a5ee3e282d21e25871059d186eaa44b3dc455f42931bb9ea89b3215aaa29764ba7bc35e8898948a3e56e9bb48eb714b42852922ba4698a4537459219b9e544c29c8149dd0efa9fc3c26eaa5e833663fcd965974f290a209ea11729a89857546d19f5039490aadb8611145fb1d266e08fdcdb084a24f2dd9a3c498fd3c281ac9417a5229b95b873fd15cd64f35e51274664f341eb45f0e3acce9ec76a29314c2e9382e271a99648c2b266a2ad24df42733a66691f3d0441f2e266759af66089e4726fa9271f2ebc9ea38f13c30d16e9c109ade6f3185e771894676aac8579954553b0f4b742dc983c71829e2b3f3a844bb21879e1833ade2751e9468c207f98a381f3159e731897e56ad43b84ec863320f499054ec8c60f948f4715939a80c41651741a2bddc2165a497cbe811ed064bdd396eae70398e68fce46ecfa634a21fd34ead2366449f9594e558991ca65d44733aaa755663734715d1868aa4b36a229a5c563a4c9209320711ad46d2a6c287e8b407f90cf39752140dd1a508f9cae26785e8628730a7afa76e9e11a24d1d777450e141f45a9a7d833e11d108a2494ae6fc212706110d449365467578d63fd300d1a59c21b7577eca92b23fb41f938ae1dd7da2e3873e430ab7ae704a58521f1a217298d1f4f9f088b21c26ff670f7d7fa4f0eb6b32a6470f4d166b31ef73cdbdc9437f493d975261f29f060ffd259967920aab9ae277687264bdeaa8e356623b7491648a16f3d6a14dc233bcf9c8984d4a872e5e0ee2d363704f9a43172dc7d4a9277268945cc9109ae211873ea745f3ee6b6bad3ae00187467789a4b429d9e30d9de81de591523e74aa66acdd9041031b345e06376ca443bb1b9f83467143a7cf3f8b7a5ccd3d8dcba30dbd67cd243e96cc994bc6c1b0f460431f4f5406572b5da2e733e2b1862e9e4e31c605b971544e881afaa0a18476f88fbb710a419a0df0060d1961e0488f3474999548130b1e1aa5b77204531acee73b743286b82b4958d010b643df5bfa2d47de324fead048cd5fb1081dfa1c33c6d09922c339872678cc4b2a8b5c16e5d09910ba4267337dc4a1f1cfaf49c8aeee3ca60f3878d9474b6f68934e31fb6d72155a72431fe43d920a728278511b3ab9e47bb2539c9c870d5dc84105a92574be75d6d07748c9c7cbfcaf3a6ae8744ccd1d29a9cc6bd2d06f92cd312e54bc67d0d05f9297ff3a3f432b3a554a10ca837ad80cbd57e6cbb7e71c2e2e439f548946497235474b86ce42afb7a7ac12441c43f332b9b5b455ceaa18fa2473feb95be495178656348e464af2638207867ef264bfae9093bafb2ff47b9a6243ddf7429fa32d284d417252a9ef429f25f424d520e2921217baf45466fe27b485c6c7f73f3f89e8318fb4d05faac50b09ca429769e2f35b21fe3c58e86362e5d1d89784d6afd0e7afb8da6542a8ceadd0e614497d3628a11fae4217ddb3c598227575a542ef1673e95b0e6234640a4d1093b3c5d0ba321e92426329fbef767ec8d150149aa0f73769f66096495068bbe464879427c9f5099d68057da132f5d377422be2928f3c0922b36f429f2fe68ca8ec29a61013faaed2a41e2e6a3c9925b41ada6e41e91f1f192574b9bdf212b2060d79127a491e496ff89c6773243466422def856a69ca11faee9261c3c94668dee449ae32a153bc45e83ac40c95357688d07e901f494ed210babc3962b1db22742134b9a327d3d8fb9512842e589748906d41e607429b59c47886d0c70f1a131276fbb3668ae6c3076d7f8b9c9fa03a737ad107b11ff1a285178dfb27ad49bca98a6517ed958e1b5ad1459342e9c66a7ac879ce453f22be8ce5e839678b8b4e88df581d7c5c77bd451ba39ad24d5f91576dd1ec6f9796d0e9d9d35a743116f329a564ec10a145ef39a394c81fa25c328bc6f547ce07dd5c7acaa28f6eea331b5673d2c5a24b593577305f73cfc1a2dd88ed2eeebda22f6516a21eca343357f41652546fe96c5a54a6159d9c14c48649195670e6f99318effd01ab68732c1d2cdc224790fb0354d1990c539931a74a62f707a4a28f92424cb1fdac53f707a0e2dfedff3ce59ea2b37c216a9bd09d3c314513f63dafeffc259d2b45132c83282573e9133252b4f3713d629697d0b15134275a6d99156370cb45d155d0ed196e796d9687a24932987ffba924c17250b471ad4f7370d3f7ca3fd19a30ef129adf23f99e6844b0e0bdd5d954893ad1fbe53cd22d7b773f9ce863e8a6e8e8d944f31a553b538ac5b0d1449723f39ccb06953f134dea28a737cec9741d13fdb5090fea29e512cdc6a0925cb158a28f3163d01b633413da4af41934537f92b58e5b28d1a89ee89f629cd221299368b6f2abeb762c9191228936a7902de73a34246589441b416cca5787f03f0b24ba903fb6860a4a744e7a447feef9e3458a1031724497637979885123ba1262763ce5f0233f8c685b74be389fd593ec8b683d72e9b831a9cca828a2df8f3163e8c8c8cc26a29113b6f24714114d6ad1abf029e1427288ae63705352548e7cd0105d070d9a563af5ba85e8c45f5299fe9c8284107d901ed364549fb8dd207aaf6caa1564f3bf268836e91043e64b20da089a8297ae18106cac0abbd9f47f68e3f829615a547eebfdd07f4815fe53b0f826ea4317aaa19255c7e4dcf0a14bb1171355376aef7be8a34c3ccd12d743573969d333394af03c0fbdc8ab247d49c76d0b1e7acb792e6386efd07ac849e9fb7afe8aedd0e7f2f6ea54ebd05eaad826644e8a13a143bbd1d523f6c94b139943ef671d3f46d6711fe5d08c5ccfdc79c9217471e8132847812c0ae4d54180bc9252658a0420505ff07e611f27078e1adc284000726028a08000e0b8f1a706c8c68d301280011c34c2700504e0120008002f400300c081c37c410001780e475f1420009ec3918d1b5f1c0000037040026c84216306c773e090216301000840030e10468d34208d1c60a0e10c9d4a99e9a99497b67ccd58631bd04038ccd0c64bcc29e24b92bea3196b0c460d6a600e1ad0b0408c32a00c04c420430ec2386348400c311c20461890468e1b0988010619321010e30b7ebeea93bb09a3c6f1429b3d65080d41458839ea426b9aa49b182dbdc1f335bec66a0c2e74e65741247929861885716a7c0dadf135488c2d74a9cc73bf5b3a63f9ac066732503114c4d0428ec751e36b182046167ab14c918d1a58e84fe8bb24eb8939fc6b031aa8063264141bd04035c82b242086155af91475e45f4355536054a19f1c2905f9f65c8fe20d2af4e71a835e48625584347280310387cb905172241a3370901c34a081386840230718346a6064dc7830688451c3c6d929f4a161b299e847f5102d066248a111dd419a2915c78842938466b950fae667b9185068dfd53cc709f9df70c98ff184f692251996b224f90f9dd087c52ad3b1c3735597da843e65e2e49c27c284fe35640ae51673b87e89622ca1f32c8bd865324689320d68a0152534daa25573a99fec0e1fbf911204396a78a0062746123ad3aa9cb34a67aca966200612ba546ee131f7955a0218c888418c2334218e98284ab354d713c30819a308bd7ccb6eff5a90a54c19d6831844e8a2c6a46a32fb184368a3ce9630dfed90776308a15895afc2c28f118446069d4c08112744ca9a92841840e8b2ee8a88233cbfbc951186c7f8411783c68cf11442595463f8a0d5aa58d232762e91915ef099c2e6091be573bc289cb9785cd04e6b9310825bf4ee735ff133a58f5db43986857e9796ce29a20b5248e12ad6520c2946d4d4d9d14cb9e8d34d29cdf194ee68132e3aed6ffd79b973031b1cf8e28b1bd8b871c386e1207cdca211a73dae74a5046db12dba2a293a892c393f2bf4518b7ed63b28a5e3280d19f9a0451b2ada94ca2c1726592df8984532b3562ee16a2a1fb2a83b52ba4bb02c132eb8c60939934b27166d5aa96cf59c6745660c16ed857dd9644267fe787dbca26d11a927df4cf9c5bdcce1c315bd8e79c4ccabf89339ade843a9dc301bc937bf6cc3072bda9013f534f7842841a4010d53c3c639d3553431490b97c34f3d7ca8221d3c8bfea9685e62ac763cc96b92ff4045a2214eb6c9dcf714bdc4ea8b713e870a9931459bc742ce97f4a8b60a7e94e26ccd6ecbd565e6ae6961472c5e8647b5d8f5c6cb400636c038cdc10729ec0bf2318a76638a117f919df3d50f51b4e193ac16cf79d9510e1c32c2c041b03f42d19bf691d9ec9ba2f90728907d3988899f441f9f689254cda52c5648bad787279af394db39ee56838f4e342acd3f72903d96318413ede8539da39a481adb29e163139d4e252b6f0853915fe9da87269a1833255d2a48cb29cb33d63e32d169f6a0947e8d291a1f98e82f2f7fc67c2d191afdb8446b95e2e58d680a8a25ba9233f5f8e9bea94278031f95e8439c97ac48f9826c89124d2a3f517d4ca22d4f3229a1e923c2a7201b242044f890449f72a95ef2cdc9795bd4c14724faf64f21b35450416b902e0f3e20d1a60efd17776257ac2430dc80f0f1883607cdd8a363b24dccb9830f47f49661592e7c8c184eff68441bf2ccb54ac8aa9f221f8c6833c69cc9334a346df2223a8db9c7e364ecaf9a1f8ae87745445159bb3b86dc1a3e12d18b342bcd98f31d218488c6e4dcb7745039447f12a3a7998a7e18a2bf48d94ac80e92b34a85e8d2829cfc393b64f39f107dccb0e79e7336c81c1a441f7573265d29985cddbce043109d90983926179525af29109de9606e318f9accfc00a2ff949fea9b3d7436918f3ff05529626758b8248f222757dcccf1c30f4d12aa5ce63f9bce531f3aeb90ed9c826a0b1d3ef41a83dc3cdfd9439bccf448d2ea4f39a387fe93b4b8162b8bdc3c0fcd75198440a8436569200e0703421445410c829082593ad31448202044268c45c24890a6b1283f13c040ca22b16820100683814040140885612004411086004110846118048128d8646307e92ce9f194dcc9cb010625805f5f96711d24af1096831684a7d28544e60c89c01534a059dfb18c98f0a906dc82e62c226b0088962c39a96e5360c613e94efbf0b8f1428201050a3df554fc417163ec23b925b0f4f166b7f0c78b52d113f61815ff48ddc54076d7262bc8be9f5e14fa1e0f554730ff008a7edfee44340683dd5530976046b2a6f8924306a6e62810a4189728c21b4d7420d06402245acd3e6f5553e79b8cfae86d6c518cd8e4f492989498d5152e7ea291940ae0d8f35fb03ce13c36d6a526480ec179bee14074b6fb5a0e65fe24d5f0509d3d674e57310efc44da9efaf1497979b58364c8c25e5394a545a2f47b2a6a9cf264acce374d25c07480ac94d90b67f35897b12a42d41b735858975f79afbc530ab30d1a51d4166e00c9defe14460dc6ed4cdae48d5c74a77c65e306c5b7225182cc009600990549319368519ee3306249692ca21bdda58dbe6e570e4542f4a03f40b7b138f9190cea6c06450035677c1f104027e4cf0ce7b0b4021fa0df4377f775cb50cf6a775e2ac3e82497202970ab3b96cb2eb6f594dea3fcf7de4a86eb90e7c610280fd6a8fc6fede9eba609ff17677749a18901f3a548e2111e9fa22cd080698293ada8d205fab063b1c66dd4416c8b2c2ba658e01730f7d56ac9bb2b6c293a0a356ba02d9531ccc3614b0cb814bcae51cd948d2cea5642fa98aa6998d72040e1fca06285b3e4c445cdc3c8b0a2e9c6ea66b7ccdf7f13cf6b4e44c8f0237e2dfff4f1672addc59abd1d695bbc39e3ce220d69fd65db26171208ca86ade8f21554680fc805405bc6c7697426363dd8f57c2d0a1391f3b6e251fcaef060d850a81c592b9851cebd71e73659f06fdc9ab74bd13d89a6a29a69b8c5343bbd2da4eed62dd43cfcf441c806e824b3a352ac6243844c5b7773d7321c3a4f558fd50fe18300aecd7151096c51a98319ffb43f9377d0b04f5b4b815f4e942cb98c16445382409d90191a76a07ce177fe58cdbecf17fb91a20feac5d3ba485ab299e9f66355c637cacabecb8c2c327e5e293bb58f7e12b93c146bc25467504b1e1a994a0e25a8d868833d3f5464eb7fe81f49adbe4f5554a7b2578d9b3900876121e99b89a93000ceaae75effff74092c953d2d29de3c97b435557011c6cac2645a0003ffd3c9cd43032f8a1076471f8145094031c6ea2a2187e3550e4eb22574da87db4845e79eabd2cf37d48d3201f759cdadb18806ef7a7b0ecafff306d11ff511a2d2c0190105721282a1acb05e8b6e059285d85f0057364eb110bc739d543e1380d382f7a7fbe552a96cc86a33e6afe66a78f25cad6be8683b6e12e5eb1ca4895c04e85a3c55027ae31819d28e829cdcbbc5ae227341a803ffd04d3952e5b0e51e3024e780adb386b7d9a069cc2291a9dd687100a510e75ae610f1f88905d7407ee610e2b03270b04b5b48fa7488534a46806e82060bdadc9fbe3da74698125ae6190eaad2b248a2bf7b80437bfd86af2a3e4fbec81ebd031b2d24f261bdc388ab1d7b9d0ec8dfc10dd9d90cf7a125289deb2aca54e79294db2ababeab83989a78e929725b95185cf79ec39a644bab5eea06be8fd20fd55c73f5b007dab0af0baaa20367587054200dfe600d528093b8d96c0816159056e6bcc73deea0db1a2648ced90afc756e38eba9b6e5eb64b315c232ccf25e74af085ee43c88372a7a282115565605e1a6031d7dff65673485c6753595aa631f7dde8d573ef340bd08a942d1f831f9140dab14771ffa789bc59d2b03b14dab9d8232fea041a3d031237ebecae2970b8338fe12eb84397eba038f7cf2a6573deba8bbcdb03e0ab0aa97b4012ba20dcd06ac205a9399c738d1a98ed97ff1ea8eaf77cc639b4533ca91aff47dee19fba0aa84ea7d120b33b5a6f09df3c5619220746d1347be85ed88d18d6e84957dacf0cc84754c7df275d73adb18fd2fc6d0b28b9e61254a39beea9fc2ad0d42e2a9c470ca5e7bc82c04f992a14e77e4cdf749c3223d8f8b75d6837f113a61980e0e6aa32f1a73a2b21bdebdea48179ff517619da2dd1461538abc54956996537e57366d401769678e3f5a801e73ee18e750de7a5b5b53ddc9c6a9cd86c8649bccaf05644ea56cda2731614d6e4a3ec8b3ea06fbb8b17ea3ce2d9627f6a90f315225e390a5ee47a545e65913437bbe3e45819c40726e66b7eab8bb3afac2a35eeb45c62577121b6639b19fdcef2366ee75ff0dcc710b53366437eb6da30c0c4d8704b98bc122d6ef6f64ddb3c31a7a39d41021ca35955d8c217614a7283959c27f873d521a7d7bc51bdb6135add6149a9d06481fd585684c989e5a97804154be7d6b3ab32199ee83473dd5a62c9df9e02f42b7a0b83037b753125be10c37adf1669bdb68231bdad0c68e808ac9bf9fd999c8291729f1ef6ad88b31b45d3a78792fe2b7017b7130153202c22056ded93417a95c2ec0880c4fd107e27890cd8c284fb6273bad3f259f5be61cbfd6d729a6e376f8e50edef92a392c40dc7dd8ae63b24165d02f95e999295e99266912966b56a0f3c1e7fa935922d9207c722844178147fd27c207864c5af95efb349910121c04e437205b1124e14bbee51e83e1d33262abc61f9327ec2639769750aa328027e0b3fb75f17cd3527958275b166a93aaa0128b57389831c278e80c8a5e41ca937a15f49837e0f4c47370b86276ae3df29961f7666f157f35ac9166cd5d6ba02b8d65c66ab7d2397440560aaba100884c9bb2f9ada1196648af891ddbe4d44a3779a66cd60598f2e2621cca0b6067a1ae62a27a364c871699501900a22fae20595275dbaeff8e991b23fc1fbb50ea55c521125a0ac33d113efb0f51e74f535ee45d2ee12990989ed16e7ea6f33e0c83438adbe8f92071aca6cee27427571b2ed1b8dc7157c61540e43d21ee612ae1128b7fe46e77e546850f8a4cb379b0ae738351b49a5981618d16f97023424f1daf838ae46948c25ba570280bd61208efba1fa6d247480ae6524eb2f758c81155d0dce9473424889771fd7512abab78c721e7d18d3a093fb89bc75f292bb069cbfff5d4b15860318e6202b195aac70279ac5c4cc8bbe618ea94f132c5631eacbbec60c6d614787c6790b42145cca9df41e77780e779bb8d6cb03be6b96711eb69b6bc8f426ac8ed78970e7a92a21d7734e788c0dbdd183bc237627081d32ef1ea783a0df39ffd640f1865c57f7cea4816b9a112962452ea3f41b28202e241f1a7850a8cb97191f7d05b514791d50e0812cbfe8c7ad47d028bb6d4caf71a31f16bc88406a5dc3c5e493c4315154960bba8c74904717cdf3e67d042fc9809e08673583545038cbe0145154bea412539997ee90521397c815bb0368bafedae27ada3fe0dab2cd55c4f15f525d7d683604a48f8bd304a64b979d64c13a89a374b7f9d3471e2392b69c68f97374feeaf834b109b19c2f053865bb61c4e798f895eb837d2a3008ed87c1041441a01d01e70b895db390c71018114c6a2f214924cce01d198656dea66b91bf70ee60c28a2df321083e48da59d4736a5a59a80846e6e325879676953f774f423edb58143271cd9cdd322dcb109c17213ea5f06a5072e06051015a95f418c67bf9f88d1fda3c2ff8b94d1a54e44c7704f05dca464be3d5293a24393758de3fce457e3d0361c72f19c0ff11b095cc163dab66708cfb00b624e0c6c9c26eb4e0a803106bc906a14da3d2660bbef19b2d5a986c708ba9c854270b12ee3d5b7fcfca9de61443517eac87f491da3f07a9cccc027ec2d7e4d00c252541f246a6f73dabff78f7cd5e0d5efac3f6eb0a707c4eb9c2bec00ea1f9fd4a2e7429acad4204120cb98537ba721fada5e350f4d7e4fbafc5771ec0cc0b8dd93c9d42d6958c40d93f9427c50f8d3849c7cbba3649a235e943e82dacc0a3fca5af88f0d6e75ae26caf4124ad1e015167387042bb95657f6cf6604c6d4e87044949f09e87d6db400b5d0baa80e9d9a61082748c250c092623b7a797b68a7ba27800ce4432d405b1857b9f52e0bc8404d8fa947b702a2539280ed01670628e1ffeb940c38f5ba7ec99cb14279e8e66686fbb29f430bd3aede9daa6811814e89baa9100ea5c2389a51ac61c1c8936f256b4f1b1dd722226c5c9c4443eaca7ab6113204f177213ab47a0d07b2ee7e6e0d42", - "0x3a65787472696e7369635f696e646578": "0x00000000", - "0x3db7a24cfdc9de785974746c14a99df94e7b9012096b41c4eb3aaf947f6ea429": "0x0400", - "0x3f1467a096bcd71a5b6a0c8155e20810308ce9615de0775a82f8a94dc3d285a1": "0x01", - "0x3f1467a096bcd71a5b6a0c8155e208103f2edf3bdf381debe331ab7446addfdc": "0x000064a7b3b6e00d0000000000000000", - "0x3f1467a096bcd71a5b6a0c8155e208104e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0x57f8dc2f5ab09467896f47300f0424384e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0x57f8dc2f5ab09467896f47300f0424385e0621c4869aa60c02be9adcc98a0d1d": "0x08d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48", - "0x5c0d1176a568c1f92944340dbfed9e9c4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0x5c0d1176a568c1f92944340dbfed9e9c530ebca703c85910e7164cb7d1c9e47b": "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d", - "0x5f9cc45b7a00c5899361e1c6099678dc4e7b9012096b41c4eb3aaf947f6ea429": "0x0500", - "0x5f9cc45b7a00c5899361e1c6099678dc5e0621c4869aa60c02be9adcc98a0d1d": "0x0888dc3417d5058ec4b4503e0c12ea1a0a89be200fe98922423d4334014fa6b0ee0100000000000000d17c2d7823ebf260fd138f2d7e27d114c0145d968b5ff5006125f2414fadae690100000000000000", - "0x5f9cc45b7a00c5899361e1c6099678dc8a2d09463effcc78a22d75b9cb87dffc": "0x0000000000000000", - "0x5f9cc45b7a00c5899361e1c6099678dcd47cb8f5328af743ddfb361e7180e7fcbb1bdbcacd6ac9340000000000000000": "0x00000000", - "0x658faa385070e074c85bf6b568cf055506d22dc781f44e506e51707fab5eea4d0300": "0xff7f", - "0x658faa385070e074c85bf6b568cf05550e30450fc4d507a846032a7fa65d9a430000": "0x01", - "0x658faa385070e074c85bf6b568cf05550e30450fc4d507a846032a7fa65d9a430300": "0x01", - "0x658faa385070e074c85bf6b568cf05552fd68e6f37598f679d0698930b5bbb470300": "0x0000", - "0x658faa385070e074c85bf6b568cf05554e7b9012096b41c4eb3aaf947f6ea429": "0x0600", - "0x658faa385070e074c85bf6b568cf05554efd2c1e9753037696296e2bfa4460950300": "0x0000000000000000", - "0x658faa385070e074c85bf6b568cf055557c875e4cff74148e4628f264b974c80": "0x0000000000000000", - "0x658faa385070e074c85bf6b568cf05555cd1c97edf92be296fb8ae73ee8611260000": "0x0000", - "0x658faa385070e074c85bf6b568cf05555cd1c97edf92be296fb8ae73ee8611260300": "0x0004", - "0x658faa385070e074c85bf6b568cf05555f3bb7bcd0a076a48abf8c256d221721": "0x0200", - "0x658faa385070e074c85bf6b568cf055564b6168414916325e7cb4f3f47691e110300": "0x0000", - "0x658faa385070e074c85bf6b568cf05556dcf6d297802ab84a1c68cb9453399920300": "0x0000", - "0x658faa385070e074c85bf6b568cf0555741b883d2519eed91857993bfd4df0ba0000": "0x4000", - "0x658faa385070e074c85bf6b568cf05557641384bb339f3758acddfd7053d33170000": "0x6400", - "0x658faa385070e074c85bf6b568cf05557641384bb339f3758acddfd7053d33170300": "0x6300", - "0x658faa385070e074c85bf6b568cf05557d15dd66fbf0cbda1d3a651b5e606df20300": "0x8096980000000000", - "0x658faa385070e074c85bf6b568cf055586cea6ddbfb037714c1e679cc83298a70000": "0x0100", - "0x658faa385070e074c85bf6b568cf0555919db2fe18203eba898cee471ef192400000": "0xffff", - "0x658faa385070e074c85bf6b568cf0555919db2fe18203eba898cee471ef192400300": "0xe803", - "0x658faa385070e074c85bf6b568cf0555a1048e9d244171852dfe8db314dc68ca0000": "0x0000", - "0x658faa385070e074c85bf6b568cf0555a1048e9d244171852dfe8db314dc68ca0300": "0x0000", - "0x658faa385070e074c85bf6b568cf0555b6522cfe03433e9e101a258ee2f580ab0300": "0x0010", - "0x658faa385070e074c85bf6b568cf0555c57fc7240b4e0c444a010d7fe83ec3ec0300": "0x8813", - "0x658faa385070e074c85bf6b568cf0555d5fe74da02c7b4bbb340fb368eee3e770000": "0x01", - "0x658faa385070e074c85bf6b568cf0555fabe6b131d9fa6e6d6cacbe7586c3b8a0000": "0x4000", - "0x658faa385070e074c85bf6b568cf0555fabe6b131d9fa6e6d6cacbe7586c3b8a0300": "0x0010", - "0x658faa385070e074c85bf6b568cf0555ffabb584688c82a9b01a0527f0afd3db0300": "0x0000", - "0x7474449cca95dc5d0c00e71735a6d17d4e7b9012096b41c4eb3aaf947f6ea429": "0x0100", - "0x84b82a4594e531d95ee4af12f83baea04e7b9012096b41c4eb3aaf947f6ea429": "0x0400", - "0x84b82a4594e531d95ee4af12f83baea0ba7fb8745735dc3be2a2c61a72c39e78": "0x0c8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a4890b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d", - "0x8a493ef65ff3987a1fbc9979200ad1af4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0x8bcc11b860d2b04ed6a8e9e0075d4ba34e7b9012096b41c4eb3aaf947f6ea429": "0x0400", - "0x8bcc11b860d2b04ed6a8e9e0075d4ba3ba7fb8745735dc3be2a2c61a72c39e78": "0x0c1cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c306721211d5404bd9da88e0204360a1a9ab8b87c66c1bc2fcdd37f3c2222cc20e659a7a1628cdd93febc04a4e0646ea20e9f5f0ce097d9a05290d4a9e054df4e", - "0xb8c7f96c134ebb49eb7e77df71f098ad4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0xbd2a529379475088d3e29a918cd478724e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0xc2261276cc9d1f8598ea4b6a74b15c2f4e7b9012096b41c4eb3aaf947f6ea429": "0x0100", - "0xc2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80": "0x00dc4eb686b8e00d", - "0xca407206ec1ab726b2636c4b145ac2874e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0xd5e1a2fa16732ce6906189438c0a82c64e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0xd8f314b7f4e6b095f0f8ee4656a448254e7b9012096b41c4eb3aaf947f6ea429": "0x0100", - "0xf0c365c3cf59d671eb72da0e7a4113c44e7b9012096b41c4eb3aaf947f6ea429": "0x0000" - }, - "childrenDefault": {} - } - } -} \ No newline at end of file