From 9c6cb13b6fcb6266c0c17c3c01a9f9c76428235b Mon Sep 17 00:00:00 2001 From: hyeon Date: Tue, 30 Jul 2024 16:01:20 +0900 Subject: [PATCH 01/72] Set branch based on main --- Lib9c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib9c b/Lib9c index 570818fda..8596c6ea3 160000 --- a/Lib9c +++ b/Lib9c @@ -1 +1 @@ -Subproject commit 570818fda746f6f43bb55af8789b006b24edee7f +Subproject commit 8596c6ea3b188929e28aa58a3ca097723b6b9286 From 15976a48429d682ba1a42a095ca1e03466a06685 Mon Sep 17 00:00:00 2001 From: Yang Chun Ung Date: Thu, 25 Jul 2024 21:00:04 +0900 Subject: [PATCH 02/72] Log state execute arguments for replay --- .../Commands/ReplayCommand.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/NineChronicles.Headless.Executable/Commands/ReplayCommand.cs b/NineChronicles.Headless.Executable/Commands/ReplayCommand.cs index 1fe5c4f9a..20ceabbb1 100644 --- a/NineChronicles.Headless.Executable/Commands/ReplayCommand.cs +++ b/NineChronicles.Headless.Executable/Commands/ReplayCommand.cs @@ -433,10 +433,16 @@ public int RemoteTx( .Select(ToAction) .Cast() .ToImmutableList(); + var blockIndex = transactionResult.BlockIndex ?? 0; + var blockProtocolVersion = (int)protocolVersion; + var preEvaluationHash = HashDigest.FromString(preEvaluationHashValue); + byte[] preEvaluationHashBytes = preEvaluationHash.ToByteArray(); + int seed = ActionEvaluator.GenerateRandomSeed(preEvaluationHashBytes, transaction.Signature, 0); + _console.Out.WriteLine($"BlockIndex: {blockIndex}, BlockProtocolVersion: {blockProtocolVersion}, Miner: {miner}, PreviousState: {previousStateRootHash}, RandomSeed: {seed}, Signer: {transaction.Signer}, TxId: {transactionId}"); var actionEvaluations = EvaluateActions( - preEvaluationHash: HashDigest.FromString(preEvaluationHashValue), - blockIndex: transactionResult.BlockIndex ?? 0, - blockProtocolVersion: (int)protocolVersion, + preEvaluationHash: preEvaluationHash, + blockIndex: blockIndex, + blockProtocolVersion: blockProtocolVersion, txid: transaction.Id, previousStates: previousStates, miner: miner, From 5e85d8cf48b99ea05e3e0f46094d469f41c380e8 Mon Sep 17 00:00:00 2001 From: Yang Chun Ung Date: Thu, 25 Jul 2024 21:00:54 +0900 Subject: [PATCH 03/72] Add replay section --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index 53f28dea5..d302f4543 100644 --- a/README.md +++ b/README.md @@ -224,3 +224,16 @@ Actions in 0 transactions for block #1 pre-evaluation hash: 10d93de7... evaluate [NetMQTransport] Broadcasting message Libplanet.Net.Messages.BlockHeaderMessage as 0x7862DD9b....Unspecified/localhost:43210. to 0 peers [Swarm] Block broadcasting complete. ``` + +--- + +## How to replay tx with remote headless + + +When using the replay remote-tx command, you can replay the results of a specific transaction on a remote node to verify the execution result. + +The remote headless node needs to enable the `--remote-key-value-service` option and enable the grpc options to retrieve chain information. + +```shell +replay remote-tx --tx {txId(hex)} --endpoint {gqlUrl(fullState gql url)} --grpc-endpoint {grpcEndpoint(remote tx grpc url)} +``` From e5d63c3e756d9e558d6a6176dc4109f2f8358c81 Mon Sep 17 00:00:00 2001 From: Jiwon Date: Thu, 25 Jul 2024 16:13:21 +0900 Subject: [PATCH 04/72] Add txStatusFilter in ncTransactions type (#2509) --- .../GraphTypes/TransactionHeadlessQuery.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/NineChronicles.Headless/GraphTypes/TransactionHeadlessQuery.cs b/NineChronicles.Headless/GraphTypes/TransactionHeadlessQuery.cs index 3741b39bb..58447472a 100644 --- a/NineChronicles.Headless/GraphTypes/TransactionHeadlessQuery.cs +++ b/NineChronicles.Headless/GraphTypes/TransactionHeadlessQuery.cs @@ -77,7 +77,9 @@ public TransactionHeadlessQuery(StandaloneContext standaloneContext) new QueryArgument> { Name = "limit", Description = "number of block to query." }, new QueryArgument> - { Name = "actionType", Description = "filter tx by having actions' type. It is regular expression." } + { Name = "actionType", Description = "filter tx by having actions' type. It is regular expression." }, + new QueryArgument>> + { Name = "txStatusFilter", Description = "filter txStatus." } ), resolve: context => { @@ -90,6 +92,7 @@ public TransactionHeadlessQuery(StandaloneContext standaloneContext) var startingBlockIndex = context.GetArgument("startingBlockIndex"); var limit = context.GetArgument("limit"); var actionType = context.GetArgument("actionType"); + var txStatusFilter = context.GetArgument?>("txStatusFilter"); var blocks = ListBlocks(blockChain, startingBlockIndex, limit); var transactions = blocks @@ -101,6 +104,15 @@ public TransactionHeadlessQuery(StandaloneContext standaloneContext) return false; } + if (txStatusFilter is not null) + { + var txResult = TxResult(standaloneContext, tx.Id) as TxResult; + if (txResult is not null && !txStatusFilter.Contains(txResult.TxStatus)) + { + return false; + } + } + return Regex.IsMatch(typeId, actionType); })); From 29715385b02b6372b218fe14f81ba4e5d34aa1cc Mon Sep 17 00:00:00 2001 From: Jiwon Date: Fri, 26 Jul 2024 17:58:53 +0900 Subject: [PATCH 05/72] Implement account diffs type (#2511) --- .../GraphTypes/StandaloneQuery.cs | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/NineChronicles.Headless/GraphTypes/StandaloneQuery.cs b/NineChronicles.Headless/GraphTypes/StandaloneQuery.cs index 78a510371..4147da88c 100644 --- a/NineChronicles.Headless/GraphTypes/StandaloneQuery.cs +++ b/NineChronicles.Headless/GraphTypes/StandaloneQuery.cs @@ -26,6 +26,7 @@ using NineChronicles.Headless.GraphTypes.Diff; using System.Security.Cryptography; using System.Text; +using Libplanet.Store.Trie; using static NineChronicles.Headless.NCActionUtils; using Transaction = Libplanet.Types.Tx.Transaction; @@ -167,6 +168,89 @@ public StandaloneQuery(StandaloneContext standaloneContext, IConfiguration confi } ); + + Field>>>( + name: "accountDiffs", + description: "This field allows you to query the diffs based accountAddress between two blocks." + + " `baseIndex` is the reference block index, and changedIndex is the block index from which to check" + + " what changes have occurred relative to `baseIndex`." + + " Both indices must not be higher than the current block on the chain nor lower than the genesis block index (0)." + + " The difference between the two blocks must be greater than zero for a valid comparison and less than ten for performance reasons.", + arguments: new QueryArguments( + new QueryArgument> + { + Name = "baseIndex", + Description = "The index of the reference block from which the state is retrieved." + }, + new QueryArgument> + { + Name = "changedIndex", + Description = "The index of the target block for comparison." + }, + new QueryArgument> + { + Name = "accountAddress", + Description = "The target accountAddress." + } + ), + resolve: context => + { + if (!(standaloneContext.BlockChain is BlockChain blockChain)) + { + throw new ExecutionError( + $"{nameof(StandaloneContext)}.{nameof(StandaloneContext.BlockChain)} was not set yet!" + ); + } + + var baseIndex = context.GetArgument("baseIndex"); + var changedIndex = context.GetArgument("changedIndex"); + var accountAddress = context.GetArgument
("accountAddress"); + + var blockInterval = Math.Abs(changedIndex - baseIndex); + if (blockInterval >= 30 || blockInterval == 0) + { + throw new ExecutionError( + "Interval between baseIndex and changedIndex should not be greater than 30 or zero" + ); + } + + var baseBlockStateRootHash = blockChain[baseIndex].StateRootHash.ToString(); + var changedBlockStateRootHash = blockChain[changedIndex].StateRootHash.ToString(); + + var baseStateRootHash = HashDigest.FromString(baseBlockStateRootHash); + var targetStateRootHash = HashDigest.FromString( + changedBlockStateRootHash + ); + + var stateStore = standaloneContext.StateStore; + var baseTrieModel = stateStore.GetStateRoot(baseStateRootHash); + var targetTrieModel = stateStore.GetStateRoot(targetStateRootHash); + + var accountKey = new KeyBytes(ByteUtil.Hex(accountAddress.ByteArray)); + + Binary GetAccountState(ITrie model, KeyBytes key) + { + return model.Get(key) is Binary state ? state : throw new Exception($"Account state not found."); + } + + var baseAccountState = GetAccountState(baseTrieModel, accountKey); + var targetAccountState = GetAccountState(targetTrieModel, accountKey); + + var baseSubTrieModel = stateStore.GetStateRoot(new HashDigest(baseAccountState)); + var targetSubTrieModel = stateStore.GetStateRoot(new HashDigest(targetAccountState)); + + var subDiff = baseSubTrieModel + .Diff(targetSubTrieModel) + .Select(diff => new StateDiffType.Value( + Encoding.Default.GetString(diff.Path.ByteArray.ToArray()), + diff.SourceValue, + diff.TargetValue)) + .ToArray(); + + return subDiff; + } + ); + Field( name: "state", arguments: new QueryArguments( From ef47f025061dd202557b1e6b2337982d1ca3b954 Mon Sep 17 00:00:00 2001 From: hyeon Date: Tue, 6 Aug 2024 11:31:50 +0900 Subject: [PATCH 06/72] bump: Bump libplanet to 5.2.0 --- Lib9c | 2 +- Libplanet.Headless/Hosting/LibplanetNodeService.cs | 2 +- .../Commands/AccountCommandTest.cs | 2 +- .../Commands/ChainCommandTest.cs | 8 ++++---- .../Commands/ChainCommand.cs | 4 ++-- .../Commands/ReplayCommand.Privates.cs | 2 +- .../Commands/ReplayCommand.cs | 4 ++-- .../Commands/StateCommand.cs | 2 +- NineChronicles.Headless.Tests/GraphQLTestUtils.cs | 4 ++-- .../GraphTypes/TransactionHeadlessQueryTest.cs | 2 +- 10 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Lib9c b/Lib9c index 8596c6ea3..c6a1ded54 160000 --- a/Lib9c +++ b/Lib9c @@ -1 +1 @@ -Subproject commit 8596c6ea3b188929e28aa58a3ca097723b6b9286 +Subproject commit c6a1ded54424bb7916e20816f16b30f15dd6a8f0 diff --git a/Libplanet.Headless/Hosting/LibplanetNodeService.cs b/Libplanet.Headless/Hosting/LibplanetNodeService.cs index 51a85c961..f918f14a4 100644 --- a/Libplanet.Headless/Hosting/LibplanetNodeService.cs +++ b/Libplanet.Headless/Hosting/LibplanetNodeService.cs @@ -133,7 +133,7 @@ IActionEvaluator BuildActionEvaluator(IActionEvaluatorConfiguration actionEvalua actionLoader), DefaultActionEvaluatorConfiguration _ => new ActionEvaluator( - _ => blockPolicy.BlockAction, + policyActionsRegistry: blockPolicy.PolicyActionsRegistry, stateStore: StateStore, actionTypeLoader: actionLoader), ForkableActionEvaluatorConfiguration forkableActionEvaluatorConfiguration => diff --git a/NineChronicles.Headless.Executable.Tests/Commands/AccountCommandTest.cs b/NineChronicles.Headless.Executable.Tests/Commands/AccountCommandTest.cs index be3194fd1..4b47a5239 100644 --- a/NineChronicles.Headless.Executable.Tests/Commands/AccountCommandTest.cs +++ b/NineChronicles.Headless.Executable.Tests/Commands/AccountCommandTest.cs @@ -48,7 +48,7 @@ public void Balance(StoreType storeType) IStagePolicy stagePolicy = new VolatileStagePolicy(); IBlockPolicy blockPolicy = new BlockPolicySource().GetPolicy(); ActionEvaluator actionEvaluator = new ActionEvaluator( - _ => blockPolicy.BlockAction, + policyActionsRegistry: blockPolicy.PolicyActionsRegistry, stateStore, new NCActionLoader()); BlockChain chain = BlockChain.Create( diff --git a/NineChronicles.Headless.Executable.Tests/Commands/ChainCommandTest.cs b/NineChronicles.Headless.Executable.Tests/Commands/ChainCommandTest.cs index 5b9d5af5e..efb84a914 100644 --- a/NineChronicles.Headless.Executable.Tests/Commands/ChainCommandTest.cs +++ b/NineChronicles.Headless.Executable.Tests/Commands/ChainCommandTest.cs @@ -88,7 +88,7 @@ public void Inspect(StoreType storeType) IStagePolicy stagePolicy = new VolatileStagePolicy(); IBlockPolicy blockPolicy = new BlockPolicySource().GetPolicy(); ActionEvaluator actionEvaluator = new ActionEvaluator( - _ => blockPolicy.BlockAction, + policyActionsRegistry: blockPolicy.PolicyActionsRegistry, stateStore, new NCActionLoader()); Block genesisBlock = BlockChain.ProposeGenesisBlock( @@ -148,7 +148,7 @@ public void Truncate(StoreType storeType) IStagePolicy stagePolicy = new VolatileStagePolicy(); IBlockPolicy blockPolicy = new BlockPolicySource().GetPolicy(); ActionEvaluator actionEvaluator = new ActionEvaluator( - _ => blockPolicy.BlockAction, + policyActionsRegistry: blockPolicy.PolicyActionsRegistry, stateStore, new NCActionLoader()); Block genesisBlock = BlockChain.ProposeGenesisBlock( @@ -226,7 +226,7 @@ public void PruneState(StoreType storeType) IStagePolicy stagePolicy = new VolatileStagePolicy(); IBlockPolicy blockPolicy = new BlockPolicySource().GetPolicy(); ActionEvaluator actionEvaluator = new ActionEvaluator( - _ => blockPolicy.BlockAction, + policyActionsRegistry: blockPolicy.PolicyActionsRegistry, stateStore, new NCActionLoader()); BlockChain chain = BlockChain.Create( @@ -278,7 +278,7 @@ public void Snapshot(StoreType storeType) IStagePolicy stagePolicy = new VolatileStagePolicy(); IBlockPolicy blockPolicy = new BlockPolicySource().GetPolicy(); ActionEvaluator actionEvaluator = new ActionEvaluator( - _ => blockPolicy.BlockAction, + policyActionsRegistry: blockPolicy.PolicyActionsRegistry, stateStore, new NCActionLoader()); BlockChain chain = BlockChain.Create( diff --git a/NineChronicles.Headless.Executable/Commands/ChainCommand.cs b/NineChronicles.Headless.Executable/Commands/ChainCommand.cs index 643d2ca16..2c9957e88 100644 --- a/NineChronicles.Headless.Executable/Commands/ChainCommand.cs +++ b/NineChronicles.Headless.Executable/Commands/ChainCommand.cs @@ -136,7 +136,7 @@ public void Inspect( Block genesisBlock = GetBlock(store, gHash); var blockChainStates = new BlockChainStates(store, stateStore); var actionEvaluator = new ActionEvaluator( - _ => blockPolicy.BlockAction, + policyActionsRegistry: blockPolicy.PolicyActionsRegistry, stateStore, new NCActionLoader()); BlockChain chain = new BlockChain( @@ -483,7 +483,7 @@ public void Snapshot( new BlockPolicy(); var blockChainStates = new BlockChainStates(store, stateStore); var actionEvaluator = new ActionEvaluator( - _ => blockPolicy.BlockAction, + policyActionsRegistry: blockPolicy.PolicyActionsRegistry, stateStore, new NCActionLoader() ); diff --git a/NineChronicles.Headless.Executable/Commands/ReplayCommand.Privates.cs b/NineChronicles.Headless.Executable/Commands/ReplayCommand.Privates.cs index 5037b6a8a..0c7ce24a5 100644 --- a/NineChronicles.Headless.Executable/Commands/ReplayCommand.Privates.cs +++ b/NineChronicles.Headless.Executable/Commands/ReplayCommand.Privates.cs @@ -57,7 +57,7 @@ public ActionContext( public int RandomSeed { get; } - public bool BlockAction => TxId is null; + public bool IsPolicyAction => TxId is null; // NOTE: Replay does not support block actions. public IReadOnlyList Txs => ImmutableList.Empty; diff --git a/NineChronicles.Headless.Executable/Commands/ReplayCommand.cs b/NineChronicles.Headless.Executable/Commands/ReplayCommand.cs index 20ceabbb1..705b715b0 100644 --- a/NineChronicles.Headless.Executable/Commands/ReplayCommand.cs +++ b/NineChronicles.Headless.Executable/Commands/ReplayCommand.cs @@ -516,7 +516,7 @@ private static (FileStream? fs, StreamWriter? sw) GetOutputFileStream( var stateStore = new TrieStateStore(stateKeyValueStore); var blockChainStates = new BlockChainStates(store, stateStore); var actionEvaluator = new ActionEvaluator( - _ => policy.BlockAction, + policyActionsRegistry: policy.PolicyActionsRegistry, stateStore, new NCActionLoader()); return ( @@ -563,7 +563,7 @@ private ActionEvaluator GetActionEvaluator(IStateStore stateStore) var policy = new BlockPolicySource().GetPolicy(); IActionLoader actionLoader = new NCActionLoader(); return new ActionEvaluator( - _ => policy.BlockAction, + policyActionsRegistry: policy.PolicyActionsRegistry, stateStore: stateStore, actionTypeLoader: actionLoader); } diff --git a/NineChronicles.Headless.Executable/Commands/StateCommand.cs b/NineChronicles.Headless.Executable/Commands/StateCommand.cs index 1bf1877cf..7aacad53e 100644 --- a/NineChronicles.Headless.Executable/Commands/StateCommand.cs +++ b/NineChronicles.Headless.Executable/Commands/StateCommand.cs @@ -109,7 +109,7 @@ IStateStore stateStore new MemoryStore(), sStore); var actionEvaluator = new ActionEvaluator( - _ => policy.BlockAction, + policyActionsRegistry: policy.PolicyActionsRegistry, sStore, new NCActionLoader()); diff --git a/NineChronicles.Headless.Tests/GraphQLTestUtils.cs b/NineChronicles.Headless.Tests/GraphQLTestUtils.cs index fbb31bb66..314f9d802 100644 --- a/NineChronicles.Headless.Tests/GraphQLTestUtils.cs +++ b/NineChronicles.Headless.Tests/GraphQLTestUtils.cs @@ -101,7 +101,7 @@ public static StandaloneContext CreateStandaloneContext() var stateStore = new TrieStateStore(new DefaultKeyValueStore(null)); var policy = new BlockPolicy(); var actionEvaluator = new ActionEvaluator( - _ => policy.BlockAction, + policyActionsRegistry: policy.PolicyActionsRegistry, stateStore, new NCActionLoader()); var genesisBlock = BlockChain.ProposeGenesisBlock(); @@ -131,7 +131,7 @@ InitializeStates initializeStates var stateStore = new TrieStateStore(new DefaultKeyValueStore(null)); var policy = new BlockPolicy(); var actionEvaluator = new ActionEvaluator( - _ => policy.BlockAction, + policyActionsRegistry: policy.PolicyActionsRegistry, stateStore, new NCActionLoader()); var genesisBlock = BlockChain.ProposeGenesisBlock( diff --git a/NineChronicles.Headless.Tests/GraphTypes/TransactionHeadlessQueryTest.cs b/NineChronicles.Headless.Tests/GraphTypes/TransactionHeadlessQueryTest.cs index 9cb5a7c67..a4dd359dc 100644 --- a/NineChronicles.Headless.Tests/GraphTypes/TransactionHeadlessQueryTest.cs +++ b/NineChronicles.Headless.Tests/GraphTypes/TransactionHeadlessQueryTest.cs @@ -45,7 +45,7 @@ public TransactionHeadlessQueryTest() _stateStore = new TrieStateStore(new DefaultKeyValueStore(null)); IBlockPolicy policy = new BlockPolicySource().GetPolicy(); var actionEvaluator = new ActionEvaluator( - _ => policy.BlockAction, + policyActionsRegistry: policy.PolicyActionsRegistry, _stateStore, new NCActionLoader()); Block genesisBlock = BlockChain.ProposeGenesisBlock( From b2375e4461489fb171997f51da2bdbfaf6eab1c5 Mon Sep 17 00:00:00 2001 From: "Kidon (Don) Seo" Date: Tue, 30 Jul 2024 02:45:11 -0400 Subject: [PATCH 07/72] Merge pull request #2516 from moreal/bump-runtime-instrumentation Bump OpenTelemetry dependencies --- .../NineChronicles.Headless.csproj | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/NineChronicles.Headless/NineChronicles.Headless.csproj b/NineChronicles.Headless/NineChronicles.Headless.csproj index f01b9ba12..5c2a6bba5 100644 --- a/NineChronicles.Headless/NineChronicles.Headless.csproj +++ b/NineChronicles.Headless/NineChronicles.Headless.csproj @@ -50,13 +50,13 @@ - - - - - - - + + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive From 2ee19e37a42c1a17265afc4c93f1662d2d6dbec0 Mon Sep 17 00:00:00 2001 From: moreal Date: Fri, 2 Aug 2024 21:59:03 +0900 Subject: [PATCH 08/72] Remove `UserContextBuilder` --- NineChronicles.Headless/GraphQLService.cs | 1 - NineChronicles.Headless/UserContextBuilder.cs | 26 ------------------- 2 files changed, 27 deletions(-) delete mode 100644 NineChronicles.Headless/UserContextBuilder.cs diff --git a/NineChronicles.Headless/GraphQLService.cs b/NineChronicles.Headless/GraphQLService.cs index 94d4cfc45..3beadf376 100644 --- a/NineChronicles.Headless/GraphQLService.cs +++ b/NineChronicles.Headless/GraphQLService.cs @@ -181,7 +181,6 @@ public void ConfigureServices(IServiceCollection services) .AddDataLoader() .AddGraphTypes(typeof(StandaloneSchema)) .AddLibplanetExplorer() - .AddUserContextBuilder() .AddGraphQLAuthorization( options => { diff --git a/NineChronicles.Headless/UserContextBuilder.cs b/NineChronicles.Headless/UserContextBuilder.cs deleted file mode 100644 index c843bb929..000000000 --- a/NineChronicles.Headless/UserContextBuilder.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using GraphQL.Server.Transports.AspNetCore; -using Libplanet.Explorer.Interfaces; -using Microsoft.AspNetCore.Http; - -namespace NineChronicles.Headless -{ - public class UserContextBuilder : IUserContextBuilder - { - private readonly StandaloneContext _standaloneContext; - - public UserContextBuilder(StandaloneContext standaloneContext) - { - _standaloneContext = standaloneContext; - } - - public Task> BuildUserContext(HttpContext httpContext) - { - return new ValueTask>(new Dictionary - { - [nameof(IBlockChainContext.Store)] = _standaloneContext.Store, - }).AsTask(); - } - } -} From 532b7e16129390de3066b411c44d27a8cbbd0133 Mon Sep 17 00:00:00 2001 From: hyeon Date: Thu, 8 Aug 2024 17:18:50 +0900 Subject: [PATCH 09/72] Bump lib9c --- Lib9c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib9c b/Lib9c index c6a1ded54..60a3c3d5f 160000 --- a/Lib9c +++ b/Lib9c @@ -1 +1 @@ -Subproject commit c6a1ded54424bb7916e20816f16b30f15dd6a8f0 +Subproject commit 60a3c3d5fe7c02af25c969b125b4ca2b912ccdab From 242357e03de2c6b722899cfd59451c3ed01e47de Mon Sep 17 00:00:00 2001 From: hyeon Date: Fri, 9 Aug 2024 14:11:49 +0900 Subject: [PATCH 10/72] Bump lib9c: Merge grind reward --- Lib9c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib9c b/Lib9c index 60a3c3d5f..4e50fe29d 160000 --- a/Lib9c +++ b/Lib9c @@ -1 +1 @@ -Subproject commit 60a3c3d5fe7c02af25c969b125b4ca2b912ccdab +Subproject commit 4e50fe29d20fe789945a81509b2f4a86055e233e From 1919a39ba11942fc5bbf2c6b47b44232bc2c60bc Mon Sep 17 00:00:00 2001 From: eugene-hong <58686228+eugene-doobu@users.noreply.github.com> Date: Fri, 9 Aug 2024 19:03:19 +0900 Subject: [PATCH 11/72] update lib9c, change combinationslotstatetype property --- Lib9c | 2 +- .../GraphTypes/States/CombinationSlotStateType.cs | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Lib9c b/Lib9c index 4e50fe29d..d077d017f 160000 --- a/Lib9c +++ b/Lib9c @@ -1 +1 @@ -Subproject commit 4e50fe29d20fe789945a81509b2f4a86055e233e +Subproject commit d077d017ff9b56ecb4cd200912d801010bffc260 diff --git a/NineChronicles.Headless/GraphTypes/States/CombinationSlotStateType.cs b/NineChronicles.Headless/GraphTypes/States/CombinationSlotStateType.cs index dbc19948c..c83945f50 100644 --- a/NineChronicles.Headless/GraphTypes/States/CombinationSlotStateType.cs +++ b/NineChronicles.Headless/GraphTypes/States/CombinationSlotStateType.cs @@ -16,13 +16,6 @@ public CombinationSlotStateType() nameof(CombinationSlotState.UnlockBlockIndex), description: "Block index at the combination slot can be usable.", resolve: context => context.Source.UnlockBlockIndex); -#pragma warning disable CS0618 - Field>( - nameof( - CombinationSlotState.UnlockStage), - description: "Stage id at the combination slot unlock.", - resolve: context => context.Source.UnlockStage); -#pragma warning restore CS0618 Field>( nameof(CombinationSlotState.StartBlockIndex), description: "Block index at the combination started.", @@ -31,6 +24,14 @@ public CombinationSlotStateType() nameof(CombinationSlotState.PetId), description: "Pet id used in equipment", resolve: context => context.Source.PetId); + Field>( + nameof(CombinationSlotState.Index), + description: "Slot Index at the combination slot", + resolve: context => context.Source.Index); + Field>( + nameof(CombinationSlotState.IsUnlocked), + description: "Is the combination slot unlocked", + resolve: context => context.Source.IsUnlocked); } } } From b07555cfc5fdbbf5419b3d8a4465f3b9da4fd23f Mon Sep 17 00:00:00 2001 From: hyeon Date: Tue, 13 Aug 2024 11:05:28 +0900 Subject: [PATCH 12/72] Bump lib9c: merge development --- Lib9c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib9c b/Lib9c index 4e50fe29d..6d0d3f7e4 160000 --- a/Lib9c +++ b/Lib9c @@ -1 +1 @@ -Subproject commit 4e50fe29d20fe789945a81509b2f4a86055e233e +Subproject commit 6d0d3f7e4c7cbcb32b61fbcfe8e9010e9cebd002 From bd00af423533cb55d1e82a4e954f8b30e398502a Mon Sep 17 00:00:00 2001 From: hyeon Date: Mon, 19 Aug 2024 11:30:52 +0900 Subject: [PATCH 13/72] Bump lib9c: new mail type --- Lib9c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib9c b/Lib9c index 6d0d3f7e4..82dfb892c 160000 --- a/Lib9c +++ b/Lib9c @@ -1 +1 @@ -Subproject commit 6d0d3f7e4c7cbcb32b61fbcfe8e9010e9cebd002 +Subproject commit 82dfb892c343f3144a23b8e901180c394e86c3d3 From fe6d94f0ede4ffb3ef8940081d873dce14e2064f Mon Sep 17 00:00:00 2001 From: hyeon Date: Mon, 19 Aug 2024 17:38:19 +0900 Subject: [PATCH 14/72] Bump lib9c --- Lib9c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib9c b/Lib9c index 82dfb892c..fbf31331a 160000 --- a/Lib9c +++ b/Lib9c @@ -1 +1 @@ -Subproject commit 82dfb892c343f3144a23b8e901180c394e86c3d3 +Subproject commit fbf31331a009d005c827ff66fb637633045ec1f1 From a3f283a305faa7fde0de11b1e7d68a6092be651f Mon Sep 17 00:00:00 2001 From: eugene-hong <58686228+eugene-doobu@users.noreply.github.com> Date: Wed, 21 Aug 2024 18:05:28 +0900 Subject: [PATCH 15/72] update lib9c --- Lib9c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib9c b/Lib9c index fbf31331a..7d6b20db2 160000 --- a/Lib9c +++ b/Lib9c @@ -1 +1 @@ -Subproject commit fbf31331a009d005c827ff66fb637633045ec1f1 +Subproject commit 7d6b20db23cfebcb0d105ee2dba2cabd8b924a12 From a7dd5297d08d600105028ccfdf67efaed83f69ad Mon Sep 17 00:00:00 2001 From: eugene-hong <58686228+eugene-doobu@users.noreply.github.com> Date: Wed, 21 Aug 2024 18:24:40 +0900 Subject: [PATCH 16/72] migration slot state --- .../GraphTypes/States/AvatarStateType.cs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/NineChronicles.Headless/GraphTypes/States/AvatarStateType.cs b/NineChronicles.Headless/GraphTypes/States/AvatarStateType.cs index eb5211594..1c218ae46 100644 --- a/NineChronicles.Headless/GraphTypes/States/AvatarStateType.cs +++ b/NineChronicles.Headless/GraphTypes/States/AvatarStateType.cs @@ -142,19 +142,13 @@ public AvatarStateType() return runeStates.Runes.Values.ToList(); } ); - Field>>>( - nameof(AvatarState.combinationSlotAddresses), - description: "Address list of combination slot.", - resolve: context => context.Source.AvatarState.combinationSlotAddresses); Field>>>( "combinationSlots", description: "Combination slots.", resolve: context => { - var addresses = context.Source.AvatarState.combinationSlotAddresses; - return context.Source.WorldState.GetLegacyStates(addresses) - .OfType() - .Select(x => new CombinationSlotState(x)); + var allSlotState = context.Source.WorldState.GetAllCombinationSlotState(context.Source.AvatarState.address); + return allSlotState.ToList(); }); Field>( nameof(AvatarState.itemMap), From 51bc3945c5853a30b8098ab23ff744004d82bf5c Mon Sep 17 00:00:00 2001 From: hyeon Date: Wed, 21 Aug 2024 22:05:38 +0900 Subject: [PATCH 17/72] Bump lib9c --- Lib9c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib9c b/Lib9c index fbf31331a..7d6b20db2 160000 --- a/Lib9c +++ b/Lib9c @@ -1 +1 @@ -Subproject commit fbf31331a009d005c827ff66fb637633045ec1f1 +Subproject commit 7d6b20db23cfebcb0d105ee2dba2cabd8b924a12 From cad1884f1179e010eeb9d22a500d77ce7fb915e1 Mon Sep 17 00:00:00 2001 From: eugene-hong <58686228+eugene-doobu@users.noreply.github.com> Date: Thu, 22 Aug 2024 12:03:54 +0900 Subject: [PATCH 18/72] fix combination slot property --- .../GraphTypes/States/Models/AvatarStateTypeTest.cs | 6 ++++-- .../States/Models/CombinationSlotStateTypeTest.cs | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/NineChronicles.Headless.Tests/GraphTypes/States/Models/AvatarStateTypeTest.cs b/NineChronicles.Headless.Tests/GraphTypes/States/Models/AvatarStateTypeTest.cs index 6bd4125ea..c6885040c 100644 --- a/NineChronicles.Headless.Tests/GraphTypes/States/Models/AvatarStateTypeTest.cs +++ b/NineChronicles.Headless.Tests/GraphTypes/States/Models/AvatarStateTypeTest.cs @@ -60,7 +60,7 @@ public async Task QueryWithCombinationSlotState(AvatarState avatarState, Diction combinationSlots { address unlockBlockIndex - unlockStage + isUnlocked startBlockIndex petId } @@ -76,6 +76,8 @@ public async Task QueryWithCombinationSlotState(AvatarState avatarState, Diction true); world = world.SetAgentState(Fixtures.UserAddress, Fixtures.AgentStateFx); + world.GetAllCombinationSlotState(Fixtures.AvatarAddress); + for (int i = 0; i < Fixtures.AvatarStateFX.combinationSlotAddresses.Count; i++) { world = world @@ -153,7 +155,7 @@ public async Task QueryActionPoint(bool modern, Dictionary expec { ["address"] = x.address.ToString(), ["unlockBlockIndex"] = x.UnlockBlockIndex, - ["unlockStage"] = x.UnlockStage, + ["isUnlocked"] = x.IsUnlocked, ["startBlockIndex"] = x.StartBlockIndex, ["petId"] = x.PetId }).ToArray(), diff --git a/NineChronicles.Headless.Tests/GraphTypes/States/Models/CombinationSlotStateTypeTest.cs b/NineChronicles.Headless.Tests/GraphTypes/States/Models/CombinationSlotStateTypeTest.cs index db6bf6e76..3b10f3a66 100644 --- a/NineChronicles.Headless.Tests/GraphTypes/States/Models/CombinationSlotStateTypeTest.cs +++ b/NineChronicles.Headless.Tests/GraphTypes/States/Models/CombinationSlotStateTypeTest.cs @@ -18,7 +18,7 @@ public async Task Query() { address unlockBlockIndex - unlockStage + isUnlocked startBlockIndex }"; @@ -30,7 +30,7 @@ public async Task Query() { ["address"] = address.ToString(), ["unlockBlockIndex"] = 0L, - ["unlockStage"] = 1, + ["isUnlocked"] = true, ["startBlockIndex"] = 0L, }; Assert.Equal(expected, data); From 2a63565714f30b9bb5ba8860bff9e00aba70a35d Mon Sep 17 00:00:00 2001 From: eugene-hong <58686228+eugene-doobu@users.noreply.github.com> Date: Thu, 22 Aug 2024 12:47:54 +0900 Subject: [PATCH 19/72] fix get combinationslot test --- NineChronicles.Headless.Tests/Common/Fixtures.cs | 5 +---- .../GraphTypes/States/Models/AvatarStateTypeTest.cs | 13 +------------ 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/NineChronicles.Headless.Tests/Common/Fixtures.cs b/NineChronicles.Headless.Tests/Common/Fixtures.cs index 89db91e00..0d9590d51 100644 --- a/NineChronicles.Headless.Tests/Common/Fixtures.cs +++ b/NineChronicles.Headless.Tests/Common/Fixtures.cs @@ -68,10 +68,7 @@ public static ShopState ShopStateFX() } return shopState; } - - public static readonly List CombinationSlotStatesFx = - AvatarStateFX.combinationSlotAddresses.Select(x => new CombinationSlotState(x, 0)).ToList(); - + public static ShardedShopStateV2 ShardedWeapon0ShopStateV2FX() { Address shardedWeapon0ShopStateV2Address = ShardedShopStateV2.DeriveAddress(ItemSubType.Weapon, "0"); diff --git a/NineChronicles.Headless.Tests/GraphTypes/States/Models/AvatarStateTypeTest.cs b/NineChronicles.Headless.Tests/GraphTypes/States/Models/AvatarStateTypeTest.cs index c6885040c..2bda35e0f 100644 --- a/NineChronicles.Headless.Tests/GraphTypes/States/Models/AvatarStateTypeTest.cs +++ b/NineChronicles.Headless.Tests/GraphTypes/States/Models/AvatarStateTypeTest.cs @@ -75,17 +75,6 @@ public async Task QueryWithCombinationSlotState(AvatarState avatarState, Diction true, true); world = world.SetAgentState(Fixtures.UserAddress, Fixtures.AgentStateFx); - - world.GetAllCombinationSlotState(Fixtures.AvatarAddress); - - for (int i = 0; i < Fixtures.AvatarStateFX.combinationSlotAddresses.Count; i++) - { - world = world - .SetLegacyState( - Fixtures.AvatarStateFX.combinationSlotAddresses[i], - Fixtures.CombinationSlotStatesFx[i].Serialize()); - } - var queryResult = await ExecuteQueryAsync( query, source: new AvatarStateType.AvatarStateContext( @@ -151,7 +140,7 @@ public async Task QueryActionPoint(bool modern, Dictionary expec new Dictionary { ["address"] = Fixtures.AvatarAddress.ToString(), - ["combinationSlots"] = Fixtures.CombinationSlotStatesFx.Select(x => new Dictionary + ["combinationSlots"] = new World(MockWorldState.CreateModern()).GetAllCombinationSlotState(Fixtures.AvatarAddress).Select(x => new Dictionary { ["address"] = x.address.ToString(), ["unlockBlockIndex"] = x.UnlockBlockIndex, From 5fec54473fc5b8887d278fda8b66e7eefdfd2e57 Mon Sep 17 00:00:00 2001 From: hyeon Date: Thu, 22 Aug 2024 16:25:44 +0900 Subject: [PATCH 20/72] Fix lint --- NineChronicles.Headless.Tests/Common/Fixtures.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/NineChronicles.Headless.Tests/Common/Fixtures.cs b/NineChronicles.Headless.Tests/Common/Fixtures.cs index 0d9590d51..38e485719 100644 --- a/NineChronicles.Headless.Tests/Common/Fixtures.cs +++ b/NineChronicles.Headless.Tests/Common/Fixtures.cs @@ -66,9 +66,10 @@ public static ShopState ShopStateFX() var shopItem = new ShopItem(UserAddress, AvatarAddress, Guid.NewGuid(), i * CurrencyFX, equipment); shopState.Register(shopItem); } + return shopState; } - + public static ShardedShopStateV2 ShardedWeapon0ShopStateV2FX() { Address shardedWeapon0ShopStateV2Address = ShardedShopStateV2.DeriveAddress(ItemSubType.Weapon, "0"); From ee43cdb5684a2826f5d3bc96a2ff63864d7b85aa Mon Sep 17 00:00:00 2001 From: hyeon Date: Fri, 23 Aug 2024 13:36:16 +0900 Subject: [PATCH 21/72] Bump lib9c --- Lib9c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib9c b/Lib9c index 7d6b20db2..2485e8841 160000 --- a/Lib9c +++ b/Lib9c @@ -1 +1 @@ -Subproject commit 7d6b20db23cfebcb0d105ee2dba2cabd8b924a12 +Subproject commit 2485e8841863cf42abdcd17846f0c18ad7743ab5 From 446a975a964c9b910a08bc8db1e99f36ae2a59f4 Mon Sep 17 00:00:00 2001 From: eugene-hong <58686228+eugene-doobu@users.noreply.github.com> Date: Mon, 26 Aug 2024 19:18:46 +0900 Subject: [PATCH 22/72] apply changes to Lib9c --- Lib9c | 2 +- .../GraphTypes/ActionQueryTest.cs | 13 ++++++++++--- .../ActionQueryFields/RapidCombination.cs | 11 ++++++----- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/Lib9c b/Lib9c index 2485e8841..1f6b70706 160000 --- a/Lib9c +++ b/Lib9c @@ -1 +1 @@ -Subproject commit 2485e8841863cf42abdcd17846f0c18ad7743ab5 +Subproject commit 1f6b707061b6158bff5a0cb11e3e9138022701d2 diff --git a/NineChronicles.Headless.Tests/GraphTypes/ActionQueryTest.cs b/NineChronicles.Headless.Tests/GraphTypes/ActionQueryTest.cs index 1ab0f3719..8275ec4d2 100644 --- a/NineChronicles.Headless.Tests/GraphTypes/ActionQueryTest.cs +++ b/NineChronicles.Headless.Tests/GraphTypes/ActionQueryTest.cs @@ -955,9 +955,16 @@ public async Task ItemEnhancement() public async Task RapidCombination() { var avatarAddress = new PrivateKey().Address; - var slotIndex = 0; + var slotIndexList = new List { 0 }; + + var slotIndexQuery = new StringBuilder("["); + foreach (var slotIndex in slotIndexList) + { + slotIndexQuery.Append($" {slotIndex}"); + } + slotIndexQuery.Append("]"); - var query = $"{{rapidCombination(avatarAddress: \"{avatarAddress}\", slotIndex: {slotIndex})}}"; + var query = $"{{rapidCombination(avatarAddress: \"{avatarAddress}\", slotIndexList: {slotIndexQuery})}}"; var queryResult = await ExecuteQueryAsync(query, standaloneContext: _standaloneContext); Assert.Null(queryResult.Errors); @@ -967,7 +974,7 @@ public async Task RapidCombination() var actionBase = DeserializeNCAction(plainValue); var action = Assert.IsType(actionBase); Assert.Equal(avatarAddress, action.avatarAddress); - Assert.Equal(slotIndex, action.slotIndex); + Assert.Equal(slotIndexList, action.slotIndexList); } [Fact] diff --git a/NineChronicles.Headless/GraphTypes/ActionQueryFields/RapidCombination.cs b/NineChronicles.Headless/GraphTypes/ActionQueryFields/RapidCombination.cs index 4a4742c8c..37dc341f1 100644 --- a/NineChronicles.Headless/GraphTypes/ActionQueryFields/RapidCombination.cs +++ b/NineChronicles.Headless/GraphTypes/ActionQueryFields/RapidCombination.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using GraphQL; using GraphQL.Types; using Libplanet.Crypto; @@ -18,20 +19,20 @@ private void RegisterRapidCombination() Name = "avatarAddress", Description = "Avatar address to execute rapid combination" }, - new QueryArgument> + new QueryArgument>> { - Name = "slotIndex", - Description = "Slot index to execute rapid" + Name = "slotIndexList", + Description = "Slot index list to execute rapid" } ), resolve: context => { var avatarAddress = context.GetArgument
("avatarAddress"); - var slotIndex = context.GetArgument("slotIndex"); + var slotIndexList = context.GetArgument>("slotIndexList"); ActionBase action = new RapidCombination { avatarAddress = avatarAddress, - slotIndex = slotIndex + slotIndexList = slotIndexList }; return Encode(context, action); }); From c8e5a704fde046914cd7a796d2a433db39c37f3d Mon Sep 17 00:00:00 2001 From: moreal Date: Wed, 28 Aug 2024 06:20:51 +0900 Subject: [PATCH 23/72] Bump `actions/*` GitHub Actions --- .github/workflows/build.yml | 4 ++-- .github/workflows/deploy_gh_pages.yaml | 8 ++++---- .github/workflows/deploy_ghpackages_docker.yml | 2 +- .github/workflows/lint.yml | 8 ++++---- .github/workflows/push_docker_image.yml | 2 +- .github/workflows/release.yaml | 2 +- .github/workflows/validate-github-actions-workflows.yaml | 2 +- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f0501a4f9..55e3613ae 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,11 +15,11 @@ jobs: - DevEx runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: recursive - name: Setup .NET Core - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: dotnet-version: 6.0.x - name: Install dependencies diff --git a/.github/workflows/deploy_gh_pages.yaml b/.github/workflows/deploy_gh_pages.yaml index 2212312e7..39789996e 100644 --- a/.github/workflows/deploy_gh_pages.yaml +++ b/.github/workflows/deploy_gh_pages.yaml @@ -8,19 +8,19 @@ jobs: runs-on: ubuntu-20.04 steps: - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: recursive - name: Set up Node.js - uses: actions/setup-node@v2 + uses: actions/setup-node@v4 with: node-version: '18' - - uses: actions/setup-dotnet@v3 + - uses: actions/setup-dotnet@v4 name: Set up .NET Core SDK with: dotnet-version: 6.0.x - name: Cache node modules - uses: actions/cache@v2 + uses: actions/cache@v4 env: cache-name: cache-node-modules with: diff --git a/.github/workflows/deploy_ghpackages_docker.yml b/.github/workflows/deploy_ghpackages_docker.yml index de654867a..65ec12ab0 100644 --- a/.github/workflows/deploy_ghpackages_docker.yml +++ b/.github/workflows/deploy_ghpackages_docker.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: recursive - name: Build the Docker image diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index febc22ff3..2a4f80500 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -6,9 +6,9 @@ jobs: format: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup .NET Core - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: dotnet-version: 6.0.x - name: dotnet format @@ -16,7 +16,7 @@ jobs: validate-appsettings-json: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install ajv-cli run: yarn global add ajv-cli - name: Validate appsettings.*.json @@ -31,6 +31,6 @@ jobs: typos: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Check typos uses: crate-ci/typos@v1.15.5 diff --git a/.github/workflows/push_docker_image.yml b/.github/workflows/push_docker_image.yml index d603c9d2b..90bde4c02 100644 --- a/.github/workflows/push_docker_image.yml +++ b/.github/workflows/push_docker_image.yml @@ -35,7 +35,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: recursive - name: login diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 097bb1501..4bc345fd0 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -15,7 +15,7 @@ jobs: submodules: true - name: Git Sumbodule Update run: git submodule update --init --recursive - - uses: actions/setup-dotnet@v3 + - uses: actions/setup-dotnet@v4 with: dotnet-version: 6.0.x - run: .github/bin/dist-pack.sh diff --git a/.github/workflows/validate-github-actions-workflows.yaml b/.github/workflows/validate-github-actions-workflows.yaml index 9bbc00379..e157a773a 100644 --- a/.github/workflows/validate-github-actions-workflows.yaml +++ b/.github/workflows/validate-github-actions-workflows.yaml @@ -12,7 +12,7 @@ jobs: validate-github-actions-workflows: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - run: | bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash) ./actionlint From 0a490552d676fecb510fec8774e58d13db929620 Mon Sep 17 00:00:00 2001 From: Jiwon Date: Wed, 28 Aug 2024 19:58:56 +0900 Subject: [PATCH 24/72] Introduce Headless.Executor (#2553) * headless executor init * Init ninechronicles headless executor * Download template files from s3 * fix lint * Add license and readme * Update error message Co-authored-by: Lee Dogeon * Add cocona docs command --------- Co-authored-by: Lee Dogeon --- NineChronicles.Headless.Executable.sln | 20 + .../Client/GithubClient.cs | 141 ++++ .../Client/HeadlessClient.cs | 48 ++ .../Client/SettingsClient.cs | 44 ++ .../Constants/Paths.cs | 19 + .../Constants/Planet.cs | 9 + .../Constants/PlanetEndpoints.cs | 24 + .../Constants/Secret.cs | 7 + NineChronicles.Headless.Executor/LICENSE | 661 ++++++++++++++++++ .../Models/AppsettingsData.cs | 11 + .../Models/HeadlessResponses.cs | 60 ++ .../NineChronicles.Headless.Executor.csproj | 21 + .../PlanetManager.cs | 28 + NineChronicles.Headless.Executor/Program.cs | 189 +++++ NineChronicles.Headless.Executor/README.md | 81 +++ 15 files changed, 1363 insertions(+) create mode 100644 NineChronicles.Headless.Executor/Client/GithubClient.cs create mode 100644 NineChronicles.Headless.Executor/Client/HeadlessClient.cs create mode 100644 NineChronicles.Headless.Executor/Client/SettingsClient.cs create mode 100644 NineChronicles.Headless.Executor/Constants/Paths.cs create mode 100644 NineChronicles.Headless.Executor/Constants/Planet.cs create mode 100644 NineChronicles.Headless.Executor/Constants/PlanetEndpoints.cs create mode 100644 NineChronicles.Headless.Executor/Constants/Secret.cs create mode 100644 NineChronicles.Headless.Executor/LICENSE create mode 100644 NineChronicles.Headless.Executor/Models/AppsettingsData.cs create mode 100644 NineChronicles.Headless.Executor/Models/HeadlessResponses.cs create mode 100644 NineChronicles.Headless.Executor/NineChronicles.Headless.Executor.csproj create mode 100644 NineChronicles.Headless.Executor/PlanetManager.cs create mode 100644 NineChronicles.Headless.Executor/Program.cs create mode 100644 NineChronicles.Headless.Executor/README.md diff --git a/NineChronicles.Headless.Executable.sln b/NineChronicles.Headless.Executable.sln index 533888054..0ebb97b87 100644 --- a/NineChronicles.Headless.Executable.sln +++ b/NineChronicles.Headless.Executable.sln @@ -82,6 +82,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Libplanet.Mocks", "Lib9c\.L EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Libplanet.Store.Remote", "Lib9c\.Libplanet\src\Libplanet.Store.Remote\Libplanet.Store.Remote.csproj", "{D1E15F81-8765-4DCA-9299-675415686C23}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NineChronicles.Headless.Executor", "NineChronicles.Headless.Executor\NineChronicles.Headless.Executor.csproj", "{59AD477A-B23C-4E0B-AA26-A528B3BC5234}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -743,6 +745,24 @@ Global {D1E15F81-8765-4DCA-9299-675415686C23}.Release|x64.Build.0 = Release|Any CPU {D1E15F81-8765-4DCA-9299-675415686C23}.Release|x86.ActiveCfg = Release|Any CPU {D1E15F81-8765-4DCA-9299-675415686C23}.Release|x86.Build.0 = Release|Any CPU + {59AD477A-B23C-4E0B-AA26-A528B3BC5234}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {59AD477A-B23C-4E0B-AA26-A528B3BC5234}.Debug|Any CPU.Build.0 = Debug|Any CPU + {59AD477A-B23C-4E0B-AA26-A528B3BC5234}.Debug|x64.ActiveCfg = Debug|Any CPU + {59AD477A-B23C-4E0B-AA26-A528B3BC5234}.Debug|x64.Build.0 = Debug|Any CPU + {59AD477A-B23C-4E0B-AA26-A528B3BC5234}.Debug|x86.ActiveCfg = Debug|Any CPU + {59AD477A-B23C-4E0B-AA26-A528B3BC5234}.Debug|x86.Build.0 = Debug|Any CPU + {59AD477A-B23C-4E0B-AA26-A528B3BC5234}.DevEx|Any CPU.ActiveCfg = Debug|Any CPU + {59AD477A-B23C-4E0B-AA26-A528B3BC5234}.DevEx|Any CPU.Build.0 = Debug|Any CPU + {59AD477A-B23C-4E0B-AA26-A528B3BC5234}.DevEx|x64.ActiveCfg = Debug|Any CPU + {59AD477A-B23C-4E0B-AA26-A528B3BC5234}.DevEx|x64.Build.0 = Debug|Any CPU + {59AD477A-B23C-4E0B-AA26-A528B3BC5234}.DevEx|x86.ActiveCfg = Debug|Any CPU + {59AD477A-B23C-4E0B-AA26-A528B3BC5234}.DevEx|x86.Build.0 = Debug|Any CPU + {59AD477A-B23C-4E0B-AA26-A528B3BC5234}.Release|Any CPU.ActiveCfg = Release|Any CPU + {59AD477A-B23C-4E0B-AA26-A528B3BC5234}.Release|Any CPU.Build.0 = Release|Any CPU + {59AD477A-B23C-4E0B-AA26-A528B3BC5234}.Release|x64.ActiveCfg = Release|Any CPU + {59AD477A-B23C-4E0B-AA26-A528B3BC5234}.Release|x64.Build.0 = Release|Any CPU + {59AD477A-B23C-4E0B-AA26-A528B3BC5234}.Release|x86.ActiveCfg = Release|Any CPU + {59AD477A-B23C-4E0B-AA26-A528B3BC5234}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/NineChronicles.Headless.Executor/Client/GithubClient.cs b/NineChronicles.Headless.Executor/Client/GithubClient.cs new file mode 100644 index 000000000..286715862 --- /dev/null +++ b/NineChronicles.Headless.Executor/Client/GithubClient.cs @@ -0,0 +1,141 @@ +using System.IO.Compression; +using System.Runtime.InteropServices; +using System.Text.Json; +using NineChronicles.Headless.Executor.Constants; + +namespace NineChronicles.Headless.Executor.Client; + +public class GithubClient +{ + private static readonly HttpClient _client = new HttpClient(); + private static readonly string BaseDownloadUrl = + "https://github.com/planetarium/NineChronicles.Headless/releases/download/"; + private static readonly string TempDirectory = Path.Combine( + Path.GetTempPath(), + "NineChroniclesHeadless" + ); + private static readonly string GitHubReleasesApiUrl = + "https://api.github.com/repos/planetarium/NineChronicles.Headless/releases"; + + public async Task DownloadAndExtract(string version, string? os = null) + { + os ??= GetOS(); + string url = BuildDownloadUrl(version, os); + string downloadPath = await DownloadFile(url, version, os); + string extractPath = ExtractFile(downloadPath, version); + + DeleteCompressedFile(downloadPath); + + return extractPath; + } + + public async Task ListRemoteVersions(int page = 1) + { + _client.DefaultRequestHeaders.UserAgent.ParseAdd("NineChronicles.Headless"); + + string url = $"{GitHubReleasesApiUrl}?page={page}&per_page=10"; + + var response = await _client.GetAsync(url); + response.EnsureSuccessStatusCode(); + + var content = await response.Content.ReadAsStringAsync(); + var releases = JsonSerializer.Deserialize>(content); + + if (releases == null || releases.Count == 0) + { + Console.WriteLine("No remote versions found."); + return; + } + + Console.WriteLine($"Remote versions (Page {page}):"); + foreach (var release in releases) + { + Console.WriteLine(release.tag_name); + } + } + + private class GitHubRelease + { + public string tag_name { get; set; } = string.Empty; + } + + private string GetOS() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + return "win-x64"; + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + return "linux-x64"; + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + return RuntimeInformation.ProcessArchitecture == Architecture.Arm64 + ? "osx-arm64" + : "osx-x64"; + } + throw new NotSupportedException("Unsupported OS platform."); + } + + private string BuildDownloadUrl(string version, string os) + { + string fileExtension = GetFileExtension(os); + return $"{BaseDownloadUrl}{version}/NineChronicles.Headless-{os}.{fileExtension}"; + } + + private string GetFileExtension(string os) + { + return os.StartsWith("win") ? "zip" : "tar.xz"; + } + + private async Task DownloadFile(string url, string version, string os) + { + string fileName = Path.Combine( + TempDirectory, + $"NineChronicles.Headless-{version}-{os}.{GetFileExtension(os)}" + ); + Directory.CreateDirectory(TempDirectory); + + using (var response = await _client.GetAsync(url)) + { + response.EnsureSuccessStatusCode(); + await using var fs = new FileStream(fileName, FileMode.Create); + await response.Content.CopyToAsync(fs); + } + + return fileName; + } + + private string ExtractFile(string filePath, string version) + { + string extractFolder = GetExtractionPath(version); + Directory.CreateDirectory(extractFolder); + + if (filePath.EndsWith(".zip")) + { + ZipFile.ExtractToDirectory(filePath, extractFolder); + } + else if (filePath.EndsWith(".tar.xz")) + { + ExtractTarXZ(filePath, extractFolder); + } + + return extractFolder; + } + + private string GetExtractionPath(string version) + { + return Path.Combine(Paths.HeadlessPath, version); + } + + private void ExtractTarXZ(string filePath, string extractFolder) + { + string command = $"tar -xf {filePath} -C {extractFolder}"; + System.Diagnostics.Process.Start("/bin/bash", $"-c \"{command}\"").WaitForExit(); + } + + private void DeleteCompressedFile(string filePath) + { + if (File.Exists(filePath)) + { + File.Delete(filePath); + } + } +} diff --git a/NineChronicles.Headless.Executor/Client/HeadlessClient.cs b/NineChronicles.Headless.Executor/Client/HeadlessClient.cs new file mode 100644 index 000000000..cbb1f7aa0 --- /dev/null +++ b/NineChronicles.Headless.Executor/Client/HeadlessClient.cs @@ -0,0 +1,48 @@ +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using NineChronicles.Headless.Executor.Models; + +namespace NineChronicles.Headless.Executor.Client; + +public class HeadlessClient +{ + private readonly HttpClient _client = new HttpClient(); + public const string GetApvQuery = + @"{ + nodeStatus { + appProtocolVersion { + version + signer + signature + extra + } + } + }"; + + public async Task GetApvAsync(string headlessUrl) + { + var request = new GraphQLRequest { Query = GetApvQuery }; + var jsonRequest = JsonSerializer.Serialize(request); + var content = new StringContent(jsonRequest, Encoding.UTF8, "application/json"); + + using var httpRequest = new HttpRequestMessage(HttpMethod.Post, headlessUrl) + { + Content = content + }; + + var response = await _client.SendAsync(httpRequest); + response.EnsureSuccessStatusCode(); + + var jsonResponse = await response.Content.ReadAsStringAsync(); + + var graphQLResponse = JsonSerializer.Deserialize(jsonResponse); + + if (graphQLResponse == null) + { + throw new Exception("Failed to deserialize GraphQL response"); + } + + return graphQLResponse.Data.NodeStatus.AppProtocolVersion; + } +} diff --git a/NineChronicles.Headless.Executor/Client/SettingsClient.cs b/NineChronicles.Headless.Executor/Client/SettingsClient.cs new file mode 100644 index 000000000..25270627b --- /dev/null +++ b/NineChronicles.Headless.Executor/Client/SettingsClient.cs @@ -0,0 +1,44 @@ +using NineChronicles.Headless.Executor.Constants; + +namespace NineChronicles.Headless.Executor.Client; + +public class SettingsClient +{ + private readonly HttpClient _httpClient; + + public SettingsClient() + { + _httpClient = new HttpClient + { + BaseAddress = new Uri( + "http://settings.planetariumhq.com.s3-website.us-east-2.amazonaws.com/" + ) + }; + } + + public async Task DownloadTemplateAsync(Planet planet, string destinationPath) + { + string relativeUrl = $"templates/appsettings.{planet}.tpl"; + await DownloadFileAsync(relativeUrl, destinationPath); + } + + public async Task DownloadGenesisBlockAsync(string destinationPath) + { + string relativeUrl = "genesis/genesis-block-for-single"; + await DownloadFileAsync(relativeUrl, destinationPath); + } + + private async Task DownloadFileAsync(string relativeUrl, string destinationPath) + { + var response = await _httpClient.GetAsync(relativeUrl); + response.EnsureSuccessStatusCode(); + + await using var fs = new FileStream( + destinationPath, + FileMode.Create, + FileAccess.Write, + FileShare.None + ); + await response.Content.CopyToAsync(fs); + } +} diff --git a/NineChronicles.Headless.Executor/Constants/Paths.cs b/NineChronicles.Headless.Executor/Constants/Paths.cs new file mode 100644 index 000000000..4f84e593d --- /dev/null +++ b/NineChronicles.Headless.Executor/Constants/Paths.cs @@ -0,0 +1,19 @@ +namespace NineChronicles.Headless.Executor.Constants; + +public class Paths +{ + public static readonly string BasePath = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), + ".planetarium", + "headless" + ); + public static readonly string HeadlessPath = Path.Combine(BasePath, "versions"); + + public static readonly string AppsettingsPath = Path.Combine(BasePath, "appsettings"); + + public static readonly string AppsettingsTplPath = Path.Combine(BasePath, "templates"); + + public static readonly string StorePath = Path.Combine(BasePath, "store"); + + public static readonly string GenesisBlockPath = Path.Combine(BasePath, "genesis-block"); +} diff --git a/NineChronicles.Headless.Executor/Constants/Planet.cs b/NineChronicles.Headless.Executor/Constants/Planet.cs new file mode 100644 index 000000000..ef2714f0d --- /dev/null +++ b/NineChronicles.Headless.Executor/Constants/Planet.cs @@ -0,0 +1,9 @@ +namespace NineChronicles.Headless.Executor.Constants; + +public enum Planet +{ + MainnetOdin, + MainnetHeimdall, + Single, + Custom +} diff --git a/NineChronicles.Headless.Executor/Constants/PlanetEndpoints.cs b/NineChronicles.Headless.Executor/Constants/PlanetEndpoints.cs new file mode 100644 index 000000000..19bd9cfe5 --- /dev/null +++ b/NineChronicles.Headless.Executor/Constants/PlanetEndpoints.cs @@ -0,0 +1,24 @@ +namespace NineChronicles.Headless.Executor.Constants; + +public static class PlanetEndpoints +{ + public static readonly IReadOnlyDictionary GraphQLEndpoints = new Dictionary< + Planet, + string + > + { + { Planet.MainnetOdin, "https://9c-main-rpc-1.nine-chronicles.com/graphql" }, + { Planet.MainnetHeimdall, "https://heimdall-rpc-1.nine-chronicles.com/graphql" } + }; + + public static string GetGraphQLEndpoint(Planet planet) + { + if (GraphQLEndpoints.TryGetValue(planet, out string endpoint)) + { + return endpoint; + } + throw new Exception( + $"GraphQL endpoint not defined for planet: {planet}. Please ensure the planet is correctly mapped in {nameof(GraphQLEndpoints)}." + ); + } +} diff --git a/NineChronicles.Headless.Executor/Constants/Secret.cs b/NineChronicles.Headless.Executor/Constants/Secret.cs new file mode 100644 index 000000000..f5c6e79e3 --- /dev/null +++ b/NineChronicles.Headless.Executor/Constants/Secret.cs @@ -0,0 +1,7 @@ +namespace NineChronicles.Headless.Executor.Constants; + +public class Secret +{ + public static readonly string PrivateKeyForSingleNode = + "9fe5f7c309495d284ca36b948fdeca0e65b21a019e2f8a03efd849df88fab102"; +} diff --git a/NineChronicles.Headless.Executor/LICENSE b/NineChronicles.Headless.Executor/LICENSE new file mode 100644 index 000000000..6bb533977 --- /dev/null +++ b/NineChronicles.Headless.Executor/LICENSE @@ -0,0 +1,661 @@ +GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + +Copyright (C) 2007 Free Software Foundation, Inc. +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. + + Preamble + +The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + +The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + +When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + +Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + +A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + +The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + +An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + +The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + +0. Definitions. + +"This License" refers to version 3 of the GNU Affero General Public License. + +"Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + +"The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + +To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + +A "covered work" means either the unmodified Program or a work based +on the Program. + +To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + +To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + +An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + +1. Source Code. + +The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + +A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + +The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + +The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + +The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + +The Corresponding Source for a work in source code form is that +same work. + +2. Basic Permissions. + +All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + +You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + +Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + +3. Protecting Users' Legal Rights From Anti-Circumvention Law. + +No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + +When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + +4. Conveying Verbatim Copies. + +You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + +You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + +5. Conveying Modified Source Versions. + +You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + +a) The work must carry prominent notices stating that you modified +it, and giving a relevant date. + +b) The work must carry prominent notices stating that it is +released under this License and any conditions added under section +7. This requirement modifies the requirement in section 4 to +"keep intact all notices". + +c) You must license the entire work, as a whole, under this +License to anyone who comes into possession of a copy. This +License will therefore apply, along with any applicable section 7 +additional terms, to the whole of the work, and all its parts, +regardless of how they are packaged. This License gives no +permission to license the work in any other way, but it does not +invalidate such permission if you have separately received it. + +d) If the work has interactive user interfaces, each must display +Appropriate Legal Notices; however, if the Program has interactive +interfaces that do not display Appropriate Legal Notices, your +work need not make them do so. + +A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + +6. Conveying Non-Source Forms. + +You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + +a) Convey the object code in, or embodied in, a physical product +(including a physical distribution medium), accompanied by the +Corresponding Source fixed on a durable physical medium +customarily used for software interchange. + +b) Convey the object code in, or embodied in, a physical product +(including a physical distribution medium), accompanied by a +written offer, valid for at least three years and valid for as +long as you offer spare parts or customer support for that product +model, to give anyone who possesses the object code either (1) a +copy of the Corresponding Source for all the software in the +product that is covered by this License, on a durable physical +medium customarily used for software interchange, for a price no +more than your reasonable cost of physically performing this +conveying of source, or (2) access to copy the +Corresponding Source from a network server at no charge. + +c) Convey individual copies of the object code with a copy of the +written offer to provide the Corresponding Source. This +alternative is allowed only occasionally and noncommercially, and +only if you received the object code with such an offer, in accord +with subsection 6b. + +d) Convey the object code by offering access from a designated +place (gratis or for a charge), and offer equivalent access to the +Corresponding Source in the same way through the same place at no +further charge. You need not require recipients to copy the +Corresponding Source along with the object code. If the place to +copy the object code is a network server, the Corresponding Source +may be on a different server (operated by you or a third party) +that supports equivalent copying facilities, provided you maintain +clear directions next to the object code saying where to find the +Corresponding Source. Regardless of what server hosts the +Corresponding Source, you remain obligated to ensure that it is +available for as long as needed to satisfy these requirements. + +e) Convey the object code using peer-to-peer transmission, provided +you inform other peers where the object code and Corresponding +Source of the work are being offered to the general public at no +charge under subsection 6d. + +A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + +A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + +"Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + +If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + +The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + +Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + +7. Additional Terms. + +"Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + +When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + +Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + +a) Disclaiming warranty or limiting liability differently from the +terms of sections 15 and 16 of this License; or + +b) Requiring preservation of specified reasonable legal notices or +author attributions in that material or in the Appropriate Legal +Notices displayed by works containing it; or + +c) Prohibiting misrepresentation of the origin of that material, or +requiring that modified versions of such material be marked in +reasonable ways as different from the original version; or + +d) Limiting the use for publicity purposes of names of licensors or +authors of the material; or + +e) Declining to grant rights under trademark law for use of some +trade names, trademarks, or service marks; or + +f) Requiring indemnification of licensors and authors of that +material by anyone who conveys the material (or modified versions of +it) with contractual assumptions of liability to the recipient, for +any liability that these contractual assumptions directly impose on +those licensors and authors. + +All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + +If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + +Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + +8. Termination. + +You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + +However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + +Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + +Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + +9. Acceptance Not Required for Having Copies. + +You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + +10. Automatic Licensing of Downstream Recipients. + +Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + +An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + +You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + +11. Patents. + +A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + +A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + +Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + +In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + +If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + +If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + +A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + +Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + +12. No Surrender of Others' Freedom. + +If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + +13. Remote Network Interaction; Use with the GNU General Public License. + +Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + +Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + +14. Revised Versions of this License. + +The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + +If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + +Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + +15. Disclaimer of Warranty. + +THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +16. Limitation of Liability. + +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + +17. Interpretation of Sections 15 and 16. + +If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + +Copyright (C) + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published +by the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + +If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + +You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/NineChronicles.Headless.Executor/Models/AppsettingsData.cs b/NineChronicles.Headless.Executor/Models/AppsettingsData.cs new file mode 100644 index 000000000..d70409bfb --- /dev/null +++ b/NineChronicles.Headless.Executor/Models/AppsettingsData.cs @@ -0,0 +1,11 @@ +namespace NineChronicles.Headless.Executor.Models; + +public class AppSettingsData +{ + public string Apv { get; set; } + public string GenesisBlockPath { get; set; } + public string StorePath { get; set; } + public string MinerPrivateKeyString { get; set; } + public string ConsensusPrivateKeyString { get; set; } + public string ConsensusSeedPublicKey { get; set; } +} diff --git a/NineChronicles.Headless.Executor/Models/HeadlessResponses.cs b/NineChronicles.Headless.Executor/Models/HeadlessResponses.cs new file mode 100644 index 000000000..08b1f1c96 --- /dev/null +++ b/NineChronicles.Headless.Executor/Models/HeadlessResponses.cs @@ -0,0 +1,60 @@ +using System.Text; +using System.Text.Json.Serialization; + +namespace NineChronicles.Headless.Executor.Models; + +public class GraphQLRequest +{ + [JsonPropertyName("query")] + public string Query { get; set; } +} + +public class AppProtocolVersion +{ + [JsonPropertyName("version")] + public int Version { get; set; } + + [JsonPropertyName("signer")] + public string Signer { get; set; } + + [JsonPropertyName("signature")] + public string Signature { get; set; } + + [JsonPropertyName("extra")] + public string Extra { get; set; } + + public string ToToken() + { + byte[] signatureBytes = Convert.FromHexString(Signature); + string sig = Convert.ToBase64String(signatureBytes).Replace('/', '.'); + + var prefix = $"{Version}/{Signer.Remove(0, 2)}/{sig}"; + + if (Extra is not null) + { + byte[] extraBytes = Convert.FromHexString(Extra); + string extra = Convert.ToBase64String(extraBytes).Replace('/', '.'); + return $"{prefix}/{extra}"; + } + + return prefix; + } +} + +public class NodeStatus +{ + [JsonPropertyName("appProtocolVersion")] + public AppProtocolVersion AppProtocolVersion { get; set; } +} + +public class Data +{ + [JsonPropertyName("nodeStatus")] + public NodeStatus NodeStatus { get; set; } +} + +public class GraphQLResponse +{ + [JsonPropertyName("data")] + public Data Data { get; set; } +} diff --git a/NineChronicles.Headless.Executor/NineChronicles.Headless.Executor.csproj b/NineChronicles.Headless.Executor/NineChronicles.Headless.Executor.csproj new file mode 100644 index 000000000..fbd049a69 --- /dev/null +++ b/NineChronicles.Headless.Executor/NineChronicles.Headless.Executor.csproj @@ -0,0 +1,21 @@ + + + + Exe + net6.0 + enable + enable + + 0.1.0 + true + 9crun + ./nupkg + + + + + + + + + diff --git a/NineChronicles.Headless.Executor/PlanetManager.cs b/NineChronicles.Headless.Executor/PlanetManager.cs new file mode 100644 index 000000000..4774fbdda --- /dev/null +++ b/NineChronicles.Headless.Executor/PlanetManager.cs @@ -0,0 +1,28 @@ +using NineChronicles.Headless.Executor.Constants; + +namespace NineChronicles.Headless.Executor; + +public class PlanetManager +{ + public void ListLocalVersions() + { + if (!Directory.Exists(Paths.HeadlessPath)) + { + Console.WriteLine($"Headless folder not found: {Paths.HeadlessPath}"); + return; + } + + var directories = Directory.GetDirectories(Paths.HeadlessPath); + if (directories.Length == 0) + { + Console.WriteLine("No local versions found."); + return; + } + + Console.WriteLine("Installed versions:"); + foreach (var dir in directories) + { + Console.WriteLine(Path.GetFileName(dir)); + } + } +} diff --git a/NineChronicles.Headless.Executor/Program.cs b/NineChronicles.Headless.Executor/Program.cs new file mode 100644 index 000000000..27db4b8ba --- /dev/null +++ b/NineChronicles.Headless.Executor/Program.cs @@ -0,0 +1,189 @@ +using System.Diagnostics; +using Cocona; +using Cocona.Docs; +using Libplanet.Common; +using Libplanet.Crypto; +using NineChronicles.Headless.Executor.Client; +using NineChronicles.Headless.Executor.Constants; +using NineChronicles.Headless.Executor.Models; + +namespace NineChronicles.Headless.Executor; + +[HasSubCommands(typeof(DocumentCommand), "docs")] +public class Program +{ + static async Task Main(string[] args) + { + await CoconaLiteApp.RunAsync(args); + } + + [Command(Description = "Install a headless")] + public async Task Install( + [Argument(Description = "The version of NineChronicles.Headless to download")] + string version, + [Option( + Description = "The OS platform to download for (optional, will auto-detect if not provided)" + )] + string? os = null + ) + { + var client = new GithubClient(); + Console.WriteLine($"Downloading version {version} of NineChronicles Headless..."); + await client.DownloadAndExtract(version, os); + Console.WriteLine("Installation complete!"); + } + + [Command(Description = "List installed headless versions")] + public async Task Versions( + [Option(Description = "List remote versions available for download")] bool remote = false, + [Option(Description = "Page number for remote version pagination")] int page = 1 + ) + { + if (remote) + { + var client = new GithubClient(); + await client.ListRemoteVersions(page); + } + else + { + var planetManager = new PlanetManager(); + planetManager.ListLocalVersions(); + } + } + + [Command(Description = "Run Headless")] + public async Task Run(string version, Planet planet) + { + string extractedPath = Path.Combine(Paths.HeadlessPath, version); + string headlessDllPath = Path.Combine( + extractedPath, + "NineChronicles.Headless.Executable.dll" + ); + if (!File.Exists(headlessDllPath)) + { + throw new FileNotFoundException($"Headless DLL not found in path {headlessDllPath}"); + } + + var appSettingsData = new AppSettingsData(); + string storePath = Path.Combine(Paths.StorePath, version, planet.ToString()); + var settingsClient = new SettingsClient(); + + switch (planet) + { + case Planet.MainnetOdin: + case Planet.MainnetHeimdall: + var headlessClient = new HeadlessClient(); + var apv = await headlessClient.GetApvAsync( + PlanetEndpoints.GetGraphQLEndpoint(planet) + ); + + appSettingsData = new AppSettingsData + { + Apv = apv.ToToken(), + StorePath = storePath, + }; + + if (!Directory.Exists(storePath)) + { + Console.WriteLine($"Warning: Store path does not exist: {storePath}"); + Console.WriteLine( + $"It is recommended to download and extract the snapshot to {storePath} to avoid starting synchronization from block 0, which can take a long time." + ); + } + break; + + case Planet.Single: + var pkey = new PrivateKey(Secret.PrivateKeyForSingleNode); + string genesisBlockPath = Path.Combine( + Paths.GenesisBlockPath, + "genesis-block-for-single" + ); + + if (!File.Exists(genesisBlockPath)) + { + Directory.CreateDirectory(Paths.GenesisBlockPath); + await settingsClient.DownloadGenesisBlockAsync(genesisBlockPath); + } + + appSettingsData = new AppSettingsData + { + StorePath = storePath, + GenesisBlockPath = genesisBlockPath, + MinerPrivateKeyString = ByteUtil.Hex(pkey.ToByteArray()), + ConsensusPrivateKeyString = ByteUtil.Hex(pkey.ToByteArray()), + ConsensusSeedPublicKey = ByteUtil.Hex(pkey.PublicKey.Format(true)) + }; + break; + } + await CreateAppSettingsFile(planet, settingsClient, appSettingsData); + + var appsettingsPath = Path.Combine(Paths.AppsettingsPath, $"appsettings.{planet}.json"); + + var startInfo = new ProcessStartInfo + { + FileName = "dotnet", + Arguments = $"{headlessDllPath} --config {appsettingsPath}", + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true, + WorkingDirectory = extractedPath + }; + + using (var process = new Process { StartInfo = startInfo }) + { + process.OutputDataReceived += (sender, args) => + { + if (!string.IsNullOrEmpty(args.Data)) + { + Console.WriteLine(args.Data); + } + }; + + process.ErrorDataReceived += (sender, args) => + { + if (!string.IsNullOrEmpty(args.Data)) + { + Console.Error.WriteLine(args.Data); + } + }; + + process.Start(); + + process.BeginOutputReadLine(); + process.BeginErrorReadLine(); + + process.WaitForExit(); + } + } + + private async Task CreateAppSettingsFile( + Planet planet, + SettingsClient client, + AppSettingsData data + ) + { + string templatePath = Path.Combine(Paths.AppsettingsTplPath, $"appsettings.{planet}.tpl"); + + if (!File.Exists(templatePath)) + { + Directory.CreateDirectory(Paths.AppsettingsTplPath); + await client.DownloadTemplateAsync(planet, templatePath); + } + + var templateContent = File.ReadAllText(templatePath); + + templateContent = templateContent + .Replace("${Apv}", data.Apv) + .Replace("${GenesisBlockPath}", data.GenesisBlockPath) + .Replace("${StorePath}", data.StorePath) + .Replace("${MinerPrivateKeyString}", data.MinerPrivateKeyString) + .Replace("${ConsensusPrivateKeyString}", data.ConsensusPrivateKeyString) + .Replace("${ConsensusSeedPublicKey}", data.ConsensusSeedPublicKey); + + var appsettingsPath = Path.Combine(Paths.AppsettingsPath, $"appsettings.{planet}.json"); + + Directory.CreateDirectory(Paths.AppsettingsPath); + File.WriteAllText(appsettingsPath, templateContent); + } +} diff --git a/NineChronicles.Headless.Executor/README.md b/NineChronicles.Headless.Executor/README.md new file mode 100644 index 000000000..f0bff0fb0 --- /dev/null +++ b/NineChronicles.Headless.Executor/README.md @@ -0,0 +1,81 @@ +### NineChronicles.Headless.Executor + +``` +# NineChronicles.Headless.Executor + +This project provides a command-line interface (CLI) to manage and execute different versions of NineChronicles Headless nodes. You can install, list, and run the headless node for specific networks such as `MainnetOdin`, `MainnetHeimdall`, or `Single`. + +## Prerequisites + +- .NET SDK 6.0 or later +- Internet connection for downloading headless versions and necessary configuration files + +## Installation + +Clone the repository and navigate to the project folder: + +```bash +git clone +cd NineChronicles.Headless.Executor +``` + +## Build and Run + +You can build and run the project using the following commands: + +```bash +dotnet build +dotnet run -- [options] +``` + +## Commands + +### Install + +Install a specific version of NineChronicles Headless: + +```bash +dotnet run -- install [--os ] +``` + +- ``: The version of NineChronicles.Headless to download. +- `--os`: Optionally specify the OS platform (auto-detected if not provided). + +### List Versions + +List installed versions or remote versions available for download: + +```bash +dotnet run -- versions [--remote] [--page ] +``` + +- `--remote`: If provided, lists remote versions available for download. +- `--page`: Specifies the page number for pagination of remote versions. + +### Run + +Run a specific version of NineChronicles Headless on a given network: + +```bash +dotnet run -- run +``` + +- ``: The version of NineChronicles.Headless to run. +- ``: The network to run the headless node on (e.g., `MainnetOdin`, `MainnetHeimdall`, `Single`). + +The `run` command automatically downloads the necessary configuration files (e.g., templates, genesis block) if they are not already present locally. + +### Example + +To run version `v100000` of NineChronicles Headless on the `MainnetOdin` network: + +```bash +dotnet run -- run v100000 MainnetOdin +``` + +## Configuration + +The project automatically downloads the necessary configuration files, such as templates and genesis blocks, when running the headless node. These files are saved in user directories for reuse. + +- Configuration templates are stored in `~/.planetarium/headless/templates/`. +- Genesis blocks are stored in `~/.planetarium/headless/genesis-block/`. From 22338f7700bfc3f041f04dcf2ede8f7e0cb67ef0 Mon Sep 17 00:00:00 2001 From: Jiwon Date: Thu, 29 Aug 2024 14:07:54 +0900 Subject: [PATCH 25/72] Add create config script for create genesis block (#2558) --- scripts/create-config-for-single.sh | 45 +++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 scripts/create-config-for-single.sh diff --git a/scripts/create-config-for-single.sh b/scripts/create-config-for-single.sh new file mode 100644 index 000000000..9965b4202 --- /dev/null +++ b/scripts/create-config-for-single.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +read -p "Enter the private key: " privateKey +read -p "Enter the public key: " publicKey +read -p "Enter the address: " address + +cat <config.json +{ + "\$schema": "./config.schema.json", + "data": { + "tablePath": "./Lib9c/Lib9c/TableCSV" + }, + "admin": { + "activate": true, + "address": "$address", + "validUntil": 1000000 + }, + "currency": { + "initialMinter": "$privateKey", + "initialCurrencyDeposit": [ + { + "address": "$address", + "amount": 1000000, + "start": 0, + "end": 0 + } + ] + }, + "initialValidatorSet": [ + { + "publicKey": "$publicKey", + "power": 1 + } + ], + "initialMeadConfigs": [ + { + "address": "$address", + "amount": "1000000" + } + ], + "initialPledgeConfigs": [] +} +EOL + +echo "config.json has been created successfully." From 427a5b7f347410b744587536660fffa48d42d74c Mon Sep 17 00:00:00 2001 From: sonohoshi Date: Thu, 29 Aug 2024 14:38:11 +0900 Subject: [PATCH 26/72] bump lib9c --- Lib9c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib9c b/Lib9c index 2485e8841..d6c8fbb40 160000 --- a/Lib9c +++ b/Lib9c @@ -1 +1 @@ -Subproject commit 2485e8841863cf42abdcd17846f0c18ad7743ab5 +Subproject commit d6c8fbb4031a8b56dcfa55b35da322f72734c6c1 From 5a2b5db48f797509e93995ba360556ceb2788e71 Mon Sep 17 00:00:00 2001 From: sonohoshi Date: Thu, 29 Aug 2024 14:44:16 +0900 Subject: [PATCH 27/72] fix RapidCombinationActionQueryFields --- .../GraphTypes/ActionQueryFields/RapidCombination.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/NineChronicles.Headless/GraphTypes/ActionQueryFields/RapidCombination.cs b/NineChronicles.Headless/GraphTypes/ActionQueryFields/RapidCombination.cs index 4a4742c8c..5f189a648 100644 --- a/NineChronicles.Headless/GraphTypes/ActionQueryFields/RapidCombination.cs +++ b/NineChronicles.Headless/GraphTypes/ActionQueryFields/RapidCombination.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using GraphQL; using GraphQL.Types; using Libplanet.Crypto; @@ -27,11 +28,11 @@ private void RegisterRapidCombination() resolve: context => { var avatarAddress = context.GetArgument
("avatarAddress"); - var slotIndex = context.GetArgument("slotIndex"); + var slotIndex = context.GetArgument>("slotIndexList"); ActionBase action = new RapidCombination { avatarAddress = avatarAddress, - slotIndex = slotIndex + slotIndexList = slotIndex }; return Encode(context, action); }); From 617f2ffa6847e47416e41fff97e588d225800e69 Mon Sep 17 00:00:00 2001 From: sonohoshi Date: Thu, 29 Aug 2024 14:47:53 +0900 Subject: [PATCH 28/72] fix ActionQuery about rapid combination --- NineChronicles.Headless.Executable/Commands/GenesisCommand.cs | 2 +- NineChronicles.Headless.Tests/GraphTypes/ActionQueryTest.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/NineChronicles.Headless.Executable/Commands/GenesisCommand.cs b/NineChronicles.Headless.Executable/Commands/GenesisCommand.cs index 0cac71bde..cf4b68141 100644 --- a/NineChronicles.Headless.Executable/Commands/GenesisCommand.cs +++ b/NineChronicles.Headless.Executable/Commands/GenesisCommand.cs @@ -324,7 +324,7 @@ public void Mine( /// Actions to be appended on end of transaction actions. /// You can add actions code to this method before generate genesis block. /// - /// + /// List of ActionBase. private static List GetAdditionalActionBases() { return new List diff --git a/NineChronicles.Headless.Tests/GraphTypes/ActionQueryTest.cs b/NineChronicles.Headless.Tests/GraphTypes/ActionQueryTest.cs index 1ab0f3719..6af5d10b1 100644 --- a/NineChronicles.Headless.Tests/GraphTypes/ActionQueryTest.cs +++ b/NineChronicles.Headless.Tests/GraphTypes/ActionQueryTest.cs @@ -967,7 +967,7 @@ public async Task RapidCombination() var actionBase = DeserializeNCAction(plainValue); var action = Assert.IsType(actionBase); Assert.Equal(avatarAddress, action.avatarAddress); - Assert.Equal(slotIndex, action.slotIndex); + Assert.Equal(slotIndex, action.slotIndexList.First()); } [Fact] From f6848518cc36d50a027678a39d8d30d73a2325a8 Mon Sep 17 00:00:00 2001 From: sonohoshi Date: Thu, 29 Aug 2024 14:51:17 +0900 Subject: [PATCH 29/72] fix RapidCombination action query --- NineChronicles.Headless.Tests/GraphTypes/ActionQueryTest.cs | 2 +- .../GraphTypes/ActionQueryFields/RapidCombination.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/NineChronicles.Headless.Tests/GraphTypes/ActionQueryTest.cs b/NineChronicles.Headless.Tests/GraphTypes/ActionQueryTest.cs index 6af5d10b1..9f5ccc43f 100644 --- a/NineChronicles.Headless.Tests/GraphTypes/ActionQueryTest.cs +++ b/NineChronicles.Headless.Tests/GraphTypes/ActionQueryTest.cs @@ -957,7 +957,7 @@ public async Task RapidCombination() var avatarAddress = new PrivateKey().Address; var slotIndex = 0; - var query = $"{{rapidCombination(avatarAddress: \"{avatarAddress}\", slotIndex: {slotIndex})}}"; + var query = $"{{rapidCombination(avatarAddress: \"{avatarAddress}\", slotIndex: [{slotIndex}])}}"; var queryResult = await ExecuteQueryAsync(query, standaloneContext: _standaloneContext); Assert.Null(queryResult.Errors); diff --git a/NineChronicles.Headless/GraphTypes/ActionQueryFields/RapidCombination.cs b/NineChronicles.Headless/GraphTypes/ActionQueryFields/RapidCombination.cs index 5f189a648..e33cd4c5e 100644 --- a/NineChronicles.Headless/GraphTypes/ActionQueryFields/RapidCombination.cs +++ b/NineChronicles.Headless/GraphTypes/ActionQueryFields/RapidCombination.cs @@ -19,9 +19,9 @@ private void RegisterRapidCombination() Name = "avatarAddress", Description = "Avatar address to execute rapid combination" }, - new QueryArgument> + new QueryArgument>> { - Name = "slotIndex", + Name = "slotIndexList", Description = "Slot index to execute rapid" } ), From bd716e5d3c1143f2009006f0880c6a1a5e5e3e65 Mon Sep 17 00:00:00 2001 From: eugene-hong <58686228+eugene-doobu@users.noreply.github.com> Date: Thu, 29 Aug 2024 14:53:06 +0900 Subject: [PATCH 30/72] Update NineChronicles.Headless/GraphTypes/ActionQueryFields/RapidCombination.cs Co-authored-by: Lee Dogeon --- .../GraphTypes/ActionQueryFields/RapidCombination.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NineChronicles.Headless/GraphTypes/ActionQueryFields/RapidCombination.cs b/NineChronicles.Headless/GraphTypes/ActionQueryFields/RapidCombination.cs index 37dc341f1..2b8261a66 100644 --- a/NineChronicles.Headless/GraphTypes/ActionQueryFields/RapidCombination.cs +++ b/NineChronicles.Headless/GraphTypes/ActionQueryFields/RapidCombination.cs @@ -19,7 +19,7 @@ private void RegisterRapidCombination() Name = "avatarAddress", Description = "Avatar address to execute rapid combination" }, - new QueryArgument>> + new QueryArgument>>> { Name = "slotIndexList", Description = "Slot index list to execute rapid" From aa60c778a9ca57feb119d3bdf115243cf4bf2c79 Mon Sep 17 00:00:00 2001 From: hyeon Date: Thu, 29 Aug 2024 15:48:12 +0900 Subject: [PATCH 31/72] Bump lib9c: custom craft --- Lib9c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib9c b/Lib9c index 6c05b1f2d..e92330bab 160000 --- a/Lib9c +++ b/Lib9c @@ -1 +1 @@ -Subproject commit 6c05b1f2d06740de90e7ee2d8d4a2531177728c4 +Subproject commit e92330babb6683665130c1e0e97330d781b85d80 From 44a6d3f1b2f5c605df377ec397ca62608d50a1b5 Mon Sep 17 00:00:00 2001 From: hyeon Date: Thu, 29 Aug 2024 16:45:28 +0900 Subject: [PATCH 32/72] Fix lint with code formatting --- .../Commands/TxCommandTest.cs | 2 +- .../GraphTypes/ActionQueryTest.cs | 4 +- .../TransactionHeadlessQueryTest.cs | 37 ++++++++++--------- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/NineChronicles.Headless.Executable.Tests/Commands/TxCommandTest.cs b/NineChronicles.Headless.Executable.Tests/Commands/TxCommandTest.cs index 1704478f8..2c6d4a71e 100644 --- a/NineChronicles.Headless.Executable.Tests/Commands/TxCommandTest.cs +++ b/NineChronicles.Headless.Executable.Tests/Commands/TxCommandTest.cs @@ -84,7 +84,7 @@ public void Sign_Stake(bool gas) [InlineData(null, 3, false)] [InlineData(null, 4, true)] [InlineData(null, 5, false)] - public void Sign_ClaimStakeReward(long? blockIndex, int? actionVersion, bool gas) + public void Sign_ClaimStakeReward(bool gas) { var filePath = Path.Combine(Path.GetTempPath(), Path.GetTempFileName()); var actionCommand = new ActionCommand(_console); diff --git a/NineChronicles.Headless.Tests/GraphTypes/ActionQueryTest.cs b/NineChronicles.Headless.Tests/GraphTypes/ActionQueryTest.cs index f6f83a5bc..8b4b1a2e5 100644 --- a/NineChronicles.Headless.Tests/GraphTypes/ActionQueryTest.cs +++ b/NineChronicles.Headless.Tests/GraphTypes/ActionQueryTest.cs @@ -934,6 +934,7 @@ public async Task ItemEnhancement() { materialQuery.Append($" \"{materialId}\""); } + materialQuery.Append("]"); var query = $"{{itemEnhancement(avatarAddress: \"{avatarAddress}\", slotIndex: {slotIndex}, " + $"itemId: \"{itemId}\", materialIds: {materialQuery})}}"; @@ -956,12 +957,13 @@ public async Task RapidCombination() { var avatarAddress = new PrivateKey().Address; var slotIndexList = new List { 0 }; - + var slotIndexQuery = new StringBuilder("["); foreach (var slotIndex in slotIndexList) { slotIndexQuery.Append($" {slotIndex}"); } + slotIndexQuery.Append("]"); var query = $"{{rapidCombination(avatarAddress: \"{avatarAddress}\", slotIndexList: {slotIndexQuery})}}"; diff --git a/NineChronicles.Headless.Tests/GraphTypes/TransactionHeadlessQueryTest.cs b/NineChronicles.Headless.Tests/GraphTypes/TransactionHeadlessQueryTest.cs index a4dd359dc..8dcb7bd86 100644 --- a/NineChronicles.Headless.Tests/GraphTypes/TransactionHeadlessQueryTest.cs +++ b/NineChronicles.Headless.Tests/GraphTypes/TransactionHeadlessQueryTest.cs @@ -14,20 +14,20 @@ using Libplanet.Action.Sys; using Libplanet.Blockchain; using Libplanet.Blockchain.Policies; -using Libplanet.Types.Blocks; -using Libplanet.Types.Consensus; using Libplanet.Crypto; using Libplanet.Store; using Libplanet.Store.Trie; +using Libplanet.Types.Blocks; +using Libplanet.Types.Consensus; using Libplanet.Types.Tx; using Nekoyume.Action; using Nekoyume.Action.Loader; +using Nekoyume.Blockchain.Policy; using NineChronicles.Headless.GraphTypes; using NineChronicles.Headless.Tests.Common; using NineChronicles.Headless.Utils; using Xunit; using static NineChronicles.Headless.NCActionUtils; -using Nekoyume.Blockchain.Policy; namespace NineChronicles.Headless.Tests.GraphTypes { @@ -192,14 +192,14 @@ public async Task CreateUnsignedTx(long? nonce) } [Theory] - [InlineData("", "")] // Empty String + [InlineData("", "")] // Empty String [InlineData( "026d06672c8d5c63c1a81c89fec5ab7faab523fd98895492d33ac32aa94dbd7c6c", "6475373a747970655f69647532323a636f6d62696e6174696f6e5f65717569706d656e743575363a76616c756573647531333a61" + "76617461724164647265737332303a467740d542f9ad3ac49ca3cb02cc9e3c761d22b975323a696431363a497d2e326a102a499a" + "b6d5ad1c56b37875383a726563697065496475313a3175393a736c6f74496e64657875313a307531313a73756252656369706549" + "646e6565" - )] // Not encoded by base64 + )] // Not encoded by base64 public async Task CreateUnsignedTxThrowsErrorsIfIncorrectArgumentPassed(string publicKey, string plainValue) { var queryFormat = @"query {{ @@ -246,7 +246,7 @@ public async Task AttachSignature() } [Theory] - [InlineData("", "")] // Empty String + [InlineData("", "")] // Empty String [InlineData( "64313a616c65313a6733323a1fc6e506d66c8c04283309518f06f1ef21ed9329366b60380fbf3bf35668c72a313a6e693065313a" + "7036353a04338573b6979f6bafcd04bcbb299d4790370ae303053a74d7f9c5251fa8074a08206660afd47acb1a9d6873d7051513" + @@ -254,8 +254,9 @@ public async Task AttachSignature() "32312d30372d30395430363a34333a33392e3436373835355a313a756c6565", "30440220433e7ef8055d89b1e7954af8f650aa1e19e11be16a6c0e6e606484f58d827f6502204030c18376184a24bff7933bb3d2" + "60994dc2d0c1721a939ae504fde6e3d8dc71" - )] // Not encoded by base64 - public async Task AttachSignatureThrowsErrorsIfIncorrectArgumentPassed(string unsignedTransaction, string signature) + )] // Not encoded by base64 + public async Task AttachSignatureThrowsErrorsIfIncorrectArgumentPassed(string unsignedTransaction, + string signature) { var query = @$"query {{ attachSignature(unsignedTransaction: ""{unsignedTransaction}"", signature: ""{signature}"") @@ -393,8 +394,7 @@ public async Task NcTransactionsOnTip() var result = await ExecuteAsync(query); Assert.NotNull(result.Data); var ncTransactions = - (object[]) - ((Dictionary)((ExecutionNode)result.Data!).ToValue()!)["ncTransactions"]; + (object[])((Dictionary)((ExecutionNode)result.Data!).ToValue()!)["ncTransactions"]; var ncTransaction = Assert.IsType>(Assert.Single(ncTransactions)); Assert.Equal(tx.Id.ToString(), ncTransaction["id"]); } @@ -403,14 +403,15 @@ private Task ExecuteAsync(string query) { var currencyFactory = new CurrencyFactory(() => _blockChain.GetWorldState(_blockChain.Tip.Hash)); var fungibleAssetValueFactory = new FungibleAssetValueFactory(currencyFactory); - return GraphQLTestUtils.ExecuteQueryAsync(query, standaloneContext: new StandaloneContext - { - BlockChain = _blockChain, - Store = _store, - NineChroniclesNodeService = _service, - CurrencyFactory = currencyFactory, - FungibleAssetValueFactory = fungibleAssetValueFactory, - }); + return GraphQLTestUtils.ExecuteQueryAsync(query, + standaloneContext: new StandaloneContext + { + BlockChain = _blockChain, + Store = _store, + NineChroniclesNodeService = _service, + CurrencyFactory = currencyFactory, + FungibleAssetValueFactory = fungibleAssetValueFactory, + }); } private BlockCommit? GenerateBlockCommit(long height, BlockHash hash, PrivateKey validator) From 829fb4be2e361923f50397d90ae5c5a22fc2f73c Mon Sep 17 00:00:00 2001 From: hyeon Date: Thu, 29 Aug 2024 16:56:09 +0900 Subject: [PATCH 33/72] Revert wrong addition --- .../Commands/TxCommandTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NineChronicles.Headless.Executable.Tests/Commands/TxCommandTest.cs b/NineChronicles.Headless.Executable.Tests/Commands/TxCommandTest.cs index 2c6d4a71e..1704478f8 100644 --- a/NineChronicles.Headless.Executable.Tests/Commands/TxCommandTest.cs +++ b/NineChronicles.Headless.Executable.Tests/Commands/TxCommandTest.cs @@ -84,7 +84,7 @@ public void Sign_Stake(bool gas) [InlineData(null, 3, false)] [InlineData(null, 4, true)] [InlineData(null, 5, false)] - public void Sign_ClaimStakeReward(bool gas) + public void Sign_ClaimStakeReward(long? blockIndex, int? actionVersion, bool gas) { var filePath = Path.Combine(Path.GetTempPath(), Path.GetTempFileName()); var actionCommand = new ActionCommand(_console); From de69cc87dd2c2a074f17db8c4090e2fde0460288 Mon Sep 17 00:00:00 2001 From: Jiwon Date: Fri, 30 Aug 2024 13:22:39 +0900 Subject: [PATCH 34/72] Handling window path to use Replace("\\", "\\\\") (#2562) --- .../NineChronicles.Headless.Executor.csproj | 7 ++- NineChronicles.Headless.Executor/Program.cs | 56 ++++++++++++++----- 2 files changed, 48 insertions(+), 15 deletions(-) diff --git a/NineChronicles.Headless.Executor/NineChronicles.Headless.Executor.csproj b/NineChronicles.Headless.Executor/NineChronicles.Headless.Executor.csproj index fbd049a69..8a3eb9822 100644 --- a/NineChronicles.Headless.Executor/NineChronicles.Headless.Executor.csproj +++ b/NineChronicles.Headless.Executor/NineChronicles.Headless.Executor.csproj @@ -5,13 +5,16 @@ net6.0 enable enable - - 0.1.0 + 0.1.2 true 9crun ./nupkg + + + + diff --git a/NineChronicles.Headless.Executor/Program.cs b/NineChronicles.Headless.Executor/Program.cs index 27db4b8ba..7526fcaa3 100644 --- a/NineChronicles.Headless.Executor/Program.cs +++ b/NineChronicles.Headless.Executor/Program.cs @@ -1,4 +1,6 @@ using System.Diagnostics; +using System.Text.Json; +using System.Text.Json.Nodes; using Cocona; using Cocona.Docs; using Libplanet.Common; @@ -90,8 +92,8 @@ public async Task Run(string version, Planet planet) $"It is recommended to download and extract the snapshot to {storePath} to avoid starting synchronization from block 0, which can take a long time." ); } + await CreateAppSettingsFile(planet, settingsClient, appSettingsData); break; - case Planet.Single: var pkey = new PrivateKey(Secret.PrivateKeyForSingleNode); string genesisBlockPath = Path.Combine( @@ -107,15 +109,16 @@ public async Task Run(string version, Planet planet) appSettingsData = new AppSettingsData { + Apv = "1/b4179Ad0d7565A6EcFA70d2a0f727461039e0159/MEUCIQDvIIp8IKCpjKojE8LzgYZzeRg9fUPl.sWHrowzHhmrxgIgBhTkSRc8BHXZwwIAwBQN8J3wGlAbOD7FRyp8bA6OH6Y=", StorePath = storePath, GenesisBlockPath = genesisBlockPath, MinerPrivateKeyString = ByteUtil.Hex(pkey.ToByteArray()), ConsensusPrivateKeyString = ByteUtil.Hex(pkey.ToByteArray()), ConsensusSeedPublicKey = ByteUtil.Hex(pkey.PublicKey.Format(true)) }; + await CreateAppSettingsFile(planet, settingsClient, appSettingsData); break; } - await CreateAppSettingsFile(planet, settingsClient, appSettingsData); var appsettingsPath = Path.Combine(Paths.AppsettingsPath, $"appsettings.{planet}.json"); @@ -171,19 +174,46 @@ AppSettingsData data await client.DownloadTemplateAsync(planet, templatePath); } - var templateContent = File.ReadAllText(templatePath); - - templateContent = templateContent - .Replace("${Apv}", data.Apv) - .Replace("${GenesisBlockPath}", data.GenesisBlockPath) - .Replace("${StorePath}", data.StorePath) - .Replace("${MinerPrivateKeyString}", data.MinerPrivateKeyString) - .Replace("${ConsensusPrivateKeyString}", data.ConsensusPrivateKeyString) - .Replace("${ConsensusSeedPublicKey}", data.ConsensusSeedPublicKey); - var appsettingsPath = Path.Combine(Paths.AppsettingsPath, $"appsettings.{planet}.json"); + string result; + + if (!File.Exists(appsettingsPath)) + { + var templateContent = File.ReadAllText(templatePath); + if (Environment.OSVersion.Platform == PlatformID.Win32NT) + { + templateContent = templateContent + .Replace("${Apv}", data.Apv) + .Replace("${GenesisBlockPath}", data.GenesisBlockPath.Replace("\\", "\\\\")) + .Replace("${StorePath}", data.StorePath.Replace("\\", "\\\\")) + .Replace("${MinerPrivateKeyString}", data.MinerPrivateKeyString) + .Replace("${ConsensusPrivateKeyString}", data.ConsensusPrivateKeyString) + .Replace("${ConsensusSeedPublicKey}", data.ConsensusSeedPublicKey); + } + else + { + templateContent = templateContent + .Replace("${Apv}", data.Apv) + .Replace("${GenesisBlockPath}", data.GenesisBlockPath) + .Replace("${StorePath}", data.StorePath) + .Replace("${MinerPrivateKeyString}", data.MinerPrivateKeyString) + .Replace("${ConsensusPrivateKeyString}", data.ConsensusPrivateKeyString) + .Replace("${ConsensusSeedPublicKey}", data.ConsensusSeedPublicKey); + } + result = templateContent; + } + else + { + var appsettingsContent = File.ReadAllText(appsettingsPath); + var jsonDoc = JsonNode.Parse(appsettingsContent); + if (jsonDoc != null && jsonDoc["Headless"] != null) + { + jsonDoc["Headless"]["AppProtocolVersionString"] = data.Apv; + } + result = jsonDoc.ToJsonString(new JsonSerializerOptions { WriteIndented = true }); + } Directory.CreateDirectory(Paths.AppsettingsPath); - File.WriteAllText(appsettingsPath, templateContent); + File.WriteAllText(appsettingsPath, result); } } From 8c73c32a3e1fa5a9714ca7d71da09da6feddefba Mon Sep 17 00:00:00 2001 From: sky1045 Date: Mon, 22 Jul 2024 17:58:30 +0900 Subject: [PATCH 35/72] [WIP]Upgrade dotnet version from 6.0 to 8.0 --- Dockerfile | 4 ++-- Dockerfile.ACC | 4 ++-- Dockerfile.ACC.amd64 | 4 ++-- Dockerfile.ACC.arm64v8 | 4 ++-- Dockerfile.amd64 | 4 ++-- Dockerfile.arm64v8 | 4 ++-- .../NineChronicles.Headless.AccessControlCenter.csproj | 2 +- .../NineChronicles.Headless.Executable.Tests.csproj | 2 +- .../NineChronicles.Headless.Executable.csproj | 2 +- .../NineChronicles.Headless.Tests.csproj | 2 +- NineChronicles.Headless/ActionEvaluationPublisher.cs | 3 ++- NineChronicles.Headless/MemoryCacheExtensions.cs | 2 +- NineChronicles.Headless/NineChronicles.Headless.csproj | 2 +- global.json | 2 +- 14 files changed, 21 insertions(+), 20 deletions(-) diff --git a/Dockerfile b/Dockerfile index ecc69e00a..6e03a4942 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:6.0-jammy AS build-env +FROM mcr.microsoft.com/dotnet/sdk:8.0-jammy AS build-env WORKDIR /app ARG COMMIT @@ -24,7 +24,7 @@ RUN dotnet publish NineChronicles.Headless.Executable/NineChronicles.Headless.Ex --version-suffix $COMMIT # Build runtime image -FROM mcr.microsoft.com/dotnet/aspnet:6.0 +FROM mcr.microsoft.com/dotnet/aspnet:8.0 WORKDIR /app RUN apt-get update && apt-get install -y libc6-dev COPY --from=build-env /app/out . diff --git a/Dockerfile.ACC b/Dockerfile.ACC index 40861ddc3..515c74228 100644 --- a/Dockerfile.ACC +++ b/Dockerfile.ACC @@ -1,5 +1,5 @@ # Use the SDK image to build the app -FROM mcr.microsoft.com/dotnet/sdk:6.0-jammy AS build-env +FROM mcr.microsoft.com/dotnet/sdk:8.0-jammy AS build-env WORKDIR /app ARG COMMIT @@ -21,7 +21,7 @@ RUN dotnet publish NineChronicles.Headless.AccessControlCenter/NineChronicles.He --version-suffix $COMMIT # Build runtime image -FROM mcr.microsoft.com/dotnet/aspnet:6.0 +FROM mcr.microsoft.com/dotnet/aspnet:8.0 WORKDIR /app RUN apt-get update && apt-get install -y libc6-dev COPY --from=build-env /app/out . diff --git a/Dockerfile.ACC.amd64 b/Dockerfile.ACC.amd64 index eeb7814d7..6bfd21e35 100644 --- a/Dockerfile.ACC.amd64 +++ b/Dockerfile.ACC.amd64 @@ -1,5 +1,5 @@ # Use the SDK image to build the app -FROM mcr.microsoft.com/dotnet/sdk:6.0-jammy AS build-env +FROM mcr.microsoft.com/dotnet/sdk:8.0-jammy AS build-env WORKDIR /app ARG COMMIT @@ -21,7 +21,7 @@ RUN dotnet publish NineChronicles.Headless.AccessControlCenter/NineChronicles.He --version-suffix $COMMIT # Build runtime image -FROM --platform=linux/amd64 mcr.microsoft.com/dotnet/aspnet:6.0-bullseye-slim +FROM --platform=linux/amd64 mcr.microsoft.com/dotnet/aspnet:8.0-bullseye-slim WORKDIR /app RUN apt-get update && apt-get install -y libc6-dev COPY --from=build-env /app/out . diff --git a/Dockerfile.ACC.arm64v8 b/Dockerfile.ACC.arm64v8 index 510a04d02..782745e8a 100644 --- a/Dockerfile.ACC.arm64v8 +++ b/Dockerfile.ACC.arm64v8 @@ -1,5 +1,5 @@ # Use the SDK image to build the app -FROM mcr.microsoft.com/dotnet/sdk:6.0-jammy AS build-env +FROM mcr.microsoft.com/dotnet/sdk:8.0-jammy AS build-env WORKDIR /app ARG COMMIT @@ -21,7 +21,7 @@ RUN dotnet publish NineChronicles.Headless.AccessControlCenter/NineChronicles.He --version-suffix $COMMIT # Build runtime image -FROM --platform=linux/arm64 mcr.microsoft.com/dotnet/aspnet:6.0-bullseye-slim-arm64v8 +FROM --platform=linux/arm64 mcr.microsoft.com/dotnet/aspnet:8.0-bookworm-slim-arm64v8 WORKDIR /app RUN apt-get update && apt-get install -y libc6-dev COPY --from=build-env /app/out . diff --git a/Dockerfile.amd64 b/Dockerfile.amd64 index 6956759fd..2c480cafd 100644 --- a/Dockerfile.amd64 +++ b/Dockerfile.amd64 @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build-env +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build-env WORKDIR /app ARG COMMIT @@ -24,7 +24,7 @@ RUN dotnet publish NineChronicles.Headless.Executable/NineChronicles.Headless.Ex --version-suffix $COMMIT # Build runtime image -FROM --platform=linux/amd64 mcr.microsoft.com/dotnet/aspnet:6.0-bullseye-slim +FROM --platform=linux/amd64 mcr.microsoft.com/dotnet/aspnet:8.0-bookworm-slim WORKDIR /app RUN apt-get update && apt-get install -y libc6-dev liblz4-dev zlib1g-dev libsnappy-dev libzstd-dev COPY --from=build-env /app/out . diff --git a/Dockerfile.arm64v8 b/Dockerfile.arm64v8 index c65b9e968..b0d7e8e89 100644 --- a/Dockerfile.arm64v8 +++ b/Dockerfile.arm64v8 @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build-env +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build-env WORKDIR /app ARG COMMIT @@ -24,7 +24,7 @@ RUN dotnet publish NineChronicles.Headless.Executable/NineChronicles.Headless.Ex --version-suffix $COMMIT # Build runtime image -FROM --platform=linux/arm64 mcr.microsoft.com/dotnet/aspnet:6.0-bullseye-slim-arm64v8 +FROM --platform=linux/arm64 mcr.microsoft.com/dotnet/aspnet:8.0-bookworm-slim-arm64v8 WORKDIR /app RUN apt-get update && apt-get install -y libc6-dev COPY --from=build-env /app/out . diff --git a/NineChronicles.Headless.AccessControlCenter/NineChronicles.Headless.AccessControlCenter.csproj b/NineChronicles.Headless.AccessControlCenter/NineChronicles.Headless.AccessControlCenter.csproj index 1ca96b941..dd1d387f2 100644 --- a/NineChronicles.Headless.AccessControlCenter/NineChronicles.Headless.AccessControlCenter.csproj +++ b/NineChronicles.Headless.AccessControlCenter/NineChronicles.Headless.AccessControlCenter.csproj @@ -1,6 +1,6 @@ - net6 + net8.0 true ..\NineChronicles.Headless.Common.ruleset enable diff --git a/NineChronicles.Headless.Executable.Tests/NineChronicles.Headless.Executable.Tests.csproj b/NineChronicles.Headless.Executable.Tests/NineChronicles.Headless.Executable.Tests.csproj index 601591534..a00edfe40 100644 --- a/NineChronicles.Headless.Executable.Tests/NineChronicles.Headless.Executable.Tests.csproj +++ b/NineChronicles.Headless.Executable.Tests/NineChronicles.Headless.Executable.Tests.csproj @@ -1,7 +1,7 @@ - net6 + net8.0 8 false diff --git a/NineChronicles.Headless.Executable/NineChronicles.Headless.Executable.csproj b/NineChronicles.Headless.Executable/NineChronicles.Headless.Executable.csproj index da4115593..538a29a47 100644 --- a/NineChronicles.Headless.Executable/NineChronicles.Headless.Executable.csproj +++ b/NineChronicles.Headless.Executable/NineChronicles.Headless.Executable.csproj @@ -2,7 +2,7 @@ Exe - net6 + net8.0 1.0.0 true ..\NineChronicles.Headless.Common.ruleset diff --git a/NineChronicles.Headless.Tests/NineChronicles.Headless.Tests.csproj b/NineChronicles.Headless.Tests/NineChronicles.Headless.Tests.csproj index 85ffad613..d1465d4a1 100644 --- a/NineChronicles.Headless.Tests/NineChronicles.Headless.Tests.csproj +++ b/NineChronicles.Headless.Tests/NineChronicles.Headless.Tests.csproj @@ -1,7 +1,7 @@ - net6 + net8.0 false false true diff --git a/NineChronicles.Headless/ActionEvaluationPublisher.cs b/NineChronicles.Headless/ActionEvaluationPublisher.cs index cc3060f00..98000be39 100644 --- a/NineChronicles.Headless/ActionEvaluationPublisher.cs +++ b/NineChronicles.Headless/ActionEvaluationPublisher.cs @@ -303,7 +303,8 @@ public IdGroupFinder(IMemoryCache memoryCache) var serializedInput = "key"; // Check cache - if (_memoryCache.TryGetValue(serializedInput, out List<(HashSet IPs, HashSet IDs)> cachedResult)) + List<(HashSet IPs, HashSet IDs)> cachedResult = new(); + if (_memoryCache.TryGetValue(serializedInput, out cachedResult!)) { return cachedResult; } diff --git a/NineChronicles.Headless/MemoryCacheExtensions.cs b/NineChronicles.Headless/MemoryCacheExtensions.cs index 3cda79d22..1d7d4d00d 100644 --- a/NineChronicles.Headless/MemoryCacheExtensions.cs +++ b/NineChronicles.Headless/MemoryCacheExtensions.cs @@ -20,7 +20,7 @@ public static byte[] SetSheet(this MemoryCache cache, string cacheKey, IValue va public static bool TryGetSheet(this MemoryCache cache, string cacheKey, out T cached) { - return cache.TryGetValue(cacheKey, out cached); + return cache.TryGetValue(cacheKey, out cached!); } public static string? GetSheet(this MemoryCache cache, string cacheKey) diff --git a/NineChronicles.Headless/NineChronicles.Headless.csproj b/NineChronicles.Headless/NineChronicles.Headless.csproj index 8c1fe7d3b..68b93d2dd 100644 --- a/NineChronicles.Headless/NineChronicles.Headless.csproj +++ b/NineChronicles.Headless/NineChronicles.Headless.csproj @@ -1,6 +1,6 @@ - net6 + net8.0 true ..\NineChronicles.Headless.Common.ruleset enable diff --git a/global.json b/global.json index c119d61ba..3d7cc68bc 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "6.0.0", + "version": "8.0.0", "rollForward": "minor" } } From 1d50688531a7e66e27448d98cb2cc9716843809e Mon Sep 17 00:00:00 2001 From: sky1045 Date: Thu, 29 Aug 2024 18:15:13 +0900 Subject: [PATCH 36/72] Fix acc dockerfile --- Dockerfile.ACC.amd64 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile.ACC.amd64 b/Dockerfile.ACC.amd64 index 6bfd21e35..2337bfa21 100644 --- a/Dockerfile.ACC.amd64 +++ b/Dockerfile.ACC.amd64 @@ -21,7 +21,7 @@ RUN dotnet publish NineChronicles.Headless.AccessControlCenter/NineChronicles.He --version-suffix $COMMIT # Build runtime image -FROM --platform=linux/amd64 mcr.microsoft.com/dotnet/aspnet:8.0-bullseye-slim +FROM --platform=linux/amd64 mcr.microsoft.com/dotnet/aspnet:8.0-bookworm-slim WORKDIR /app RUN apt-get update && apt-get install -y libc6-dev COPY --from=build-env /app/out . From 9023edb96b09a740a2da4436b843a03a21f31d20 Mon Sep 17 00:00:00 2001 From: sky1045 Date: Tue, 3 Sep 2024 16:39:25 +0900 Subject: [PATCH 37/72] Bump lib9c --- Lib9c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib9c b/Lib9c index 776c9113f..88ad21631 160000 --- a/Lib9c +++ b/Lib9c @@ -1 +1 @@ -Subproject commit 776c9113f7fd8f99b5645222d45b57dd7ad2cb82 +Subproject commit 88ad2163150ee60895c31e09f8222411510f5980 From 245490e5467dee2a2eb8fbaad7dd4acfbb4223d4 Mon Sep 17 00:00:00 2001 From: moreal Date: Wed, 4 Sep 2024 14:19:27 +0900 Subject: [PATCH 38/72] Fix `ActionCommandTest` --- .../Commands/ActionCommandTest.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/NineChronicles.Headless.Executable.Tests/Commands/ActionCommandTest.cs b/NineChronicles.Headless.Executable.Tests/Commands/ActionCommandTest.cs index 29eade8fb..b408ac5a7 100644 --- a/NineChronicles.Headless.Executable.Tests/Commands/ActionCommandTest.cs +++ b/NineChronicles.Headless.Executable.Tests/Commands/ActionCommandTest.cs @@ -94,7 +94,7 @@ public void TransferAsset( } else { - Assert.Contains("System.FormatException: Input string was not in a correct format.", _console.Error.ToString()); + Assert.Contains("System.FormatException", _console.Error.ToString()); } } @@ -136,7 +136,7 @@ public void ClaimStakeReward(string addressString, int expectedCode) } else { - Assert.Contains("System.FormatException: Input string was not in a correct format.", _console.Error.ToString()); + Assert.Contains("System.FormatException", _console.Error.ToString()); } } @@ -163,7 +163,7 @@ public void MigrateMonsterCollection(string addressString, int expectedCode) } else { - Assert.Contains("System.FormatException: Input string was not in a correct format.", _console.Error.ToString()); + Assert.Contains("System.FormatException", _console.Error.ToString()); } } } From 77f1d14279d8711c92e6157acc2cd7c62ea7d26b Mon Sep 17 00:00:00 2001 From: moreal Date: Wed, 4 Sep 2024 16:30:17 +0900 Subject: [PATCH 39/72] Bump lib9c to development --- Lib9c | 2 +- NineChronicles.Headless.Tests/ArenaParticipantsWorkerTest.cs | 4 ++-- NineChronicles.Headless.Tests/Common/Fixtures.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib9c b/Lib9c index 776c9113f..65ef35b14 160000 --- a/Lib9c +++ b/Lib9c @@ -1 +1 @@ -Subproject commit 776c9113f7fd8f99b5645222d45b57dd7ad2cb82 +Subproject commit 65ef35b1430241baa826f0c041a23ae158697688 diff --git a/NineChronicles.Headless.Tests/ArenaParticipantsWorkerTest.cs b/NineChronicles.Headless.Tests/ArenaParticipantsWorkerTest.cs index 887b59f4f..0655d7702 100644 --- a/NineChronicles.Headless.Tests/ArenaParticipantsWorkerTest.cs +++ b/NineChronicles.Headless.Tests/ArenaParticipantsWorkerTest.cs @@ -110,7 +110,7 @@ public void GetArenaParticipants() var tableSheets = new TableSheets(_sheets); var agentAddress = new PrivateKey().Address; var avatarAddress = Addresses.GetAvatarAddress(agentAddress, 0); - var avatarState = new AvatarState( + var avatarState = AvatarState.Create( avatarAddress, agentAddress, 0, @@ -119,7 +119,7 @@ public void GetArenaParticipants() "avatar_state" ); var avatar2Address = Addresses.GetAvatarAddress(agentAddress, 1); - var avatarState2 = new AvatarState( + var avatarState2 = AvatarState.Create( avatar2Address, agentAddress, 0, diff --git a/NineChronicles.Headless.Tests/Common/Fixtures.cs b/NineChronicles.Headless.Tests/Common/Fixtures.cs index 38e485719..a85151104 100644 --- a/NineChronicles.Headless.Tests/Common/Fixtures.cs +++ b/NineChronicles.Headless.Tests/Common/Fixtures.cs @@ -26,7 +26,7 @@ public static class Fixtures public static readonly TableSheets TableSheetsFX = new(TableSheetsImporter.ImportSheets()); - public static readonly AvatarState AvatarStateFX = new( + public static readonly AvatarState AvatarStateFX = AvatarState.Create( AvatarAddress, UserAddress, 0, From 3edd99d39b3c52b408d05e3f99b616cf0c09ac22 Mon Sep 17 00:00:00 2001 From: Say Cheong Date: Thu, 5 Sep 2024 14:58:01 +0900 Subject: [PATCH 40/72] Replaced preload state reporting with dummies --- .../GraphTypes/StandaloneSubscriptionTest.cs | 91 ------------------- .../GraphTypes/StandaloneSubscription.cs | 31 +------ 2 files changed, 4 insertions(+), 118 deletions(-) diff --git a/NineChronicles.Headless.Tests/GraphTypes/StandaloneSubscriptionTest.cs b/NineChronicles.Headless.Tests/GraphTypes/StandaloneSubscriptionTest.cs index 91cde4e91..c6bf40997 100644 --- a/NineChronicles.Headless.Tests/GraphTypes/StandaloneSubscriptionTest.cs +++ b/NineChronicles.Headless.Tests/GraphTypes/StandaloneSubscriptionTest.cs @@ -126,97 +126,6 @@ public async Task SubscribeTx() return (block, transactions); } - [Fact] - public async Task SubscribePreloadProgress() - { - var cts = new CancellationTokenSource(); - - var apvPrivateKey = new PrivateKey(); - var apv = AppProtocolVersion.Sign(apvPrivateKey, 0); - var genesisBlock = BlockChain.ProposeGenesisBlock( - transactions: new IAction[] - { - new Initialize( - new ValidatorSet( - new[] - { - new Validator(ProposerPrivateKey.PublicKey, BigInteger.One), - new Validator(apvPrivateKey.PublicKey, BigInteger.One) - } - .ToList()), - states: ImmutableDictionary.Create()) - }.Select((sa, nonce) => Transaction.Create(nonce, new PrivateKey(), null, new[] { sa.PlainValue })) - .ToImmutableList(), - privateKey: new PrivateKey()); - var validators = new List - { - ProposerPrivateKey, apvPrivateKey - }.OrderBy(x => x.Address).ToList(); - - // 에러로 인하여 NineChroniclesNodeService 를 사용할 수 없습니다. https://git.io/JfS0M - // 따라서 LibplanetNodeService로 비슷한 환경을 맞춥니다. - // 1. 노드를 생성합니다. - var seedNode = CreateLibplanetNodeService(genesisBlock, apv, apvPrivateKey.PublicKey); - await StartAsync(seedNode.Swarm, cts.Token); - - // 2. Progress를 넘겨 preloadProgress subscription 과 연결합니다. - var service = CreateLibplanetNodeService( - genesisBlock, - apv, - apvPrivateKey.PublicKey, - new Progress(state => - { - StandaloneContextFx.PreloadStateSubject.OnNext(state); - }), - new[] { seedNode.Swarm.AsPeer }); - - Block block = seedNode.BlockChain.ProposeBlock(ProposerPrivateKey); - seedNode.BlockChain.Append(block, GenerateBlockCommit(block.Index, block.Hash, validators)); - var result = await ExecuteSubscriptionQueryAsync("subscription { preloadProgress { currentPhase totalPhase extra { type currentCount totalCount } } }"); - Assert.IsType(result); - - _ = service.StartAsync(cts.Token); - - await service.PreloadEnded.WaitAsync(cts.Token); - - var subscribeResult = (SubscriptionExecutionResult)result; - var stream = subscribeResult.Streams!.Values.FirstOrDefault(); - - // BlockHashDownloadState : 2 - // BlockDownloadState : 1 - // BlockVerificationState : 1 - // ActionExecutionState : 1 - var preloadProgressRecords = - new List<(long currentPhase, long totalPhase, string type, long currentCount, long totalCount)>(); - var expectedPreloadProgress = new[] - { - (1L, 5L, "BlockHashDownloadState", 0L, 0L), - (1L, 5L, "BlockHashDownloadState", 1L, 1L), - (2L, 5L, "BlockDownloadState", 1L, 1L), - (3L, 5L, "BlockVerificationState", 1L, 1L), - (5L, 5L, "ActionExecutionState", 1L, 1L), - }.ToImmutableHashSet(); - foreach (var index in Enumerable.Range(1, expectedPreloadProgress.Count())) - { - var rawEvents = await stream.Take(index); - var events = (Dictionary)((ExecutionNode)rawEvents.Data!).ToValue()!; - var preloadProgress = (Dictionary)events["preloadProgress"]; - var preloadProgressExtra = (Dictionary)preloadProgress["extra"]; - - preloadProgressRecords.Add(( - (long)preloadProgress["currentPhase"], - (long)preloadProgress["totalPhase"], - (string)preloadProgressExtra["type"], - (long)preloadProgressExtra["currentCount"], - (long)preloadProgressExtra["totalCount"])); - } - - Assert.Equal(expectedPreloadProgress, preloadProgressRecords.ToImmutableHashSet()); - - await seedNode.StopAsync(cts.Token); - await service.StopAsync(cts.Token); - } - [Fact(Timeout = 25000)] public async Task SubscribeDifferentAppProtocolVersionEncounter() { diff --git a/NineChronicles.Headless/GraphTypes/StandaloneSubscription.cs b/NineChronicles.Headless/GraphTypes/StandaloneSubscription.cs index f0d278ecc..083aa38cf 100644 --- a/NineChronicles.Headless/GraphTypes/StandaloneSubscription.cs +++ b/NineChronicles.Headless/GraphTypes/StandaloneSubscription.cs @@ -90,34 +90,11 @@ public PreloadStateExtraType() public PreloadStateType() { - Field>(name: "currentPhase", resolve: context => context.Source.CurrentPhase); - Field>(name: "totalPhase", resolve: context => BlockSyncState.TotalPhase); + // Dummy report. + Field>(name: "currentPhase", resolve: context => 0); + Field>(name: "totalPhase", resolve: context => 0); Field>(name: "extra", resolve: context => - { - var preloadState = context.Source; - return preloadState switch - { - ActionExecutionState actionExecutionState => new PreloadStateExtra(nameof(ActionExecutionState), - actionExecutionState.ExecutedBlockCount, - actionExecutionState.TotalBlockCount), - BlockDownloadState blockDownloadState => new PreloadStateExtra(nameof(BlockDownloadState), - blockDownloadState.ReceivedBlockCount, - blockDownloadState.TotalBlockCount), - BlockHashDownloadState blockHashDownloadState => new PreloadStateExtra( - nameof(BlockHashDownloadState), - blockHashDownloadState.ReceivedBlockHashCount, - blockHashDownloadState.EstimatedTotalBlockHashCount), - BlockVerificationState blockVerificationState => new PreloadStateExtra( - nameof(BlockVerificationState), - blockVerificationState.VerifiedBlockCount, - blockVerificationState.TotalBlockCount), - StateDownloadState stateDownloadState => new PreloadStateExtra( - nameof(StateDownloadState), - stateDownloadState.ReceivedIterationCount, - stateDownloadState.TotalIterationCount), - _ => throw new ExecutionError($"Not supported preload state. {preloadState.GetType()}"), - }; - }); + new PreloadStateExtra(nameof(BlockSyncState), 0, 0)); } } From 1dd286e3cc960e3ad80c822be5a4e240617eda1f Mon Sep 17 00:00:00 2001 From: Say Cheong Date: Fri, 6 Sep 2024 09:58:45 +0900 Subject: [PATCH 41/72] Added deprecation note --- NineChronicles.Headless/GraphTypes/StandaloneSubscription.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/NineChronicles.Headless/GraphTypes/StandaloneSubscription.cs b/NineChronicles.Headless/GraphTypes/StandaloneSubscription.cs index 083aa38cf..af0600912 100644 --- a/NineChronicles.Headless/GraphTypes/StandaloneSubscription.cs +++ b/NineChronicles.Headless/GraphTypes/StandaloneSubscription.cs @@ -143,6 +143,7 @@ public StandaloneSubscription(StandaloneContext standaloneContext, IConfiguratio AddField(new EventStreamFieldType { Name = "preloadProgress", + DeprecationReason = "Since Libplanet 5.3.0 preload progress is no longer reported.", Type = typeof(PreloadStateType), Resolver = new FuncFieldResolver(context => (context.Source as BlockSyncState)!), Subscriber = new EventStreamResolver(context => StandaloneContext.PreloadStateSubject.AsObservable()), From f91e6151eb0a67db7f7a870178a00e8f3b392fe1 Mon Sep 17 00:00:00 2001 From: Say Cheong Date: Fri, 6 Sep 2024 10:23:34 +0900 Subject: [PATCH 42/72] Cleanup --- Libplanet.Headless/Hosting/LibplanetNodeService.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/Libplanet.Headless/Hosting/LibplanetNodeService.cs b/Libplanet.Headless/Hosting/LibplanetNodeService.cs index f918f14a4..8cc6e3b77 100644 --- a/Libplanet.Headless/Hosting/LibplanetNodeService.cs +++ b/Libplanet.Headless/Hosting/LibplanetNodeService.cs @@ -373,9 +373,6 @@ Task BootstrapSwarmAsync(int depth) dialTimeout: null, cancellationToken: cancellationToken); - // We assume the first phase of preloading is BlockHashDownloadState... - ((IProgress)PreloadProgress)?.Report(new BlockHashDownloadState()); - if (peers.Any()) { try From 9f2de6fd69d8ac4512f2cd78791419ac3757fb42 Mon Sep 17 00:00:00 2001 From: Say Cheong Date: Fri, 6 Sep 2024 17:40:24 +0900 Subject: [PATCH 43/72] Bump libplanet to 5.3.0-alpha.3 --- Lib9c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib9c b/Lib9c index 65ef35b14..930f3ad2e 160000 --- a/Lib9c +++ b/Lib9c @@ -1 +1 @@ -Subproject commit 65ef35b1430241baa826f0c041a23ae158697688 +Subproject commit 930f3ad2e0ec02aecbe6f54161a7b2a22ec2a9dc From eaaa59d0c63a97701cf660b361155818df9ce079 Mon Sep 17 00:00:00 2001 From: Say Cheong Date: Fri, 6 Sep 2024 17:56:58 +0900 Subject: [PATCH 44/72] Bump fix --- Libplanet.Headless/Hosting/LibplanetNodeService.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Libplanet.Headless/Hosting/LibplanetNodeService.cs b/Libplanet.Headless/Hosting/LibplanetNodeService.cs index 8cc6e3b77..c0b0c3f46 100644 --- a/Libplanet.Headless/Hosting/LibplanetNodeService.cs +++ b/Libplanet.Headless/Hosting/LibplanetNodeService.cs @@ -199,7 +199,6 @@ IActionEvaluator BuildActionEvaluator(IActionEvaluatorConfiguration actionEvalua var hostOptions = new Net.Options.HostOptions(Properties.Host, shuffledIceServers, Properties.Port ?? default); var swarmOptions = new Net.Options.SwarmOptions { - BranchpointThreshold = 50, MinimumBroadcastTarget = Properties.MinimumBroadcastTarget, BucketSize = Properties.BucketSize, MaximumPollPeers = Properties.MaximumPollPeers, From bea0bd98e3e52256b206a9b74a2305ae3e063b37 Mon Sep 17 00:00:00 2001 From: moreal Date: Mon, 9 Sep 2024 16:04:08 +0900 Subject: [PATCH 45/72] ci(gh-actions): specify project to build --- .github/workflows/deploy_gh_pages.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy_gh_pages.yaml b/.github/workflows/deploy_gh_pages.yaml index 39789996e..67d20f9e8 100644 --- a/.github/workflows/deploy_gh_pages.yaml +++ b/.github/workflows/deploy_gh_pages.yaml @@ -33,10 +33,12 @@ jobs: ${{ runner.os }}- - name: Install dependencies run: yarn global add graphql @graphql-inspector/cli + - name: Install .NET dependencies + run: dotnet restore + - name: Build GraphQL Node + run: dotnet build --no-restore --project NineChronicles.Headless.Executable - name: Build GraphQL Schema run: | - dotnet restore - dotnet build dotnet run --project NineChronicles.Headless.Executable -- \ --graphql-server \ --graphql-port 30000 \ From 7fa0698a2398629462515283c2e35de420b3a144 Mon Sep 17 00:00:00 2001 From: moreal Date: Mon, 9 Sep 2024 16:48:51 +0900 Subject: [PATCH 46/72] ci(gh-actions): remove invalid option --- .github/workflows/deploy_gh_pages.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy_gh_pages.yaml b/.github/workflows/deploy_gh_pages.yaml index 67d20f9e8..a11b9f606 100644 --- a/.github/workflows/deploy_gh_pages.yaml +++ b/.github/workflows/deploy_gh_pages.yaml @@ -36,7 +36,7 @@ jobs: - name: Install .NET dependencies run: dotnet restore - name: Build GraphQL Node - run: dotnet build --no-restore --project NineChronicles.Headless.Executable + run: dotnet build --no-restore NineChronicles.Headless.Executable - name: Build GraphQL Schema run: | dotnet run --project NineChronicles.Headless.Executable -- \ From e752b3b49be6f9d2037fa16eba52a42206f862b3 Mon Sep 17 00:00:00 2001 From: hyeon Date: Tue, 10 Sep 2024 10:55:29 +0900 Subject: [PATCH 47/72] bump lib9c --- Lib9c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib9c b/Lib9c index 930f3ad2e..31cbd41a9 160000 --- a/Lib9c +++ b/Lib9c @@ -1 +1 @@ -Subproject commit 930f3ad2e0ec02aecbe6f54161a7b2a22ec2a9dc +Subproject commit 31cbd41a99ed7b17a33fd1ea2597600dfd9b9906 From 23fd4019385a938ad35dc3b088090059df3d8464 Mon Sep 17 00:00:00 2001 From: hyeon Date: Tue, 10 Sep 2024 11:25:23 +0900 Subject: [PATCH 48/72] bump lib9c --- Lib9c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib9c b/Lib9c index 88ad21631..bbe92005e 160000 --- a/Lib9c +++ b/Lib9c @@ -1 +1 @@ -Subproject commit 88ad2163150ee60895c31e09f8222411510f5980 +Subproject commit bbe92005e00028e0caac21040c95eb49d99baade From c305cb2e55c9fb6d3f45124f10c35aa1450740ce Mon Sep 17 00:00:00 2001 From: Yang Chun Ung Date: Tue, 10 Sep 2024 21:10:44 +0900 Subject: [PATCH 49/72] Draft CONTRIBUTING.md --- CONTRIBUTING.md | 324 ++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 232 ++-------------------------------- 2 files changed, 333 insertions(+), 223 deletions(-) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..bf209bb7f --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,324 @@ +Contributor guide +================= + +Note: This document at present is for only code contributors. +We should expand it so that it covers reporting bugs, filing issues, +and writing docs. + + +Questions & online chat [![Discord](https://img.shields.io/discord/928926944937013338.svg?color=7289da&logo=discord&logoColor=white)][Discord server] +----------------------- + +We have a [Discord server] to discuss Nine Chronicles. There are some channel +for purposes in the *NINE CHRONICLES* category: + +- *#9c-headless*: Chat with maintainers and contributors of NineChronicles.Headless. + Ask questions to hack and use Nine Chronicles.Headless and to make a patch for it. People here + usually speak in Korean, but feel free to speak in English. + +[Discord server]: https://planetarium.dev/discord + + +Prerequisites +------------- + +You need [.NET Core] SDK 6.0+ which provides the latest C# compiler and .NET VM. +Read and follow the instruction to install .NET Core SDK on +the [.NET Core downloads page][1]. +FYI if you use macOS and [Homebrew] you can install it by +`brew cask install dotnet-sdk` command. + +Make sure that your .NET Core SDK is 6.0 or higher. You could show +the version you are using by `dotnet --info` command. + +Although it is not necessary, you should install a proper IDE for .NET +(or an [OmniSharp] extension for your favorite editor — except it takes +hours to properly configure and integrate with your editor). +C# is not like JavaScript or Python; it is painful to code in C# without IDE. + +Unless you already have your favorite setup, we recommend you to use +[Visual Studio Code]. It is free, open source, and made by Microsoft, which +made .NET as well. So Visual Studio Code has a [first-party C# extension][2] +which works well together. + +[.NET Core]: https://dot.net/ +[Homebrew]: https://brew.sh/ +[OmniSharp]: http://www.omnisharp.net/ +[Visual Studio Code]: https://code.visualstudio.com/ +[1]: https://dotnet.microsoft.com/download +[2]: https://marketplace.visualstudio.com/items?itemName=ms-vscode.csharp + +## Run + +If you want to run node to interact with mainnet, you can run the below command line: + +``` +dotnet run --project NineChronicles.Headless.Executable -C appsettings.mainnet.json --store-path={PATH_TO_STORE} +``` + +For more information on the command line options, refer to the [CLI Documentation](https://planetarium.github.io/NineChronicles.Headless/cli). + +### Use `appsettings.{network}.json` to provide CLI options + +You can provide headless CLI options using file, `appsettings.json`. You'll find the default file at [here](NineChronicles.Headless.Executable/appsettings.json). +The path of `appsettings.json` can be either local file storage or URL. +Refer full configuration fields from [this file](NineChronicles.Headless.Executable/Configuration.cs), set your options into `appsettings.json` under `Headless` section. +You can also run headless server with previous way; You don't need to change anything if you don't want to. +In case that the same option is provided from both `appsetting.json` and CLI option, the CLI option value is used instead from `appsettings.json`. + +The default `appsettings.json` is an example for your own appsettings file. +`appsettings.{network}.json` are runnable appsettings file and you can run local node for each network using following command: +```shell +dotnet run --project NineChronicles.Headless.Executable -C appsettings.{network}.json --store-type={YOUR_OWN_STORE_PATH} +``` +- appsettings.mainnet.json + - This makes your node to connect to the Nine Chronicles mainnet (production). +- appsettings.internal.json + - This makes your node to connect to the Nine Chronicles internal network, which is test before release new version. + - Internal network is kind of hard-fork of mainnet at some point to test new version. + - You CANNOT use mainnet storage for internal headless node. +- appsettings.previewnet.json + - This makes your node to connect to the Nine Chronicles preview network to show feature preview. + - This network is totally different network from genesis block. + - Previewnet can be restarted from genesis block without any announcement to prepare next feature. + +Please make sure the store in the path you provided must save right data for the network to connect. +You cannot share data from any of those networks. + +If you want to run your own isolated local network, please copy `appsettings.json` to `appsettings.local.json` and edit the contents. +```shell +cp appsettings.json appsettings.local.json +# Edit contents of appsettings.local.json +dotnet run --project NineChronicles.Headless.Executable -C appsettings.local.json --store-type={YOUR_OWN_STORE_PATH} +``` + +#### Caveat +APVs can be changed as Nine Chronicles deploys new version. +You have to fit your APV sting to current on-chain version string. +You can get APV strings at the following places: +- mainnet: [Official released config.json](https://release.nine-chronicles.com/9c-launcher-config.json) - `AppProtocolVersion` +- internal: [Internal network config](https://github.com/planetarium/9c-k8s-config/blob/main/9c-internal/configmap-versions.yaml) - `APP_PROTOCOL_VERSION` +- previewnet: [Previewnet config](https://github.com/planetarium/9c-k8s-config/blob/main/9c-previewnet/configmap-versions.yaml) - `APP_PROTOCOL_VERSION` + +## Docker Build + +A headless image can be created by running the command below in the directory where the solution is located. + +``` +$ docker build . -t --build-arg COMMIT= +``` +* Nine Chronicles Team uses `` to build an image with the latest git commit and push to the [official Docker Hub repository](https://hub.docker.com/repository/docker/planetariumhq/ninechronicles-headless). However, if you want to build and push to your own Docker Hub account, the `` can be any value. + +### Format + +Formatting for `PrivateKey` or `Peer` follows the format in [Nekoyume Project README][../README.md]. + +## How to run NineChronicles Headless on AWS EC2 instance using Docker + +### On Your AWS EC2 Instance + +#### Pre-requisites + +- Docker environment: [Docker Installation Guide](https://docs.docker.com/get-started/#set-up-your-docker-environment) +- AWS EC2 instance: [AWS EC2 Guide](https://docs.aws.amazon.com/ec2/index.html) + +#### 1. Pull `planetariumhq/ninechronicles-headless` Docker image to your AWS EC2 instance from the [official Docker Hub repository](https://hub.docker.com/repository/docker/planetariumhq/ninechronicles-headless). + +- If you would like to build your own Docker image from your local machine, refer to [this section](#building-your-own-docker-image-from-your-local-machine). + +``` +$ docker pull planetariumhq/ninechronicles-headless:[] (ex: v100300) +``` +- Please refer to the `docker` value in https://release.nine-chronicles.com/apv.json for the latest official Docker tag name. +- [Docker Pull Guide](https://docs.docker.com/engine/reference/commandline/pull/) + +#### 2. Create a Docker volume for blockchain data persistence + +``` +$ docker volume create [] (ex: 9c-volume) +``` +- [Docker Volume Guide](https://docs.docker.com/engine/reference/commandline/volume_create/) + +#### 3. Run your Docker image with your Docker volume mounted (use -d for detached mode) + +
+$ docker run \
+--detach \
+--volume 9c-volume:/app/data \
+planetariumhq/ninechronicles-headless:[] \
+[NineChronicles Headless Options]
+
+#### Note) + +- If you want to use the same headless options as your Nine Chronicles game client, please refer to the `headlessArgs` values in value in https://release.nine-chronicles.com/apv.json. +- If you are using an [Elastic IP](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html) on your AWS instance, you can add the IP address in the `--host` option and not use the `--ice-server` option. +- For mining, make sure to include the `--miner-private-key` option with your private key. + +- [Docker Volumes Usage](https://docs.docker.com/storage/volumes/) + +### Building Your Own Docker Image from Your Local Machine + +#### Pre-requisites + +- Docker environment: [Docker Installation Guide](https://docs.docker.com/get-started/#set-up-your-docker-environment) +- Docker Hub account: [Docker Hub Guide](https://docs.docker.com/docker-hub/) + +#### 1. Build Docker image with the tag name in `[/]` format. + +``` +$ docker build . --tag [/]:[] --build-arg COMMIT=[] +``` +- [Docker Build Guide](https://docs.docker.com/engine/reference/commandline/build/) + +#### 2. Push your Docker image to your Docker Hub account. + +``` +$ docker push [/]:[] +``` +- [Docker Push Guide](https://docs.docker.com/engine/reference/commandline/push/) + +## Nine Chronicles GraphQL API Documentation + +Check out [Nine Chronicles GraphQL API Tutorial](https://www.notion.so/Getting-Started-with-Nine-Chronicles-GraphQL-API-a14388a910844a93ab8dc0a2fe269f06) to get you started with using GraphQL API with NineChronicles Headless. + +For more information on the GraphQL API, refer to the [NineChronicles Headless GraphQL Documentation](https://planetarium.github.io/NineChronicles.Headless/graphql). + +--- + +## Create a new genesis block + +### 1. Create config file for genesis block +1. Copy `config.json.example` to `config.json` +2. Change values inside `config.json` + - `data.tablePath` is required. + - If you have `PendingActivation` file, set file path to `extra.pendingActivationStatePath` + +#### Structure of genesis block +| Key | Type | Required | Description | +|:-------------------------------------------|---------------------|:--------:|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| data | | Required | Related to the game data. This field is required. | +| data.tablePath | string | | Path of game data table. `Lib9c/Lib9c/TableCSV` for NineChronicles. | +| currency | | Optional | Related to currency data. Set initial mint / deposits. | +| currency.initialMinter | PrivateKey (string) | | PrivateKey of initial minter.
Initial minting Tx. will be signed using this key and included in genesis block. | +| currency.initialCurrencyDeposit | List | | Initial deposit data. These data will be created to Tx. and goes inside of genesis block.
If you leave this to null, the `initialMinter` will get 10000 currency as default. | +| currency.initialCurrencyDeposit[i].address | Address (string) | | Address of depositor. Use address string except leading `0x`. | +| currency.initialCurrencyDeposit[i].amount | BigInteger | | Amount of currency give to depositor.
This amount will be given every block from start to end. ex) 100 from 0 to 9: total 1000 currency will be given. | +| currency.initialCurrencyDeposit[i].start | long | | First block to give currency to depositor. genesis block is #0 | +| currency.initialCurrencyDeposit[i].end | long | | Last block to give currency to depositor.
If you want to give only once, set this value as same as `start`. | +| currency.allowMint | boolean | | Allow/Disallow additional mint or burn against the initial currency. | +| admin | | Optional | Related to admin setting. | +| admin.activate | bool | | If true, give admin privilege to admin address. | +| admin.address | Address (string) | | Address to be admin. If not provided, the `initialMinter` will be set as admin. | +| admin.validUntil | long | | Block number of admin lifetime. Admin address loses its privilege after this block. | +| initialValidatorSet | | Optional | Initial Validator set for this blockchain. Do not provide this section if you want to use default setting. | +| initialValidatorSet[i].publicKey | PublicKey (string) | | Public Key of validator. | +| initialValidatorSet[i].power | long | | Voting power of validator. Min. value of voting power is 1. | +| initialMeadConfigs | | Optional | Initial MEAD distributions | +| initialMeadConfigs[i].address | Address (string) | | Recipient address | +| initialMeadConfigs[i].amount | BigInteger | | Amount of initial MEAD | +| initialPledgeConfigs | | Optional | Initial pledges introduced from NCIP-15 | +| initialPledgeConfigs[i].agentAddress | Address (string) | | Address of agent who will be funded | +| initialPledgeConfigs[i].patronAddress | Address (string) | | Address of patron who will fund | +| initialPledgeConfigs[i].mead | int | | Amount of MEAD that will be funded per each blocks | + +### 2. Create genesis block + +```shell +dotnet run --project ./NineChronicles.Headless.Executable/ genesis ./config.json +``` + +After this step, you will get `genesis-block` file as output and another info in addition. + +### 3. Run Headless node with genesis block + +```shell +dotnet run --project ./NineChronicles.Headless.Executable/ \ + -V=[APP PROTOCOL VERSION] \ + -G=[PATH/TO/GENESIS/BLOCK] \ + --store-type=memory \ + --store-path= [PATH/TO/BLOCK/STORAGE] \ + --host=localhost \ + --port=43210 \ + --miner-private-key=[PRIVATE_KEY_OF_BLOCK_MINER] +``` +If you see log like this, all process is successfully done: + +```text +Start mining. +[BlockChain] 424037645/18484: Starting to mine block #1 with difficulty 5000000 and previous hash 29f53d22... +[BlockChain] Gathering transactions to mine for block #1 from 0 staged transactions... +[BlockChain] Gathered total of 0 transactions to mine for block #1 from 0 staged transactions. +Evaluating actions in the block #1 pre-evaluation hash: 10d93de7... +Evaluating policy block action for block #1 System.Collections.Immutable.ImmutableArray`1[System.Byte] +Actions in 0 transactions for block #1 pre-evaluation hash: 10d93de7... evaluated in 20ms. +[BlockChain] 424037645/18484: Mined block #1 0838b084... with difficulty 5000000 and previous hash 29f53d22... +[BlockChain] Trying to append block #1 0838b084... +[BlockChain] Unstaging 0 transactions from block #1 0838b084... +[BlockChain] Unstaged 0 transactions from block #1 0838b084... +[Swarm] Trying to broadcast blocks... +[NetMQTransport] Broadcasting message Libplanet.Net.Messages.BlockHeaderMessage as 0x7862DD9b....Unspecified/localhost:43210. to 0 peers +[Swarm] Block broadcasting complete. +[BlockChain] Appended the block #1 0838b084... +[BlockChain] Invoking renderers for #1 0838b084... (1 renderer(s), 0 action renderer(s)) +[LoggedRenderer] Invoking RenderBlock() for #1 0838b084... (was #0 29f53d22...)... +[LoggedRenderer] Invoked RenderBlock() for #1 0838b084... (was #0 29f53d22...). +[BlockChain] Invoked renderers for #1 0838b084... (1 renderer(s), 0 action renderer(s)) +[Swarm] Trying to broadcast blocks... +[NetMQTransport] Broadcasting message Libplanet.Net.Messages.BlockHeaderMessage as 0x7862DD9b....Unspecified/localhost:43210. to 0 peers +[Swarm] Block broadcasting complete. +``` + +--- + +## How to replay tx with remote headless + + +When using the replay remote-tx command, you can replay the results of a specific transaction on a remote node to verify the execution result. + +The remote headless node needs to enable the `--remote-key-value-service` option and enable the grpc options to retrieve chain information. + +```shell +replay remote-tx --tx {txId(hex)} --endpoint {gqlUrl(fullState gql url)} --grpc-endpoint {grpcEndpoint(remote tx grpc url)} +``` + +Projects +-------- + +The [planetarium/NineChronicles.Headless](https://github.com/planetarium/NineChronicles.Headless) repository +on GitHub consists of several projects. + +- .NET projects under the umbrella of *NineChronicles.Headless.Executable.sln* + + +### .NET projects + +- *Libplanet.Extensions.ForkableActionEvaluator*: `IActionEvaluator` implementation for target range block index. + +- *Libplanet.Extensions.PluggedActionEvaluator*: `IActionEvaluator` implementation for [AssemblyLoadContext](https://learn.microsoft.com/en-us/dotnet/core/dependency-loading/understanding-assemblyloadcontext), for dynamic DLL loading. + +- *Libplanet.Headless*: minimal implementation of Libplanet node. + +- *NineChronicles.Headless.AccessControlCenter*: Manage network transaction staging by address in [NCStagingPolicy](https://github.com/planetarium/lib9c/blob/v200220/Lib9c.Policy/NCStagePolicy.cs). + +- *NineChronicles.Headless.Executable*: Turns NineChronicles.Headless node into a single executable binary so that it is easy to distribute. + +- *NineChronicles.Headless.Executor*: command-line interface (CLI) to manage and execute different versions of NineChronicles.Headless nodes. + +- *NineChronicles.Headless*: The main project, implementation for NineChronicles node. + +- *Libplanet.Extensions.ForkableActionEvaluator.Tests*: Unit tests for the *Libplanet.Extensions.ForkableActionEvaluator* project. + +- *Libplanet.Headless.Tests*: Unit tests for the *Libplanet..Headless* project. + +- *NineChronicles.Headless.Executable.Tests*: Unit tests for the *NineChronicles.Headless.Executable* project. + +- *NineChronicles.Headless.Tests*: Unit tests for the *NineChronicles.Headless* project. + + + +Tests +----- + +To build and run unit tests at a time with .NET Core execute the below command: + + dotnet test diff --git a/README.md b/README.md index d302f4543..a48e2e109 100644 --- a/README.md +++ b/README.md @@ -5,235 +5,21 @@ [![Discourse posts](https://img.shields.io/discourse/posts?server=https%3A%2F%2Fdevforum.nine-chronicles.com%2F&logo=discourse&label=9c-devforum&color=00D1C2 )](https://devforum.nine-chronicles.com) -## Run - -If you want to run node to interact with mainnet, you can run the below command line: - -``` -dotnet run --project NineChronicles.Headless.Executable -C appsettings.mainnet.json --store-path={PATH_TO_STORE} -``` - -For more information on the command line options, refer to the [CLI Documentation](https://planetarium.github.io/NineChronicles.Headless/cli). - -### Use `appsettings.{network}.json` to provide CLI options - -You can provide headless CLI options using file, `appsettings.json`. You'll find the default file at [here](NineChronicles.Headless.Executable/appsettings.json). -The path of `appsettings.json` can be either local file storage or URL. -Refer full configuration fields from [this file](NineChronicles.Headless.Executable/Configuration.cs), set your options into `appsettings.json` under `Headless` section. -You can also run headless server with previous way; You don't need to change anything if you don't want to. -In case that the same option is provided from both `appsetting.json` and CLI option, the CLI option value is used instead from `appsettings.json`. - -The default `appsettings.json` is an example for your own appsettings file. -`appsettings.{network}.json` are runnable appsettings file and you can run local node for each network using following command: -```shell -dotnet run --project NineChronicles.Headless.Executable -C appsettings.{network}.json --store-type={YOUR_OWN_STORE_PATH} -``` -- appsettings.mainnet.json - - This makes your node to connect to the Nine Chronicles mainnet (production). -- appsettings.internal.json - - This makes your node to connect to the Nine Chronicles internal network, which is test before release new version. - - Internal network is kind of hard-fork of mainnet at some point to test new version. - - You CANNOT use mainnet storage for internal headless node. -- appsettings.previewnet.json - - This makes your node to connect to the Nine Chronicles preview network to show feature preview. - - This network is totally different network from genesis block. - - Previewnet can be restarted from genesis block without any announcement to prepare next feature. - -Please make sure the store in the path you provided must save right data for the network to connect. -You cannot share data from any of those networks. - -If you want to run your own isolated local network, please copy `appsettings.json` to `appsettings.local.json` and edit the contents. -```shell -cp appsettings.json appsettings.local.json -# Edit contents of appsettings.local.json -dotnet run --project NineChronicles.Headless.Executable -C appsettings.local.json --store-type={YOUR_OWN_STORE_PATH} -``` - -#### Caveat -APVs can be changed as Nine Chronicles deploys new version. -You have to fit your APV sting to current on-chain version string. -You can get APV strings at the following places: -- mainnet: [Official released config.json](https://release.nine-chronicles.com/9c-launcher-config.json) - `AppProtocolVersion` -- internal: [Internal network config](https://github.com/planetarium/9c-k8s-config/blob/main/9c-internal/configmap-versions.yaml) - `APP_PROTOCOL_VERSION` -- previewnet: [Previewnet config](https://github.com/planetarium/9c-k8s-config/blob/main/9c-previewnet/configmap-versions.yaml) - `APP_PROTOCOL_VERSION` - -## Docker Build - -A headless image can be created by running the command below in the directory where the solution is located. - -``` -$ docker build . -t --build-arg COMMIT= -``` -* Nine Chronicles Team uses `` to build an image with the latest git commit and push to the [official Docker Hub repository](https://hub.docker.com/repository/docker/planetariumhq/ninechronicles-headless). However, if you want to build and push to your own Docker Hub account, the `` can be any value. - -### Format - -Formatting for `PrivateKey` or `Peer` follows the format in [Nekoyume Project README][../README.md]. - -## How to run NineChronicles Headless on AWS EC2 instance using Docker - -### On Your AWS EC2 Instance - -#### Pre-requisites - -- Docker environment: [Docker Installation Guide](https://docs.docker.com/get-started/#set-up-your-docker-environment) -- AWS EC2 instance: [AWS EC2 Guide](https://docs.aws.amazon.com/ec2/index.html) - -#### 1. Pull `planetariumhq/ninechronicles-headless` Docker image to your AWS EC2 instance from the [official Docker Hub repository](https://hub.docker.com/repository/docker/planetariumhq/ninechronicles-headless). - -- If you would like to build your own Docker image from your local machine, refer to [this section](#building-your-own-docker-image-from-your-local-machine). - -``` -$ docker pull planetariumhq/ninechronicles-headless:[] (ex: v100300) -``` -- Please refer to the `docker` value in https://release.nine-chronicles.com/apv.json for the latest official Docker tag name. -- [Docker Pull Guide](https://docs.docker.com/engine/reference/commandline/pull/) - -#### 2. Create a Docker volume for blockchain data persistence - -``` -$ docker volume create [] (ex: 9c-volume) -``` -- [Docker Volume Guide](https://docs.docker.com/engine/reference/commandline/volume_create/) - -#### 3. Run your Docker image with your Docker volume mounted (use -d for detached mode) - -
-$ docker run \
---detach \
---volume 9c-volume:/app/data \
-planetariumhq/ninechronicles-headless:[] \
-[NineChronicles Headless Options]
-
-#### Note) - -- If you want to use the same headless options as your Nine Chronicles game client, please refer to the `headlessArgs` values in value in https://release.nine-chronicles.com/apv.json. -- If you are using an [Elastic IP](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html) on your AWS instance, you can add the IP address in the `--host` option and not use the `--ice-server` option. -- For mining, make sure to include the `--miner-private-key` option with your private key. - -- [Docker Volumes Usage](https://docs.docker.com/storage/volumes/) - -### Building Your Own Docker Image from Your Local Machine - -#### Pre-requisites - -- Docker environment: [Docker Installation Guide](https://docs.docker.com/get-started/#set-up-your-docker-environment) -- Docker Hub account: [Docker Hub Guide](https://docs.docker.com/docker-hub/) - -#### 1. Build Docker image with the tag name in `[/]` format. - -``` -$ docker build . --tag [/]:[] --build-arg COMMIT=[] -``` -- [Docker Build Guide](https://docs.docker.com/engine/reference/commandline/build/) - -#### 2. Push your Docker image to your Docker Hub account. - -``` -$ docker push [/]:[] -``` -- [Docker Push Guide](https://docs.docker.com/engine/reference/commandline/push/) - -## Nine Chronicles GraphQL API Documentation - -Check out [Nine Chronicles GraphQL API Tutorial](https://www.notion.so/Getting-Started-with-Nine-Chronicles-GraphQL-API-a14388a910844a93ab8dc0a2fe269f06) to get you started with using GraphQL API with NineChronicles Headless. - -For more information on the GraphQL API, refer to the [NineChronicles Headless GraphQL Documentation](https://planetarium.github.io/NineChronicles.Headless/graphql). +NineChronicles.Headless is a blockchain node implemented using the blockchain library [Libplanet] and the game's protocol [lib9c]. --- -## Create a new genesis block - -### 1. Create config file for genesis block -1. Copy `config.json.example` to `config.json` -2. Change values inside `config.json` - - `data.tablePath` is required. - - If you have `PendingActivation` file, set file path to `extra.pendingActivationStatePath` - -#### Structure of genesis block -| Key | Type | Required | Description | -|:-------------------------------------------|---------------------|:--------:|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| data | | Required | Related to the game data. This field is required. | -| data.tablePath | string | | Path of game data table. `Lib9c/Lib9c/TableCSV` for NineChronicles. | -| currency | | Optional | Related to currency data. Set initial mint / deposits. | -| currency.initialMinter | PrivateKey (string) | | PrivateKey of initial minter.
Initial minting Tx. will be signed using this key and included in genesis block. | -| currency.initialCurrencyDeposit | List | | Initial deposit data. These data will be created to Tx. and goes inside of genesis block.
If you leave this to null, the `initialMinter` will get 10000 currency as default. | -| currency.initialCurrencyDeposit[i].address | Address (string) | | Address of depositor. Use address string except leading `0x`. | -| currency.initialCurrencyDeposit[i].amount | BigInteger | | Amount of currency give to depositor.
This amount will be given every block from start to end. ex) 100 from 0 to 9: total 1000 currency will be given. | -| currency.initialCurrencyDeposit[i].start | long | | First block to give currency to depositor. genesis block is #0 | -| currency.initialCurrencyDeposit[i].end | long | | Last block to give currency to depositor.
If you want to give only once, set this value as same as `start`. | -| currency.allowMint | boolean | | Allow/Disallow additional mint or burn against the initial currency. | -| admin | | Optional | Related to admin setting. | -| admin.activate | bool | | If true, give admin privilege to admin address. | -| admin.address | Address (string) | | Address to be admin. If not provided, the `initialMinter` will be set as admin. | -| admin.validUntil | long | | Block number of admin lifetime. Admin address loses its privilege after this block. | -| initialValidatorSet | | Optional | Initial Validator set for this blockchain. Do not provide this section if you want to use default setting. | -| initialValidatorSet[i].publicKey | PublicKey (string) | | Public Key of validator. | -| initialValidatorSet[i].power | long | | Voting power of validator. Min. value of voting power is 1. | -| initialMeadConfigs | | Optional | Initial MEAD distributions | -| initialMeadConfigs[i].address | Address (string) | | Recipient address | -| initialMeadConfigs[i].amount | BigInteger | | Amount of initial MEAD | -| initialPledgeConfigs | | Optional | Initial pledges introduced from NCIP-15 | -| initialPledgeConfigs[i].agentAddress | Address (string) | | Address of agent who will be funded | -| initialPledgeConfigs[i].patronAddress | Address (string) | | Address of patron who will fund | -| initialPledgeConfigs[i].mead | int | | Amount of MEAD that will be funded per each blocks | - -### 2. Create genesis block - -```shell -dotnet run --project ./NineChronicles.Headless.Executable/ genesis ./config.json -``` +## Blockchain network -After this step, you will get `genesis-block` file as output and another info in addition. - -### 3. Run Headless node with genesis block - -```shell -dotnet run --project ./NineChronicles.Headless.Executable/ \ - -V=[APP PROTOCOL VERSION] \ - -G=[PATH/TO/GENESIS/BLOCK] \ - --store-type=memory \ - --store-path= [PATH/TO/BLOCK/STORAGE] \ - --host=localhost \ - --port=43210 \ - --miner-private-key=[PRIVATE_KEY_OF_BLOCK_MINER] -``` -If you see log like this, all process is successfully done: - -```text -Start mining. -[BlockChain] 424037645/18484: Starting to mine block #1 with difficulty 5000000 and previous hash 29f53d22... -[BlockChain] Gathering transactions to mine for block #1 from 0 staged transactions... -[BlockChain] Gathered total of 0 transactions to mine for block #1 from 0 staged transactions. -Evaluating actions in the block #1 pre-evaluation hash: 10d93de7... -Evaluating policy block action for block #1 System.Collections.Immutable.ImmutableArray`1[System.Byte] -Actions in 0 transactions for block #1 pre-evaluation hash: 10d93de7... evaluated in 20ms. -[BlockChain] 424037645/18484: Mined block #1 0838b084... with difficulty 5000000 and previous hash 29f53d22... -[BlockChain] Trying to append block #1 0838b084... -[BlockChain] Unstaging 0 transactions from block #1 0838b084... -[BlockChain] Unstaged 0 transactions from block #1 0838b084... -[Swarm] Trying to broadcast blocks... -[NetMQTransport] Broadcasting message Libplanet.Net.Messages.BlockHeaderMessage as 0x7862DD9b....Unspecified/localhost:43210. to 0 peers -[Swarm] Block broadcasting complete. -[BlockChain] Appended the block #1 0838b084... -[BlockChain] Invoking renderers for #1 0838b084... (1 renderer(s), 0 action renderer(s)) -[LoggedRenderer] Invoking RenderBlock() for #1 0838b084... (was #0 29f53d22...)... -[LoggedRenderer] Invoked RenderBlock() for #1 0838b084... (was #0 29f53d22...). -[BlockChain] Invoked renderers for #1 0838b084... (1 renderer(s), 0 action renderer(s)) -[Swarm] Trying to broadcast blocks... -[NetMQTransport] Broadcasting message Libplanet.Net.Messages.BlockHeaderMessage as 0x7862DD9b....Unspecified/localhost:43210. to 0 peers -[Swarm] Block broadcasting complete. -``` - ---- +https://nine-chronicles.dev/contributing/getting-started#blockchain-network -## How to replay tx with remote headless +## GraphQL +https://nine-chronicles.dev/general/get-state/get-state-with-headless-graphql -When using the replay remote-tx command, you can replay the results of a specific transaction on a remote node to verify the execution result. +## Contribution -The remote headless node needs to enable the `--remote-key-value-service` option and enable the grpc options to retrieve chain information. +Any contributions are welcome. Please check [CONTRIBUTING](CONTRIBUTING.md). -```shell -replay remote-tx --tx {txId(hex)} --endpoint {gqlUrl(fullState gql url)} --grpc-endpoint {grpcEndpoint(remote tx grpc url)} -``` +[Libplanet]: https://github.com/planetarium/libplanet +[lib9c]: https://github.com/planetarium/lib9c From 6ec7c596d39eed967349fcced75b31c0c713875c Mon Sep 17 00:00:00 2001 From: hyeon Date: Fri, 13 Sep 2024 12:00:17 +0900 Subject: [PATCH 50/72] Bump lib9c --- Lib9c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib9c b/Lib9c index bbe92005e..f48c5aca4 160000 --- a/Lib9c +++ b/Lib9c @@ -1 +1 @@ -Subproject commit bbe92005e00028e0caac21040c95eb49d99baade +Subproject commit f48c5aca44555460f80955b0d413436886c67d70 From 2f5b2101be73b248c2b1d767eea3cffab80395c6 Mon Sep 17 00:00:00 2001 From: hyeon Date: Fri, 13 Sep 2024 12:28:41 +0900 Subject: [PATCH 51/72] Fix broken tests --- .../ArenaParticipantsWorkerTest.cs | 39 ++++++++++++++++--- .../Common/Fixtures.cs | 20 ++++++++-- 2 files changed, 49 insertions(+), 10 deletions(-) diff --git a/NineChronicles.Headless.Tests/ArenaParticipantsWorkerTest.cs b/NineChronicles.Headless.Tests/ArenaParticipantsWorkerTest.cs index 887b59f4f..7d5c406c3 100644 --- a/NineChronicles.Headless.Tests/ArenaParticipantsWorkerTest.cs +++ b/NineChronicles.Headless.Tests/ArenaParticipantsWorkerTest.cs @@ -7,9 +7,11 @@ using Libplanet.Mocks; using Nekoyume; using Nekoyume.Action; +using Nekoyume.Model; using Nekoyume.Model.Arena; using Nekoyume.Model.EnumType; using Nekoyume.Model.Item; +using Nekoyume.Model.Quest; using Nekoyume.Model.State; using Nekoyume.Module; using Nekoyume.TableData; @@ -92,7 +94,8 @@ public void AvatarAddrAndScoresWithRank() .SetLegacyState(sheetAddress, csv.Serialize()) .SetLegacyState(participantsAddr, participants.Serialize()) .SetLegacyState(arenaScore.Address, arenaScore.Serialize()); - var actual = ArenaParticipantsWorker.AvatarAddrAndScoresWithRank(participants.AvatarAddresses, currentRoundData, state); + var actual = + ArenaParticipantsWorker.AvatarAddrAndScoresWithRank(participants.AvatarAddresses, currentRoundData, state); Assert.Equal(2, actual.Count); var first = actual.First(); Assert.Equal(avatarAddress, first.avatarAddr); @@ -114,7 +117,16 @@ public void GetArenaParticipants() avatarAddress, agentAddress, 0, - tableSheets.GetAvatarSheets(), + new QuestList( + tableSheets.QuestSheet, + tableSheets.QuestRewardSheet, + tableSheets.QuestItemRewardSheet, + tableSheets.EquipmentItemRecipeSheet, + tableSheets.EquipmentItemSubRecipeSheet + ), + new WorldInformation( + 0, tableSheets.WorldSheet, GameConfig.IsEditor, "test" + ), new Address(), "avatar_state" ); @@ -123,7 +135,16 @@ public void GetArenaParticipants() avatar2Address, agentAddress, 0, - tableSheets.GetAvatarSheets(), + new QuestList( + tableSheets.QuestSheet, + tableSheets.QuestRewardSheet, + tableSheets.QuestItemRewardSheet, + tableSheets.EquipmentItemRecipeSheet, + tableSheets.EquipmentItemSubRecipeSheet + ), + new WorldInformation( + 0, tableSheets.WorldSheet, GameConfig.IsEditor, "test" + ), new Address(), "avatar_state2" ); @@ -131,7 +152,9 @@ public void GetArenaParticipants() // equipment var equipmentSheet = tableSheets.EquipmentItemSheet; var random = new Random(0); - var equipment = (Equipment)ItemFactory.CreateItem(equipmentSheet.Values.First(r => r.ItemSubType == ItemSubType.Armor), random); + var equipment = + (Equipment)ItemFactory.CreateItem(equipmentSheet.Values.First(r => r.ItemSubType == ItemSubType.Armor), + random); equipment.equipped = true; avatarState.inventory.AddItem(equipment); avatarState2.inventory.AddItem(equipment); @@ -182,8 +205,12 @@ public void GetArenaParticipants() { state = state.SetLegacyState(Addresses.GetSheetAddress(key), s.Serialize()); } - var avatarAddrAndScoresWithRank = ArenaParticipantsWorker.AvatarAddrAndScoresWithRank(participants.AvatarAddresses, currentRoundData, state); - var actual = ArenaParticipantsWorker.GetArenaParticipants(state, participants.AvatarAddresses, avatarAddrAndScoresWithRank); + + var avatarAddrAndScoresWithRank = + ArenaParticipantsWorker.AvatarAddrAndScoresWithRank(participants.AvatarAddresses, currentRoundData, state); + var actual = + ArenaParticipantsWorker.GetArenaParticipants(state, participants.AvatarAddresses, + avatarAddrAndScoresWithRank); Assert.Equal(2, actual.Count); var first = actual.First(); Assert.Equal(avatarAddress, first.AvatarAddr); diff --git a/NineChronicles.Headless.Tests/Common/Fixtures.cs b/NineChronicles.Headless.Tests/Common/Fixtures.cs index 38e485719..f950e1e42 100644 --- a/NineChronicles.Headless.Tests/Common/Fixtures.cs +++ b/NineChronicles.Headless.Tests/Common/Fixtures.cs @@ -6,7 +6,10 @@ using Libplanet.Common; using Libplanet.Crypto; using Libplanet.Types.Assets; +using Nekoyume; +using Nekoyume.Model; using Nekoyume.Model.Item; +using Nekoyume.Model.Quest; using Nekoyume.Model.State; namespace NineChronicles.Headless.Tests @@ -24,13 +27,21 @@ public static class Fixtures public static readonly Address StakeStateAddress = StakeState.DeriveAddress(UserAddress); - public static readonly TableSheets TableSheetsFX = new(TableSheetsImporter.ImportSheets()); + public static readonly TableSheets TableSheetsFX = new (TableSheetsImporter.ImportSheets()); - public static readonly AvatarState AvatarStateFX = new( + public static readonly AvatarState AvatarStateFX = new ( AvatarAddress, UserAddress, 0, - TableSheetsFX.GetAvatarSheets(), + new QuestList( + TableSheetsFX.GetAvatarSheets().QuestSheet, + TableSheetsFX.GetAvatarSheets().QuestRewardSheet, + TableSheetsFX.GetAvatarSheets().QuestItemRewardSheet, + TableSheetsFX.GetAvatarSheets().EquipmentItemRecipeSheet, + TableSheetsFX.GetAvatarSheets().EquipmentItemSubRecipeSheet + ), + new WorldInformation(0, TableSheetsFX.GetAvatarSheets().WorldSheet, + GameConfig.IsEditor, "test"), new Address(), "avatar_state_fx" ); @@ -54,7 +65,8 @@ public static ShopState ShopStateFX() var equipment = ItemFactory.CreateItemUsable(row, Guid.Empty, 0); if (equipment is ITradableItem tradableItem) { - var shopItem = new ShopItem(UserAddress, AvatarAddress, Guid.NewGuid(), index * CurrencyFX, tradableItem); + var shopItem = new ShopItem(UserAddress, AvatarAddress, Guid.NewGuid(), index * CurrencyFX, + tradableItem); shopState.Register(shopItem); } } From c39f4736c6d78ca93514fc1e6df83f33fc12a8ed Mon Sep 17 00:00:00 2001 From: hyeon Date: Fri, 13 Sep 2024 12:39:33 +0900 Subject: [PATCH 52/72] Fix lint --- NineChronicles.Headless.Tests/Common/Fixtures.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NineChronicles.Headless.Tests/Common/Fixtures.cs b/NineChronicles.Headless.Tests/Common/Fixtures.cs index f950e1e42..d081b135b 100644 --- a/NineChronicles.Headless.Tests/Common/Fixtures.cs +++ b/NineChronicles.Headless.Tests/Common/Fixtures.cs @@ -27,9 +27,9 @@ public static class Fixtures public static readonly Address StakeStateAddress = StakeState.DeriveAddress(UserAddress); - public static readonly TableSheets TableSheetsFX = new (TableSheetsImporter.ImportSheets()); + public static readonly TableSheets TableSheetsFX = new(TableSheetsImporter.ImportSheets()); - public static readonly AvatarState AvatarStateFX = new ( + public static readonly AvatarState AvatarStateFX = new( AvatarAddress, UserAddress, 0, From cc455c288d4a2161dbe5c0d205c1ea1b94163583 Mon Sep 17 00:00:00 2001 From: Moreal Date: Thu, 19 Sep 2024 09:55:28 +0900 Subject: [PATCH 53/72] Remove deprecated devforum link --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index a48e2e109..0aa5b8f38 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,6 @@ [![Planetarium Discord invite](https://img.shields.io/discord/539405872346955788?color=6278DA&label=Planetarium&logo=discord&logoColor=white)](https://discord.gg/JyujU8E4SD) [![Planetarium-Dev Discord Invite](https://img.shields.io/discord/928926944937013338?color=6278DA&label=Planetarium-dev&logo=discord&logoColor=white)](https://discord.gg/RYJDyFRYY7) -[![Discourse posts](https://img.shields.io/discourse/posts?server=https%3A%2F%2Fdevforum.nine-chronicles.com%2F&logo=discourse&label=9c-devforum&color=00D1C2 -)](https://devforum.nine-chronicles.com) NineChronicles.Headless is a blockchain node implemented using the blockchain library [Libplanet] and the game's protocol [lib9c]. From 04d15c2a15148b794cdfa393e949105c8a7ccc25 Mon Sep 17 00:00:00 2001 From: Moreal Date: Thu, 19 Sep 2024 10:10:08 +0900 Subject: [PATCH 54/72] Write invitations to developer portal --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 0aa5b8f38..85929efb2 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,11 @@ [![Planetarium Discord invite](https://img.shields.io/discord/539405872346955788?color=6278DA&label=Planetarium&logo=discord&logoColor=white)](https://discord.gg/JyujU8E4SD) [![Planetarium-Dev Discord Invite](https://img.shields.io/discord/928926944937013338?color=6278DA&label=Planetarium-dev&logo=discord&logoColor=white)](https://discord.gg/RYJDyFRYY7) +> [!TIP] +> If you're new to Nine Chronicles, try to visit our **Developer Portal**! +> +> https://nine-chronicles.dev/ + NineChronicles.Headless is a blockchain node implemented using the blockchain library [Libplanet] and the game's protocol [lib9c]. --- From 0d920eae33be87a5e94fc4a9865fd78fc87a73d5 Mon Sep 17 00:00:00 2001 From: moreal Date: Tue, 13 Aug 2024 08:52:48 +0900 Subject: [PATCH 55/72] Refactor with repositories - Introduce `IBlockChainRepository`. - Introduce `IWorldStateRepository`. - Introduce `ITransactionRepository`. - Introduce `IStateTrieRepository`. - Replace the usage of `StandaloneContext.BlockChain` with repositories. - Separate `NodeStatusType` GraphQL type and `NodeStatus` record type. --- NineChronicles.Headless.Executable/Program.cs | 1 + .../Action/ActionContext.cs | 44 ++ .../GraphQLTestUtils.cs | 17 + .../GraphTypes/GraphQLTestBase.cs | 26 +- .../GraphTypes/StandaloneQueryTest.cs | 574 ++++++++---------- .../NineChronicles.Headless.Tests.csproj | 6 + NineChronicles.Headless/BlockChainContext.cs | 2 +- .../Domain/Model/BlockChain/Block.cs | 22 + NineChronicles.Headless/GraphQLService.cs | 10 + .../GraphTypes/BlockHeaderType.cs | 1 + .../GraphTypes/NodeStatus.cs | 59 +- .../GraphTypes/StandaloneQuery.cs | 242 ++------ .../GraphTypes/StandaloneSubscription.cs | 4 +- .../HostBuilderExtensions.cs | 1 + .../NineChroniclesNodeService.cs | 2 + .../BlockChain/BlockChainRepository.cs | 87 +++ .../BlockChain/IBlockChainRepository.cs | 14 + .../StateTrie/IStateTrieRepository.cs | 13 + .../StateTrie/StateTrieRepository.cs | 87 +++ .../Transaction/ITransactionRepository.cs | 12 + .../Transaction/TransactionRepository.cs | 31 + .../WorldState/IWorldStateRepository.cs | 13 + .../WorldState/WorldStateRepository.cs | 32 + NineChronicles.Headless/StandaloneContext.cs | 10 +- 24 files changed, 746 insertions(+), 564 deletions(-) create mode 100644 NineChronicles.Headless.Tests/Action/ActionContext.cs create mode 100644 NineChronicles.Headless/Domain/Model/BlockChain/Block.cs create mode 100644 NineChronicles.Headless/Repositories/BlockChain/BlockChainRepository.cs create mode 100644 NineChronicles.Headless/Repositories/BlockChain/IBlockChainRepository.cs create mode 100644 NineChronicles.Headless/Repositories/StateTrie/IStateTrieRepository.cs create mode 100644 NineChronicles.Headless/Repositories/StateTrie/StateTrieRepository.cs create mode 100644 NineChronicles.Headless/Repositories/Transaction/ITransactionRepository.cs create mode 100644 NineChronicles.Headless/Repositories/Transaction/TransactionRepository.cs create mode 100644 NineChronicles.Headless/Repositories/WorldState/IWorldStateRepository.cs create mode 100644 NineChronicles.Headless/Repositories/WorldState/WorldStateRepository.cs diff --git a/NineChronicles.Headless.Executable/Program.cs b/NineChronicles.Headless.Executable/Program.cs index 125cd02aa..c4a0fc92c 100644 --- a/NineChronicles.Headless.Executable/Program.cs +++ b/NineChronicles.Headless.Executable/Program.cs @@ -442,6 +442,7 @@ IActionLoader MakeSingleActionLoader() hostBuilder.ConfigureServices(services => { services.AddSingleton(_ => standaloneContext); + services.AddSingleton(standaloneContext.KeyStore); services.AddOpenTelemetry() .ConfigureResource(resource => resource.AddService( serviceName: Assembly.GetEntryAssembly()?.GetName().Name ?? "NineChronicles.Headless", diff --git a/NineChronicles.Headless.Tests/Action/ActionContext.cs b/NineChronicles.Headless.Tests/Action/ActionContext.cs new file mode 100644 index 000000000..8f13f472c --- /dev/null +++ b/NineChronicles.Headless.Tests/Action/ActionContext.cs @@ -0,0 +1,44 @@ +using System.Collections.Generic; +using Libplanet.Action; +using Libplanet.Action.State; +using Libplanet.Crypto; +using Libplanet.Extensions.ActionEvaluatorCommonComponents; +using Libplanet.Types.Evidence; +using Libplanet.Types.Tx; + +namespace NineChronicles.Headless.Tests.Action; + +public class ActionContext : IActionContext +{ + private long UsedGas { get; set; } + + public Address Signer { get; init; } + public TxId? TxId { get; init; } + public Address Miner { get; init; } + public long BlockIndex { get; init; } + public int BlockProtocolVersion { get; init; } + public IWorld PreviousState { get; init; } + public int RandomSeed { get; init; } + public bool IsPolicyAction { get; init; } + public IReadOnlyList Txs { get; init; } + public IReadOnlyList Evidence { get; init; } + public void UseGas(long gas) + { + UsedGas += gas; + } + + public IRandom GetRandom() + { + return new Random(RandomSeed); + } + + public long GasUsed() + { + return UsedGas; + } + + public long GasLimit() + { + return 0L; + } +} diff --git a/NineChronicles.Headless.Tests/GraphQLTestUtils.cs b/NineChronicles.Headless.Tests/GraphQLTestUtils.cs index 314f9d802..e113ac220 100644 --- a/NineChronicles.Headless.Tests/GraphQLTestUtils.cs +++ b/NineChronicles.Headless.Tests/GraphQLTestUtils.cs @@ -24,6 +24,10 @@ using Nekoyume.Action.Loader; using Nekoyume.Model.State; using Nekoyume.Module; +using NineChronicles.Headless.Repositories.BlockChain; +using NineChronicles.Headless.Repositories.StateTrie; +using NineChronicles.Headless.Repositories.Transaction; +using NineChronicles.Headless.Repositories.WorldState; using NineChronicles.Headless.Utils; namespace NineChronicles.Headless.Tests @@ -61,6 +65,10 @@ public static Task ExecuteQueryAsync( services.AddLibplanetExplorer(); services.AddSingleton(); + services.AddTransient(); + services.AddTransient(); + services.AddSingleton(); + services.AddSingleton(); var serviceProvider = services.BuildServiceProvider(); return ExecuteQueryAsync( @@ -78,6 +86,15 @@ public static Task ExecuteQueryAsync( where TObjectGraphType : IObjectGraphType { var graphType = (IObjectGraphType)serviceProvider.GetService(typeof(TObjectGraphType))!; + return ExecuteQueryAsync(graphType, query, userContext, source); + } + + public static Task ExecuteQueryAsync( + IObjectGraphType graphType, + string query, + IDictionary? userContext = null, + object? source = null) + { var documentExecutor = new DocumentExecuter(); return documentExecutor.ExecuteAsync(new ExecutionOptions { diff --git a/NineChronicles.Headless.Tests/GraphTypes/GraphQLTestBase.cs b/NineChronicles.Headless.Tests/GraphTypes/GraphQLTestBase.cs index 01e1d1889..e8c1dfc97 100644 --- a/NineChronicles.Headless.Tests/GraphTypes/GraphQLTestBase.cs +++ b/NineChronicles.Headless.Tests/GraphTypes/GraphQLTestBase.cs @@ -35,6 +35,13 @@ using System.Threading.Tasks; using Bencodex.Types; using Libplanet.Types.Tx; +using Moq; +using NineChronicles.Headless.Executable.Tests.KeyStore; +using NineChronicles.Headless.Repositories; +using NineChronicles.Headless.Repositories.BlockChain; +using NineChronicles.Headless.Repositories.StateTrie; +using NineChronicles.Headless.Repositories.Transaction; +using NineChronicles.Headless.Repositories.WorldState; using Xunit.Abstractions; namespace NineChronicles.Headless.Tests.GraphTypes @@ -86,12 +93,10 @@ public GraphQLTestBase(ITestOutputHelper output) privateKey: AdminPrivateKey); var ncService = ServiceBuilder.CreateNineChroniclesNodeService(genesisBlock, ProposerPrivateKey); - var tempKeyStorePath = Path.Join(Path.GetTempPath(), Path.GetRandomFileName()); - var keyStore = new Web3KeyStore(tempKeyStorePath); StandaloneContextFx = new StandaloneContext { - KeyStore = keyStore, + KeyStore = KeyStore, DifferentAppProtocolVersionEncounterInterval = TimeSpan.FromSeconds(1), NotificationInterval = TimeSpan.FromSeconds(1), NodeExceptionInterval = TimeSpan.FromSeconds(1), @@ -117,6 +122,12 @@ public GraphQLTestBase(ITestOutputHelper output) ); services.AddSingleton(publisher); services.AddSingleton(StandaloneContextFx); + services.AddTransient(provider => provider.GetService().BlockChain); + services.AddSingleton(WorldStateRepository.Object); + services.AddSingleton(BlockChainRepository.Object); + services.AddSingleton(StateTrieRepository.Object); + services.AddSingleton(TransactionRepository.Object); + services.AddSingleton(KeyStore); services.AddSingleton(configuration); services.AddGraphTypes(); services.AddLibplanetExplorer(); @@ -129,6 +140,12 @@ public GraphQLTestBase(ITestOutputHelper output) DocumentExecutor = new DocumentExecuter(); } + protected Mock WorldStateRepository { get; } = new(); + protected Mock StateTrieRepository { get; } = new(); + protected Mock BlockChainRepository { get; } = new(); + protected Mock TransactionRepository { get; } = new(); + protected IKeyStore KeyStore { get; } = new InMemoryKeyStore(); + protected PrivateKey AdminPrivateKey { get; } = new PrivateKey(); protected Address AdminAddress => AdminPrivateKey.Address; @@ -150,9 +167,6 @@ protected List GenesisValidators protected BlockChain BlockChain => StandaloneContextFx.BlockChain!; - protected IKeyStore KeyStore => - StandaloneContextFx.KeyStore!; - protected IDocumentExecuter DocumentExecutor { get; } protected SubscriptionDocumentExecuter SubscriptionDocumentExecuter { get; } = new SubscriptionDocumentExecuter(); diff --git a/NineChronicles.Headless.Tests/GraphTypes/StandaloneQueryTest.cs b/NineChronicles.Headless.Tests/GraphTypes/StandaloneQueryTest.cs index d668b7cef..e993818c0 100644 --- a/NineChronicles.Headless.Tests/GraphTypes/StandaloneQueryTest.cs +++ b/NineChronicles.Headless.Tests/GraphTypes/StandaloneQueryTest.cs @@ -6,11 +6,14 @@ using System.IO; using System.Linq; using System.Numerics; +using System.Security.Cryptography; using System.Threading; using System.Threading.Tasks; using Bencodex; using Bencodex.Types; using GraphQL.Execution; +using GraphQL.Types; +using Lib9c; using Libplanet.Action; using Libplanet.Action.State; using Libplanet.Action.Sys; @@ -19,19 +22,28 @@ using Libplanet.Crypto; using Libplanet.Headless.Hosting; using Libplanet.KeyStore; +using Libplanet.Mocks; using Libplanet.Net; +using Libplanet.Store.Trie; using Libplanet.Types.Assets; using Libplanet.Types.Blocks; using Libplanet.Types.Consensus; using Libplanet.Types.Tx; +using Moq; using Nekoyume; using Nekoyume.Action; using Nekoyume.Blockchain.Policy; using Nekoyume.Helper; using Nekoyume.Model; +using Nekoyume.Model.Item; +using Nekoyume.Model.Quest; using Nekoyume.Model.State; using Nekoyume.Module; using Nekoyume.TableData; +using NineChronicles.Headless.Executable; +using NineChronicles.Headless.GraphTypes; +using NineChronicles.Headless.Repositories.WorldState; +using NineChronicles.Headless.Tests.Action; using NineChronicles.Headless.Tests.Common; using Xunit; using Xunit.Abstractions; @@ -42,6 +54,7 @@ namespace NineChronicles.Headless.Tests.GraphTypes public partial class StandaloneQueryTest : GraphQLTestBase { private readonly Dictionary _sheets; + private readonly IObjectGraphType _graph; public StandaloneQueryTest(ITestOutputHelper output) : base(output) { @@ -51,14 +64,33 @@ public StandaloneQueryTest(ITestOutputHelper output) : base(output) [Fact] public async Task GetState() { - AppendEmptyBlock(GenesisValidators); + var adminAddress = new PrivateKey().Address; Address adminStateAddress = AdminState.Address; + var worldState = new World(MockUtil.MockModernWorldState) + .SetLegacyState(adminStateAddress, new AdminState(adminAddress, 10000).Serialize()); + var stateRootHash = worldState.Trie.Hash; + + var tip = new Domain.Model.BlockChain.Block( + BlockHash.FromString("613dfa26e104465790625ae7bc03fc27a64947c02a9377565ec190405ef7154b"), + BlockHash.FromString("36456be15af9a5b9b13a02c7ce1e849ae9cba8781ec309010499cdb93e29237d"), + default(Address), + 0, + Timestamp: DateTimeOffset.UtcNow, + StateRootHash: stateRootHash, + Transactions: ImmutableArray.Empty + ); + + BlockChainRepository.Setup(repository => repository.GetTip()) + .Returns(tip); + WorldStateRepository.Setup(repository => repository.GetWorldState(stateRootHash)) + .Returns(worldState); + var result = await ExecuteQueryAsync($"query {{ state(accountAddress: \"{ReservedAddresses.LegacyAccount}\", address: \"{adminStateAddress}\") }}"); var data = (Dictionary)((ExecutionNode)result.Data!).ToValue()!; IValue rawVal = new Codec().Decode(ByteUtil.ParseHex((string)data!["state"])); AdminState adminState = new AdminState((Dictionary)rawVal); - Assert.Equal(AdminAddress, adminState.AdminAddress); + Assert.Equal(adminAddress, adminState.AdminAddress); } [Theory] @@ -230,25 +262,39 @@ public async Task NodeStatusStagedTxIds() [Fact] public async Task NodeStatusGetTopMostBlocks() { - PrivateKey userPrivateKey = new PrivateKey(); - var validators = new List + Domain.Model.BlockChain.Block MakeFakeBlock(long index) { - ProposerPrivateKey, - userPrivateKey, - }.OrderBy(x => x.Address).ToList(); - var service = MakeNineChroniclesNodeService(userPrivateKey); - StandaloneContextFx.NineChroniclesNodeService = service; - StandaloneContextFx.BlockChain = service.Swarm?.BlockChain; - - var blockChain = StandaloneContextFx.BlockChain; - for (int i = 0; i < 10; i++) - { - Block block = blockChain!.ProposeBlock( - userPrivateKey, - lastCommit: GenerateBlockCommit(BlockChain.Tip.Index, BlockChain.Tip.Hash, validators)); - blockChain!.Append(block, GenerateBlockCommit(block.Index, block.Hash, validators)); + return new Domain.Model.BlockChain.Block( + BlockHash.FromString("613dfa26e104465790625ae7bc03fc27a64947c02a9377565ec190405ef7154b"), null, + default, index, DateTimeOffset.UtcNow, MerkleTrie.EmptyRootHash, ImmutableArray.Empty); } + BlockChainRepository.Setup(repo => repo.IterateBlocksDescending(0)) + .Returns(new List + { + MakeFakeBlock(10), + MakeFakeBlock(9), + MakeFakeBlock(8), + MakeFakeBlock(7), + MakeFakeBlock(6), + MakeFakeBlock(5), + MakeFakeBlock(4), + MakeFakeBlock(3), + MakeFakeBlock(2), + MakeFakeBlock(1), + MakeFakeBlock(0), + }); + BlockChainRepository.Setup(repo => repo.IterateBlocksDescending(5)) + .Returns(new List + { + MakeFakeBlock(5), + MakeFakeBlock(4), + MakeFakeBlock(3), + MakeFakeBlock(2), + MakeFakeBlock(1), + MakeFakeBlock(0), + }); + var queryWithoutOffset = @"query { nodeStatus { topmostBlocks(limit: 1) { @@ -549,18 +595,24 @@ public async Task ActivationStatus(bool existsActivatedAccounts) [Fact] public async Task GoldBalance() { - var userPrivateKey = new PrivateKey(); - var userAddress = userPrivateKey.Address; - var validators = new List - { - ProposerPrivateKey, userPrivateKey - }.OrderBy(x => x.Address).ToList(); - var service = MakeNineChroniclesNodeService(userPrivateKey); - StandaloneContextFx.NineChroniclesNodeService = service; - StandaloneContextFx.BlockChain = service.Swarm?.BlockChain; - AppendEmptyBlock(validators); + var userAddress = new PrivateKey().Address; + var worldState = new World(MockUtil.MockModernWorldState) + .SetLegacyState(Addresses.GoldCurrency, new GoldCurrencyState(Currencies.Crystal).Serialize()); + var stateRootHash = worldState.Trie.Hash; + var tip = new Domain.Model.BlockChain.Block( + BlockHash.FromString("613dfa26e104465790625ae7bc03fc27a64947c02a9377565ec190405ef7154b"), + BlockHash.FromString("36456be15af9a5b9b13a02c7ce1e849ae9cba8781ec309010499cdb93e29237d"), + default(Address), + 0, + Timestamp: DateTimeOffset.UtcNow, + StateRootHash: stateRootHash, + Transactions: ImmutableArray.Empty + ); + BlockChainRepository.Setup(repository => repository.GetTip()) + .Returns(tip); + WorldStateRepository.Setup(repository => repository.GetWorldState(stateRootHash)) + .Returns(worldState); - var blockChain = StandaloneContextFx.BlockChain; var query = $"query {{ goldBalance(address: \"{userAddress}\") }}"; var queryResult = await ExecuteQueryAsync(query); var data = (Dictionary)((ExecutionNode)queryResult.Data!).ToValue()!; @@ -571,12 +623,22 @@ public async Task GoldBalance() }, data ); - - Block block = blockChain!.ProposeBlock( - userPrivateKey, - lastCommit: GenerateBlockCommit(BlockChain.Tip.Index, BlockChain.Tip.Hash, validators)); - blockChain!.Append(block, GenerateBlockCommit(block.Index, block.Hash, validators)); - AppendEmptyBlock(validators); + + worldState = worldState.MintAsset(new ActionContext(), userAddress, Currencies.Crystal * 10); + stateRootHash = worldState.Trie.Hash; + tip = new Domain.Model.BlockChain.Block( + BlockHash.FromString("613dfa26e104465790625ae7bc03fc27a64947c02a9377565ec190405ef7154b"), + BlockHash.FromString("36456be15af9a5b9b13a02c7ce1e849ae9cba8781ec309010499cdb93e29237d"), + default(Address), + 0, + Timestamp: DateTimeOffset.UtcNow, + StateRootHash: stateRootHash, + Transactions: ImmutableArray.Empty + ); + BlockChainRepository.Setup(repository => repository.GetTip()) + .Returns(tip); + WorldStateRepository.Setup(repository => repository.GetWorldState(stateRootHash)) + .Returns(worldState); queryResult = await ExecuteQueryAsync(query); data = (Dictionary)((ExecutionNode)queryResult.Data!).ToValue()!; @@ -594,37 +656,39 @@ public async Task GoldBalance() [InlineData("memo")] public async Task TransferNCGHistories(string? memo) { - PrivateKey senderKey = ProposerPrivateKey, recipientKey = new PrivateKey(); + PrivateKey senderKey = new PrivateKey(), recipientKey = new PrivateKey(); Address sender = senderKey.Address, recipient = recipientKey.Address; - Block block = BlockChain.ProposeBlock( - ProposerPrivateKey, - lastCommit: GenerateBlockCommit(BlockChain.Tip.Index, BlockChain.Tip.Hash, GenesisValidators)); - BlockChain.Append(block, GenerateBlockCommit(block.Index, block.Hash, GenesisValidators)); - block = BlockChain.ProposeBlock( - ProposerPrivateKey, - lastCommit: GenerateBlockCommit(BlockChain.Tip.Index, BlockChain.Tip.Hash, GenesisValidators)); - BlockChain.Append(block, GenerateBlockCommit(block.Index, block.Hash, GenesisValidators)); - - var currency = new GoldCurrencyState((Dictionary)BlockChain.GetWorldState().GetLegacyState(Addresses.GoldCurrency)).Currency; - Transaction MakeTx(ActionBase action) + var blockHash = BlockHash.FromString("613dfa26e104465790625ae7bc03fc27a64947c02a9377565ec190405ef7154b"); + Transaction MakeTx(long nonce, ActionBase action) { - return BlockChain.MakeTransaction(ProposerPrivateKey, new ActionBase[] { action }); + return Transaction.Create(nonce, senderKey, blockHash, new[] { action.PlainValue }); } + + var currency = Currency.Uncapped("NCG", 2, null); var txs = new[] { - MakeTx(new TransferAsset0(sender, recipient, new FungibleAssetValue(currency, 1, 0), memo)), - MakeTx(new TransferAsset(sender, recipient, new FungibleAssetValue(currency, 1, 0), memo)), + MakeTx(0, new TransferAsset0(sender, recipient, new FungibleAssetValue(currency, 1, 0), memo)), + MakeTx(1, new TransferAsset(sender, recipient, new FungibleAssetValue(currency, 1, 0), memo)), }; + var block = new Domain.Model.BlockChain.Block( + blockHash, + BlockHash.FromString("36456be15af9a5b9b13a02c7ce1e849ae9cba8781ec309010499cdb93e29237d"), + default(Address), + 0, + Timestamp: DateTimeOffset.UtcNow, + StateRootHash: MerkleTrie.EmptyRootHash, + Transactions: txs.ToImmutableArray() + ); - block = BlockChain.ProposeBlock( - ProposerPrivateKey, lastCommit: GenerateBlockCommit(BlockChain.Tip.Index, BlockChain.Tip.Hash, GenesisValidators)); - BlockChain.Append(block, GenerateBlockCommit(block.Index, block.Hash, GenesisValidators)); - - foreach (var tx in txs) - { - Assert.NotNull(StandaloneContextFx.Store?.GetTxExecution(block.Hash, tx.Id)); - } + BlockChainRepository.Setup(repo => repo.GetBlock(blockHash)) + .Returns(block); + TransactionRepository.Setup(repo => repo.GetTxExecution(blockHash, txs[0].Id)) + .Returns(new TxExecution( + blockHash, txs[0].Id, false, MerkleTrie.EmptyRootHash, MerkleTrie.EmptyRootHash, new List())); + TransactionRepository.Setup(repo => repo.GetTxExecution(blockHash, txs[1].Id)) + .Returns(new TxExecution( + blockHash, txs[1].Id, false, MerkleTrie.EmptyRootHash, MerkleTrie.EmptyRootHash, new List())); var blockHashHex = ByteUtil.Hex(block.Hash.ToByteArray()); var result = @@ -691,6 +755,26 @@ public async Task MonsterCollectionStatus_AgentState_Null(bool miner) { Assert.Equal(userPrivateKey, StandaloneContextFx.NineChroniclesNodeService.MinerPrivateKey!); } + + // FIXME: Remove the above lines after removing `StandaloneContext` dependency. + var worldState = new World(MockUtil.MockModernWorldState) + .SetLegacyState(Addresses.GoldCurrency, new GoldCurrencyState(Currencies.Crystal).Serialize()) + .MintAsset(new ActionContext(), userAddress, Currencies.Crystal * 10); + var stateRootHash = worldState.Trie.Hash; + var tip = new Domain.Model.BlockChain.Block( + BlockHash.FromString("613dfa26e104465790625ae7bc03fc27a64947c02a9377565ec190405ef7154b"), + BlockHash.FromString("36456be15af9a5b9b13a02c7ce1e849ae9cba8781ec309010499cdb93e29237d"), + default(Address), + 0, + Timestamp: DateTimeOffset.UtcNow, + StateRootHash: stateRootHash, + Transactions: ImmutableArray.Empty + ); + BlockChainRepository.Setup(repository => repository.GetTip()) + .Returns(tip); + WorldStateRepository.Setup(repository => repository.GetWorldState(stateRootHash)) + .Returns(worldState); + string queryArgs = miner ? "" : $@"(address: ""{userAddress}"")"; string query = $@"query {{ monsterCollectionStatus{queryArgs} {{ @@ -729,23 +813,26 @@ public async Task MonsterCollectionStatus_MonsterCollectionState_Null(bool miner { StandaloneContextFx.NineChroniclesNodeService.MinerPrivateKey = null; } - var action = new CreateAvatar - { - index = 0, - hair = 1, - lens = 2, - ear = 3, - tail = 4, - name = "action", - }; - var blockChain = StandaloneContextFx.BlockChain; - var transaction = blockChain.MakeTransaction(userPrivateKey, new ActionBase[] { action }); - blockChain.StageTransaction(transaction); - Block block = blockChain.ProposeBlock( - userPrivateKey, - lastCommit: GenerateBlockCommit(BlockChain.Tip.Index, BlockChain.Tip.Hash, validators)); - blockChain.Append(block, GenerateBlockCommit(block.Index, block.Hash, validators)); - AppendEmptyBlock(validators); + + // FIXME: Remove the above lines after removing `StandaloneContext` dependency. + var worldState = new World(MockUtil.MockModernWorldState) + .SetLegacyState(Addresses.GoldCurrency, new GoldCurrencyState(Currencies.Crystal).Serialize()) + .SetAgentState(userAddress, new AgentState(userAddress)) + .MintAsset(new ActionContext(), userAddress, Currencies.Crystal * 10); + var stateRootHash = worldState.Trie.Hash; + var tip = new Domain.Model.BlockChain.Block( + BlockHash.FromString("613dfa26e104465790625ae7bc03fc27a64947c02a9377565ec190405ef7154b"), + BlockHash.FromString("36456be15af9a5b9b13a02c7ce1e849ae9cba8781ec309010499cdb93e29237d"), + default(Address), + 0, + Timestamp: DateTimeOffset.UtcNow, + StateRootHash: stateRootHash, + Transactions: ImmutableArray.Empty + ); + BlockChainRepository.Setup(repository => repository.GetTip()) + .Returns(tip); + WorldStateRepository.Setup(repository => repository.GetWorldState(stateRootHash)) + .Returns(worldState); string queryArgs = miner ? "" : $@"(address: ""{userAddress}"")"; string query = $@"query {{ @@ -772,40 +859,31 @@ public async Task MonsterCollectionStatus_MonsterCollectionState_Null(bool miner [Fact] public async Task Avatar() { - var userPrivateKey = new PrivateKey(); - var userAddress = userPrivateKey.Address; - var validators = new List - { - ProposerPrivateKey, userPrivateKey - }.OrderBy(x => x.Address).ToList(); - var service = MakeNineChroniclesNodeService(userPrivateKey); - StandaloneContextFx.NineChroniclesNodeService = service; - StandaloneContextFx.BlockChain = service.Swarm!.BlockChain; - var action = new CreateAvatar - { - index = 0, - hair = 1, - lens = 2, - ear = 3, - tail = 4, - name = "action", - }; - var blockChain = StandaloneContextFx.BlockChain; - var transaction = blockChain.MakeTransaction(userPrivateKey, new ActionBase[] { action }); - blockChain.StageTransaction(transaction); - Block block = blockChain.ProposeBlock( - userPrivateKey, - lastCommit: GenerateBlockCommit(BlockChain.Tip.Index, BlockChain.Tip.Hash, validators)); - blockChain.Append(block, GenerateBlockCommit(block.Index, block.Hash, validators)); - AppendEmptyBlock(validators); - - var avatarAddress = userAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CreateAvatar.DeriveFormat, - 0 - ) + var agentAddress = new Address("f189c04126e2e708cd7d17cd68a7b7f10bbb6f16"); + var avatarAddress = new Address("f1a005c01e683dbcab9a306d5cc70d5e57fccfa9"); + var avatarState = new AvatarState((List)new Codec().Decode(Convert.FromHexString( + "6c6c32303af1a005c01e683dbcab9a306d5cc70d5e57fccfa96569326575353a6261447561693130303031306569333336656937313231346575383a313134393233323632303af189c04126e2e708cd7d17cd68a7b7f10bbb6f166c647531303a6174746163686d656e74647531313a616374696f6e506f696e7475313a3075313a636c647531333a646563696d616c506c61636573313a1275373a6d696e746572736e75363a7469636b657275373a4352595354414c65693065657531373a656e68616e63656d656e74526573756c7475373a5375636365737375343a676f6c6469306575323a696431363a17b05d00fea9864c901ede7c9f4d31bb7531303a6974656d557361626c65647531303a62756666536b696c6c736c657531343a656c656d656e74616c5f7479706575343a4c616e6475363a65715f65787075323a333275383a65717569707065646675353a677261646575313a3175323a696475383a313034313330303075363a6974656d496431363a788c0c286da7c14abde5ded62de0f44d7531333a6974656d5f7375625f7479706575383a4e65636b6c61636575393a6974656d5f7479706575393a45717569706d656e7475353a6c6576656c75313a3275323a6f6375313a337531383a7265717569726564426c6f636b496e64657875383a313134393232363775363a7365745f696475313a3475363a736b696c6c736c6475363a6368616e636575313a3875353a706f77657275313a3075383a736b696c6c526f776475353a636f6d626f6675383a636f6f6c646f776e693235657531343a656c656d656e74616c5f7479706575363a4e6f726d616c75393a6869745f636f756e7469316575323a696469323430303030657531343a736b696c6c5f63617465676f727975373a486974427566667531373a736b696c6c5f7461726765745f7479706575343a53656c667531303a736b696c6c5f7479706575343a427566666565657531393a7370696e655f7265736f757263655f7061746875383a313034313330303075343a737461746475343a74797065343a0500000075353a76616c756575333a3335376575383a73746174734d617064343a03000000647531353a6164646974696f6e616c56616c75657531313a33312e303030303030303075383a7374617454797065343a0300000075353a76616c756575313a3065343a05000000647531353a6164646974696f6e616c56616c75657531323a3130362e303030303030303075383a7374617454797065343a0500000075353a76616c756575383a3434322e323133316565657531383a6d6174657269616c4974656d49644c6973746c31363ad5f36402d57e214691607fa35606e52931363a7f45c50e8c9cdc48b87b1c28af35597031363a11eaf70e63890447894dacb39c8402d0657531333a7072654974656d557361626c65647531303a62756666536b696c6c736c657531343a656c656d656e74616c5f7479706575343a4c616e6475363a65715f65787075313a3875383a65717569707065646675353a677261646575313a3175323a696475383a313034313330303075363a6974656d496431363a788c0c286da7c14abde5ded62de0f44d7531333a6974656d5f7375625f7479706575383a4e65636b6c61636575393a6974656d5f7479706575393a45717569706d656e7475353a6c6576656c75313a3075323a6f6375313a337531383a7265717569726564426c6f636b496e64657875383a313134383936323075363a7365745f696475313a3475363a736b696c6c736c6475363a6368616e636575313a3875353a706f77657275313a3075383a736b696c6c526f776475353a636f6d626f6675383a636f6f6c646f776e693235657531343a656c656d656e74616c5f7479706575363a4e6f726d616c75393a6869745f636f756e7469316575323a696469323430303030657531343a736b696c6c5f63617465676f727975373a486974427566667531373a736b696c6c5f7461726765745f7479706575343a53656c667531303a736b696c6c5f7479706575343a427566666565657531393a7370696e655f7265736f757263655f7061746875383a313034313330303075343a737461746475343a74797065343a0500000075353a76616c756575333a3335376575383a73746174734d617064343a03000000647531353a6164646974696f6e616c56616c756575323a333175383a7374617454797065343a0300000075353a76616c756575313a3065343a05000000647531353a6164646974696f6e616c56616c756575333a31303675383a7374617454797065343a0500000075353a76616c756575333a33353765656575363a7479706549647532353a6974656d5f656e68616e63656d656e7431332e726573756c74657531303a626c6f636b496e64657875383a313134393232323775323a696431363a17b05d00fea9864c901ede7c9f4d31bb7531383a7265717569726564426c6f636b496e64657875383a313134393232363775363a7479706549647531313a6974656d456e68616e636565647531303a626c6f636b496e64657875383a313134373830303375323a696431363af4bef400ccc4624da8f69f1e78a0478375323a706931363af4bef400ccc4624da8f69f1e78a047837531383a7265717569726564426c6f636b496e64657875383a313134373830303375363a7479706549647531373a50726f6475637453656c6c65724d61696c65647531303a626c6f636b496e64657875383a313134383035363375323a696431363adc9740029e56f544bcde568ecce9adbf75323a706931363adc9740029e56f544bcde568ecce9adbf7531383a7265717569726564426c6f636b496e64657875383a313134383035363375363a7479706549647531373a50726f6475637453656c6c65724d61696c65647531303a6174746163686d656e74647531313a616374696f6e506f696e7475313a3075343a676f6c6469306575323a696431363a070d1d1d75c4a849a6ee8e626b08542e7531303a6974656d557361626c65647531303a62756666536b696c6c736c657531343a656c656d656e74616c5f7479706575343a4c616e6475363a65715f65787075313a3875383a65717569707065646675353a677261646575313a3175323a696475383a313034313330303075363a6974656d496431363a080f06a366c6e84c993ac8525b1d6cf27531333a6974656d5f7375625f7479706575383a4e65636b6c61636575393a6974656d5f7479706575393a45717569706d656e7475353a6c6576656c75313a3075323a6f6375313a337531383a7265717569726564426c6f636b496e64657875383a313134393033323275363a7365745f696475313a3475363a736b696c6c736c657531393a7370696e655f7265736f757263655f7061746875383a313034313330303075343a737461746475343a74797065343a0500000075353a76616c756575333a3335376575383a73746174734d617064343a03000000647531353a6164646974696f6e616c56616c756575323a323675383a7374617454797065343a0300000075353a76616c756575313a3065343a05000000647531353a6164646974696f6e616c56616c756575333a31373175383a7374617454797065343a0500000075353a76616c756575333a33353765656575393a6d6174657269616c736c6475353a636f756e7475323a313575383a6d6174657269616c647531343a656c656d656e74616c5f7479706575363a4e6f726d616c75353a677261646575313a3175323a696475363a33303333303075373a6974656d5f696433323a1bd96c8d5bce17827b894e01d4eb87bd853bc6a48baee9e6151ce568ae43ad397531333a6974656d5f7375625f747970657531373a45717569706d656e744d6174657269616c75393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323075383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630303975373a6974656d5f696433323a67f6ff0b0e20202a8e63742adf804355ceaee3ab636ed3065bd535985e7109a87531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323975383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630313075373a6974656d5f696433323ae0e69c7f4f16174438570e79ef52f5091ff761615a29dc70d3babbb4a099ce337531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323075383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630313175373a6974656d5f696433323a2d85afe3aa2e0ebc49df0149cf939feeddbfb9049a1e0c3bd7d8c00a948fece67531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656575383a726563697065496475333a3131317531313a737562526563697065496475333a32363075363a7479706549647532343a636f6d62696e6174696f6e2e726573756c742d6d6f64656c657531303a626c6f636b496e64657875383a313134383935393875323a696431363a070d1d1d75c4a849a6ee8e626b08542e7531383a7265717569726564426c6f636b496e64657875383a313134393033323275363a7479706549647531353a636f6d62696e6174696f6e4d61696c65647531303a626c6f636b496e64657875383a313134373837373975313a666c6c647531333a646563696d616c506c61636573313a1275373a6d696e746572736e75363a7469636b657275373a4352595354414c65693234303030303030303030303030303030303030303065656575313a696c6c693830303230316569313265656575323a696431363a5580de2c0e57bc4a936439bd3e0e548275313a6d7536303a706174726f6c207265776172642046314130303543303145363833644263416239413330366435634337304435453537666363466139202f203331327531383a7265717569726564426c6f636b496e64657875383a313134373837373975363a7479706549647531343a436c61696d4974656d734d61696c65647531303a6174746163686d656e74647531313a616374696f6e506f696e7475313a3075343a676f6c6469306575323a696431363a91fe9e33e696034cae9720cea467aaed7531303a6974656d557361626c65647531303a62756666536b696c6c736c657531343a656c656d656e74616c5f7479706575343a57696e6475363a65715f65787075323a313075383a65717569707065646675353a677261646575313a3175323a696475383a313035313430303075363a6974656d496431363afc0b4deaa2aa1342910de9bb0f4e868f7531333a6974656d5f7375625f7479706575343a52696e6775393a6974656d5f7479706575393a45717569706d656e7475353a6c6576656c75313a3075323a6f6375313a337531383a7265717569726564426c6f636b496e64657875383a313135303236383775363a7365745f696475313a3575363a736b696c6c736c657531393a7370696e655f7265736f757263655f7061746875383a313035313430303075343a737461746475343a74797065343a0300000075353a76616c756575333a3130376575383a73746174734d617064343a03000000647531353a6164646974696f6e616c56616c756575323a393275383a7374617454797065343a0300000075353a76616c756575333a31303765343a06000000647531353a6164646974696f6e616c56616c756575333a34323075383a7374617454797065343a0600000075353a76616c756575313a3065656575393a6d6174657269616c736c6475353a636f756e7475323a323475383a6d6174657269616c647531343a656c656d656e74616c5f7479706575363a4e6f726d616c75353a677261646575313a3175323a696475363a33303334303075373a6974656d5f696433323a45c8a87009caf8f9d3ecf58618fa6e2b14fe0edb2283d373e3c190c56eb96d8a7531333a6974656d5f7375625f747970657531373a45717569706d656e744d6174657269616c75393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a313275383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a57696e6475353a677261646575313a3175323a696475363a33303630343275373a6974656d5f696433323a31f48810fa91236281c165659d65003cfb611205a52c1ff6e02c019b86625dda7531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a343775383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a57696e6475353a677261646575313a3275323a696475363a33303630353075373a6974656d5f696433323adf0c212eb56526891629367fe889cfce0ea89a04e21d11a05b19ff9231802b4c7531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a373075383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a57696e6475353a677261646575313a3275323a696475363a33303630353175373a6974656d5f696433323a5eac6f2b799a1fc20a50f005f2df8783fefec63595787804b4418ece2b3d07177531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656575383a726563697065496475333a3133377531313a737562526563697065496475333a33323375363a7479706549647532343a636f6d62696e6174696f6e2e726573756c742d6d6f64656c657531303a626c6f636b496e64657875383a313134393232333075323a696431363a91fe9e33e696034cae9720cea467aaed7531383a7265717569726564426c6f636b496e64657875383a313135303236383775363a7479706549647531353a636f6d62696e6174696f6e4d61696c65647531303a6174746163686d656e74647531313a616374696f6e506f696e7475313a3075343a676f6c6469306575323a696431363aa09bb5427904a84db14bf0e004729f247531303a6974656d557361626c65647531303a62756666536b696c6c736c657531343a656c656d656e74616c5f7479706575363a4e6f726d616c75363a65715f65787075313a3575383a65717569707065646675353a677261646575313a3175323a696475383a313035313030303075363a6974656d496431363a31541a02030725409e67ad7b14fd1d807531333a6974656d5f7375625f7479706575343a52696e6775393a6974656d5f7479706575393a45717569706d656e7475353a6c6576656c75313a3075323a6f6375313a337531383a7265717569726564426c6f636b496e64657875383a313134383334363275363a7365745f696475313a3175363a736b696c6c736c657531393a7370696e655f7265736f757263655f7061746875383a313035313030303075343a737461746475343a74797065343a0300000075353a76616c756575313a386575383a73746174734d617064343a02000000647531353a6164646974696f6e616c56616c756575313a3675383a7374617454797065343a0200000075353a76616c756575313a3065343a03000000647531353a6164646974696f6e616c56616c756575313a3775383a7374617454797065343a0300000075353a76616c756575313a3865656575393a6d6174657269616c736c6475353a636f756e7475313a3275383a6d6174657269616c647531343a656c656d656e74616c5f7479706575363a4e6f726d616c75353a677261646575313a3175323a696475363a33303334303075373a6974656d5f696433323a45c8a87009caf8f9d3ecf58618fa6e2b14fe0edb2283d373e3c190c56eb96d8a7531333a6974656d5f7375625f747970657531373a45717569706d656e744d6174657269616c75393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475313a3275383a6d6174657269616c647531343a656c656d656e74616c5f7479706575353a576174657275353a677261646575313a3175323a696475363a33303630303175373a6974656d5f696433323a77cfad5273885820b69e61c2106ae06583f69c7f6d82a229b59e5f1b984164be7531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475313a3275383a6d6174657269616c647531343a656c656d656e74616c5f7479706575353a576174657275353a677261646575313a3175323a696475363a33303630303275373a6974656d5f696433323a28a2c38b0934225a8f2327b9bd8cf7c7eaf3551bde8203f44248c011938e97707531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475313a3175383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4669726575353a677261646575313a3175323a696475363a33303630323375373a6974656d5f696433323a1af5e747fc81a7f3149af024db2e5025b6749a000d66b22e665acdd45b8dbd177531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656575383a726563697065496475333a3133337531313a737562526563697065496475333a34353875363a7479706549647532343a636f6d62696e6174696f6e2e726573756c742d6d6f64656c657531303a626c6f636b496e64657875383a313134383334353475323a696431363aa09bb5427904a84db14bf0e004729f247531383a7265717569726564426c6f636b496e64657875383a313134383334363275363a7479706549647531353a636f6d62696e6174696f6e4d61696c65647531303a626c6f636b496e64657875383a313134383132393975313a696c6c6936303032303165693565656575323a696431363aecaa0b486ea7564da3971e00d5fb8b9d75313a6d7535313a7b22736561736f6e5f70617373223a207b226e223a205b32315d2c202270223a205b5d2c202274223a2022636c61696d227d7d7531383a7265717569726564426c6f636b496e64657875383a313134383132393975363a7479706549647531343a436c61696d4974656d734d61696c65647531303a626c6f636b496e64657875383a313134383934363675313a666c6c647531333a646563696d616c506c61636573313a1275373a6d696e746572736e75363a7469636b657275373a4352595354414c65693234303030303030303030303030303030303030303065656575313a696c6c693830303230316569313265656575323a696431363a5f21e54bd0119549a07713182f22ee7a75313a6d7536303a706174726f6c207265776172642046314130303543303145363833644263416239413330366435634337304435453537666363466139202f203331337531383a7265717569726564426c6f636b496e64657875383a313134383934363675363a7479706549647531343a436c61696d4974656d734d61696c65647531303a6174746163686d656e74647531313a616374696f6e506f696e7475313a3075343a676f6c6469306575323a696431363a48e84158fc051044a7316a5a8e3fed177531303a6974656d557361626c65647531303a62756666536b696c6c736c657531343a656c656d656e74616c5f7479706575343a4c616e6475363a65715f65787075313a3875383a65717569707065646675353a677261646575313a3175323a696475383a313034313330303075363a6974656d496431363af62bd25f4b3e964682fee972bdf6174f7531333a6974656d5f7375625f7479706575383a4e65636b6c61636575393a6974656d5f7479706575393a45717569706d656e7475353a6c6576656c75313a3075323a6f6375313a337531383a7265717569726564426c6f636b496e64657875383a313134383334363975363a7365745f696475313a3475363a736b696c6c736c6475363a6368616e636575313a3875353a706f77657275313a3075383a736b696c6c526f776475353a636f6d626f6675383a636f6f6c646f776e693235657531343a656c656d656e74616c5f7479706575363a4e6f726d616c75393a6869745f636f756e7469316575323a696469323430303030657531343a736b696c6c5f63617465676f727975373a486974427566667531373a736b696c6c5f7461726765745f7479706575343a53656c667531303a736b696c6c5f7479706575343a427566666565657531393a7370696e655f7265736f757263655f7061746875383a313034313330303075343a737461746475343a74797065343a0500000075353a76616c756575333a3335376575383a73746174734d617064343a03000000647531353a6164646974696f6e616c56616c756575323a333075383a7374617454797065343a0300000075353a76616c756575313a3065343a05000000647531353a6164646974696f6e616c56616c756575323a393975383a7374617454797065343a0500000075353a76616c756575333a33353765656575393a6d6174657269616c736c6475353a636f756e7475323a313575383a6d6174657269616c647531343a656c656d656e74616c5f7479706575363a4e6f726d616c75353a677261646575313a3175323a696475363a33303333303075373a6974656d5f696433323a1bd96c8d5bce17827b894e01d4eb87bd853bc6a48baee9e6151ce568ae43ad397531333a6974656d5f7375625f747970657531373a45717569706d656e744d6174657269616c75393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323075383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630303975373a6974656d5f696433323a67f6ff0b0e20202a8e63742adf804355ceaee3ab636ed3065bd535985e7109a87531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323975383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630313075373a6974656d5f696433323ae0e69c7f4f16174438570e79ef52f5091ff761615a29dc70d3babbb4a099ce337531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323075383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630313175373a6974656d5f696433323a2d85afe3aa2e0ebc49df0149cf939feeddbfb9049a1e0c3bd7d8c00a948fece67531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656575383a726563697065496475333a3131317531313a737562526563697065496475333a32363075363a7479706549647532343a636f6d62696e6174696f6e2e726573756c742d6d6f64656c657531303a626c6f636b496e64657875383a313134383334343975323a696431363a48e84158fc051044a7316a5a8e3fed177531383a7265717569726564426c6f636b496e64657875383a313134383334363975363a7479706549647531353a636f6d62696e6174696f6e4d61696c65647531303a626c6f636b496e64657875383a313134383035363375323a696431363a3c5cc35a76d6b9459e6edcac8ae2539575323a706931363a3c5cc35a76d6b9459e6edcac8ae253957531383a7265717569726564426c6f636b496e64657875383a313134383035363375363a7479706549647531373a50726f6475637453656c6c65724d61696c65647531303a6174746163686d656e74647531313a616374696f6e506f696e7475313a3075343a676f6c6469306575323a696431363a5978fb5b2ec75949aec15d76f13d87827531303a6974656d557361626c65647531303a62756666536b696c6c736c657531343a656c656d656e74616c5f7479706575363a4e6f726d616c75363a65715f65787075313a3575383a65717569707065646675353a677261646575313a3175323a696475383a313035313030303075363a6974656d496431363a83c590459b76b6418b041f9f372544ca7531333a6974656d5f7375625f7479706575343a52696e6775393a6974656d5f7479706575393a45717569706d656e7475353a6c6576656c75313a3075323a6f6375313a347531383a7265717569726564426c6f636b496e64657875383a313134383937353675363a7365745f696475313a3175363a736b696c6c736c6475363a6368616e636575313a3875353a706f77657275313a3075383a736b696c6c526f776475353a636f6d626f6675383a636f6f6c646f776e693235657531343a656c656d656e74616c5f7479706575363a4e6f726d616c75393a6869745f636f756e7469316575323a696469323130303030657531343a736b696c6c5f63617465676f72797531303a41747461636b427566667531373a736b696c6c5f7461726765745f7479706575343a53656c667531303a736b696c6c5f7479706575343a427566666565657531393a7370696e655f7265736f757263655f7061746875383a313035313030303075343a737461746475343a74797065343a0300000075353a76616c756575313a386575383a73746174734d617064343a02000000647531353a6164646974696f6e616c56616c756575313a3475383a7374617454797065343a0200000075353a76616c756575313a3065343a03000000647531353a6164646974696f6e616c56616c756575313a3875383a7374617454797065343a0300000075353a76616c756575313a3865656575393a6d6174657269616c736c6475353a636f756e7475313a3275383a6d6174657269616c647531343a656c656d656e74616c5f7479706575363a4e6f726d616c75353a677261646575313a3175323a696475363a33303334303075373a6974656d5f696433323a45c8a87009caf8f9d3ecf58618fa6e2b14fe0edb2283d373e3c190c56eb96d8a7531333a6974656d5f7375625f747970657531373a45717569706d656e744d6174657269616c75393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475313a3275383a6d6174657269616c647531343a656c656d656e74616c5f7479706575353a576174657275353a677261646575313a3175323a696475363a33303630303175373a6974656d5f696433323a77cfad5273885820b69e61c2106ae06583f69c7f6d82a229b59e5f1b984164be7531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475313a3275383a6d6174657269616c647531343a656c656d656e74616c5f7479706575353a576174657275353a677261646575313a3175323a696475363a33303630303275373a6974656d5f696433323a28a2c38b0934225a8f2327b9bd8cf7c7eaf3551bde8203f44248c011938e97707531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475313a3175383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4669726575353a677261646575313a3175323a696475363a33303630323375373a6974656d5f696433323a1af5e747fc81a7f3149af024db2e5025b6749a000d66b22e665acdd45b8dbd177531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656575383a726563697065496475333a3133337531313a737562526563697065496475333a34353875363a7479706549647532343a636f6d62696e6174696f6e2e726573756c742d6d6f64656c657531303a626c6f636b496e64657875383a313134383937333675323a696431363a5978fb5b2ec75949aec15d76f13d87827531383a7265717569726564426c6f636b496e64657875383a313134383937353675363a7479706549647531353a636f6d62696e6174696f6e4d61696c65647531303a626c6f636b496e64657875383a313134383035363375323a696431363a75ff80623e199846804b450232e452dd75323a706931363a75ff80623e199846804b450232e452dd7531383a7265717569726564426c6f636b496e64657875383a313134383035363375363a7479706549647531373a50726f6475637453656c6c65724d61696c65647531303a626c6f636b496e64657875383a313134383035363375323a696431363a5797bc645cc0f045b117e4e133e323bb75323a706931363a5797bc645cc0f045b117e4e133e323bb7531383a7265717569726564426c6f636b496e64657875383a313134383035363375363a7479706549647531373a50726f6475637453656c6c65724d61696c65647531303a6174746163686d656e74647531313a616374696f6e506f696e7475313a3075343a676f6c6469306575323a696431363aeb3383670cd49a41aa6a956fb38caa267531303a6974656d557361626c65647531303a62756666536b696c6c736c657531343a656c656d656e74616c5f7479706575343a57696e6475363a65715f65787075323a313075383a65717569707065646675353a677261646575313a3175323a696475383a313035313430303075363a6974656d496431363aa8f4c138733f0e4f851abb2a7552555b7531333a6974656d5f7375625f7479706575343a52696e6775393a6974656d5f7479706575393a45717569706d656e7475353a6c6576656c75313a3075323a6f6375313a347531383a7265717569726564426c6f636b496e64657875383a313134393233343475363a7365745f696475313a3575363a736b696c6c736c6475363a6368616e636575313a3975353a706f77657275343a3334323875383a736b696c6c526f776475353a636f6d626f6675383a636f6f6c646f776e693133657531343a656c656d656e74616c5f7479706575343a57696e6475393a6869745f636f756e7469356575323a696469313430303035657531343a736b696c6c5f63617465676f72797531303a4172656141747461636b7531373a736b696c6c5f7461726765745f7479706575373a456e656d6965737531303a736b696c6c5f7479706575363a41747461636b6565657531393a7370696e655f7265736f757263655f7061746875383a313035313430303075343a737461746475343a74797065343a0300000075353a76616c756575333a3130376575383a73746174734d617064343a03000000647531353a6164646974696f6e616c56616c756575323a393175383a7374617454797065343a0300000075353a76616c756575333a31303765343a06000000647531353a6164646974696f6e616c56616c756575333a34303175383a7374617454797065343a0600000075353a76616c756575313a3065656575393a6d6174657269616c736c6475353a636f756e7475323a323475383a6d6174657269616c647531343a656c656d656e74616c5f7479706575363a4e6f726d616c75353a677261646575313a3175323a696475363a33303334303075373a6974656d5f696433323a45c8a87009caf8f9d3ecf58618fa6e2b14fe0edb2283d373e3c190c56eb96d8a7531333a6974656d5f7375625f747970657531373a45717569706d656e744d6174657269616c75393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a313275383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a57696e6475353a677261646575313a3175323a696475363a33303630343275373a6974656d5f696433323a31f48810fa91236281c165659d65003cfb611205a52c1ff6e02c019b86625dda7531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a343775383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a57696e6475353a677261646575313a3275323a696475363a33303630353075373a6974656d5f696433323adf0c212eb56526891629367fe889cfce0ea89a04e21d11a05b19ff9231802b4c7531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a373075383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a57696e6475353a677261646575313a3275323a696475363a33303630353175373a6974656d5f696433323a5eac6f2b799a1fc20a50f005f2df8783fefec63595787804b4418ece2b3d07177531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656575383a726563697065496475333a3133377531313a737562526563697065496475333a33323375363a7479706549647532343a636f6d62696e6174696f6e2e726573756c742d6d6f64656c657531303a626c6f636b496e64657875383a313134393233323475323a696431363aeb3383670cd49a41aa6a956fb38caa267531383a7265717569726564426c6f636b496e64657875383a313134393233343475363a7479706549647531353a636f6d62696e6174696f6e4d61696c65647531303a626c6f636b496e64657875383a313134383035363375323a696431363a1463b76e102ce24e841f3f88020aa05275323a706931363a1463b76e102ce24e841f3f88020aa0527531383a7265717569726564426c6f636b496e64657875383a313134383035363375363a7479706549647531373a50726f6475637453656c6c65724d61696c65647531303a626c6f636b496e64657875383a313134393232343275313a666c6c647531333a646563696d616c506c61636573313a1275373a6d696e746572736e75363a7469636b657275373a4352595354414c656931353030303030303030303030303030303030303030303065656575323a696431363afa061a8852396448896835e2906fe61175313a6d7535313a7b22736561736f6e5f70617373223a207b226e223a205b32325d2c202270223a205b5d2c202274223a2022636c61696d227d7d7531383a7265717569726564426c6f636b496e64657875383a313134393232343275363a7479706549647531343a436c61696d4974656d734d61696c65647531303a626c6f636b496e64657875383a313134383035363375323a696431363ab966678b92d4424d99fde7bd69d2148775323a706931363ab966678b92d4424d99fde7bd69d214877531383a7265717569726564426c6f636b496e64657875383a313134383035363375363a7479706549647531373a50726f6475637453656c6c65724d61696c65647531303a626c6f636b496e64657875383a313134383035363375323a696431363ad88ca59d18c2ad409e257322e0e3f33475323a706931363ad88ca59d18c2ad409e257322e0e3f3347531383a7265717569726564426c6f636b496e64657875383a313134383035363375363a7479706549647531373a50726f6475637453656c6c65724d61696c65647531303a626c6f636b496e64657875383a313134373836333675323a696431363a05c08f9e2558b849be91dcea16e6d8a475323a706931363a05c08f9e2558b849be91dcea16e6d8a47531383a7265717569726564426c6f636b496e64657875383a313134373836333675363a7479706549647531373a50726f6475637453656c6c65724d61696c65647531303a6174746163686d656e74647531313a616374696f6e506f696e7475313a3075343a676f6c6469306575323a696431363a99257ba2c86ea4449a8ca8132be300f37531303a6974656d557361626c65647531303a62756666536b696c6c736c657531343a656c656d656e74616c5f7479706575343a57696e6475363a65715f65787075323a313075383a65717569707065646675353a677261646575313a3175323a696475383a313035313430303075363a6974656d496431363af2b0e55aa26e454984c09067ce4162827531333a6974656d5f7375625f7479706575343a52696e6775393a6974656d5f7479706575393a45717569706d656e7475353a6c6576656c75313a3075323a6f6375313a337531383a7265717569726564426c6f636b496e64657875383a313135303236383675363a7365745f696475313a3575363a736b696c6c736c657531393a7370696e655f7265736f757263655f7061746875383a313035313430303075343a737461746475343a74797065343a0300000075353a76616c756575333a3130376575383a73746174734d617064343a03000000647531353a6164646974696f6e616c56616c756575323a393475383a7374617454797065343a0300000075353a76616c756575333a31303765343a06000000647531353a6164646974696f6e616c56616c756575333a33393675383a7374617454797065343a0600000075353a76616c756575313a3065656575393a6d6174657269616c736c6475353a636f756e7475323a323475383a6d6174657269616c647531343a656c656d656e74616c5f7479706575363a4e6f726d616c75353a677261646575313a3175323a696475363a33303334303075373a6974656d5f696433323a45c8a87009caf8f9d3ecf58618fa6e2b14fe0edb2283d373e3c190c56eb96d8a7531333a6974656d5f7375625f747970657531373a45717569706d656e744d6174657269616c75393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a313275383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a57696e6475353a677261646575313a3175323a696475363a33303630343275373a6974656d5f696433323a31f48810fa91236281c165659d65003cfb611205a52c1ff6e02c019b86625dda7531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a343775383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a57696e6475353a677261646575313a3275323a696475363a33303630353075373a6974656d5f696433323adf0c212eb56526891629367fe889cfce0ea89a04e21d11a05b19ff9231802b4c7531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a373075383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a57696e6475353a677261646575313a3275323a696475363a33303630353175373a6974656d5f696433323a5eac6f2b799a1fc20a50f005f2df8783fefec63595787804b4418ece2b3d07177531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656575383a726563697065496475333a3133377531313a737562526563697065496475333a33323375363a7479706549647532343a636f6d62696e6174696f6e2e726573756c742d6d6f64656c657531303a626c6f636b496e64657875383a313134393232323975323a696431363a99257ba2c86ea4449a8ca8132be300f37531383a7265717569726564426c6f636b496e64657875383a313135303236383675363a7479706549647531353a636f6d62696e6174696f6e4d61696c65647531303a6174746163686d656e74647531313a616374696f6e506f696e7475313a3075343a676f6c6469306575323a696431363a6f177dabab873a4397f195fad7011e067531303a6974656d557361626c65647531303a62756666536b696c6c736c657531343a656c656d656e74616c5f7479706575343a4c616e6475363a65715f65787075313a3875383a65717569707065646675353a677261646575313a3175323a696475383a313034313330303075363a6974656d496431363ab84219dad196ff44a8f53e9bf494a01b7531333a6974656d5f7375625f7479706575383a4e65636b6c61636575393a6974656d5f7479706575393a45717569706d656e7475353a6c6576656c75313a3075323a6f6375313a337531383a7265717569726564426c6f636b496e64657875383a313134393033323175363a7365745f696475313a3475363a736b696c6c736c657531393a7370696e655f7265736f757263655f7061746875383a313034313330303075343a737461746475343a74797065343a0500000075353a76616c756575333a3335376575383a73746174734d617064343a03000000647531353a6164646974696f6e616c56616c756575323a323375383a7374617454797065343a0300000075353a76616c756575313a3065343a05000000647531353a6164646974696f6e616c56616c756575333a31373275383a7374617454797065343a0500000075353a76616c756575333a33353765656575393a6d6174657269616c736c6475353a636f756e7475323a313575383a6d6174657269616c647531343a656c656d656e74616c5f7479706575363a4e6f726d616c75353a677261646575313a3175323a696475363a33303333303075373a6974656d5f696433323a1bd96c8d5bce17827b894e01d4eb87bd853bc6a48baee9e6151ce568ae43ad397531333a6974656d5f7375625f747970657531373a45717569706d656e744d6174657269616c75393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323075383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630303975373a6974656d5f696433323a67f6ff0b0e20202a8e63742adf804355ceaee3ab636ed3065bd535985e7109a87531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323975383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630313075373a6974656d5f696433323ae0e69c7f4f16174438570e79ef52f5091ff761615a29dc70d3babbb4a099ce337531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323075383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630313175373a6974656d5f696433323a2d85afe3aa2e0ebc49df0149cf939feeddbfb9049a1e0c3bd7d8c00a948fece67531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656575383a726563697065496475333a3131317531313a737562526563697065496475333a32363075363a7479706549647532343a636f6d62696e6174696f6e2e726573756c742d6d6f64656c657531303a626c6f636b496e64657875383a313134383935393775323a696431363a6f177dabab873a4397f195fad7011e067531383a7265717569726564426c6f636b496e64657875383a313134393033323175363a7479706549647531353a636f6d62696e6174696f6e4d61696c65647531303a6174746163686d656e74647531313a616374696f6e506f696e7475313a3075343a676f6c6469306575323a696431363af3c9f6b3f36aa0488c73dc597a06b36c7531303a6974656d557361626c65647531303a62756666536b696c6c736c657531343a656c656d656e74616c5f7479706575343a4c616e6475363a65715f65787075313a3875383a65717569707065646675353a677261646575313a3175323a696475383a313034313330303075363a6974656d496431363a788c0c286da7c14abde5ded62de0f44d7531333a6974656d5f7375625f7479706575383a4e65636b6c61636575393a6974656d5f7479706575393a45717569706d656e7475353a6c6576656c75313a3075323a6f6375313a337531383a7265717569726564426c6f636b496e64657875383a313134383936323075363a7365745f696475313a3475363a736b696c6c736c6475363a6368616e636575313a3875353a706f77657275313a3075383a736b696c6c526f776475353a636f6d626f6675383a636f6f6c646f776e693235657531343a656c656d656e74616c5f7479706575363a4e6f726d616c75393a6869745f636f756e7469316575323a696469323430303030657531343a736b696c6c5f63617465676f727975373a486974427566667531373a736b696c6c5f7461726765745f7479706575343a53656c667531303a736b696c6c5f7479706575343a427566666565657531393a7370696e655f7265736f757263655f7061746875383a313034313330303075343a737461746475343a74797065343a0500000075353a76616c756575333a3335376575383a73746174734d617064343a03000000647531353a6164646974696f6e616c56616c756575323a333175383a7374617454797065343a0300000075353a76616c756575313a3065343a05000000647531353a6164646974696f6e616c56616c756575333a31303675383a7374617454797065343a0500000075353a76616c756575333a33353765656575393a6d6174657269616c736c6475353a636f756e7475323a313575383a6d6174657269616c647531343a656c656d656e74616c5f7479706575363a4e6f726d616c75353a677261646575313a3175323a696475363a33303333303075373a6974656d5f696433323a1bd96c8d5bce17827b894e01d4eb87bd853bc6a48baee9e6151ce568ae43ad397531333a6974656d5f7375625f747970657531373a45717569706d656e744d6174657269616c75393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323075383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630303975373a6974656d5f696433323a67f6ff0b0e20202a8e63742adf804355ceaee3ab636ed3065bd535985e7109a87531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323975383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630313075373a6974656d5f696433323ae0e69c7f4f16174438570e79ef52f5091ff761615a29dc70d3babbb4a099ce337531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323075383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630313175373a6974656d5f696433323a2d85afe3aa2e0ebc49df0149cf939feeddbfb9049a1e0c3bd7d8c00a948fece67531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656575383a726563697065496475333a3131317531313a737562526563697065496475333a32363075363a7479706549647532343a636f6d62696e6174696f6e2e726573756c742d6d6f64656c657531303a626c6f636b496e64657875383a313134383936303075323a696431363af3c9f6b3f36aa0488c73dc597a06b36c7531383a7265717569726564426c6f636b496e64657875383a313134383936323075363a7479706549647531353a636f6d62696e6174696f6e4d61696c65647531303a6174746163686d656e74647531313a616374696f6e506f696e7475313a3075313a636c647531333a646563696d616c506c61636573313a1275373a6d696e746572736e75363a7469636b657275373a4352595354414c65693065657531373a656e68616e63656d656e74526573756c7475373a5375636365737375343a676f6c6469306575323a696431363a360225bce61f584cb67a5f45441797eb7531303a6974656d557361626c65647531303a62756666536b696c6c736c657531343a656c656d656e74616c5f7479706575343a57696e6475363a65715f65787075333a36343075383a65717569707065646675353a677261646575313a3275323a696475383a313031323430303075363a6974656d496431363abb94ea9d0a698e4581e9e177e9efbd017531333a6974656d5f7375625f7479706575363a576561706f6e75393a6974656d5f7479706575393a45717569706d656e7475353a6c6576656c75313a3275323a6f6375313a337531383a7265717569726564426c6f636b496e64657875383a313134383134353275363a7365745f696475323a313075363a736b696c6c736c6475363a6368616e636575323a323875353a706f77657275343a3336353775383a736b696c6c526f776475353a636f6d626f6675383a636f6f6c646f776e6933657531343a656c656d656e74616c5f7479706575343a57696e6475393a6869745f636f756e7469326575323a696469313430303033657531343a736b696c6c5f63617465676f72797531323a446f75626c6541747461636b7531373a736b696c6c5f7461726765745f7479706575353a456e656d797531303a736b696c6c5f7479706575363a41747461636b6565657531393a7370696e655f7265736f757263655f7061746875383a313031323430303075343a737461746475343a74797065343a0200000075353a76616c756575333a3332376575383a73746174734d617064343a02000000647531353a6164646974696f6e616c56616c75657531323a3131372e303030303030303075383a7374617454797065343a0200000075353a76616c756575383a3339302e3533373665343a06000000647531353a6164646974696f6e616c56616c75657531323a3439382e303030303030303075383a7374617454797065343a0600000075353a76616c756575313a306565657531383a6d6174657269616c4974656d49644c6973746c31363aa30c9f43ac29414abdc8e2e2cac3a6e131363ac2746f747d8e964791104ce99ccc779931363a71acadf8602fbf4ab80c58f1c1329c33657531333a7072654974656d557361626c65647531303a62756666536b696c6c736c657531343a656c656d656e74616c5f7479706575343a57696e6475363a65715f65787075333a31383075383a65717569707065646675353a677261646575313a3275323a696475383a313031323430303075363a6974656d496431363abb94ea9d0a698e4581e9e177e9efbd017531333a6974656d5f7375625f7479706575363a576561706f6e75393a6974656d5f7479706575393a45717569706d656e7475353a6c6576656c75313a3075323a6f6375313a337531383a7265717569726564426c6f636b496e64657875383a313134363938333075363a7365745f696475323a313075363a736b696c6c736c6475363a6368616e636575323a323875353a706f77657275343a3336353775383a736b696c6c526f776475353a636f6d626f6675383a636f6f6c646f776e6933657531343a656c656d656e74616c5f7479706575343a57696e6475393a6869745f636f756e7469326575323a696469313430303033657531343a736b696c6c5f63617465676f72797531323a446f75626c6541747461636b7531373a736b696c6c5f7461726765745f7479706575353a456e656d797531303a736b696c6c5f7479706575363a41747461636b6565657531393a7370696e655f7265736f757263655f7061746875383a313031323430303075343a737461746475343a74797065343a0200000075353a76616c756575333a3332376575383a73746174734d617064343a02000000647531353a6164646974696f6e616c56616c756575333a31313775383a7374617454797065343a0200000075353a76616c756575333a33323765343a06000000647531353a6164646974696f6e616c56616c756575333a34393875383a7374617454797065343a0600000075353a76616c756575313a3065656575363a7479706549647532353a6974656d5f656e68616e63656d656e7431332e726573756c74657531303a626c6f636b496e64657875383a313134383133303275323a696431363a360225bce61f584cb67a5f45441797eb7531383a7265717569726564426c6f636b496e64657875383a313134383134353275363a7479706549647531313a6974656d456e68616e636565647531303a6174746163686d656e74647531313a616374696f6e506f696e7475313a3075343a676f6c6469306575323a696431363a83ca3ec0f936834b8e68d82f1a74023e7531303a6974656d557361626c65647531303a62756666536b696c6c736c657531343a656c656d656e74616c5f7479706575343a57696e6475363a65715f65787075323a313075383a65717569707065646675353a677261646575313a3175323a696475383a313035313430303075363a6974656d496431363a171b65986137df448b463fd62824e4997531333a6974656d5f7375625f7479706575343a52696e6775393a6974656d5f7479706575393a45717569706d656e7475353a6c6576656c75313a3075323a6f6375313a337531383a7265717569726564426c6f636b496e64657875383a313135303032313975363a7365745f696475313a3575363a736b696c6c736c657531393a7370696e655f7265736f757263655f7061746875383a313035313430303075343a737461746475343a74797065343a0300000075353a76616c756575333a3130376575383a73746174734d617064343a03000000647531353a6164646974696f6e616c56616c756575323a393475383a7374617454797065343a0300000075353a76616c756575333a31303765343a06000000647531353a6164646974696f6e616c56616c756575333a33373475383a7374617454797065343a0600000075353a76616c756575313a3065656575393a6d6174657269616c736c6475353a636f756e7475323a323475383a6d6174657269616c647531343a656c656d656e74616c5f7479706575363a4e6f726d616c75353a677261646575313a3175323a696475363a33303334303075373a6974656d5f696433323a45c8a87009caf8f9d3ecf58618fa6e2b14fe0edb2283d373e3c190c56eb96d8a7531333a6974656d5f7375625f747970657531373a45717569706d656e744d6174657269616c75393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a313275383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a57696e6475353a677261646575313a3175323a696475363a33303630343275373a6974656d5f696433323a31f48810fa91236281c165659d65003cfb611205a52c1ff6e02c019b86625dda7531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a343775383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a57696e6475353a677261646575313a3275323a696475363a33303630353075373a6974656d5f696433323adf0c212eb56526891629367fe889cfce0ea89a04e21d11a05b19ff9231802b4c7531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a373075383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a57696e6475353a677261646575313a3275323a696475363a33303630353175373a6974656d5f696433323a5eac6f2b799a1fc20a50f005f2df8783fefec63595787804b4418ece2b3d07177531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656575383a726563697065496475333a3133377531313a737562526563697065496475333a33323375363a7479706549647532343a636f6d62696e6174696f6e2e726573756c742d6d6f64656c657531303a626c6f636b496e64657875383a313134383937363275323a696431363a83ca3ec0f936834b8e68d82f1a74023e7531383a7265717569726564426c6f636b496e64657875383a313135303032313975363a7479706549647531353a636f6d62696e6174696f6e4d61696c65647531303a6174746163686d656e74647531313a616374696f6e506f696e7475313a3075343a676f6c6469306575323a696431363a410bdbc1e7784944a326a7c33283949c7531303a6974656d557361626c65647531303a62756666536b696c6c736c657531343a656c656d656e74616c5f7479706575343a4c616e6475363a65715f65787075313a3875383a65717569707065646675353a677261646575313a3175323a696475383a313034313330303075363a6974656d496431363a11eaf70e63890447894dacb39c8402d07531333a6974656d5f7375625f7479706575383a4e65636b6c61636575393a6974656d5f7479706575393a45717569706d656e7475353a6c6576656c75313a3075323a6f6375313a327531383a7265717569726564426c6f636b496e64657875383a313134383139313675363a7365745f696475313a3475363a736b696c6c736c657531393a7370696e655f7265736f757263655f7061746875383a313034313330303075343a737461746475343a74797065343a0500000075353a76616c756575333a3335376575383a73746174734d617064343a03000000647531353a6164646974696f6e616c56616c756575323a323875383a7374617454797065343a0300000075353a76616c756575313a3065343a05000000647531353a6164646974696f6e616c56616c756575333a31313075383a7374617454797065343a0500000075353a76616c756575333a33353765656575393a6d6174657269616c736c6475353a636f756e7475323a313575383a6d6174657269616c647531343a656c656d656e74616c5f7479706575363a4e6f726d616c75353a677261646575313a3175323a696475363a33303333303075373a6974656d5f696433323a1bd96c8d5bce17827b894e01d4eb87bd853bc6a48baee9e6151ce568ae43ad397531333a6974656d5f7375625f747970657531373a45717569706d656e744d6174657269616c75393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323075383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630303975373a6974656d5f696433323a67f6ff0b0e20202a8e63742adf804355ceaee3ab636ed3065bd535985e7109a87531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323975383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630313075373a6974656d5f696433323ae0e69c7f4f16174438570e79ef52f5091ff761615a29dc70d3babbb4a099ce337531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323075383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630313175373a6974656d5f696433323a2d85afe3aa2e0ebc49df0149cf939feeddbfb9049a1e0c3bd7d8c00a948fece67531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656575383a726563697065496475333a3131317531313a737562526563697065496475333a32363075363a7479706549647532343a636f6d62696e6174696f6e2e726573756c742d6d6f64656c657531303a626c6f636b496e64657875383a313134383133303775323a696431363a410bdbc1e7784944a326a7c33283949c7531383a7265717569726564426c6f636b496e64657875383a313134383139313675363a7479706549647531353a636f6d62696e6174696f6e4d61696c65647531303a6174746163686d656e74647531313a616374696f6e506f696e7475313a3075343a676f6c6469306575323a696431363a70fe8ac41b84c746859508c0892a6c907531303a6974656d557361626c65647531303a62756666536b696c6c736c657531343a656c656d656e74616c5f7479706575363a4e6f726d616c75363a65715f65787075313a3575383a65717569707065646675353a677261646575313a3175323a696475383a313035313030303075363a6974656d496431363aa0490f2ce8a1cd47ad9d579a9e9304a07531333a6974656d5f7375625f7479706575343a52696e6775393a6974656d5f7479706575393a45717569706d656e7475353a6c6576656c75313a3075323a6f6375313a337531383a7265717569726564426c6f636b496e64657875383a313134383334363175363a7365745f696475313a3175363a736b696c6c736c657531393a7370696e655f7265736f757263655f7061746875383a313035313030303075343a737461746475343a74797065343a0300000075353a76616c756575313a386575383a73746174734d617064343a02000000647531353a6164646974696f6e616c56616c756575313a3775383a7374617454797065343a0200000075353a76616c756575313a3065343a03000000647531353a6164646974696f6e616c56616c756575313a3675383a7374617454797065343a0300000075353a76616c756575313a3865656575393a6d6174657269616c736c6475353a636f756e7475313a3275383a6d6174657269616c647531343a656c656d656e74616c5f7479706575363a4e6f726d616c75353a677261646575313a3175323a696475363a33303334303075373a6974656d5f696433323a45c8a87009caf8f9d3ecf58618fa6e2b14fe0edb2283d373e3c190c56eb96d8a7531333a6974656d5f7375625f747970657531373a45717569706d656e744d6174657269616c75393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475313a3275383a6d6174657269616c647531343a656c656d656e74616c5f7479706575353a576174657275353a677261646575313a3175323a696475363a33303630303175373a6974656d5f696433323a77cfad5273885820b69e61c2106ae06583f69c7f6d82a229b59e5f1b984164be7531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475313a3275383a6d6174657269616c647531343a656c656d656e74616c5f7479706575353a576174657275353a677261646575313a3175323a696475363a33303630303275373a6974656d5f696433323a28a2c38b0934225a8f2327b9bd8cf7c7eaf3551bde8203f44248c011938e97707531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475313a3175383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4669726575353a677261646575313a3175323a696475363a33303630323375373a6974656d5f696433323a1af5e747fc81a7f3149af024db2e5025b6749a000d66b22e665acdd45b8dbd177531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656575383a726563697065496475333a3133337531313a737562526563697065496475333a34353875363a7479706549647532343a636f6d62696e6174696f6e2e726573756c742d6d6f64656c657531303a626c6f636b496e64657875383a313134383334353375323a696431363a70fe8ac41b84c746859508c0892a6c907531383a7265717569726564426c6f636b496e64657875383a313134383334363175363a7479706549647531353a636f6d62696e6174696f6e4d61696c65647531303a6174746163686d656e74647531313a616374696f6e506f696e7475313a3075343a676f6c6469306575323a696431363ac11851cdf4576d49a113d7d756ed35897531303a6974656d557361626c65647531303a62756666536b696c6c736c657531343a656c656d656e74616c5f7479706575343a4c616e6475363a65715f65787075313a3875383a65717569707065646675353a677261646575313a3175323a696475383a313034313330303075363a6974656d496431363a7f45c50e8c9cdc48b87b1c28af3559707531333a6974656d5f7375625f7479706575383a4e65636b6c61636575393a6974656d5f7479706575393a45717569706d656e7475353a6c6576656c75313a3075323a6f6375313a337531383a7265717569726564426c6f636b496e64657875383a313134383230333275363a7365745f696475313a3475363a736b696c6c736c657531393a7370696e655f7265736f757263655f7061746875383a313034313330303075343a737461746475343a74797065343a0500000075353a76616c756575333a3335376575383a73746174734d617064343a03000000647531353a6164646974696f6e616c56616c756575323a323875383a7374617454797065343a0300000075353a76616c756575313a3065343a05000000647531353a6164646974696f6e616c56616c756575333a31383475383a7374617454797065343a0500000075353a76616c756575333a33353765656575393a6d6174657269616c736c6475353a636f756e7475323a313575383a6d6174657269616c647531343a656c656d656e74616c5f7479706575363a4e6f726d616c75353a677261646575313a3175323a696475363a33303333303075373a6974656d5f696433323a1bd96c8d5bce17827b894e01d4eb87bd853bc6a48baee9e6151ce568ae43ad397531333a6974656d5f7375625f747970657531373a45717569706d656e744d6174657269616c75393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323075383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630303975373a6974656d5f696433323a67f6ff0b0e20202a8e63742adf804355ceaee3ab636ed3065bd535985e7109a87531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323975383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630313075373a6974656d5f696433323ae0e69c7f4f16174438570e79ef52f5091ff761615a29dc70d3babbb4a099ce337531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323075383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630313175373a6974656d5f696433323a2d85afe3aa2e0ebc49df0149cf939feeddbfb9049a1e0c3bd7d8c00a948fece67531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656575383a726563697065496475333a3131317531313a737562526563697065496475333a32363075363a7479706549647532343a636f6d62696e6174696f6e2e726573756c742d6d6f64656c657531303a626c6f636b496e64657875383a313134383133303875323a696431363ac11851cdf4576d49a113d7d756ed35897531383a7265717569726564426c6f636b496e64657875383a313134383230333275363a7479706549647531353a636f6d62696e6174696f6e4d61696c65647531303a6174746163686d656e74647531313a616374696f6e506f696e7475313a3075343a676f6c6469306575323a696431363ab21cf1d3f2538e4c9496080cb00216657531303a6974656d557361626c65647531303a62756666536b696c6c736c657531343a656c656d656e74616c5f7479706575343a4c616e6475363a65715f65787075313a3875383a65717569707065646675353a677261646575313a3175323a696475383a313034313330303075363a6974656d496431363ad5f36402d57e214691607fa35606e5297531333a6974656d5f7375625f7479706575383a4e65636b6c61636575393a6974656d5f7479706575393a45717569706d656e7475353a6c6576656c75313a3075323a6f6375313a327531383a7265717569726564426c6f636b496e64657875383a313134383139313575363a7365745f696475313a3475363a736b696c6c736c657531393a7370696e655f7265736f757263655f7061746875383a313034313330303075343a737461746475343a74797065343a0500000075353a76616c756575333a3335376575383a73746174734d617064343a03000000647531353a6164646974696f6e616c56616c756575323a333075383a7374617454797065343a0300000075353a76616c756575313a3065343a05000000647531353a6164646974696f6e616c56616c756575333a31313675383a7374617454797065343a0500000075353a76616c756575333a33353765656575393a6d6174657269616c736c6475353a636f756e7475323a313575383a6d6174657269616c647531343a656c656d656e74616c5f7479706575363a4e6f726d616c75353a677261646575313a3175323a696475363a33303333303075373a6974656d5f696433323a1bd96c8d5bce17827b894e01d4eb87bd853bc6a48baee9e6151ce568ae43ad397531333a6974656d5f7375625f747970657531373a45717569706d656e744d6174657269616c75393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323075383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630303975373a6974656d5f696433323a67f6ff0b0e20202a8e63742adf804355ceaee3ab636ed3065bd535985e7109a87531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323975383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630313075373a6974656d5f696433323ae0e69c7f4f16174438570e79ef52f5091ff761615a29dc70d3babbb4a099ce337531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323075383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630313175373a6974656d5f696433323a2d85afe3aa2e0ebc49df0149cf939feeddbfb9049a1e0c3bd7d8c00a948fece67531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656575383a726563697065496475333a3131317531313a737562526563697065496475333a32363075363a7479706549647532343a636f6d62696e6174696f6e2e726573756c742d6d6f64656c657531303a626c6f636b496e64657875383a313134383133303675323a696431363ab21cf1d3f2538e4c9496080cb00216657531383a7265717569726564426c6f636b496e64657875383a313134383139313575363a7479706549647531353a636f6d62696e6174696f6e4d61696c65647531303a6174746163686d656e74647531313a616374696f6e506f696e7475313a3075343a676f6c6469306575323a696431363a885a5cdfbb73604e99edf84bb44705387531303a6974656d557361626c65647531303a62756666536b696c6c736c657531343a656c656d656e74616c5f7479706575343a57696e6475363a65715f65787075323a313075383a65717569707065646675353a677261646575313a3175323a696475383a313035313430303075363a6974656d496431363af48685a80203184fb5b78808f005198e7531333a6974656d5f7375625f7479706575343a52696e6775393a6974656d5f7479706575393a45717569706d656e7475353a6c6576656c75313a3075323a6f6375313a327531383a7265717569726564426c6f636b496e64657875383a313134393138323175363a7365745f696475313a3575363a736b696c6c736c657531393a7370696e655f7265736f757263655f7061746875383a313035313430303075343a737461746475343a74797065343a0300000075353a76616c756575333a3130376575383a73746174734d617064343a03000000647531353a6164646974696f6e616c56616c756575323a343775383a7374617454797065343a0300000075353a76616c756575333a31303765343a06000000647531353a6164646974696f6e616c56616c756575333a34343275383a7374617454797065343a0600000075353a76616c756575313a3065656575393a6d6174657269616c736c6475353a636f756e7475323a323475383a6d6174657269616c647531343a656c656d656e74616c5f7479706575363a4e6f726d616c75353a677261646575313a3175323a696475363a33303334303075373a6974656d5f696433323a45c8a87009caf8f9d3ecf58618fa6e2b14fe0edb2283d373e3c190c56eb96d8a7531333a6974656d5f7375625f747970657531373a45717569706d656e744d6174657269616c75393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a313275383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a57696e6475353a677261646575313a3175323a696475363a33303630343275373a6974656d5f696433323a31f48810fa91236281c165659d65003cfb611205a52c1ff6e02c019b86625dda7531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a343775383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a57696e6475353a677261646575313a3275323a696475363a33303630353075373a6974656d5f696433323adf0c212eb56526891629367fe889cfce0ea89a04e21d11a05b19ff9231802b4c7531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a373075383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a57696e6475353a677261646575313a3275323a696475363a33303630353175373a6974656d5f696433323a5eac6f2b799a1fc20a50f005f2df8783fefec63595787804b4418ece2b3d07177531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656575383a726563697065496475333a3133377531313a737562526563697065496475333a33323375363a7479706549647532343a636f6d62696e6174696f6e2e726573756c742d6d6f64656c657531303a626c6f636b496e64657875383a313134383334353575323a696431363a885a5cdfbb73604e99edf84bb44705387531383a7265717569726564426c6f636b496e64657875383a313134393138323175363a7479706549647531353a636f6d62696e6174696f6e4d61696c6565693131343932333234656939383832333735656930656475313a3175313a3175323a313075313a3175333a31303075333a32303375333a31303175313a3175333a31303275333a31343875333a31303375323a313175333a31303475313a3575333a31303575313a3275333a31303675313a3175333a31303775313a3275333a31303875313a3175333a31303975323a313075323a313175313a3175333a31313075323a313175333a31313175313a3975333a31313275313a3175333a31313375313a3175333a31313475313a3175333a31313575313a3175333a31313675313a3175333a31313775313a3175333a31313875313a3175333a31313975313a3175323a313275313a3175333a31323075313a3175333a31323175313a3175333a31323275313a3175333a31323375313a3175333a31323475313a3175333a31323575313a3175333a31323675313a3175333a31323775313a3175333a31323875313a3175333a31323975313a3175323a313375313a3175333a31333075313a3175333a31333175313a3175333a31333275313a3175333a31333375313a3175333a31333475313a3175333a31333575313a3175333a31333675313a3175333a31333775313a3175333a31333875313a3175333a31333975313a3175323a313475313a3175333a31343075313a3175333a31343175313a3175333a31343275313a3175333a31343375313a3175333a31343475313a3175333a31343575313a3175333a31343675313a3175333a31343775313a3175333a31343875313a3275333a31343975313a3475323a313575323a313275333a31353075323a333475333a31353175343a3130373275333a31353275313a3175333a31353375313a3275333a31353475313a3175333a31353575313a3175333a31353675323a313175333a31353775313a3275333a31353875313a3175333a31353975323a313975323a313675313a3175333a31363075313a3175333a31363175313a3275333a31363275323a313875333a31363375313a3175333a31363475313a3175333a31363575313a3175333a31363675313a3175333a31363775323a313575333a31363875313a3375333a31363975313a3275323a313775313a3175333a31373075323a313275333a31373175323a333275333a31373275313a3175333a31373375333a37383775333a31373475333a31373375333a31373575333a32303475333a31373675313a3775333a31373775313a3775333a31373875313a3275333a31373975313a3175323a313875313a3675333a31383075323a313075333a31383175323a313875333a31383275323a323575333a31383375313a3175333a31383475313a3175333a31383575313a3175333a31383675313a3175333a31383775313a3175333a31383875313a3175333a31383975313a3175323a313975313a3175333a31393075313a3175333a31393175313a3175333a31393275313a3175333a31393375313a3175333a31393475313a3175333a31393575323a323375333a31393675323a323475333a31393775313a3175333a31393875313a3175333a31393975313a3175313a3275313a3175323a323075313a3175333a32303075313a3275333a32303175313a3175333a32303275313a3175333a32303375313a3175333a32303475313a3175333a32303575313a3175333a32303675313a3175333a32303775313a3275333a32303875323a323175333a32303975313a3175323a323175313a3275333a32313075313a3175333a32313175313a3175333a32313275313a3175333a32313375313a3175333a32313475313a3175333a32313575313a3175333a32313675313a3175333a32313775323a313275333a32313875313a3175333a32313975313a3975323a323275313a3175333a32323075313a3375333a32323175313a3175333a32323275313a3175333a32323375313a3175333a32323475313a3175333a32323575313a3175333a32323675313a3175333a32323775313a3175333a32323875313a3175333a32323975313a3175323a323375313a3375333a32333075313a3275333a32333175313a3175333a32333275313a3175333a32333375313a3175333a32333475313a3175333a32333575313a3175333a32333675313a3175333a32333775313a3175333a32333875313a3175333a32333975313a3175323a323475313a3475333a32343075313a3175333a32343175313a3175333a32343275313a3175333a32343375313a3175333a32343475313a3175333a32343575313a3175333a32343675313a3175333a32343775313a3175333a32343875313a3175333a32343975313a3275323a323575313a3175333a32353075313a3175333a32353175313a3175333a32353275313a3175333a32353375313a3175333a32353475323a313675333a32353575313a3175333a32353675313a3175333a32353775313a3175333a32353875313a3175333a32353975313a3175323a323675313a3175333a32363075313a3175333a32363175313a3175333a32363275313a3175333a32363375313a3175333a32363475313a3175333a32363575313a3175333a32363675313a3175333a32363775313a3175333a32363875313a3175333a32363975313a3175323a323775323a343075333a32373075313a3175333a32373175313a3175333a32373275313a3175333a32373375313a3175333a32373475313a3175333a32373575313a3175333a32373675313a3175333a32373775313a3175333a32373875313a3175333a32373975313a3175323a323875323a333075333a32383075323a313275333a32383175313a3175333a32383275313a3175333a32383375313a3175333a32383475313a3175333a32383575313a3175333a32383675313a3175333a32383775313a3175333a32383875313a3175333a32383975323a333075323a323975313a3175333a32393075313a3175333a32393175313a3175333a32393275313a3175333a32393375313a3175333a32393475313a3175333a32393575323a313975333a32393675313a3775333a32393775313a3175333a32393875313a3775333a32393975313a3175313a3375313a3175323a333075313a3175333a33303075313a3875333a33303175313a3175333a33303275313a3175333a33303375313a3175333a33303475313a3175333a33303575313a3175333a33303675313a3175333a33303775313a3175333a33303875313a3175333a33303975313a3175323a333175313a3375333a33313075313a3175333a33313175313a3175333a33313275313a3175333a33313375313a3175333a33313475313a3175333a33313575313a3175333a33313675313a3175333a33313775313a3175333a33313875313a3175333a33313975313a3175323a333275313a3775333a33323075313a3175333a33323175313a3175333a33323275313a3175333a33323375313a3175333a33323475313a3175333a33323575313a3275333a33323675313a3175333a33323775313a3175333a33323875313a3175333a33323975313a3175323a333375313a3175333a33333075313a3175333a33333175313a3375333a33333275313a3175323a333475313a3375323a333575313a3175323a333675313a3875323a333775313a3375323a333875313a3975323a333975313a3175313a3475313a3175323a343075313a3175323a343175313a3175323a343275313a3175323a343375313a3375323a343475313a3275323a343575313a3175323a343675313a3175323a343775313a3175323a343875313a3175323a343975313a3275313a3575313a3175323a353075313a3175323a353175313a3675323a353275333a31373375323a353375333a34323175323a353475313a3375323a353575333a31353775323a353675313a3775323a353775323a323275323a353875313a3275323a353975313a3275313a3675313a3175323a363075313a3175323a363175313a3175323a363275313a3175323a363375333a31363775323a363475323a353675323a363575323a343175323a363675323a313775323a363775323a323075323a363875323a353775323a363975313a3875313a3775313a3175323a373075323a323275323a373175313a3875323a373275323a323775323a373375333a32313075323a373475323a383275323a373575333a31353275323a373675323a323875323a373775323a343575323a373875323a323175323a373975323a313575313a3875313a3175323a383075323a313475323a383175323a323275323a383275323a313175323a383375323a373275323a383475313a3775323a383575323a313475323a383675313a3675323a383775313a3375323a383875313a3275323a383975313a3275313a3975313a3275323a393075313a3275323a393175313a3275323a393275313a3275323a393375313a3175323a393475313a3175323a393575313a3275323a393675313a3175323a393775313a3975323a393875313a3475323a393975313a33656475363a32303130303075333a36333975363a32303130303175333a31383575363a32303130303275333a32343075363a32303130303375323a393875363a32303130303475333a31353775363a32303130303575313a3175363a32303130303675313a3775363a32303130303775323a323075363a32303130303875323a313575363a32303230303075343a3531373675363a32303230303175343a3432303375363a32303230303275343a3135393575363a32303230303375333a34343775363a32303230303475333a34353975363a32303230303575343a3133303875363a32303230303675323a323075363a32303230303775333a32303375363a32303330303075343a3138303675363a32303330303175333a33333275363a32303330303275333a33383375363a32303330303375323a353675363a32303330303475323a333975363a32303330303575323a323475363a32303330303675323a313075363a32303330303775323a333475363a32303430303075343a3530333075363a32303430303175333a33383775363a32303430303275343a3133363475363a32303430313075343a3237303475363a32303430313175333a39373775363a32303430313275343a3331373575363a32303430313375343a3433313475363a32303430323075343a3138333475363a32303430323175333a32343375363a32303430323275333a33323275363a32303430323375343a3133303275363a32303530303075343a3833353375363a32303530303175353a313038373775363a32303530303275343a3237363975363a32303530303375333a37303875363a32303530303475323a363075363a32303530303575333a38393475363a32303530303675323a333075363a32303530303775313a3275363a32303630303075343a3136383675363a32303630303175343a3135393775363a32303630303275333a36363775363a32303630303375333a31373175363a32303630303475333a31333675363a32303630303575323a373575363a32303630303675313a3675363a32303630303775313a3175363a32303730303075343a3135353875363a32303730303175343a3131343575363a32303730303275333a36343475363a32303730303375333a38393775363a32303730303475333a33353075363a32303730303575333a32313475363a32303730303675323a323375363a32303730303775313a3875363a32303830303075343a3231353375363a32303830303175343a3135373775363a32303830303275343a3233323775363a32303830303375333a35353275363a32303830303475333a33393375363a32303830303575313a32656475383a313031313030303075323a313375383a313031313130303075313a3375383a313031313230303075313a3275383a313031313330303075313a3175383a313031313430303075323a313275383a313031323030303075323a333475383a313031323130303075313a3775383a313031323230303075313a3875383a313031323330303075313a3175383a313031323430303075323a373475383a313031333030303075333a34333675383a313031333030303175323a313875383a313031333130303075313a3975383a313031333130303175313a3175383a313031333230303075313a3575383a313031333230303175323a313675383a313031333330303075323a313475383a313031333330303175323a313375383a313031333430303075313a3875383a313031333430303175313a3475383a313031343030303075313a3175383a313031343130303075323a313375383a313031343330303075313a3875383a313031353130303075313a3475383a313032313030303075313a3375383a313032313130303075323a313475383a313032313230303075323a313675383a313032313330303075313a3375383a313032313430303075313a3475383a313032323030303075333a31303975383a313032323130303075323a313175383a313032323230303075313a3775383a313032323330303075313a3175383a313032323430303075323a353875383a313032333030303075323a313675383a313032333030303175313a3375383a313032333130303075313a3175383a313032333130303175323a313475383a313032333230303075313a3175383a313032333230303175323a313775383a313032333330303075313a3375383a313032333330303175313a3975383a313032333430303075313a3575383a313032343130303075313a3375383a313032343330303075313a3475383a313032353230303175313a3475383a313033313030303075313a3175383a313033313130303075313a3375383a313033313230303075313a3375383a313033313330303075313a3775383a313033313430303075313a3675383a313033323030303075323a313075383a313033323130303075313a3275383a313033323230303075313a3375383a313033323330303075323a323475383a313033323430303075313a3175383a313033333030303075323a313075383a313033333130303075323a313675383a313033333230303075313a3475383a313033333330303075313a3475383a313033333430303075313a3375383a313033343030303075333a31333775383a313033343130303075313a3775383a313033343330303075313a3175383a313033343430303075313a3175383a313033353130303175313a3475383a313033353330303075313a3275383a313033353430303075313a3175383a313033353430303175313a3275383a313034313030303075313a3175383a313034313130303075313a3775383a313034313230303075313a3275383a313034313330303075323a313075383a313034313430303075313a3175383a313034323030303075323a383775383a313034323130303075323a313175383a313034323230303075313a3775383a313034323330303075323a323575383a313034333030303075323a383375383a313034333130303075313a3175383a313034333230303075323a313875383a313034333330303075313a3875383a313034343030303075313a3275383a313034343430303075313a3175383a313034353130303075323a313075383a313034353130303175313a3275383a313034353230303175313a3175383a313034353330303075313a3175383a313034353430303075313a3175383a313035313030303075323a313775383a313035313130303075313a3375383a313035313230303075313a3275383a313035313330303075313a3175383a313035313430303075323a353875383a313035323030303075323a323975383a313035323130303075323a313075383a313035323230303075323a313275383a313035323330303075313a3875383a313035323430303075323a313575383a313035333030303075333a31333375383a313035333130303075313a3775383a313035333230303075323a313275383a313035333330303075313a3875383a313035333430303075313a3375383a313035343030303075313a3175383a313035343330303075313a3175383a313035343430303075323a313675383a313035353130303075313a3275383a313036313030303075333a34383375383a313036323030303075333a32343275383a313036323030303175323a323675383a313036323030303275323a323075383a313036323030303375323a313675383a313036333030303075323a323975383a313036333030303175313a3775383a313036333030303275313a3975383a313036333030303375323a313075383a313036343030303275313a3175383a313230303130303175323a323475383a313230303130303275323a313275383a313230303130303375313a3675363a32303130303075313a3975363a32303130303175323a363775363a32303130303275313a3475363a32303130303375323a313075363a32303130303575323a313375363a32303130303675313a3675363a32303130303875313a3875363a32303130303975313a3775363a32303130313075313a3975363a32303130313175313a3475363a32303130313275313a3375363a32303130313375313a3275363a32303130313575323a343275363a32303130313675313a3575363a32303130313875323a373475363a32303130313975313a3575363a32303130323175323a383775363a32303130323275323a323575363a32303130323375313a3575363a32303130323475313a3775363a32303130323575323a343675363a32303130323675313a3575363a32303130323775313a3775363a33303230303075323a323375363a33303230303175323a313575363a33303230303275323a313675363a33303230303375323a343975363a33303230303475323a323875363a33303230303575323a313775363a33303230303675323a313175363a33303230303875323a313875363a33303230303975323a313075363a33303330303075323a373675363a33303330303175333a35373175363a33303330303275343a3230373575363a33303330303375333a32373775363a33303330303475333a31383675363a33303331303075323a323475363a33303331303175333a34323775363a33303331303275333a38393375363a33303331303375323a393975363a33303331303475313a3775363a33303332303075323a343275363a33303332303175333a32313575363a33303332303275343a3135303575363a33303332303375333a31363275363a33303332303475333a31323975363a33303333303075323a343175363a33303333303175333a33373675363a33303333303275333a35363675363a33303333303375323a353975363a33303333303475323a343775363a33303334303075333a32373375363a33303334303175333a33333775363a33303334303275343a3136363575363a33303334303375333a32313075363a33303334303475323a333475363a33303430303075313a3175363a33303430303175313a3175363a33303430303275313a3175363a33303430303375313a3175363a33303630303075333a31343775363a33303630303175333a31313075363a33303630303275323a373775363a33303630303375333a31343575363a33303630303475333a31353975363a33303630303575323a373075363a33303630303675333a31383775363a33303630303775323a393775363a33303630303875343a3130393475363a33303630303975333a31343975363a33303630313075333a33393675363a33303630313175323a363775363a33303630313275333a33333275363a33303630313375333a33303975363a33303630313475333a31343575363a33303630313575343a3138303275363a33303630313675333a31303575363a33303630313775333a31303175363a33303630323375333a33303175363a33303630323475333a32313775363a33303630323575333a31343175363a33303630323675333a33353475363a33303630323775333a32313675363a33303630323875333a31363075363a33303630323975333a34383375363a33303630333075333a32313275363a33303630333175323a353275363a33303630333575343a3135333575363a33303630333675333a31373375363a33303630333775333a37313775363a33303630333875333a32373175363a33303630333975333a32353975363a33303630343075343a3334363975363a33303630343175333a38303375363a33303630343275343a3232333375363a33303630343375333a35373575363a33303630343475333a34303075363a33303630343575323a393475363a33303630343675323a323375363a33303630343775313a3275363a33303630343875323a313675363a33303630343975313a3975363a33303630353075343a3136323575363a33303630353175343a3132383175363a33303630353275333a36353975363a33303630353375333a37323275363a33303630353475333a36353375363a33303630353575333a34313475363a33303630373075333a31303675363a33303630373275313a3175363a33303630373375323a343175363a33303630373475313a3575363a33303630373575313a3675363a33303630373675313a3575363a33303630373775313a3475363a33303630373875313a3875363a33303630373975323a373875363a33303630383075333a37393775363a33303630383175333a33313575363a34303030303075373a3132303738343075363a35303030303075343a3635363875363a36303031303175313a3275363a36303031303275313a33656475313a3075313a3175313a3175333a34343775313a3275333a32333475313a3375343a3438393375313a3475333a35323975313a3575343a3231303875313a3675333a343530656931656931656939656937656c32303a25ff1be7d26b566a17a406ae8825de3a52034b1132303a68f8b334d7429661c95cb2283628c14da722be7d32303a74573255a354a272c5650b58645427a00ce7e1f132303af69af3454d83ea6f512a8398aac66e2c17ec07ff6532303aae75ca68c5bb8583c379348de5e562933d2b4cee65"))); + avatarState.inventory = new Inventory(); + avatarState.worldInformation = new WorldInformation((Dictionary)new Codec().Decode(Convert.FromHexString( + "6475313a316475323a496475313a3175343a4e616d6575393a59676764726173696c7531303a5374616765426567696e75313a317532323a5374616765436c6561726564426c6f636b496e64657875363a3437323632387531343a5374616765436c6561726564496475323a353075383a5374616765456e6475323a35307531383a556e6c6f636b6564426c6f636b496e64657875363a3434343436366575353a31303030316475323a496475353a313030303175343a4e616d657531313a4d696d69736272756e6e727531303a5374616765426567696e75383a31303030303030317532323a5374616765436c6561726564426c6f636b496e64657875323a2d317531343a5374616765436c6561726564496475323a2d3175383a5374616765456e6475383a31303030303032307531383a556e6c6f636b6564426c6f636b496e64657875363a3438373734336575313a326475323a496475313a3275343a4e616d6575373a416c666865696d7531303a5374616765426567696e75323a35317532323a5374616765436c6561726564426c6f636b496e64657875363a3438373734337531343a5374616765436c6561726564496475333a31303075383a5374616765456e6475333a3130307531383a556e6c6f636b6564426c6f636b496e64657875363a3437323632386575313a336475323a496475313a3375343a4e616d657531323a5376617274616c666865696d7531303a5374616765426567696e75333a3130317532323a5374616765436c6561726564426c6f636b496e64657875363a3530343031387531343a5374616765436c6561726564496475333a31353075383a5374616765456e6475333a3135307531383a556e6c6f636b6564426c6f636b496e64657875363a3438373734336575313a346475323a496475313a3475343a4e616d6575363a4173676172647531303a5374616765426567696e75333a3135317532323a5374616765436c6561726564426c6f636b496e64657875373a343839313637337531343a5374616765436c6561726564496475333a32303075383a5374616765456e6475333a3230307531383a556e6c6f636b6564426c6f636b496e64657875363a3530343031386575313a356475323a496475313a3575343a4e616d657531303a4d757370656c6865696d7531303a5374616765426567696e75333a3230317532323a5374616765436c6561726564426c6f636b496e64657875373a373132353232397531343a5374616765436c6561726564496475333a32353075383a5374616765456e6475333a3235307531383a556e6c6f636b6564426c6f636b496e64657875373a343839313637336575313a366475323a496475313a3675343a4e616d6575393a4a6f74756e6865696d7531303a5374616765426567696e75333a3235317532323a5374616765436c6561726564426c6f636b496e64657875383a31313237353837337531343a5374616765436c6561726564496475333a33303075383a5374616765456e6475333a3330307531383a556e6c6f636b6564426c6f636b496e64657875373a373132353232396575313a376475323a496475313a3775343a4e616d6575383a4e69666c6865696d7531303a5374616765426567696e75333a3330317532323a5374616765436c6561726564426c6f636b496e64657875383a31313439323332367531343a5374616765436c6561726564496475333a33333275383a5374616765456e6475333a3335307531383a556e6c6f636b6564426c6f636b496e64657875383a31313237353837336565"))); + avatarState.questList = new QuestList((List)new Codec().Decode(Convert.FromHexString( + "6c6935656c6c7531303a776f726c6451756573747469316569306569313030303031656475363a34303030303075323a32306574656c7531303a776f726c6451756573747469326569306569313030303032656475363a34303030303075323a32306574656c7531303a776f726c6451756573747469336569306569313030303033656475363a33303330303075313a3175363a34303030303075333a3430306574656c7531303a776f726c6451756573747469346569306569313030303034656475363a33303630343075313a376574656c7531303a776f726c6451756573747469356569306569313030303035656475363a34303030303075323a32306574656c7531303a776f726c6451756573747469366569306569313030303036656475363a33303331303075313a316574656c7531303a776f726c6451756573747469376569306569313030303037656475363a34303030303075323a32306574656c7531303a776f726c6451756573747469386569306569313030303038656475363a34303030303075323a32306574656c7531303a776f726c6451756573747469396569306569313030303039656475363a33303332303075313a316574656c7531303a776f726c645175657374746931306569306569313030303130656475363a34303030303075323a32306574656c7531303a776f726c645175657374746931316569306569313030303131656475363a33303630323375313a3175363a33303630343175313a326574656c7531303a776f726c645175657374746931326569306569313030303132656475363a34303030303075323a32306574656c7531303a776f726c645175657374746931336569306569313030303133656475363a33303630323575313a3375363a33303630343175313a326574656c7531303a776f726c645175657374746931346569306569313030303134656475363a34303030303075323a32306574656c7531303a776f726c645175657374746931356569306569313030303135656475363a33303333303075313a316574656c7531303a776f726c645175657374746931366569306569313030303136656475363a34303030303075323a32306574656c7531303a776f726c645175657374746931376569306569313030303137656475363a34303030303075323a32306574656c7531303a776f726c645175657374746931386569306569313030303138656475363a34303030303075323a32306574656c7531303a776f726c645175657374746931396569306569313030303139656475363a34303030303075323a323075363a35303030303075313a316574656c7531303a776f726c645175657374746932306569306569313030303230656475363a33303334303075313a316574656c7531303a776f726c645175657374746932316569306569313030303231656475363a33303630303175313a3175363a33303630343475313a316574656c7531303a776f726c645175657374746932326569306569313030303232656475363a33303630303075313a3175363a33303630303275313a316574656c7531303a776f726c645175657374746932336569306569313030303233656475363a34303030303075323a32306574656c7531303a776f726c645175657374746932346569306569313030303234656475363a33303330303175313a326574656c7531303a776f726c645175657374746932356569306569313030303235656475363a33303630303075313a3175363a33303630303175313a316574656c7531303a776f726c645175657374746932366569306569313030303236656475363a34303030303075323a32306574656c7531303a776f726c645175657374746932376569306569313030303237656475363a34303030303075323a32306574656c7531303a776f726c645175657374746932386569306569313030303238656475363a34303030303075323a32306574656c7531303a776f726c645175657374746932396569306569313030303239656475363a34303030303075323a32306574656c7531303a776f726c645175657374746933306569306569313030303330656475363a34303030303075323a32306574656c7531303a776f726c645175657374746933316569306569313030303331656475363a34303030303075323a32306574656c7531303a776f726c645175657374746933326569306569313030303332656475363a34303030303075323a32306574656c7531303a776f726c645175657374746933336569306569313030303333656475363a34303030303075323a32306574656c7531303a776f726c645175657374746933346569306569313030303334656475363a34303030303075323a32306574656c7531303a776f726c645175657374746933356569306569313030303335656475363a34303030303075323a32306574656c7531303a776f726c645175657374746933366569306569313030303336656475363a34303030303075323a32306574656c7531303a776f726c645175657374746933376569306569313030303337656475363a34303030303075323a32306574656c7531303a776f726c645175657374746933386569306569313030303338656475363a34303030303075323a32306574656c7531303a776f726c645175657374746933396569306569313030303339656475363a34303030303075323a32306574656c7531303a776f726c645175657374746934306569306569313030303430656475363a34303030303075323a323075363a35303030303075313a316574656c7531303a776f726c645175657374746934316569306569313030303431656475363a34303030303075323a32306574656c7531303a776f726c645175657374746934326569306569313030303432656475363a34303030303075323a32306574656c7531303a776f726c645175657374746934336569306569313030303433656475363a34303030303075323a32306574656c7531303a776f726c645175657374746934346569306569313030303434656475363a34303030303075323a32306574656c7531303a776f726c645175657374746934356569306569313030303435656475363a34303030303075323a32306574656c7531303a776f726c645175657374746934366569306569313030303436656475363a34303030303075323a32306574656c7531303a776f726c645175657374746934376569306569313030303437656475363a34303030303075323a32306574656c7531303a776f726c645175657374746934386569306569313030303438656475363a34303030303075323a32306574656c7531303a776f726c645175657374746934396569306569313030303439656475363a34303030303075323a32306574656c7531303a776f726c645175657374746935306569306569313030303530656475363a33303430303275313a316574656c7531303a776f726c645175657374746935316569306569313030303531656475363a34303030303075323a32306574656c7531303a776f726c645175657374746935326569306569313030303532656475363a34303030303075323a32306574656c7531303a776f726c645175657374746935336569306569313030303533656475363a34303030303075323a32306574656c7531303a776f726c645175657374746935346569306569313030303534656475363a34303030303075323a32306574656c7531303a776f726c645175657374746935356569306569313030303535656475363a34303030303075323a32306574656c7531303a776f726c645175657374746935366569306569313030303536656475363a34303030303075323a32306574656c7531303a776f726c645175657374746935376569306569313030303537656475363a34303030303075323a32306574656c7531303a776f726c645175657374746935386569306569313030303538656475363a34303030303075323a32306574656c7531303a776f726c645175657374746935396569306569313030303539656475363a34303030303075323a32306574656c7531303a776f726c645175657374746936306569306569313030303630656475363a34303030303075323a323075363a35303030303075313a316574656c7531303a776f726c645175657374746936316569306569313030303631656475363a34303030303075323a32306574656c7531303a776f726c645175657374746936326569306569313030303632656475363a34303030303075323a32306574656c7531303a776f726c645175657374746936336569306569313030303633656475363a34303030303075323a32306574656c7531303a776f726c645175657374746936346569306569313030303634656475363a34303030303075323a32306574656c7531303a776f726c645175657374746936356569306569313030303635656475363a34303030303075323a32306574656c7531303a776f726c645175657374746936366569306569313030303636656475363a34303030303075323a32306574656c7531303a776f726c645175657374746936376569306569313030303637656475363a34303030303075323a32306574656c7531303a776f726c645175657374746936386569306569313030303638656475363a34303030303075323a32306574656c7531303a776f726c645175657374746936396569306569313030303639656475363a34303030303075323a32306574656c7531303a776f726c645175657374746937306569306569313030303730656475363a34303030303075323a32306574656c7531303a776f726c645175657374746937316569306569313030303731656475363a34303030303075323a32306574656c7531303a776f726c645175657374746937326569306569313030303732656475363a34303030303075323a32306574656c7531303a776f726c645175657374746937336569306569313030303733656475363a34303030303075323a32306574656c7531303a776f726c645175657374746937346569306569313030303734656475363a34303030303075323a32306574656c7531303a776f726c645175657374746937356569306569313030303735656475363a34303030303075323a32306574656c7531303a776f726c645175657374746937366569306569313030303736656475363a34303030303075323a32306574656c7531303a776f726c645175657374746937376569306569313030303737656475363a34303030303075323a32306574656c7531303a776f726c645175657374746937386569306569313030303738656475363a34303030303075323a32306574656c7531303a776f726c645175657374746937396569306569313030303739656475363a34303030303075323a32306574656c7531303a776f726c645175657374746938306569306569313030303830656475363a34303030303075323a323075363a35303030303075313a316574656c7531303a776f726c645175657374746938316569306569313030303831656475363a34303030303075323a32306574656c7531303a776f726c645175657374746938326569306569313030303832656475363a34303030303075323a32306574656c7531303a776f726c645175657374746938336569306569313030303833656475363a34303030303075323a32306574656c7531303a776f726c645175657374746938346569306569313030303834656475363a34303030303075323a32306574656c7531303a776f726c645175657374746938356569306569313030303835656475363a34303030303075323a32306574656c7531303a776f726c645175657374746938366569306569313030303836656475363a34303030303075323a32306574656c7531303a776f726c645175657374746938376569306569313030303837656475363a34303030303075323a32306574656c7531303a776f726c645175657374746938386569306569313030303838656475363a34303030303075323a32306574656c7531303a776f726c645175657374746938396569306569313030303839656475363a34303030303075323a32306574656c7531303a776f726c645175657374746939306569306569313030303930656475363a34303030303075323a32306574656c7531303a776f726c645175657374746939316569306569313030303931656475363a34303030303075323a32306574656c7531303a776f726c645175657374746939326569306569313030303932656475363a34303030303075323a32306574656c7531303a776f726c645175657374746939336569306569313030303933656475363a34303030303075323a32306574656c7531303a776f726c645175657374746939346569306569313030303934656475363a34303030303075323a32306574656c7531303a776f726c645175657374746939356569306569313030303935656475363a34303030303075323a32306574656c7531303a776f726c645175657374746939366569306569313030303936656475363a34303030303075323a32306574656c7531303a776f726c645175657374746939376569306569313030303937656475363a34303030303075323a32306574656c7531303a776f726c645175657374746939386569306569313030303938656475363a34303030303075323a32306574656c7531303a776f726c645175657374746939396569306569313030303939656475363a34303030303075323a323075363a35303030303075313a316574656c7531303a776f726c64517565737474693130306569306569313030313030656475363a33303430303175313a316574656c7531303a776f726c64517565737474693130316569306569313030313031656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693130326569306569313030313032656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693130336569306569313030313033656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693130346569306569313030313034656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693130356569306569313030313035656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693130366569306569313030313036656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693130376569306569313030313037656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693130386569306569313030313038656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693130396569306569313030313039656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693131306569306569313030313130656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693131316569306569313030313131656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693131326569306569313030313132656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693131336569306569313030313133656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693131346569306569313030313134656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693131356569306569313030313135656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693131366569306569313030313136656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693131376569306569313030313137656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693131386569306569313030313138656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693131396569306569313030313139656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693132306569306569313030313230656475363a34303030303075323a323075363a35303030303075313a316574656c7531303a776f726c64517565737474693132316569306569313030313231656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693132326569306569313030313232656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693132336569306569313030313233656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693132346569306569313030313234656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693132356569306569313030313235656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693132366569306569313030313236656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693132376569306569313030313237656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693132386569306569313030313238656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693132396569306569313030313239656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693133306569306569313030313330656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693133316569306569313030313331656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693133326569306569313030313332656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693133336569306569313030313333656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693133346569306569313030313334656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693133356569306569313030313335656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693133366569306569313030313336656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693133376569306569313030313337656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693133386569306569313030313338656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693133396569306569313030313339656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693134306569306569313030313430656475363a34303030303075323a323075363a35303030303075313a316574656c7531303a776f726c64517565737474693134316569306569313030313431656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693134326569306569313030313432656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693134336569306569313030313433656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693134346569306569313030313434656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693134356569306569313030313435656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693134366569306569313030313436656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693134376569306569313030313437656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693134386569306569313030313438656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693134396569306569313030313439656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693135306569306569313030313530656475363a33303430303075313a316574656c7531303a776f726c64517565737474693135316569306569313030313531656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693135326569306569313030313532656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693135336569306569313030313533656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693135346569306569313030313534656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693135356569306569313030313535656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693135366569306569313030313536656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693135376569306569313030313537656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693135386569306569313030313538656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693135396569306569313030313539656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693136306569306569313030313630656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693136316569306569313030313631656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693136326569306569313030313632656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693136336569306569313030313633656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693136346569306569313030313634656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693136356569306569313030313635656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693136366569306569313030313636656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693136376569306569313030313637656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693136386569306569313030313638656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693136396569306569313030313639656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693137306569306569313030313730656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693137316569306569313030313731656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693137326569306569313030313732656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693137336569306569313030313733656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693137346569306569313030313734656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693137356569306569313030313735656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693137366569306569313030313736656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693137376569306569313030313737656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693137386569306569313030313738656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693137396569306569313030313739656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693138306569306569313030313830656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693138316569306569313030313831656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693138326569306569313030313832656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693138336569306569313030313833656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693138346569306569313030313834656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693138356569306569313030313835656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693138366569306569313030313836656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693138376569306569313030313837656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693138386569306569313030313838656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693138396569306569313030313839656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693139306569306569313030313930656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693139316569306569313030313931656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693139326569306569313030313932656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693139336569306569313030313933656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693139346569306569313030313934656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693139356569306569313030313935656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693139366569306569313030313936656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693139376569306569313030313937656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693139386569306569313030313938656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693139396569306569313030313939656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693230306569306569313030323030656475363a33303430303375313a316574656c7531303a776f726c64517565737474693230316569306569313030323031656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693230326569306569313030323032656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693230336569306569313030323033656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693230346569306569313030323034656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693230356569306569313030323035656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693230366569306569313030323036656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693230376569306569313030323037656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693230386569306569313030323038656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693230396569306569313030323039656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693231306569306569313030323130656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693231316569306569313030323131656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693231326569306569313030323132656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693231336569306569313030323133656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693231346569306569313030323134656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693231356569306569313030323135656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693231366569306569313030323136656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693231376569306569313030323137656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693231386569306569313030323138656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693231396569306569313030323139656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693232306569306569313030323230656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693232316569306569313030323231656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693232326569306569313030323232656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693232336569306569313030323233656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693232346569306569313030323234656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693232356569306569313030323235656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693232366569306569313030323236656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693232376569306569313030323237656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693232386569306569313030323238656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693232396569306569313030323239656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693233306569306569313030323330656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693233316569306569313030323331656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693233326569306569313030323332656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693233336569306569313030323333656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693233346569306569313030323334656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693233356569306569313030323335656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693233366569306569313030323336656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693233376569306569313030323337656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693233386569306569313030323338656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693233396569306569313030323339656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693234306569306569313030323430656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693234316569306569313030323431656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693234326569306569313030323432656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693234336569306569313030323433656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693234346569306569313030323434656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693234356569306569313030323435656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693234366569306569313030323436656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693234376569306569313030323437656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693234386569306569313030323438656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693234396569306569313030323439656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693235306569306569313030323530656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693235316569306569313030323531656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693235326569306569313030323532656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693235336569306569313030323533656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693235346569306569313030323534656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693235356569306569313030323535656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693235366569306569313030323536656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693235376569306569313030323537656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693235386569306569313030323538656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693235396569306569313030323539656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693236306569306569313030323630656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693236316569306569313030323631656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693236326569306569313030323632656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693236336569306569313030323633656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693236346569306569313030323634656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693236356569306569313030323635656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693236366569306569313030323636656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693236376569306569313030323637656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693236386569306569313030323638656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693236396569306569313030323639656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693237306569306569313030323730656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693237316569306569313030323731656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693237326569306569313030323732656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693237336569306569313030323733656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693237346569306569313030323734656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693237356569306569313030323735656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693237366569306569313030323736656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693237376569306569313030323737656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693237386569306569313030323738656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693237396569306569313030323739656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693238306569306569313030323830656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693238316569306569313030323831656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693238326569306569313030323832656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693238336569306569313030323833656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693238346569306569313030323834656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693238356569306569313030323835656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693238366569306569313030323836656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693238376569306569313030323837656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693238386569306569313030323838656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693238396569306569313030323839656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693239306569306569313030323930656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693239316569306569313030323931656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693239326569306569313030323932656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693239336569306569313030323933656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693239346569306569313030323934656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693239356569306569313030323935656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693239366569306569313030323936656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693239376569306569313030323937656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693239386569306569313030323938656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693239396569306569313030323939656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693330306569306569313030333030656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693330316569306569313030333031656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693330326569306569313030333032656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693330336569306569313030333033656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693330346569306569313030333034656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693330356569306569313030333035656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693330366569306569313030333036656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693330376569306569313030333037656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693330386569306569313030333038656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693330396569306569313030333039656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693331306569306569313030333130656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693331316569306569313030333131656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693331326569306569313030333132656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693331336569306569313030333133656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693331346569306569313030333134656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693331356569306569313030333135656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693331366569306569313030333136656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693331376569306569313030333137656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693331386569306569313030333138656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693331396569306569313030333139656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693332306569306569313030333230656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693332316569306569313030333231656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693332326569306569313030333232656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693332336569306569313030333233656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693332346569306569313030333234656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693332356569306569313030333235656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693332366569306569313030333236656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693332376569306569313030333237656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693332386569306569313030333238656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693332396569306569313030333239656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693333306569306569313030333330656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693333316569306569313030333331656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693333326569306569313030333332656475363a34303030303075323a32306574656c7531303a776f726c64517565737466693333336569306569313030333333656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693333346569306569313030333334656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693333356569306569313030333335656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693333366569306569313030333336656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693333376569306569313030333337656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693333386569306569313030333338656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693333396569306569313030333339656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693334306569306569313030333430656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693334316569306569313030333431656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693334326569306569313030333432656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693334336569306569313030333433656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693334346569306569313030333434656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693334356569306569313030333435656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693334366569306569313030333436656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693334376569306569313030333437656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693334386569306569313030333438656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693334396569306569313030333439656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693335306569306569313030333530656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693335316569306569313030333531656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693335326569306569313030333532656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693335336569306569313030333533656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693335346569306569313030333534656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693335356569306569313030333535656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693335366569306569313030333536656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693335376569306569313030333537656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693335386569306569313030333538656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693335396569306569313030333539656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693336306569306569313030333630656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693336316569306569313030333631656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693336326569306569313030333632656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693336336569306569313030333633656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693336346569306569313030333634656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693336356569306569313030333635656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693336366569306569313030333636656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693336376569306569313030333637656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693336386569306569313030333638656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693336396569306569313030333639656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693337306569306569313030333730656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693337316569306569313030333731656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693337326569306569313030333732656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693337336569306569313030333733656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693337346569306569313030333734656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693337356569306569313030333735656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693337366569306569313030333736656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693337376569306569313030333737656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693337386569306569313030333738656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693337396569306569313030333739656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693338306569306569313030333830656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693338316569306569313030333831656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693338326569306569313030333832656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693338336569306569313030333833656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693338346569306569313030333834656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693338356569306569313030333835656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693338366569306569313030333836656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693338376569306569313030333837656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693338386569306569313030333838656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693338396569306569313030333839656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693339306569306569313030333930656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693339316569306569313030333931656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693339326569306569313030333932656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693339336569306569313030333933656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693339346569306569313030333934656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693339356569306569313030333935656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693339366569306569313030333936656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693339376569306569313030333937656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693339386569306569313030333938656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693339396569306569313030333939656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693430306569306569313030343030656475363a34303030303075333a3530306566656c7531323a636f6c6c65637451756573747469316569316569323030303031656475363a33303230303175313a3175363a33303230303275313a3165746932303130303065656c7531323a636f6c6c65637451756573747469316569316569323030303032656475363a33303230303475313a3275363a33303230303675313a3165746932303130303165656c7531323a636f6c6c65637451756573747469316569316569323030303033656475363a33303230303375313a3165746932303130303265656c7531323a636f6c6c65637451756573747469316569316569323030303034656475363a33303230303375313a3265746932303130303365656c7531323a636f6c6c65637451756573746669316569306569323030303035656475363a33303230303375313a3275363a33303230303575313a3265666932303130303465656c7531323a636f6c6c65637451756573747469316569316569323030303036656475363a33303230303375313a3165746932303130303565656c7531323a636f6c6c65637451756573747469316569316569323030303037656475363a33303230303375313a3265746932303130303665656c7531323a636f6c6c65637451756573746669316569306569323030303038656475363a33303230303075313a3275363a33303230303375313a3265666932303130303765656c7531323a636f6c6c65637451756573747469316569316569323030303039656475363a33303230303875313a3165746932303130303865656c7531323a636f6c6c65637451756573747469316569316569323030303130656475363a33303230303075313a3275363a33303230303875313a3265746932303130303965656c7531323a636f6c6c65637451756573747469316569316569323030303131656475363a33303230303975313a3165746932303130313065656c7531323a636f6c6c65637451756573747469316569316569323030303132656475363a33303230303875313a3165746932303130313165656c7531323a636f6c6c65637451756573747469316569316569323030303133656475363a33303230303575313a3275363a33303230303875313a3265746932303130313265656c7531323a636f6c6c65637451756573747469316569316569323030303134656475363a33303230303975313a3165746932303130313365656c7531363a636f6d62696e6174696f6e51756573747469316569316569333030303031656475363a33303230303175313a316574693265693665656c7531363a636f6d62696e6174696f6e51756573747469336569336569333030303032656475363a33303230303175313a316574693265693665656c7531363a636f6d62696e6174696f6e51756573747469356569356569333030303033656475363a33303230303175313a316574693265693665656c7531363a636f6d62696e6174696f6e517565737474693130656931306569333030303034656475363a33303230303175313a326574693265693665656c7531363a636f6d62696e6174696f6e517565737474693530656935306569333030303035656475363a33303230303175313a326574693265693665656c7531363a636f6d62696e6174696f6e51756573747469316569316569333030303036656475363a33303230303375313a316574693265693765656c7531363a636f6d62696e6174696f6e51756573747469336569336569333030303037656475363a33303230303375313a316574693265693765656c7531363a636f6d62696e6174696f6e51756573747469356569356569333030303038656475363a33303230303375313a316574693265693765656c7531363a636f6d62696e6174696f6e517565737474693130656931306569333030303039656475363a33303230303375313a326574693265693765656c7531363a636f6d62696e6174696f6e517565737474693530656935306569333030303130656475363a33303230303375313a326574693265693765656c7531363a636f6d62696e6174696f6e51756573747469316569316569333030303131656475363a33303230303575313a316574693265693865656c7531363a636f6d62696e6174696f6e51756573747469336569336569333030303132656475363a33303230303575313a316574693265693865656c7531363a636f6d62696e6174696f6e51756573747469356569356569333030303133656475363a33303230303575313a316574693265693865656c7531363a636f6d62696e6174696f6e517565737474693130656931306569333030303134656475363a33303230303575313a326574693265693865656c7531363a636f6d62696e6174696f6e517565737474693530656935306569333030303135656475363a33303230303575313a326574693265693865656c7531363a636f6d62696e6174696f6e51756573747469316569316569333030303136656475363a33303230303075313a316574693265693965656c7531363a636f6d62696e6174696f6e51756573747469336569336569333030303137656475363a33303230303075313a316574693265693965656c7531363a636f6d62696e6174696f6e51756573747469356569356569333030303138656475363a33303230303075313a316574693265693965656c7531363a636f6d62696e6174696f6e517565737474693130656931306569333030303139656475363a33303230303075313a326574693265693965656c7531363a636f6d62696e6174696f6e517565737474693530656935306569333030303230656475363a33303230303075313a326574693265693965656c7531363a636f6d62696e6174696f6e51756573747469316569316569333030303231656475363a33303230303175313a31657469326569313065656c7531363a636f6d62696e6174696f6e51756573747469336569336569333030303232656475363a33303230303175313a31657469326569313065656c7531363a636f6d62696e6174696f6e51756573747469356569356569333030303233656475363a33303230303175313a31657469326569313065656c7531363a636f6d62696e6174696f6e517565737474693130656931306569333030303234656475363a33303230303175313a32657469326569313065656c7531363a636f6d62696e6174696f6e517565737474693530656935306569333030303235656475363a33303230303175313a32657469326569313065656c7531363a636f6d62696e6174696f6e51756573747469316569316569333030303236656475363a33303230303375313a316574693065693065656c7531363a636f6d62696e6174696f6e517565737474693130656931306569333030303237656475363a33303230303375313a316574693065693065656c7531363a636f6d62696e6174696f6e517565737474693230656932306569333030303238656475363a33303230303375313a316574693065693065656c7531363a636f6d62696e6174696f6e517565737474693330656933306569333030303239656475363a33303230303375313a326574693065693065656c7531363a636f6d62696e6174696f6e517565737474693530656935306569333030303330656475363a33303230303375313a326574693065693065656c7531303a747261646551756573747469316569316569343030303031656475363a33303230303075313a326574693165656c7531303a7472616465517565737474693130656931306569343030303032656475363a33303230303075313a326574693165656c7531303a7472616465517565737474693530656935306569343030303033656475363a33303230303875313a326574693165656c7531303a74726164655175657374746931303065693130306569343030303034656475363a33303230303975313a326574693165656c7531303a747261646551756573747469316569316569343030303035656475363a33303230303575313a326574693065656c7531303a7472616465517565737474693130656931306569343030303036656475363a33303230303575313a326574693065656c7531303a7472616465517565737474693530656935306569343030303037656475363a33303230303875313a326574693065656c7531303a74726164655175657374746931303065693130306569343030303038656475363a33303230303975313a326574693065656c7531323a6d6f6e7374657251756573747469316569316569353030303031656475363a33303230303475313a3265746932303130303565656c7531323a6d6f6e7374657251756573747469316569316569353030303032656475363a33303230303475313a3275363a33303230303675313a3165746932303230303765656c7531323a6d6f6e7374657251756573747469316569316569353030303033656475363a33303230303875313a3265746932303330303765656c7531323a6d6f6e7374657251756573747469316569316569353030303034656475363a33303230303975313a3265746932303530303765656c7532303a6974656d456e68616e63656d656e7451756573747469336569316569363030303031656475363a33303230303275313a326574693165693165656c7532303a6974656d456e68616e63656d656e7451756573746669336569356569363030303032656475363a33303230303475313a326566693165693665656c7532303a6974656d456e68616e63656d656e7451756573747469366569316569363030303033656475363a33303230303475313a326574693265693165656c7532303a6974656d456e68616e63656d656e7451756573746669366569316569363030303034656475363a33303230303475313a3275363a33303230303675313a316566693265693665656c7532303a6974656d456e68616e63656d656e7451756573746669396569306569363030303035656475363a33303230303475313a3275363a33303230303675313a316566693365693165656c7532303a6974656d456e68616e63656d656e7451756573746669396569306569363030303036656475363a33303230303875313a326566693365693665656c7532303a6974656d456e68616e63656d656e7451756573746669396569306569363030303037656475363a33303230303975313a326566693465693165656c7532303a6974656d456e68616e63656d656e7451756573746669396569306569363030303038656475363a33303230303975313a326566693465693665656c7532303a6974656d456e68616e63656d656e7451756573746669396569306569363030303039656475363a33303230303975313a326566693565693165656c7532303a6974656d456e68616e63656d656e7451756573746669396569306569363030303130656475363a33303230303975313a326566693565693665656c7531323a67656e6572616c51756573747469316569316569373030303031656475363a33303230303275313a316574693165656c7531323a67656e6572616c517565737474693130656931306569373030303032656475363a33303230303275313a326574693165656c7531323a67656e6572616c517565737474693530656935306569373030303033656475363a33303230303275313a326574693165656c7531323a67656e6572616c517565737474693130656931306569373130303030656475363a33303230303275313a316574693265656c7531323a67656e6572616c517565737474693230656932306569373130303031656475363a33303230303275313a316574693265656c7531323a67656e6572616c517565737474693330656933306569373130303032656475363a33303230303375313a3275363a33303230303575313a326574693265656c7531323a67656e6572616c517565737474693530656935306569373130303033656475363a33303230303375313a3275363a33303230303575313a326574693265656c7531323a67656e6572616c517565737474693730656937306569373130303034656475363a33303230303475313a326574693265656c7531323a67656e6572616c517565737474693930656939306569373130303035656475363a33303230303475313a3275363a33303230303675313a316574693265656c7531323a67656e6572616c5175657374746931303065693130306569373130303036656475363a33303230303475313a3275363a33303230303675313a316574693265656c7531323a67656e6572616c5175657374746931323065693132306569373130303037656475363a33303230303475313a3275363a33303230303675313a316574693265656c7531323a67656e6572616c5175657374746931343065693134306569373130303038656475363a33303230303475313a3275363a33303230303675313a316574693265656c7531323a67656e6572616c5175657374746931363065693136306569373130303039656475363a33303230303475313a3275363a33303230303675313a316574693265656c7531323a67656e6572616c5175657374746931383065693138306569373130303130656475363a33303230303475313a3275363a33303230303675313a316574693265656c7531323a67656e6572616c5175657374746932303065693230306569373130303131656475363a33303230303475313a3275363a33303230303675313a316574693265656c7531323a67656e6572616c51756573747469316569316569373230303030656475363a33303230303275313a316574693365656c7531323a67656e6572616c517565737474693130656931306569373230303031656475363a33303230303275313a316574693365656c7531323a67656e6572616c517565737474693530656935306569373230303032656475363a33303230303275313a326574693365656c7531323a67656e6572616c5175657374746931303065693130306569373230303033656475363a33303230303275313a326574693365656c7531323a67656e6572616c517565737474693130656931316569373930303030656475363a33303230303375313a316574693465656c7531323a67656e6572616c517565737474693230656932306569373930303031656475363a33303230303375313a316574693465656c7531323a67656e6572616c517565737474693330656933316569373930303032656475363a33303230303375313a326574693465656c7531323a67656e6572616c517565737474693430656934306569373930303033656475363a33303230303375313a326574693465656c7531323a67656e6572616c517565737474693530656935306569373930303034656475363a33303230303375313a326574693465656c7531343a6974656d477261646551756573747469366569366569383030303030656475363a33303230303375313a3265746931656c69313031313030303065693130313131303030656931303231303030306569313032313130303065693130333130303030656931303431303030306565656c7531343a6974656d477261646551756573747469366569366569383030303031656475363a33303230303375313a3265746932656c69313031323030303065693130313231303030656931303132323030306569313032323030303065693130323231303030656931303332303030306565656c7531343a6974656d477261646551756573747469366569366569383030303032656475363a33303230303075313a3275363a33303230303375313a3265746933656c69313031333030303065693130313331303030656931303133333030306569313032333030303065693130323331303030656931303233313030316565656c7531343a6974656d477261646551756573747469366569366569383030303033656475363a33303230303875313a3265746934656c693230313030396569323031303132656931303334303030306569313033343130303065693130333434303030656931303434343030306565656c7531343a6974656d477261646551756573747469366569366569383030303034656475363a33303230303975313a3265746935656c693230313031306569323031303133656932303130313665693230313031396569323031303234656931303435323030316565656c7532303a6974656d54797065436f6c6c65637451756573747469356569356569393030303030656475363a33303230303375313a3165746c693330323030316569333033303030656933303331303065693330363034306569343030303030656575383a4d6174657269616c656c7532303a6974656d54797065436f6c6c656374517565737474693130656931306569393030303031656475363a33303230303075313a3275363a33303230303375313a3265746c69333032303031656933303230303265693330323030336569333032303035656933303330303065693330333130306569333033323030656933303630323365693330363034306569343030303030656575383a4d6174657269616c656c7532303a6974656d54797065436f6c6c656374517565737474693230656932306569393030303032656475363a33303230303075313a3275363a33303230303375313a3265746c693330323030306569333032303031656933303230303265693330323030336569333032303035656933303330303065693330333130306569333033323030656933303333303065693330333430306569333036303030656933303630303165693330363032336569333036303234656933303630323565693330363034306569333036303431656933303630343465693430303030306569353030303030656575383a4d6174657269616c656c7532303a6974656d54797065436f6c6c656374517565737474693330656933306569393030303033656475363a33303230303075313a3275363a33303230303375313a3265746c6933303230303065693330323030316569333032303032656933303230303365693330323030346569333032303035656933303230303665693330333030306569333033303031656933303331303065693330333130316569333033323030656933303332303165693330333330306569333033333031656933303334303065693330343030326569333036303030656933303630303165693330363030326569333036303039656933303630323365693330363032346569333036303235656933303630343065693330363034316569333036303433656933303630343465693430303030306569353030303030656575383a4d6174657269616c656c75393a476f6c6451756573747469313030656931353030656931303030303030656475363a33303230303375313a326574693065656c75393a476f6c645175657374746931303030656931353030656931303030303031656475363a33303230303475313a3275363a33303230303675313a316574693065656c75393a476f6c6451756573747469313030303065693138303732656931303030303033656475363a33303230303875313a326574693065656c75393a476f6c64517565737474693130306569313030656931303030303034656475363a33303230303075313a3275363a33303230303375313a326574693165656c75393a476f6c645175657374746931303030656931393330656931303030303035656475363a33303230303475313a3275363a33303230303675313a316574693165656c75393a476f6c6451756573747469313030303065693132353830656931303030303036656475363a33303230303875313a326574693165656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303031656475363a33303330303075313a31657475313a3175313a33656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303032656475363a33303330303075313a31657475313a3275323a3131656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303033656475363a33303330303075313a31657475313a3375323a3231656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303034656475363a33303330303075313a31657475313a3475323a3531656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303035656475363a33303330303075313a31657475313a3575323a3939656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303036656475363a33303330303175313a32657475313a3675323a3234656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303037656475363a33303330303175313a32657475313a3775323a3239656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303038656475363a33303330303175313a32657475313a3875323a3337656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303039656475363a33303330303175313a32657475313a3975333a313134656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303130656475363a33303330303175313a32657475323a313075333a313734656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303131656475363a33303330303275313a33657475323a313175323a3633656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303132656475363a33303330303275313a33657475323a313275323a3636656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303133656475363a33303330303275313a33657475323a313375323a3834656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303134656475363a33303330303275313a33657475323a313475333a313934656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303135656475363a33303330303275313a33657475323a313575333a323631656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303136656475363a33303330303275313a33657475323a313675333a313330656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303137656475363a33303330303275313a33657475323a313775333a313334656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303138656475363a33303330303275313a33657475323a313875333a313538656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303139656475363a33303330303275313a33657475323a313975333a323831656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303230656475363a33303330303275313a33657475323a323075333a333534656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303231656475363a33303330303375313a3465746932316575333a323136656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303232656475363a33303330303375313a34657475323a323275333a323231656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303233656475363a33303330303375313a3465666932336575333a323431656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303234656475363a33303330303375313a3465746932346575333a333837656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303235656475363a33303330303375313a3465666932356575333a353136656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303236656475363a33303330303375313a3465666932366575333a333031656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303237656475363a33303330303375313a3465746932376575333a333036656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303238656475363a33303330303375313a3465666932386575333a333330656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303239656475363a33303330303375313a3465666932396575333a353631656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303330656475363a33303330303375313a3465666933306575333a363736656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303331656475363a33303330303475313a3565666933316575333a343135656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303332656475363a33303330303475313a3565666933326575333a343232656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303333656475363a33303330303475313a3565666933336575333a343736656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303334656475363a33303330303475313a3565666933346575333a363936656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303335656475363a33303330303475313a3565666933356575333a373531656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303336656475363a33303330303475313a3565666933366575333a363036656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303337656475363a33303330303475313a3565666933376575333a363136656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303338656475363a33303330303475313a3565666933386575333a363536656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303339656475363a33303330303475313a3565666933396575333a383036656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303430656475363a33303330303475313a3565666934306575333a383330656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303431656475363a33303330303475313a3565666934316575333a383534656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303432656475363a33303331303075313a31657475323a343275313a36656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303433656475363a33303331303075313a31657475323a343375323a3133656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303434656475363a33303331303075313a31657475323a343475323a3232656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303435656475363a33303331303075313a31657475323a343575323a3539656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303436656475363a33303331303075313a31657475323a343675333a313131656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303437656475363a33303331303175313a32657475323a343775323a3333656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303438656475363a33303331303175313a32657475323a343875323a3335656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303439656475363a33303331303175313a32657475323a343975323a3435656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303530656475363a33303331303175313a32657475323a353075333a313236656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303531656475363a33303331303175313a32657475323a353175333a313832656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303532656475363a33303331303275313a33657475323a353275323a3735656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303533656475363a33303331303275313a33657475323a353375323a3738656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303534656475363a33303331303275313a33657475323a353475323a3936656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303535656475363a33303331303275313a33657475323a353575333a323032656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303536656475363a33303331303275313a33657475323a353675333a323736656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303537656475363a33303331303275313a33657475323a353775333a313436656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303538656475363a33303331303275313a33657475323a353875333a313530656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303539656475363a33303331303275313a33657475323a353975333a313636656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303630656475363a33303331303275313a33657475323a363075333a323931656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303631656475363a33303331303275313a3365666936316575333a333733656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303632656475363a33303331303375313a3465666936326575333a323331656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303633656475363a33303331303375313a3465746936336575333a323336656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303634656475363a33303331303375313a3465666936346575333a323536656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303635656475363a33303331303375313a3465746936356575333a343038656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303636656475363a33303331303375313a3465666936366575333a353433656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303637656475363a33303331303375313a3465666936376575333a333138656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303638656475363a33303331303375313a3465666936386575333a333234656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303639656475363a33303331303375313a3465746936396575333a333432656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303730656475363a33303331303375313a3465666937306575333a353838656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303731656475363a33303331303375313a3465666937316575333a363836656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303732656475363a33303331303475313a3565666937326575333a343532656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303733656475363a33303331303475313a3565666937336575333a343630656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303734656475363a33303331303475313a3565666937346575333a353030656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303735656475363a33303331303475313a3565666937356575333a373037656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303736656475363a33303331303475313a3565666937366575333a373632656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303737656475363a33303331303475313a3565666937376575333a363336656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303738656475363a33303331303475313a3565666937386575333a363436656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303739656475363a33303331303475313a3565666937396575333a363636656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303830656475363a33303331303475313a3565666938306575333a383138656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303831656475363a33303331303475313a3565666938316575333a383432656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303832656475363a33303331303475313a3565666938326575333a383636656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303833656475363a33303332303075313a31657475323a383375313a39656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303834656475363a33303332303075313a31657475323a383475323a3137656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303835656475363a33303332303075313a31657475323a383575323a3235656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303836656475363a33303332303075313a31657475323a383675323a3639656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303837656475363a33303332303075313a31657475323a383775333a313338656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303838656475363a33303332303175313a32657475323a383875323a3339656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303839656475363a33303332303175313a32657475323a383975323a3431656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303930656475363a33303332303175313a32657475323a393075323a3533656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303931656475363a33303332303175313a32657475323a393175333a313632656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303932656475363a33303332303175313a3265666939326575333a323731656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303933656475363a33303332303275313a33657475323a393375323a3837656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303934656475363a33303332303275313a33657475323a393475323a3930656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303935656475363a33303332303275313a33657475323a393575333a313038656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303936656475363a33303332303275313a33657475323a393675333a333132656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303937656475363a33303332303275313a3365666939376575333a343834656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303938656475363a33303332303375313a34657475323a393875333a313836656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303939656475363a33303332303375313a34657475323a393975333a313930656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313030656475363a33303332303375313a346566693130306575333a323236656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313031656475363a33303332303375313a346566693130316575333a353235656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313032656475363a33303332303375313a346566693130326575333a353730656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313033656475363a33303332303475313a356566693130336575333a333630656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313034656475363a33303332303475313a356566693130346575333a333636656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313035656475363a33303332303475313a356566693130356575333a343434656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313036656475363a33303332303475313a356574693130366575333a373138656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313037656475363a33303332303475313a356574693130376575333a373733656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313038656475363a33303333303075313a31657475333a31303875323a3135656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313039656475363a33303333303075313a31657475333a31303975323a3139656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313130656475363a33303333303075313a31657475333a31313075323a3331656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313131656475363a33303333303075313a31657475333a31313175323a3831656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313132656475363a33303333303075313a31657475333a31313275333a313534656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313133656475363a33303333303175313a32657475333a31313375323a3437656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313134656475363a33303333303175313a32657475333a31313475323a3439656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313135656475363a33303333303175313a32657475333a31313575323a3631656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313136656475363a33303333303175313a32657475333a31313675333a313738656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313137656475363a33303333303175313a326566693131376575333a323936656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313138656475363a33303333303275313a33657475333a31313875333a313032656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313139656475363a33303333303275313a33657475333a31313975333a313035656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313230656475363a33303333303275313a33657475333a31323075333a313233656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313231656475363a33303333303275313a33657475333a31323175333a333438656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313232656475363a33303333303275313a336566693132326575333a353038656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313233656475363a33303333303375313a34657475333a31323375333a323036656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313234656475363a33303333303375313a346566693132346575333a323131656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313235656475363a33303333303375313a346566693132356575333a323636656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313236656475363a33303333303375313a346566693132366575333a353532656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313237656475363a33303333303375313a346566693132376575333a353937656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313238656475363a33303333303475313a356566693132386575333a333934656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313239656475363a33303333303475313a35657475333a31323975333a343031656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313330656475363a33303333303475313a356566693133306575333a343638656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313331656475363a33303333303475313a356574693133316575333a373239656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313332656475363a33303333303475313a356574693133326575333a373834656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313333656475363a33303334303075313a31657475333a31333375323a3230656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313334656475363a33303334303075313a31657475333a31333475323a3237656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313335656475363a33303334303075313a31657475333a31333575323a3433656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313336656475363a33303334303075313a31657475333a31333675323a3933656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313337656475363a33303334303075313a31657475333a31333775333a313730656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313338656475363a33303334303175313a32657475333a31333875323a3535656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313339656475363a33303334303175313a32657475333a31333975323a3537656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313430656475363a33303334303175313a32657475333a31343075323a3732656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313431656475363a33303334303175313a32657475333a31343175333a313938656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313432656475363a33303334303175313a32657475333a31343275333a333336656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313433656475363a33303334303275313a33657475333a31343375333a313137656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313434656475363a33303334303275313a33657475333a31343475333a313230656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313435656475363a33303334303275313a33657475333a31343575333a313432656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313436656475363a33303334303275313a336566693134366575333a333830656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313437656475363a33303334303275313a33657475333a31343775333a353334656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313438656475363a33303334303375313a346574693134386575333a323436656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313439656475363a33303334303375313a346566693134396575333a323531656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313530656475363a33303334303375313a346566693135306575333a323836656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313531656475363a33303334303375313a346574693135316575333a353739656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313532656475363a33303334303375313a346574693135326575333a363236656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313533656475363a33303334303475313a356566693135336575333a343239656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313534656475363a33303334303475313a356574693135346575333a343336656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313535656475363a33303334303475313a356566693135356575333a343932656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313536656475363a33303334303475313a356566693135366575333a373430656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313537656475363a33303334303475313a356566693135376575333a373935656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313538656475363a33303332303475323a31326566693136316575333a333330656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313539656475363a33303332303475323a31326574693136326575333a333130656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313630656475363a33303332303475323a31326566693136336575333a333130656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313631656475363a33303332303475323a31326566693136346575333a333330656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313632656475363a33303332303475323a31326574693136356575333a333330656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313633656475363a33303333303475323a31336566693136366575333a333335656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313634656475363a33303333303475323a31336574693136376575333a333230656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313635656475363a33303333303475323a31336574693136386575333a333230656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313636656475363a33303333303475323a31336566693136396575333a333335656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313637656475363a33303333303475323a31336566693137306575333a333335656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313638656475363a33303330303575323a3530656669313839656933383065656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313639656475363a33303330303575323a3530656669313930656933353565656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313730656475363a33303330303575323a3530656669313931656933353565656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313731656475363a33303330303575323a3530656669313932656933383065656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313732656475363a33303330303575323a3530656669313933656934303065656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313733656475363a33303331303575323a3530656669313934656933383565656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313734656475363a33303331303575323a3530656669313935656933363565656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313735656475363a33303331303575323a3530656669313936656933363565656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313736656475363a33303331303575323a3530656669313937656933383565656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313737656475363a33303331303575323a3530656669313938656933393865656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313738656475363a33303332303575323a3530656669313939656933383065656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313739656475363a33303332303575323a3530656669323030656933363065656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313830656475363a33303332303575323a3530656669323031656933363065656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313831656475363a33303332303575323a3530656669323032656933383065656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313832656475363a33303332303575323a3530656669323033656933393265656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313833656475363a33303333303575323a3530656669323034656933383565656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313834656475363a33303333303575323a3530656669323035656933373065656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313835656475363a33303333303575323a3530656669323036656933373065656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313836656475363a33303333303575323a3530656669323037656933383565656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313837656475363a33303333303575323a3530656669323038656933393465656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313838656475363a33303334303575323a3530656669323039656933393065656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313839656475363a33303334303575323a3530656669323130656933373565656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313930656475363a33303334303575323a3530656669323131656933373565656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313931656475363a33303334303575323a3530656669323132656933393065656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313932656475363a33303334303575323a353065666932313365693339366565656c69313030333332656565"))); + var worldState = new World(MockUtil.MockModernWorldState) + .SetAvatarState(avatarAddress, avatarState); + var stateRootHash = worldState.Trie.Hash; + var tip = new Domain.Model.BlockChain.Block( + BlockHash.FromString("613dfa26e104465790625ae7bc03fc27a64947c02a9377565ec190405ef7154b"), + BlockHash.FromString("36456be15af9a5b9b13a02c7ce1e849ae9cba8781ec309010499cdb93e29237d"), + default(Address), + 0, + Timestamp: DateTimeOffset.UtcNow, + StateRootHash: stateRootHash, + Transactions: ImmutableArray.Empty ); + BlockChainRepository.Setup(repository => repository.GetTip()) + .Returns(tip); + WorldStateRepository.Setup(repository => repository.GetWorldState(stateRootHash)) + .Returns(worldState); string query = $@"query {{ stateQuery {{ @@ -823,90 +901,30 @@ public async Task Avatar() [InlineData(false)] public async Task ActivationKeyNonce(bool trim) { - var adminPrivateKey = new PrivateKey(); - var adminAddress = adminPrivateKey.Address; - var activatedAccounts = ImmutableHashSet
.Empty; - var nonce = new byte[] { 0x00, 0x01, 0x02, 0x03 }; var privateKey = new PrivateKey(); - (ActivationKey activationKey, PendingActivationState pendingActivation) = - ActivationKey.Create(privateKey, nonce); - var pendingActivationStates = new List - { - pendingActivation, - }; - Block genesis = - BlockChain.ProposeGenesisBlock( - transactions: ImmutableList.Empty - .Add( - Transaction.Create( - 0, ProposerPrivateKey, - null, - new IAction[] - { - new Initialize( - new ValidatorSet( - GenesisValidators.Select( - v => new Validator(v.PublicKey, BigInteger.One)).ToList()), - ImmutableDictionary.Create()) - }.Select(a => a.PlainValue))) - .Add( - Transaction.Create( - 1, - ProposerPrivateKey, - null, - new ActionBase[] - { - new InitializeStates( - rankingState: new RankingState0(), - shopState: new ShopState(), - gameConfigState: new GameConfigState(), - redeemCodeState: new RedeemCodeState(Bencodex.Types.Dictionary.Empty - .Add("address", RedeemCodeState.Address.Serialize()) - .Add("map", Bencodex.Types.Dictionary.Empty) - ), - adminAddressState: new AdminState(adminAddress, 1500000), - activatedAccountsState: new ActivatedAccountsState(activatedAccounts), -#pragma warning disable CS0618 - // Use of obsolete method Currency.Legacy(): - // https://github.com/planetarium/lib9c/discussions/1319 - goldCurrencyState: new GoldCurrencyState(Currency.Legacy("NCG", 2, null)), -#pragma warning restore CS0618 - goldDistributions: new GoldDistribution[0], - tableSheets: _sheets, - pendingActivationStates: pendingActivationStates.ToArray() - ), - }.ToPlainValues())) - ); - - var apvPrivateKey = new PrivateKey(); - var apv = AppProtocolVersion.Sign(apvPrivateKey, 0); - var userPrivateKey = new PrivateKey(); - var consensusPrivateKey = new PrivateKey(); - var properties = new LibplanetNodeServiceProperties - { - Host = System.Net.IPAddress.Loopback.ToString(), - AppProtocolVersion = apv, - GenesisBlock = genesis, - StorePath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()), - StoreStatesCacheSize = 2, - SwarmPrivateKey = new PrivateKey(), - ConsensusPrivateKey = consensusPrivateKey, - ConsensusPort = null, - Port = null, - NoMiner = true, - Render = false, - Peers = ImmutableHashSet.Empty, - TrustedAppProtocolVersionSigners = null, - IceServers = ImmutableList.Empty, - ConsensusSeeds = ImmutableList.Empty, - ConsensusPeers = ImmutableList.Empty - }; + var random = new Random(); + var nonce = new byte[10]; + random.NextBytes(nonce); + var (activationKey, pendingActivationState) = ActivationKey.Create(privateKey, nonce); + + var worldState = new World(MockUtil.MockModernWorldState) + .SetLegacyState(activationKey.PendingAddress, pendingActivationState.Serialize()); + var stateRootHash = worldState.Trie.Hash; + + var tip = new Domain.Model.BlockChain.Block( + BlockHash.FromString("613dfa26e104465790625ae7bc03fc27a64947c02a9377565ec190405ef7154b"), + BlockHash.FromString("36456be15af9a5b9b13a02c7ce1e849ae9cba8781ec309010499cdb93e29237d"), + default(Address), + 0, + Timestamp: DateTimeOffset.UtcNow, + StateRootHash: stateRootHash, + Transactions: ImmutableArray.Empty + ); - var blockPolicy = NineChroniclesNodeService.GetBlockPolicy(Planet.Odin, StaticActionLoaderSingleton.Instance, null); - var service = new NineChroniclesNodeService(userPrivateKey, properties, blockPolicy, Planet.Odin, StaticActionLoaderSingleton.Instance); - StandaloneContextFx.NineChroniclesNodeService = service; - StandaloneContextFx.BlockChain = service.Swarm?.BlockChain; - AppendEmptyBlock(GenesisValidators); + BlockChainRepository.Setup(repo => repo.GetTip()) + .Returns(tip); + WorldStateRepository.Setup(repo => repo.GetWorldState(stateRootHash)) + .Returns(worldState); var code = activationKey.Encode(); if (trim) @@ -923,150 +941,72 @@ public async Task ActivationKeyNonce(bool trim) [Theory] [InlineData("1", "invitationCode format is invalid.")] [InlineData("9330b3287bd2bbc38770c69ae7cd380350c60a1dff9ec41254f3048d5b3eb01c", "invitationCode format is invalid.")] + public async Task ActivationKeyNonce_ThrowError_WithInvalidFormatCode(string code, string msg) + { + var query = $"query {{ activationKeyNonce(invitationCode: \"{code}\") }}"; + var queryResult = await ExecuteQueryAsync(query); + Assert.NotNull(queryResult.Errors); + Assert.Single(queryResult.Errors!); + Assert.Equal(msg, queryResult.Errors!.First().Message); + } + + [Theory] [InlineData("9330b3287bd2bbc38770c69ae7cd380350c60a1dff9ec41254f3048d5b3eb01c/44C889Af1e1e90213Cff5d69C9086c34ecCb60B0", "invitationCode is invalid.")] - public async Task ActivationKeyNonce_Throw_ExecutionError(string code, string msg) + public async Task ActivationKeyNonce_ThrowError_WithOutdatedCode(string code, string msg) { - var adminPrivateKey = new PrivateKey(); - var adminAddress = adminPrivateKey.Address; - var activatedAccounts = ImmutableHashSet
.Empty; - var pendingActivationStates = new List(); - - Block genesis = - BlockChain.ProposeGenesisBlock( - transactions: ImmutableList.Empty - .Add(Transaction.Create( - 0, - new PrivateKey(), - null, - new ActionBase[] - { - new InitializeStates( - rankingState: new RankingState0(), - shopState: new ShopState(), - gameConfigState: new GameConfigState(), - redeemCodeState: new RedeemCodeState(Bencodex.Types.Dictionary.Empty - .Add("address", RedeemCodeState.Address.Serialize()) - .Add("map", Bencodex.Types.Dictionary.Empty) - ), - adminAddressState: new AdminState(adminAddress, 1500000), - activatedAccountsState: new ActivatedAccountsState(activatedAccounts), -#pragma warning disable CS0618 - // Use of obsolete method Currency.Legacy(): - // https://github.com/planetarium/lib9c/discussions/1319 - goldCurrencyState: new GoldCurrencyState(Currency.Legacy("NCG", 2, null)), -#pragma warning restore CS0618 - goldDistributions: new GoldDistribution[0], - tableSheets: _sheets, - pendingActivationStates: pendingActivationStates.ToArray() - ), - }.ToPlainValues())) - ); + var activationKey = ActivationKey.Decode(code); + + var worldState = new World(MockUtil.MockModernWorldState) + .SetLegacyState(activationKey.PendingAddress, Bencodex.Types.Null.Value); + var stateRootHash = worldState.Trie.Hash; + + var tip = new Domain.Model.BlockChain.Block( + BlockHash.FromString("613dfa26e104465790625ae7bc03fc27a64947c02a9377565ec190405ef7154b"), + BlockHash.FromString("36456be15af9a5b9b13a02c7ce1e849ae9cba8781ec309010499cdb93e29237d"), + default(Address), + 0, + Timestamp: DateTimeOffset.UtcNow, + StateRootHash: stateRootHash, + Transactions: ImmutableArray.Empty + ); - var apvPrivateKey = new PrivateKey(); - var apv = AppProtocolVersion.Sign(apvPrivateKey, 0); - var userPrivateKey = new PrivateKey(); - var consensusPrivateKey = new PrivateKey(); - var properties = new LibplanetNodeServiceProperties - { - Host = System.Net.IPAddress.Loopback.ToString(), - AppProtocolVersion = apv, - GenesisBlock = genesis, - StorePath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()), - StoreStatesCacheSize = 2, - SwarmPrivateKey = new PrivateKey(), - ConsensusPrivateKey = consensusPrivateKey, - ConsensusPort = null, - Port = null, - NoMiner = true, - Render = false, - Peers = ImmutableHashSet.Empty, - TrustedAppProtocolVersionSigners = null, - IceServers = ImmutableList.Empty, - ConsensusSeeds = ImmutableList.Empty, - ConsensusPeers = ImmutableList.Empty - }; - var blockPolicy = new BlockPolicySource().GetPolicy(); - - var service = new NineChroniclesNodeService(userPrivateKey, properties, blockPolicy, Planet.Odin, StaticActionLoaderSingleton.Instance); - StandaloneContextFx.NineChroniclesNodeService = service; - StandaloneContextFx.BlockChain = service.Swarm?.BlockChain; + BlockChainRepository.Setup(repo => repo.GetTip()) + .Returns(tip); + WorldStateRepository.Setup(repo => repo.GetWorldState(stateRootHash)) + .Returns(worldState); var query = $"query {{ activationKeyNonce(invitationCode: \"{code}\") }}"; var queryResult = await ExecuteQueryAsync(query); Assert.NotNull(queryResult.Errors); Assert.Single(queryResult.Errors!); Assert.Equal(msg, queryResult.Errors!.First().Message); - } [Fact] public async Task Balance() { - var adminPrivateKey = new PrivateKey(); - var adminAddress = adminPrivateKey.Address; - var activatedAccounts = ImmutableHashSet
.Empty; - var pendingActivationStates = new List(); - - Block genesis = - BlockChain.ProposeGenesisBlock( - transactions: ImmutableList.Empty.Add( - Transaction.Create(0, new PrivateKey(), null, - new ActionBase[] - { - new InitializeStates( - rankingState: new RankingState0(), - shopState: new ShopState(), - gameConfigState: new GameConfigState(), - redeemCodeState: new RedeemCodeState(Bencodex.Types.Dictionary.Empty - .Add("address", RedeemCodeState.Address.Serialize()) - .Add("map", Bencodex.Types.Dictionary.Empty) - ), - adminAddressState: new AdminState(adminAddress, 1500000), - activatedAccountsState: new ActivatedAccountsState(activatedAccounts), -#pragma warning disable CS0618 - // Use of obsolete method Currency.Legacy(): https://github.com/planetarium/lib9c/discussions/1319 - goldCurrencyState: new GoldCurrencyState(Currency.Legacy("NCG", 2, null)), -#pragma warning restore CS0618 - goldDistributions: new GoldDistribution[0], - tableSheets: _sheets, - pendingActivationStates: pendingActivationStates.ToArray() - ), - }.ToPlainValues())) - ); - - var apvPrivateKey = new PrivateKey(); - var apv = AppProtocolVersion.Sign(apvPrivateKey, 0); - - var userPrivateKey = new PrivateKey(); - var consensusPrivateKey = new PrivateKey(); - var properties = new LibplanetNodeServiceProperties - { - Host = System.Net.IPAddress.Loopback.ToString(), - AppProtocolVersion = apv, - GenesisBlock = genesis, - StorePath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()), - StoreStatesCacheSize = 2, - SwarmPrivateKey = new PrivateKey(), - ConsensusPrivateKey = consensusPrivateKey, - ConsensusPort = null, - Port = null, - NoMiner = true, - Render = false, - Peers = ImmutableHashSet.Empty, - TrustedAppProtocolVersionSigners = null, - IceServers = ImmutableList.Empty, - ConsensusSeeds = ImmutableList.Empty, - ConsensusPeers = ImmutableList.Empty - }; - var blockPolicy = new BlockPolicySource().GetPolicy(); - - var service = new NineChroniclesNodeService(userPrivateKey, properties, blockPolicy, Planet.Odin, StaticActionLoaderSingleton.Instance); - StandaloneContextFx.NineChroniclesNodeService = service; - StandaloneContextFx.BlockChain = service.Swarm?.BlockChain; + var address = new PrivateKey().Address; + var worldState = new World(MockUtil.MockModernWorldState); + var stateRootHash = worldState.Trie.Hash; + + var tip = new Domain.Model.BlockChain.Block( + BlockHash.FromString("613dfa26e104465790625ae7bc03fc27a64947c02a9377565ec190405ef7154b"), + BlockHash.FromString("36456be15af9a5b9b13a02c7ce1e849ae9cba8781ec309010499cdb93e29237d"), + default(Address), + 0, + Timestamp: DateTimeOffset.UtcNow, + StateRootHash: stateRootHash, + Transactions: ImmutableArray.Empty + ); + + BlockChainRepository.Setup(repo => repo.GetTip()) + .Returns(tip); + WorldStateRepository.Setup(repo => repo.GetWorldState(stateRootHash)) + .Returns(worldState); var query = $@"query {{ stateQuery {{ - balance(address: ""{adminAddress}"", currency: {{ decimalPlaces: 18, ticker: ""CRYSTAL"" }}) {{ + balance(address: ""{address}"", currency: {{ decimalPlaces: 18, ticker: ""CRYSTAL"" }}) {{ quantity currency {{ ticker diff --git a/NineChronicles.Headless.Tests/NineChronicles.Headless.Tests.csproj b/NineChronicles.Headless.Tests/NineChronicles.Headless.Tests.csproj index 85ffad613..a5a69b9d2 100644 --- a/NineChronicles.Headless.Tests/NineChronicles.Headless.Tests.csproj +++ b/NineChronicles.Headless.Tests/NineChronicles.Headless.Tests.csproj @@ -21,10 +21,12 @@ + + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -44,4 +46,8 @@ + + + + diff --git a/NineChronicles.Headless/BlockChainContext.cs b/NineChronicles.Headless/BlockChainContext.cs index 17a53f10a..34d04d631 100644 --- a/NineChronicles.Headless/BlockChainContext.cs +++ b/NineChronicles.Headless/BlockChainContext.cs @@ -15,7 +15,7 @@ public BlockChainContext(StandaloneContext standaloneContext) _standaloneContext = standaloneContext; } - public bool Preloaded => _standaloneContext.NodeStatus.PreloadEnded; + public bool Preloaded => _standaloneContext.PreloadEnded; public BlockChain BlockChain => _standaloneContext.BlockChain; public IStore Store => _standaloneContext.Store; public Swarm Swarm => _standaloneContext.Swarm; diff --git a/NineChronicles.Headless/Domain/Model/BlockChain/Block.cs b/NineChronicles.Headless/Domain/Model/BlockChain/Block.cs new file mode 100644 index 000000000..439144261 --- /dev/null +++ b/NineChronicles.Headless/Domain/Model/BlockChain/Block.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Security.Cryptography; +using Libplanet.Common; +using Libplanet.Crypto; +using Libplanet.Types.Blocks; +using Libplanet.Types.Tx; + +namespace NineChronicles.Headless.Domain.Model.BlockChain; + +using StateRootHash = HashDigest; + +public record Block( +#pragma warning disable SA1313 + BlockHash Hash, + BlockHash? PreviousHash, + Address Miner, + long Index, + DateTimeOffset Timestamp, + StateRootHash StateRootHash, + IEnumerable Transactions); +#pragma warning restore SA1313 diff --git a/NineChronicles.Headless/GraphQLService.cs b/NineChronicles.Headless/GraphQLService.cs index 3beadf376..9104fdbfa 100644 --- a/NineChronicles.Headless/GraphQLService.cs +++ b/NineChronicles.Headless/GraphQLService.cs @@ -18,6 +18,10 @@ using NineChronicles.Headless.GraphTypes; using NineChronicles.Headless.Middleware; using NineChronicles.Headless.Properties; +using NineChronicles.Headless.Repositories.BlockChain; +using NineChronicles.Headless.Repositories.StateTrie; +using NineChronicles.Headless.Repositories.Transaction; +using NineChronicles.Headless.Repositories.WorldState; using Serilog; namespace NineChronicles.Headless @@ -157,6 +161,12 @@ public void ConfigureServices(IServiceCollection services) } services.AddTransient(); + + // Repositories + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); services.AddHealthChecks(); diff --git a/NineChronicles.Headless/GraphTypes/BlockHeaderType.cs b/NineChronicles.Headless/GraphTypes/BlockHeaderType.cs index 575114bc4..3a06b6313 100644 --- a/NineChronicles.Headless/GraphTypes/BlockHeaderType.cs +++ b/NineChronicles.Headless/GraphTypes/BlockHeaderType.cs @@ -2,6 +2,7 @@ using Libplanet.Crypto; using Libplanet.Types.Blocks; using Libplanet.Explorer.GraphTypes; +using Block = NineChronicles.Headless.Domain.Model.BlockChain.Block; namespace NineChronicles.Headless.GraphTypes { diff --git a/NineChronicles.Headless/GraphTypes/NodeStatus.cs b/NineChronicles.Headless/GraphTypes/NodeStatus.cs index e03ef3bb6..3a21cbb15 100644 --- a/NineChronicles.Headless/GraphTypes/NodeStatus.cs +++ b/NineChronicles.Headless/GraphTypes/NodeStatus.cs @@ -1,6 +1,5 @@ using GraphQL; using GraphQL.Types; -using Libplanet.Blockchain; using Libplanet.Crypto; using Libplanet.Types.Blocks; using Libplanet.Explorer.GraphTypes; @@ -10,11 +9,17 @@ using System.Collections.Immutable; using System.Linq; using System.Reflection; +using NineChronicles.Headless.Repositories.BlockChain; +using Block = NineChronicles.Headless.Domain.Model.BlockChain.Block; namespace NineChronicles.Headless.GraphTypes { - public class NodeStatusType : ObjectGraphType + public class NodeStatusType : ObjectGraphType { +#pragma warning disable SA1313 + public record NodeStatus(bool BootstrapEnded, bool PreloadEnded, bool IsMining); +#pragma warning restore SA1313 + private static readonly string _productVersion = Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "Unknown"; @@ -22,13 +27,7 @@ public class NodeStatusType : ObjectGraphType Assembly.GetExecutingAssembly().GetCustomAttribute() ?.InformationalVersion ?? "Unknown"; - public bool BootstrapEnded { get; set; } - - public bool PreloadEnded { get; set; } - - public bool IsMining { get; set; } - - public NodeStatusType(StandaloneContext context) + public NodeStatusType(StandaloneContext context, IBlockChainRepository blockChainRepository) { Field>( name: "bootstrapEnded", @@ -43,9 +42,7 @@ public NodeStatusType(StandaloneContext context) Field>( name: "tip", description: "Block header of the tip block from the current canonical chain.", - resolve: _ => context.BlockChain is { } blockChain - ? BlockHeaderType.FromBlock(blockChain.Tip) - : null + resolve: _ => BlockHeaderType.FromBlock(blockChainRepository.GetTip()) ); Field>>( name: "topmostBlocks", @@ -72,13 +69,8 @@ public NodeStatusType(StandaloneContext context) description: "The topmost blocks from the current node.", resolve: fieldContext => { - if (context.BlockChain is null) - { - throw new InvalidOperationException($"{nameof(context.BlockChain)} is null."); - } - IEnumerable blocks = - GetTopmostBlocks(context.BlockChain, fieldContext.GetArgument("offset")); + blockChainRepository.IterateBlocksDescending(fieldContext.GetArgument("offset")); if (fieldContext.GetArgument("miner") is { } miner) { blocks = blocks.Where(b => b.Miner.Equals(miner)); @@ -136,9 +128,7 @@ public NodeStatusType(StandaloneContext context) name: "genesis", description: "Block header of the genesis block from the current chain.", resolve: fieldContext => - context.BlockChain is { } blockChain - ? BlockHeaderType.FromBlock(blockChain.Genesis) - : null + BlockHeaderType.FromBlock(blockChainRepository.GetBlock(0)) ); Field>( name: "isMining", @@ -173,32 +163,5 @@ context.BlockChain is { } blockChain resolve: _ => _informationalVersion ); } - - private IEnumerable GetTopmostBlocks(BlockChain blockChain, int offset) - { - Block block = blockChain.Tip; - - while (offset > 0) - { - offset--; - if (block.PreviousHash is { } prev) - { - block = blockChain[prev]; - } - } - - while (true) - { - yield return block; - if (block.PreviousHash is { } prev) - { - block = blockChain[prev]; - } - else - { - break; - } - } - } } } diff --git a/NineChronicles.Headless/GraphTypes/StandaloneQuery.cs b/NineChronicles.Headless/GraphTypes/StandaloneQuery.cs index 8b3ab9dde..cc9e97804 100644 --- a/NineChronicles.Headless/GraphTypes/StandaloneQuery.cs +++ b/NineChronicles.Headless/GraphTypes/StandaloneQuery.cs @@ -26,10 +26,13 @@ using NineChronicles.Headless.GraphTypes.States; using NineChronicles.Headless.GraphTypes.Diff; using System.Security.Cryptography; -using System.Text; -using Libplanet.Store.Trie; +using Libplanet.KeyStore; +using NineChronicles.Headless.Repositories.BlockChain; +using NineChronicles.Headless.Repositories.StateTrie; +using NineChronicles.Headless.Repositories.Transaction; +using NineChronicles.Headless.Repositories.WorldState; using static NineChronicles.Headless.NCActionUtils; -using Transaction = Libplanet.Types.Tx.Transaction; +using Block = NineChronicles.Headless.Domain.Model.BlockChain.Block; namespace NineChronicles.Headless.GraphTypes { @@ -37,7 +40,7 @@ public class StandaloneQuery : ObjectGraphType { private static readonly ActivitySource ActivitySource = new ActivitySource("NineChronicles.Headless.GraphTypes.StandaloneQuery"); - public StandaloneQuery(StandaloneContext standaloneContext, IConfiguration configuration, ActionEvaluationPublisher publisher, StateMemoryCache stateMemoryCache) + public StandaloneQuery(StandaloneContext standaloneContext, IKeyStore keyStore, IConfiguration configuration, StateMemoryCache stateMemoryCache, IWorldStateRepository worldStateRepository, IBlockChainRepository blockChainRepository, ITransactionRepository transactionRepository, IStateTrieRepository stateTrieRepository) { bool useSecretToken = configuration[GraphQLService.SecretTokenKey] is { }; if (Convert.ToBoolean(configuration.GetSection("Jwt")["EnableJwtAuthentication"])) @@ -59,28 +62,18 @@ public StandaloneQuery(StandaloneContext standaloneContext, IConfiguration confi resolve: context => { using var activity = ActivitySource.StartActivity("stateQuery"); - BlockHash blockHash = (context.GetArgument("hash"), context.GetArgument("index")) switch + Block block = (context.GetArgument("hash"), context.GetArgument("index")) switch { - ({ } bytes, null) => new BlockHash(bytes), - (null, { } index) => standaloneContext.BlockChain[index].Hash, + ({ } bytes, null) => blockChainRepository.GetBlock(new BlockHash(bytes)), + (null, { } index) => blockChainRepository.GetBlock(index), (not null, not null) => throw new ArgumentException("Only one of 'hash' and 'index' must be given."), - (null, null) => standaloneContext.BlockChain.Tip.Hash, + (null, null) => blockChainRepository.GetTip(), }; - activity?.AddTag("BlockHash", blockHash.ToString()); - - if (!(standaloneContext.BlockChain is { } chain)) - { - return null; - } - - if (!(blockHash is { } hash)) - { - return null; - } + activity?.AddTag("BlockHash", block.Hash.ToString()); return new StateContext( - chain.GetWorldState(blockHash), - chain[blockHash].Index, + worldStateRepository.GetWorldState(block.StateRootHash), + block.Index, stateMemoryCache ); } @@ -108,13 +101,6 @@ public StandaloneQuery(StandaloneContext standaloneContext, IConfiguration confi resolve: context => { using var activity = ActivitySource.StartActivity("diffs"); - if (!(standaloneContext.BlockChain is BlockChain blockChain)) - { - throw new ExecutionError( - $"{nameof(StandaloneContext)}.{nameof(StandaloneContext.BlockChain)} was not set yet!" - ); - } - var baseIndex = context.GetArgument("baseIndex"); var changedIndex = context.GetArgument("changedIndex"); @@ -126,51 +112,15 @@ public StandaloneQuery(StandaloneContext standaloneContext, IConfiguration confi ); } - var baseBlockStateRootHash = blockChain[baseIndex].StateRootHash.ToString(); - var changedBlockStateRootHash = blockChain[changedIndex].StateRootHash.ToString(); + var baseBlockStateRootHash = blockChainRepository.GetBlock(baseIndex).StateRootHash.ToString(); + var changedBlockStateRootHash = blockChainRepository.GetBlock(changedIndex).StateRootHash.ToString(); var baseStateRootHash = HashDigest.FromString(baseBlockStateRootHash); var targetStateRootHash = HashDigest.FromString( changedBlockStateRootHash ); - var stateStore = standaloneContext.StateStore; - var baseTrieModel = stateStore.GetStateRoot(baseStateRootHash); - var targetTrieModel = stateStore.GetStateRoot(targetStateRootHash); - - IDiffType[] diffs = baseTrieModel - .Diff(targetTrieModel) - .Select(x => - { - if (x.TargetValue is not null) - { - var baseSubTrieModel = stateStore.GetStateRoot(new HashDigest((Binary)x.SourceValue)); - var targetSubTrieModel = stateStore.GetStateRoot(new HashDigest((Binary)x.TargetValue)); - var subDiff = baseSubTrieModel - .Diff(targetSubTrieModel) - .Select(diff => - { - return new StateDiffType.Value( - Encoding.Default.GetString(diff.Path.ByteArray.ToArray()), - diff.SourceValue, - diff.TargetValue); - }).ToArray(); - return (IDiffType)new RootStateDiffType.Value( - Encoding.Default.GetString(x.Path.ByteArray.ToArray()), - subDiff - ); - } - else - { - return new StateDiffType.Value( - Encoding.Default.GetString(x.Path.ByteArray.ToArray()), - x.SourceValue, - x.TargetValue - ); - } - }).ToArray(); - - return diffs; + return stateTrieRepository.CompareStateTrie(baseStateRootHash, targetStateRootHash); } ); @@ -201,13 +151,6 @@ public StandaloneQuery(StandaloneContext standaloneContext, IConfiguration confi resolve: context => { using var activity = ActivitySource.StartActivity("accountDiffs"); - if (!(standaloneContext.BlockChain is BlockChain blockChain)) - { - throw new ExecutionError( - $"{nameof(StandaloneContext)}.{nameof(StandaloneContext.BlockChain)} was not set yet!" - ); - } - var baseIndex = context.GetArgument("baseIndex"); var changedIndex = context.GetArgument("changedIndex"); var accountAddress = context.GetArgument
("accountAddress"); @@ -220,39 +163,15 @@ public StandaloneQuery(StandaloneContext standaloneContext, IConfiguration confi ); } - var baseBlockStateRootHash = blockChain[baseIndex].StateRootHash.ToString(); - var changedBlockStateRootHash = blockChain[changedIndex].StateRootHash.ToString(); + var baseBlockStateRootHash = blockChainRepository.GetBlock(baseIndex).StateRootHash.ToString(); + var changedBlockStateRootHash = blockChainRepository.GetBlock(changedIndex).StateRootHash.ToString(); var baseStateRootHash = HashDigest.FromString(baseBlockStateRootHash); var targetStateRootHash = HashDigest.FromString( changedBlockStateRootHash ); - var stateStore = standaloneContext.StateStore; - var baseTrieModel = stateStore.GetStateRoot(baseStateRootHash); - var targetTrieModel = stateStore.GetStateRoot(targetStateRootHash); - - var accountKey = new KeyBytes(ByteUtil.Hex(accountAddress.ByteArray)); - - Binary GetAccountState(ITrie model, KeyBytes key) - { - return model.Get(key) is Binary state ? state : throw new Exception($"Account state not found."); - } - - var baseAccountState = GetAccountState(baseTrieModel, accountKey); - var targetAccountState = GetAccountState(targetTrieModel, accountKey); - - var baseSubTrieModel = stateStore.GetStateRoot(new HashDigest(baseAccountState)); - var targetSubTrieModel = stateStore.GetStateRoot(new HashDigest(targetAccountState)); - - var subDiff = baseSubTrieModel - .Diff(targetSubTrieModel) - .Select(diff => new StateDiffType.Value( - Encoding.Default.GetString(diff.Path.ByteArray.ToArray()), - diff.SourceValue, - diff.TargetValue)) - .ToArray(); - return subDiff; + return stateTrieRepository.CompareStateAccountTrie(baseStateRootHash, targetStateRootHash, accountAddress); } ); @@ -267,29 +186,22 @@ Binary GetAccountState(ITrie model, KeyBytes key) resolve: context => { using var activity = ActivitySource.StartActivity("state"); - if (!(standaloneContext.BlockChain is BlockChain blockChain)) - { - throw new ExecutionError( - $"{nameof(StandaloneContext)}.{nameof(StandaloneContext.BlockChain)} was not set yet!"); - } - - var blockHash = (context.GetArgument("hash"), context.GetArgument("index")) switch + var block = (context.GetArgument("hash"), context.GetArgument("index")) switch { (not null, not null) => throw new ArgumentException( "Only one of 'hash' and 'index' must be given."), - (null, { } index) => blockChain[index].Hash, - ({ } bytes, null) => new BlockHash(bytes), - (null, null) => blockChain.Tip.Hash, + (null, { } index) => blockChainRepository.GetBlock(index), + ({ } bytes, null) => blockChainRepository.GetBlock(new BlockHash(bytes)), + (null, null) => blockChainRepository.GetTip(), }; var accountAddress = context.GetArgument
("accountAddress"); var address = context.GetArgument
("address"); activity? - .AddTag("BlockHash", blockHash.ToString()) + .AddTag("BlockHash", block.Hash.ToString()) .AddTag("Address", address.ToString()); - - var state = blockChain - .GetWorldState(blockHash) + var state = worldStateRepository + .GetWorldState(block.StateRootHash) .GetAccountState(accountAddress) .GetState(address); @@ -320,31 +232,15 @@ Binary GetAccountState(ITrie model, KeyBytes key) activity?.AddTag("BlockHash", blockHash.ToString()); - if (!(standaloneContext.Store is { } store)) - { - throw new InvalidOperationException(); - } - - if (!(store.GetBlockDigest(blockHash) is { } digest)) - { - throw new ArgumentException("blockHash"); - } + var block = blockChainRepository.GetBlock(blockHash); var recipient = context.GetArgument("recipient"); - IEnumerable blockTxs = digest.TxIds - .Select(bytes => new TxId(bytes)) - .Select(txid => - { - return store.GetTransaction(txid) ?? - throw new InvalidOperationException($"Transaction {txid} not found."); - }); - - var filtered = blockTxs + var filtered = block.Transactions .Where(tx => tx.Actions.Count == 1) .Select(tx => ( - store.GetTxExecution(blockHash, tx.Id) ?? + transactionRepository.GetTxExecution(blockHash, tx.Id) ?? throw new InvalidOperationException($"TxExecution {tx.Id} not found."), ToAction(tx.Actions[0]) )) @@ -369,7 +265,7 @@ Binary GetAccountState(ITrie model, KeyBytes key) Field( name: "keyStore", deprecationReason: "Use `planet key` command instead. https://www.npmjs.com/package/@planetarium/cli", - resolve: context => standaloneContext.KeyStore + resolve: context => keyStore ).AuthorizeWithLocalPolicyIf(useSecretToken); Field>( @@ -377,31 +273,32 @@ Binary GetAccountState(ITrie model, KeyBytes key) resolve: _ => { using var activity = ActivitySource.StartActivity("nodeStatus"); - return new NodeStatusType(standaloneContext); + return standaloneContext.NodeStatus; }); Field>( name: "chainQuery", deprecationReason: "Use /graphql/explorer", - resolve: context => new { } + resolve: _ => new object() ); Field>( name: "validation", description: "The validation method provider for Libplanet types.", - resolve: context => new ValidationQuery(standaloneContext)); + resolve: _ => new object() + ); Field>( name: "activationStatus", description: "Check if the provided address is activated.", deprecationReason: "Since NCIP-15, it doesn't care account activation.", - resolve: context => new ActivationStatusQuery(standaloneContext)) + resolve: _ => new object()) .AuthorizeWithLocalPolicyIf(useSecretToken); Field>( name: "peerChainState", description: "Get the peer's block chain state", - resolve: context => new PeerChainStateQuery(standaloneContext)); + resolve: _ => new object()); Field>( name: "goldBalance", @@ -412,26 +309,21 @@ Binary GetAccountState(ITrie model, KeyBytes key) resolve: context => { using var activity = ActivitySource.StartActivity("goldBalance"); - if (!(standaloneContext.BlockChain is BlockChain blockChain)) - { - throw new ExecutionError( - $"{nameof(StandaloneContext)}.{nameof(StandaloneContext.BlockChain)} was not set yet!"); - } - Address address = context.GetArgument
("address"); byte[] blockHashByteArray = context.GetArgument("hash"); - var blockHash = blockHashByteArray is null - ? blockChain.Tip.Hash - : new BlockHash(blockHashByteArray); + var block = blockHashByteArray is null + ? blockChainRepository.GetTip() + : blockChainRepository.GetBlock(new BlockHash(blockHashByteArray)); + var worldState = worldStateRepository.GetWorldState(block.StateRootHash); Currency currency = new GoldCurrencyState( - (Dictionary)blockChain.GetWorldState(blockHash).GetLegacyState(GoldCurrencyState.Address) + (Dictionary)worldState + .GetLegacyState(GoldCurrencyState.Address) ).Currency; activity? - .AddTag("BlockHash", blockHash.ToString()) + .AddTag("BlockHash", block.Hash.ToString()) .AddTag("Address", address.ToString()); - - return blockChain.GetWorldState(blockHash).GetBalance( + return worldState.GetBalance( address, currency ).GetQuantityString(); @@ -448,15 +340,10 @@ Binary GetAccountState(ITrie model, KeyBytes key) resolve: context => { using var activity = ActivitySource.StartActivity("nextTxNonce"); - if (!(standaloneContext.BlockChain is BlockChain blockChain)) - { - throw new ExecutionError( - $"{nameof(StandaloneContext)}.{nameof(StandaloneContext.BlockChain)} was not set yet!"); - } Address address = context.GetArgument
("address"); activity?.AddTag("Address", address.ToString()); - return blockChain.GetNextTxNonce(address); + return transactionRepository.GetNextTxNonce(address); } ); @@ -470,14 +357,8 @@ Binary GetAccountState(ITrie model, KeyBytes key) ), resolve: context => { - if (!(standaloneContext.BlockChain is BlockChain blockChain)) - { - throw new ExecutionError( - $"{nameof(StandaloneContext)}.{nameof(StandaloneContext.BlockChain)} was not set yet!"); - } - var txId = context.GetArgument("txId"); - return blockChain.GetTransaction(txId); + return transactionRepository.GetTransaction(txId); } ); @@ -532,13 +413,11 @@ Binary GetAccountState(ITrie model, KeyBytes key) agentAddress = (Address)address; } - - BlockHash offset = blockChain.Tip.Hash; - + HashDigest offset = blockChainRepository.GetTip().StateRootHash; activity? .AddTag("BlockHash", offset.ToString()) .AddTag("Address", address.ToString()); - IWorldState worldState = blockChain.GetWorldState(offset); + IWorldState worldState = worldStateRepository.GetWorldState(offset); #pragma warning disable S3247 if (worldState.GetAgentState(agentAddress) is { } agentState) #pragma warning restore S3247 @@ -580,7 +459,7 @@ Binary GetAccountState(ITrie model, KeyBytes key) resolve: context => { using var activity = ActivitySource.StartActivity("transaction"); - return new TransactionHeadlessQuery(standaloneContext); + return new object(); }); Field>( @@ -600,9 +479,10 @@ Binary GetAccountState(ITrie model, KeyBytes key) $"{nameof(StandaloneContext)}.{nameof(StandaloneContext.BlockChain)} was not set yet!"); } + var worldState = worldStateRepository.GetWorldState(blockChainRepository.GetTip().StateRootHash); string invitationCode = context.GetArgument("invitationCode"); ActivationKey activationKey = ActivationKey.Decode(invitationCode); - if (blockChain.GetWorldState().GetLegacyState(activationKey.PendingAddress) is Dictionary dictionary) + if (worldState.GetLegacyState(activationKey.PendingAddress) is Dictionary dictionary) { var pending = new PendingActivationState(dictionary); ActivateAccount action = activationKey.CreateActivateAccount(pending.Nonce); @@ -629,12 +509,6 @@ Binary GetAccountState(ITrie model, KeyBytes key) ), resolve: context => { - if (!(standaloneContext.BlockChain is { } blockChain)) - { - throw new ExecutionError( - $"{nameof(StandaloneContext)}.{nameof(StandaloneContext.BlockChain)} was not set yet!"); - } - ActivationKey activationKey; try { @@ -646,7 +520,9 @@ Binary GetAccountState(ITrie model, KeyBytes key) { throw new ExecutionError("invitationCode format is invalid."); } - if (blockChain.GetWorldState().GetLegacyState(activationKey.PendingAddress) is Dictionary dictionary) + + var worldState = worldStateRepository.GetWorldState(blockChainRepository.GetTip().StateRootHash); + if (worldState.GetLegacyState(activationKey.PendingAddress) is Dictionary dictionary) { var pending = new PendingActivationState(dictionary); return ByteUtil.Hex(pending.Nonce); @@ -659,7 +535,7 @@ Binary GetAccountState(ITrie model, KeyBytes key) Field>( name: "rpcInformation", description: "Query for rpc mode information.", - resolve: context => new RpcInformationQuery(publisher) + resolve: _ => new object() ); Field>( @@ -668,7 +544,7 @@ Binary GetAccountState(ITrie model, KeyBytes key) resolve: context => { using var activity = ActivitySource.StartActivity("actionQuery"); - return new ActionQuery(standaloneContext); + return new object(); }); Field>( @@ -698,7 +574,7 @@ Binary GetAccountState(ITrie model, KeyBytes key) resolve: context => { using var activity = ActivitySource.StartActivity("actionTxQuery"); - return new ActionTxQuery(standaloneContext); + return new object(); }); Field>( @@ -707,7 +583,7 @@ Binary GetAccountState(ITrie model, KeyBytes key) resolve: context => { using var activity = ActivitySource.StartActivity("addressQuery"); - return new AddressQuery(standaloneContext); + return new object(); }); } } diff --git a/NineChronicles.Headless/GraphTypes/StandaloneSubscription.cs b/NineChronicles.Headless/GraphTypes/StandaloneSubscription.cs index af0600912..502ce41c7 100644 --- a/NineChronicles.Headless/GraphTypes/StandaloneSubscription.cs +++ b/NineChronicles.Headless/GraphTypes/StandaloneSubscription.cs @@ -152,8 +152,8 @@ public StandaloneSubscription(StandaloneContext standaloneContext, IConfiguratio { Name = "nodeStatus", Type = typeof(NodeStatusType), - Resolver = new FuncFieldResolver(context => (context.Source as NodeStatusType)!), - Subscriber = new EventStreamResolver(context => StandaloneContext.NodeStatusSubject.AsObservable()), + Resolver = new FuncFieldResolver(context => (context.Source as NodeStatusType.NodeStatus)!), + Subscriber = new EventStreamResolver(context => StandaloneContext.NodeStatusSubject.AsObservable()), }); AddField(new EventStreamFieldType { diff --git a/NineChronicles.Headless/HostBuilderExtensions.cs b/NineChronicles.Headless/HostBuilderExtensions.cs index 0767f4bbc..9224d976f 100644 --- a/NineChronicles.Headless/HostBuilderExtensions.cs +++ b/NineChronicles.Headless/HostBuilderExtensions.cs @@ -35,6 +35,7 @@ NineChroniclesNodeService service services.AddSingleton(provider => service.Swarm); services.AddSingleton(provider => service.BlockChain); services.AddSingleton(provider => service.Store); + services.AddSingleton(provider => service.StateStore); services.AddSingleton(provider => Serilog.Log.Logger); services.AddSingleton(provider => service.StateKeyValueStore); diff --git a/NineChronicles.Headless/NineChroniclesNodeService.cs b/NineChronicles.Headless/NineChroniclesNodeService.cs index ceef8bcb4..1133b47ca 100644 --- a/NineChronicles.Headless/NineChroniclesNodeService.cs +++ b/NineChronicles.Headless/NineChroniclesNodeService.cs @@ -54,6 +54,8 @@ public class NineChroniclesNodeService : IHostedService, IDisposable public IStore Store => NodeService.Store; + public IStateStore StateStore => NodeService.StateStore; + public IKeyValueStore StateKeyValueStore => NodeService.StateKeyValueStore; public PrivateKey? MinerPrivateKey { get; set; } diff --git a/NineChronicles.Headless/Repositories/BlockChain/BlockChainRepository.cs b/NineChronicles.Headless/Repositories/BlockChain/BlockChainRepository.cs new file mode 100644 index 000000000..a97f61961 --- /dev/null +++ b/NineChronicles.Headless/Repositories/BlockChain/BlockChainRepository.cs @@ -0,0 +1,87 @@ +namespace NineChronicles.Headless.Repositories.BlockChain; + +using System.Collections.Generic; +using Libplanet.Blockchain; +using Libplanet.Types.Blocks; +using Block = NineChronicles.Headless.Domain.Model.BlockChain.Block; +using LibplanetBlock = Libplanet.Types.Blocks.Block; + +public class BlockChainRepository : IBlockChainRepository +{ + private readonly BlockChain _blockChain; + + private static Block Convert(LibplanetBlock block) + { + return new Block( + block.Hash, + block.PreviousHash, + block.Miner, + block.Index, + block.Timestamp, + block.StateRootHash, + block.Transactions + ); + } + + public BlockChainRepository(BlockChain blockChain) + { + _blockChain = blockChain; + } + + public Block GetTip() + { + return FetchTip(); + } + + public Block GetBlock(long index) + { + return FetchBlock(index); + } + + public Block GetBlock(BlockHash blockHash) + { + return FetchBlock(blockHash); + } + + public IEnumerable IterateBlocksDescending(long offset) + { + Block block = FetchTip(); + + while (offset > 0) + { + offset--; + if (block.PreviousHash is { } prev) + { + block = FetchBlock(prev); + } + } + + while (true) + { + yield return block; + if (block.PreviousHash is { } prev) + { + block = FetchBlock(prev); + } + else + { + break; + } + } + } + + private Block FetchTip() + { + return Convert(_blockChain.Tip); + } + + private Block FetchBlock(BlockHash blockHash) + { + return Convert(_blockChain[blockHash]); + } + + private Block FetchBlock(long index) + { + return Convert(_blockChain[index]); + } +} diff --git a/NineChronicles.Headless/Repositories/BlockChain/IBlockChainRepository.cs b/NineChronicles.Headless/Repositories/BlockChain/IBlockChainRepository.cs new file mode 100644 index 000000000..57fa71abf --- /dev/null +++ b/NineChronicles.Headless/Repositories/BlockChain/IBlockChainRepository.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using Libplanet.Types.Blocks; + +namespace NineChronicles.Headless.Repositories.BlockChain; + +using Block = NineChronicles.Headless.Domain.Model.BlockChain.Block; + +public interface IBlockChainRepository +{ + Block GetTip(); + Block GetBlock(long index); + Block GetBlock(BlockHash blockHash); + IEnumerable IterateBlocksDescending(long offset); +} diff --git a/NineChronicles.Headless/Repositories/StateTrie/IStateTrieRepository.cs b/NineChronicles.Headless/Repositories/StateTrie/IStateTrieRepository.cs new file mode 100644 index 000000000..da5bdbce9 --- /dev/null +++ b/NineChronicles.Headless/Repositories/StateTrie/IStateTrieRepository.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using System.Security.Cryptography; +using Libplanet.Common; +using Libplanet.Crypto; +using NineChronicles.Headless.GraphTypes.Diff; + +namespace NineChronicles.Headless.Repositories.StateTrie; + +public interface IStateTrieRepository +{ + IEnumerable CompareStateTrie(HashDigest baseStateRootHash, HashDigest targetStateRootHash); + IEnumerable CompareStateAccountTrie(HashDigest baseStateRootHash, HashDigest targetStateRootHash, Address accountAddress); +} diff --git a/NineChronicles.Headless/Repositories/StateTrie/StateTrieRepository.cs b/NineChronicles.Headless/Repositories/StateTrie/StateTrieRepository.cs new file mode 100644 index 000000000..193468362 --- /dev/null +++ b/NineChronicles.Headless/Repositories/StateTrie/StateTrieRepository.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using Bencodex.Types; +using Libplanet.Common; +using Libplanet.Crypto; +using Libplanet.Store; +using Libplanet.Store.Trie; +using NineChronicles.Headless.GraphTypes.Diff; + +namespace NineChronicles.Headless.Repositories.StateTrie; + +public class StateTrieRepository : IStateTrieRepository +{ + private readonly IStateStore _stateStore; + + public StateTrieRepository(IStateStore stateStore) + { + _stateStore = stateStore; + } + + public IEnumerable CompareStateTrie(HashDigest baseStateRootHash, HashDigest targetStateRootHash) + { + var baseTrieModel = _stateStore.GetStateRoot(baseStateRootHash); + var targetTrieModel = _stateStore.GetStateRoot(targetStateRootHash); + + return baseTrieModel + .Diff(targetTrieModel) + .Select(x => + { + if (x.TargetValue is not null) + { + var baseSubTrieModel = _stateStore.GetStateRoot(new HashDigest((Binary)x.SourceValue)); + var targetSubTrieModel = _stateStore.GetStateRoot(new HashDigest((Binary)x.TargetValue)); + var subDiff = baseSubTrieModel + .Diff(targetSubTrieModel) + .Select(diff => + { + return new StateDiffType.Value( + Encoding.Default.GetString(diff.Path.ByteArray.ToArray()), + diff.SourceValue, + diff.TargetValue); + }).ToArray(); + return (IDiffType)new RootStateDiffType.Value( + Encoding.Default.GetString(x.Path.ByteArray.ToArray()), + subDiff + ); + } + else + { + return new StateDiffType.Value( + Encoding.Default.GetString(x.Path.ByteArray.ToArray()), + x.SourceValue, + x.TargetValue + ); + } + }); + } + + public IEnumerable CompareStateAccountTrie(HashDigest baseStateRootHash, HashDigest targetStateRootHash, Address accountAddress) + { + var baseTrieModel = _stateStore.GetStateRoot(baseStateRootHash); + var targetTrieModel = _stateStore.GetStateRoot(targetStateRootHash); + + var accountKey = new KeyBytes(ByteUtil.Hex(accountAddress.ByteArray)); + + Binary GetAccountState(ITrie model, KeyBytes key) + { + return model.Get(key) is Binary state ? state : throw new Exception($"Account state not found."); + } + + var baseAccountState = GetAccountState(baseTrieModel, accountKey); + var targetAccountState = GetAccountState(targetTrieModel, accountKey); + + var baseSubTrieModel = _stateStore.GetStateRoot(new HashDigest(baseAccountState)); + var targetSubTrieModel = _stateStore.GetStateRoot(new HashDigest(targetAccountState)); + + return baseSubTrieModel + .Diff(targetSubTrieModel) + .Select(diff => new StateDiffType.Value( + Encoding.Default.GetString(diff.Path.ByteArray.ToArray()), + diff.SourceValue, + diff.TargetValue)); + } +} diff --git a/NineChronicles.Headless/Repositories/Transaction/ITransactionRepository.cs b/NineChronicles.Headless/Repositories/Transaction/ITransactionRepository.cs new file mode 100644 index 000000000..59e8cb8ee --- /dev/null +++ b/NineChronicles.Headless/Repositories/Transaction/ITransactionRepository.cs @@ -0,0 +1,12 @@ +namespace NineChronicles.Headless.Repositories.Transaction; + +using Libplanet.Crypto; +using Libplanet.Types.Blocks; +using Libplanet.Types.Tx; + +public interface ITransactionRepository +{ + Transaction? GetTransaction(TxId txId); + TxExecution? GetTxExecution(BlockHash blockHash, TxId txId); + long GetNextTxNonce(Address address); +} diff --git a/NineChronicles.Headless/Repositories/Transaction/TransactionRepository.cs b/NineChronicles.Headless/Repositories/Transaction/TransactionRepository.cs new file mode 100644 index 000000000..8fe828f2e --- /dev/null +++ b/NineChronicles.Headless/Repositories/Transaction/TransactionRepository.cs @@ -0,0 +1,31 @@ +namespace NineChronicles.Headless.Repositories.Transaction; + +using Libplanet.Blockchain; +using Libplanet.Crypto; +using Libplanet.Types.Blocks; +using Libplanet.Types.Tx; + +public class TransactionRepository : ITransactionRepository +{ + private readonly BlockChain _blockChain; + + public TransactionRepository(BlockChain blockChain) + { + _blockChain = blockChain; + } + + public Transaction? GetTransaction(TxId txId) + { + return _blockChain.GetTransaction(txId); + } + + public TxExecution? GetTxExecution(BlockHash blockHash, TxId txId) + { + return _blockChain.GetTxExecution(blockHash, txId); + } + + public long GetNextTxNonce(Address address) + { + return _blockChain.GetNextTxNonce(address); + } +} diff --git a/NineChronicles.Headless/Repositories/WorldState/IWorldStateRepository.cs b/NineChronicles.Headless/Repositories/WorldState/IWorldStateRepository.cs new file mode 100644 index 000000000..e4fe41f86 --- /dev/null +++ b/NineChronicles.Headless/Repositories/WorldState/IWorldStateRepository.cs @@ -0,0 +1,13 @@ +using System.Security.Cryptography; +using Libplanet.Action.State; +using Libplanet.Common; +using Libplanet.Types.Blocks; + +namespace NineChronicles.Headless.Repositories.WorldState; + +public interface IWorldStateRepository +{ + IWorldState GetWorldState(long index); + IWorldState GetWorldState(BlockHash blockHash); + IWorldState GetWorldState(HashDigest stateRootHash); +} diff --git a/NineChronicles.Headless/Repositories/WorldState/WorldStateRepository.cs b/NineChronicles.Headless/Repositories/WorldState/WorldStateRepository.cs new file mode 100644 index 000000000..6cc389a4f --- /dev/null +++ b/NineChronicles.Headless/Repositories/WorldState/WorldStateRepository.cs @@ -0,0 +1,32 @@ +namespace NineChronicles.Headless.Repositories.WorldState; + +using System.Security.Cryptography; +using Libplanet.Action.State; +using Libplanet.Common; +using Libplanet.Types.Blocks; +using Libplanet.Blockchain; + +public class WorldStateRepository : IWorldStateRepository +{ + private readonly BlockChain _blockChain; + + public WorldStateRepository(BlockChain blockChain) + { + _blockChain = blockChain; + } + + public IWorldState GetWorldState(long index) + { + return _blockChain.GetWorldState(_blockChain[index].StateRootHash); + } + + public IWorldState GetWorldState(BlockHash blockHash) + { + return _blockChain.GetWorldState(blockHash); + } + + public IWorldState GetWorldState(HashDigest stateRootHash) + { + return _blockChain.GetWorldState(stateRootHash); + } +} diff --git a/NineChronicles.Headless/StandaloneContext.cs b/NineChronicles.Headless/StandaloneContext.cs index 6ad387e9a..8aa9bca85 100644 --- a/NineChronicles.Headless/StandaloneContext.cs +++ b/NineChronicles.Headless/StandaloneContext.cs @@ -36,7 +36,7 @@ public IKeyStore KeyStore public bool BootstrapEnded { get; set; } public bool PreloadEnded { get; set; } public bool IsMining { get; set; } - public ReplaySubject NodeStatusSubject { get; } = new(1); + public ReplaySubject NodeStatusSubject { get; } = new(1); public ReplaySubject PreloadStateSubject { get; } = new(5); public Subject DifferentAppProtocolVersionEncounterSubject { get; } = @@ -51,12 +51,8 @@ public IKeyStore KeyStore AgentAddresses { get; } = new ConcurrentDictionary>(); - public NodeStatusType NodeStatus => new(this) - { - BootstrapEnded = BootstrapEnded, - PreloadEnded = PreloadEnded, - IsMining = IsMining, - }; + public NodeStatusType.NodeStatus NodeStatus => new( + BootstrapEnded: BootstrapEnded, PreloadEnded: PreloadEnded, IsMining: IsMining); public IStore Store { From a95e420d75a7c93bfe260afdb0997009b9514561 Mon Sep 17 00:00:00 2001 From: moreal Date: Thu, 5 Sep 2024 22:47:33 +0900 Subject: [PATCH 56/72] Apply `dotnet format` --- .../Commands/TxCommandTest.cs | 15 +++------------ NineChronicles.Headless.Tests/GraphQLTestUtils.cs | 2 +- .../GraphTypes/StandaloneQueryTest.cs | 8 ++++---- NineChronicles.Headless/GraphQLService.cs | 2 +- .../BlockChain/BlockChainRepository.cs | 2 +- 5 files changed, 10 insertions(+), 19 deletions(-) diff --git a/NineChronicles.Headless.Executable.Tests/Commands/TxCommandTest.cs b/NineChronicles.Headless.Executable.Tests/Commands/TxCommandTest.cs index 1704478f8..dc09855de 100644 --- a/NineChronicles.Headless.Executable.Tests/Commands/TxCommandTest.cs +++ b/NineChronicles.Headless.Executable.Tests/Commands/TxCommandTest.cs @@ -73,18 +73,9 @@ public void Sign_Stake(bool gas) } [Theory] - [InlineData(null, null, false)] - [InlineData(0, null, true)] - [InlineData(ClaimStakeReward2.ObsoletedIndex - 1, null, false)] - [InlineData(ClaimStakeReward2.ObsoletedIndex, null, true)] - [InlineData(ClaimStakeReward2.ObsoletedIndex + 1, null, false)] - [InlineData(long.MaxValue, null, true)] - [InlineData(null, 1, false)] - [InlineData(null, 2, true)] - [InlineData(null, 3, false)] - [InlineData(null, 4, true)] - [InlineData(null, 5, false)] - public void Sign_ClaimStakeReward(long? blockIndex, int? actionVersion, bool gas) + [InlineData(true)] + [InlineData(false)] + public void Sign_ClaimStakeReward(bool gas) { var filePath = Path.Combine(Path.GetTempPath(), Path.GetTempFileName()); var actionCommand = new ActionCommand(_console); diff --git a/NineChronicles.Headless.Tests/GraphQLTestUtils.cs b/NineChronicles.Headless.Tests/GraphQLTestUtils.cs index e113ac220..88707debf 100644 --- a/NineChronicles.Headless.Tests/GraphQLTestUtils.cs +++ b/NineChronicles.Headless.Tests/GraphQLTestUtils.cs @@ -88,7 +88,7 @@ public static Task ExecuteQueryAsync( var graphType = (IObjectGraphType)serviceProvider.GetService(typeof(TObjectGraphType))!; return ExecuteQueryAsync(graphType, query, userContext, source); } - + public static Task ExecuteQueryAsync( IObjectGraphType graphType, string query, diff --git a/NineChronicles.Headless.Tests/GraphTypes/StandaloneQueryTest.cs b/NineChronicles.Headless.Tests/GraphTypes/StandaloneQueryTest.cs index e993818c0..5503d6fb5 100644 --- a/NineChronicles.Headless.Tests/GraphTypes/StandaloneQueryTest.cs +++ b/NineChronicles.Headless.Tests/GraphTypes/StandaloneQueryTest.cs @@ -623,7 +623,7 @@ public async Task GoldBalance() }, data ); - + worldState = worldState.MintAsset(new ActionContext(), userAddress, Currencies.Crystal * 10); stateRootHash = worldState.Trie.Hash; tip = new Domain.Model.BlockChain.Block( @@ -813,7 +813,7 @@ public async Task MonsterCollectionStatus_MonsterCollectionState_Null(bool miner { StandaloneContextFx.NineChroniclesNodeService.MinerPrivateKey = null; } - + // FIXME: Remove the above lines after removing `StandaloneContext` dependency. var worldState = new World(MockUtil.MockModernWorldState) .SetLegacyState(Addresses.GoldCurrency, new GoldCurrencyState(Currencies.Crystal).Serialize()) @@ -949,7 +949,7 @@ public async Task ActivationKeyNonce_ThrowError_WithInvalidFormatCode(string cod Assert.Single(queryResult.Errors!); Assert.Equal(msg, queryResult.Errors!.First().Message); } - + [Theory] [InlineData("9330b3287bd2bbc38770c69ae7cd380350c60a1dff9ec41254f3048d5b3eb01c/44C889Af1e1e90213Cff5d69C9086c34ecCb60B0", "invitationCode is invalid.")] public async Task ActivationKeyNonce_ThrowError_WithOutdatedCode(string code, string msg) @@ -998,7 +998,7 @@ public async Task Balance() StateRootHash: stateRootHash, Transactions: ImmutableArray.Empty ); - + BlockChainRepository.Setup(repo => repo.GetTip()) .Returns(tip); WorldStateRepository.Setup(repo => repo.GetWorldState(stateRootHash)) diff --git a/NineChronicles.Headless/GraphQLService.cs b/NineChronicles.Headless/GraphQLService.cs index 9104fdbfa..c68027eb6 100644 --- a/NineChronicles.Headless/GraphQLService.cs +++ b/NineChronicles.Headless/GraphQLService.cs @@ -161,7 +161,7 @@ public void ConfigureServices(IServiceCollection services) } services.AddTransient(); - + // Repositories services.AddSingleton(); services.AddSingleton(); diff --git a/NineChronicles.Headless/Repositories/BlockChain/BlockChainRepository.cs b/NineChronicles.Headless/Repositories/BlockChain/BlockChainRepository.cs index a97f61961..dcf0b5486 100644 --- a/NineChronicles.Headless/Repositories/BlockChain/BlockChainRepository.cs +++ b/NineChronicles.Headless/Repositories/BlockChain/BlockChainRepository.cs @@ -79,7 +79,7 @@ private Block FetchBlock(BlockHash blockHash) { return Convert(_blockChain[blockHash]); } - + private Block FetchBlock(long index) { return Convert(_blockChain[index]); From c599eeef9449ffda11109c2e1717d8b451781cdd Mon Sep 17 00:00:00 2001 From: moreal Date: Thu, 5 Sep 2024 23:24:55 +0900 Subject: [PATCH 57/72] Setup states simply --- .../GraphTypes/GraphQLTestBase.cs | 21 +++ .../GraphTypes/StandaloneQueryTest.cs | 169 +++--------------- 2 files changed, 41 insertions(+), 149 deletions(-) diff --git a/NineChronicles.Headless.Tests/GraphTypes/GraphQLTestBase.cs b/NineChronicles.Headless.Tests/GraphTypes/GraphQLTestBase.cs index e8c1dfc97..eff90d826 100644 --- a/NineChronicles.Headless.Tests/GraphTypes/GraphQLTestBase.cs +++ b/NineChronicles.Headless.Tests/GraphTypes/GraphQLTestBase.cs @@ -34,6 +34,8 @@ using System.Threading; using System.Threading.Tasks; using Bencodex.Types; +using Libplanet.Action.State; +using Libplanet.Mocks; using Libplanet.Types.Tx; using Moq; using NineChronicles.Headless.Executable.Tests.KeyStore; @@ -201,6 +203,25 @@ protected async Task StartAsync( return task; } + protected void SetupStatesOnTip(Func func) + { + var worldState = func(new World(MockUtil.MockModernWorldState)); + var stateRootHash = worldState.Trie.Hash; + var tip = new Domain.Model.BlockChain.Block( + BlockHash.FromString("613dfa26e104465790625ae7bc03fc27a64947c02a9377565ec190405ef7154b"), + BlockHash.FromString("36456be15af9a5b9b13a02c7ce1e849ae9cba8781ec309010499cdb93e29237d"), + default(Address), + 0, + Timestamp: DateTimeOffset.UtcNow, + StateRootHash: stateRootHash, + Transactions: ImmutableArray.Empty + ); + BlockChainRepository.Setup(repository => repository.GetTip()) + .Returns(tip); + WorldStateRepository.Setup(repository => repository.GetWorldState(stateRootHash)) + .Returns(worldState); + } + protected LibplanetNodeService CreateLibplanetNodeService( Block genesisBlock, AppProtocolVersion appProtocolVersion, diff --git a/NineChronicles.Headless.Tests/GraphTypes/StandaloneQueryTest.cs b/NineChronicles.Headless.Tests/GraphTypes/StandaloneQueryTest.cs index 5503d6fb5..019b1762d 100644 --- a/NineChronicles.Headless.Tests/GraphTypes/StandaloneQueryTest.cs +++ b/NineChronicles.Headless.Tests/GraphTypes/StandaloneQueryTest.cs @@ -66,24 +66,9 @@ public async Task GetState() { var adminAddress = new PrivateKey().Address; Address adminStateAddress = AdminState.Address; - var worldState = new World(MockUtil.MockModernWorldState) - .SetLegacyState(adminStateAddress, new AdminState(adminAddress, 10000).Serialize()); - var stateRootHash = worldState.Trie.Hash; - var tip = new Domain.Model.BlockChain.Block( - BlockHash.FromString("613dfa26e104465790625ae7bc03fc27a64947c02a9377565ec190405ef7154b"), - BlockHash.FromString("36456be15af9a5b9b13a02c7ce1e849ae9cba8781ec309010499cdb93e29237d"), - default(Address), - 0, - Timestamp: DateTimeOffset.UtcNow, - StateRootHash: stateRootHash, - Transactions: ImmutableArray.Empty - ); - - BlockChainRepository.Setup(repository => repository.GetTip()) - .Returns(tip); - WorldStateRepository.Setup(repository => repository.GetWorldState(stateRootHash)) - .Returns(worldState); + SetupStatesOnTip(world => world + .SetLegacyState(adminStateAddress, new AdminState(adminAddress, 10000).Serialize())); var result = await ExecuteQueryAsync($"query {{ state(accountAddress: \"{ReservedAddresses.LegacyAccount}\", address: \"{adminStateAddress}\") }}"); var data = (Dictionary)((ExecutionNode)result.Data!).ToValue()!; @@ -596,22 +581,9 @@ public async Task ActivationStatus(bool existsActivatedAccounts) public async Task GoldBalance() { var userAddress = new PrivateKey().Address; - var worldState = new World(MockUtil.MockModernWorldState) - .SetLegacyState(Addresses.GoldCurrency, new GoldCurrencyState(Currencies.Crystal).Serialize()); - var stateRootHash = worldState.Trie.Hash; - var tip = new Domain.Model.BlockChain.Block( - BlockHash.FromString("613dfa26e104465790625ae7bc03fc27a64947c02a9377565ec190405ef7154b"), - BlockHash.FromString("36456be15af9a5b9b13a02c7ce1e849ae9cba8781ec309010499cdb93e29237d"), - default(Address), - 0, - Timestamp: DateTimeOffset.UtcNow, - StateRootHash: stateRootHash, - Transactions: ImmutableArray.Empty - ); - BlockChainRepository.Setup(repository => repository.GetTip()) - .Returns(tip); - WorldStateRepository.Setup(repository => repository.GetWorldState(stateRootHash)) - .Returns(worldState); + + SetupStatesOnTip(world => + world.SetLegacyState(Addresses.GoldCurrency, new GoldCurrencyState(Currencies.Crystal).Serialize())); var query = $"query {{ goldBalance(address: \"{userAddress}\") }}"; var queryResult = await ExecuteQueryAsync(query); @@ -624,21 +596,9 @@ public async Task GoldBalance() data ); - worldState = worldState.MintAsset(new ActionContext(), userAddress, Currencies.Crystal * 10); - stateRootHash = worldState.Trie.Hash; - tip = new Domain.Model.BlockChain.Block( - BlockHash.FromString("613dfa26e104465790625ae7bc03fc27a64947c02a9377565ec190405ef7154b"), - BlockHash.FromString("36456be15af9a5b9b13a02c7ce1e849ae9cba8781ec309010499cdb93e29237d"), - default(Address), - 0, - Timestamp: DateTimeOffset.UtcNow, - StateRootHash: stateRootHash, - Transactions: ImmutableArray.Empty - ); - BlockChainRepository.Setup(repository => repository.GetTip()) - .Returns(tip); - WorldStateRepository.Setup(repository => repository.GetWorldState(stateRootHash)) - .Returns(worldState); + SetupStatesOnTip(world => + world.SetLegacyState(Addresses.GoldCurrency, new GoldCurrencyState(Currencies.Crystal).Serialize()) + .MintAsset(new ActionContext(), userAddress, Currencies.Crystal * 10)); queryResult = await ExecuteQueryAsync(query); data = (Dictionary)((ExecutionNode)queryResult.Data!).ToValue()!; @@ -757,23 +717,9 @@ public async Task MonsterCollectionStatus_AgentState_Null(bool miner) } // FIXME: Remove the above lines after removing `StandaloneContext` dependency. - var worldState = new World(MockUtil.MockModernWorldState) - .SetLegacyState(Addresses.GoldCurrency, new GoldCurrencyState(Currencies.Crystal).Serialize()) - .MintAsset(new ActionContext(), userAddress, Currencies.Crystal * 10); - var stateRootHash = worldState.Trie.Hash; - var tip = new Domain.Model.BlockChain.Block( - BlockHash.FromString("613dfa26e104465790625ae7bc03fc27a64947c02a9377565ec190405ef7154b"), - BlockHash.FromString("36456be15af9a5b9b13a02c7ce1e849ae9cba8781ec309010499cdb93e29237d"), - default(Address), - 0, - Timestamp: DateTimeOffset.UtcNow, - StateRootHash: stateRootHash, - Transactions: ImmutableArray.Empty - ); - BlockChainRepository.Setup(repository => repository.GetTip()) - .Returns(tip); - WorldStateRepository.Setup(repository => repository.GetWorldState(stateRootHash)) - .Returns(worldState); + SetupStatesOnTip(world => + world.SetLegacyState(Addresses.GoldCurrency, new GoldCurrencyState(Currencies.Crystal).Serialize()) + .MintAsset(new ActionContext(), userAddress, Currencies.Crystal * 10)); string queryArgs = miner ? "" : $@"(address: ""{userAddress}"")"; string query = $@"query {{ @@ -815,24 +761,10 @@ public async Task MonsterCollectionStatus_MonsterCollectionState_Null(bool miner } // FIXME: Remove the above lines after removing `StandaloneContext` dependency. - var worldState = new World(MockUtil.MockModernWorldState) + SetupStatesOnTip(world => world .SetLegacyState(Addresses.GoldCurrency, new GoldCurrencyState(Currencies.Crystal).Serialize()) .SetAgentState(userAddress, new AgentState(userAddress)) - .MintAsset(new ActionContext(), userAddress, Currencies.Crystal * 10); - var stateRootHash = worldState.Trie.Hash; - var tip = new Domain.Model.BlockChain.Block( - BlockHash.FromString("613dfa26e104465790625ae7bc03fc27a64947c02a9377565ec190405ef7154b"), - BlockHash.FromString("36456be15af9a5b9b13a02c7ce1e849ae9cba8781ec309010499cdb93e29237d"), - default(Address), - 0, - Timestamp: DateTimeOffset.UtcNow, - StateRootHash: stateRootHash, - Transactions: ImmutableArray.Empty - ); - BlockChainRepository.Setup(repository => repository.GetTip()) - .Returns(tip); - WorldStateRepository.Setup(repository => repository.GetWorldState(stateRootHash)) - .Returns(worldState); + .MintAsset(new ActionContext(), userAddress, Currencies.Crystal * 10)); string queryArgs = miner ? "" : $@"(address: ""{userAddress}"")"; string query = $@"query {{ @@ -868,22 +800,8 @@ public async Task Avatar() "6475313a316475323a496475313a3175343a4e616d6575393a59676764726173696c7531303a5374616765426567696e75313a317532323a5374616765436c6561726564426c6f636b496e64657875363a3437323632387531343a5374616765436c6561726564496475323a353075383a5374616765456e6475323a35307531383a556e6c6f636b6564426c6f636b496e64657875363a3434343436366575353a31303030316475323a496475353a313030303175343a4e616d657531313a4d696d69736272756e6e727531303a5374616765426567696e75383a31303030303030317532323a5374616765436c6561726564426c6f636b496e64657875323a2d317531343a5374616765436c6561726564496475323a2d3175383a5374616765456e6475383a31303030303032307531383a556e6c6f636b6564426c6f636b496e64657875363a3438373734336575313a326475323a496475313a3275343a4e616d6575373a416c666865696d7531303a5374616765426567696e75323a35317532323a5374616765436c6561726564426c6f636b496e64657875363a3438373734337531343a5374616765436c6561726564496475333a31303075383a5374616765456e6475333a3130307531383a556e6c6f636b6564426c6f636b496e64657875363a3437323632386575313a336475323a496475313a3375343a4e616d657531323a5376617274616c666865696d7531303a5374616765426567696e75333a3130317532323a5374616765436c6561726564426c6f636b496e64657875363a3530343031387531343a5374616765436c6561726564496475333a31353075383a5374616765456e6475333a3135307531383a556e6c6f636b6564426c6f636b496e64657875363a3438373734336575313a346475323a496475313a3475343a4e616d6575363a4173676172647531303a5374616765426567696e75333a3135317532323a5374616765436c6561726564426c6f636b496e64657875373a343839313637337531343a5374616765436c6561726564496475333a32303075383a5374616765456e6475333a3230307531383a556e6c6f636b6564426c6f636b496e64657875363a3530343031386575313a356475323a496475313a3575343a4e616d657531303a4d757370656c6865696d7531303a5374616765426567696e75333a3230317532323a5374616765436c6561726564426c6f636b496e64657875373a373132353232397531343a5374616765436c6561726564496475333a32353075383a5374616765456e6475333a3235307531383a556e6c6f636b6564426c6f636b496e64657875373a343839313637336575313a366475323a496475313a3675343a4e616d6575393a4a6f74756e6865696d7531303a5374616765426567696e75333a3235317532323a5374616765436c6561726564426c6f636b496e64657875383a31313237353837337531343a5374616765436c6561726564496475333a33303075383a5374616765456e6475333a3330307531383a556e6c6f636b6564426c6f636b496e64657875373a373132353232396575313a376475323a496475313a3775343a4e616d6575383a4e69666c6865696d7531303a5374616765426567696e75333a3330317532323a5374616765436c6561726564426c6f636b496e64657875383a31313439323332367531343a5374616765436c6561726564496475333a33333275383a5374616765456e6475333a3335307531383a556e6c6f636b6564426c6f636b496e64657875383a31313237353837336565"))); avatarState.questList = new QuestList((List)new Codec().Decode(Convert.FromHexString( "6c6935656c6c7531303a776f726c6451756573747469316569306569313030303031656475363a34303030303075323a32306574656c7531303a776f726c6451756573747469326569306569313030303032656475363a34303030303075323a32306574656c7531303a776f726c6451756573747469336569306569313030303033656475363a33303330303075313a3175363a34303030303075333a3430306574656c7531303a776f726c6451756573747469346569306569313030303034656475363a33303630343075313a376574656c7531303a776f726c6451756573747469356569306569313030303035656475363a34303030303075323a32306574656c7531303a776f726c6451756573747469366569306569313030303036656475363a33303331303075313a316574656c7531303a776f726c6451756573747469376569306569313030303037656475363a34303030303075323a32306574656c7531303a776f726c6451756573747469386569306569313030303038656475363a34303030303075323a32306574656c7531303a776f726c6451756573747469396569306569313030303039656475363a33303332303075313a316574656c7531303a776f726c645175657374746931306569306569313030303130656475363a34303030303075323a32306574656c7531303a776f726c645175657374746931316569306569313030303131656475363a33303630323375313a3175363a33303630343175313a326574656c7531303a776f726c645175657374746931326569306569313030303132656475363a34303030303075323a32306574656c7531303a776f726c645175657374746931336569306569313030303133656475363a33303630323575313a3375363a33303630343175313a326574656c7531303a776f726c645175657374746931346569306569313030303134656475363a34303030303075323a32306574656c7531303a776f726c645175657374746931356569306569313030303135656475363a33303333303075313a316574656c7531303a776f726c645175657374746931366569306569313030303136656475363a34303030303075323a32306574656c7531303a776f726c645175657374746931376569306569313030303137656475363a34303030303075323a32306574656c7531303a776f726c645175657374746931386569306569313030303138656475363a34303030303075323a32306574656c7531303a776f726c645175657374746931396569306569313030303139656475363a34303030303075323a323075363a35303030303075313a316574656c7531303a776f726c645175657374746932306569306569313030303230656475363a33303334303075313a316574656c7531303a776f726c645175657374746932316569306569313030303231656475363a33303630303175313a3175363a33303630343475313a316574656c7531303a776f726c645175657374746932326569306569313030303232656475363a33303630303075313a3175363a33303630303275313a316574656c7531303a776f726c645175657374746932336569306569313030303233656475363a34303030303075323a32306574656c7531303a776f726c645175657374746932346569306569313030303234656475363a33303330303175313a326574656c7531303a776f726c645175657374746932356569306569313030303235656475363a33303630303075313a3175363a33303630303175313a316574656c7531303a776f726c645175657374746932366569306569313030303236656475363a34303030303075323a32306574656c7531303a776f726c645175657374746932376569306569313030303237656475363a34303030303075323a32306574656c7531303a776f726c645175657374746932386569306569313030303238656475363a34303030303075323a32306574656c7531303a776f726c645175657374746932396569306569313030303239656475363a34303030303075323a32306574656c7531303a776f726c645175657374746933306569306569313030303330656475363a34303030303075323a32306574656c7531303a776f726c645175657374746933316569306569313030303331656475363a34303030303075323a32306574656c7531303a776f726c645175657374746933326569306569313030303332656475363a34303030303075323a32306574656c7531303a776f726c645175657374746933336569306569313030303333656475363a34303030303075323a32306574656c7531303a776f726c645175657374746933346569306569313030303334656475363a34303030303075323a32306574656c7531303a776f726c645175657374746933356569306569313030303335656475363a34303030303075323a32306574656c7531303a776f726c645175657374746933366569306569313030303336656475363a34303030303075323a32306574656c7531303a776f726c645175657374746933376569306569313030303337656475363a34303030303075323a32306574656c7531303a776f726c645175657374746933386569306569313030303338656475363a34303030303075323a32306574656c7531303a776f726c645175657374746933396569306569313030303339656475363a34303030303075323a32306574656c7531303a776f726c645175657374746934306569306569313030303430656475363a34303030303075323a323075363a35303030303075313a316574656c7531303a776f726c645175657374746934316569306569313030303431656475363a34303030303075323a32306574656c7531303a776f726c645175657374746934326569306569313030303432656475363a34303030303075323a32306574656c7531303a776f726c645175657374746934336569306569313030303433656475363a34303030303075323a32306574656c7531303a776f726c645175657374746934346569306569313030303434656475363a34303030303075323a32306574656c7531303a776f726c645175657374746934356569306569313030303435656475363a34303030303075323a32306574656c7531303a776f726c645175657374746934366569306569313030303436656475363a34303030303075323a32306574656c7531303a776f726c645175657374746934376569306569313030303437656475363a34303030303075323a32306574656c7531303a776f726c645175657374746934386569306569313030303438656475363a34303030303075323a32306574656c7531303a776f726c645175657374746934396569306569313030303439656475363a34303030303075323a32306574656c7531303a776f726c645175657374746935306569306569313030303530656475363a33303430303275313a316574656c7531303a776f726c645175657374746935316569306569313030303531656475363a34303030303075323a32306574656c7531303a776f726c645175657374746935326569306569313030303532656475363a34303030303075323a32306574656c7531303a776f726c645175657374746935336569306569313030303533656475363a34303030303075323a32306574656c7531303a776f726c645175657374746935346569306569313030303534656475363a34303030303075323a32306574656c7531303a776f726c645175657374746935356569306569313030303535656475363a34303030303075323a32306574656c7531303a776f726c645175657374746935366569306569313030303536656475363a34303030303075323a32306574656c7531303a776f726c645175657374746935376569306569313030303537656475363a34303030303075323a32306574656c7531303a776f726c645175657374746935386569306569313030303538656475363a34303030303075323a32306574656c7531303a776f726c645175657374746935396569306569313030303539656475363a34303030303075323a32306574656c7531303a776f726c645175657374746936306569306569313030303630656475363a34303030303075323a323075363a35303030303075313a316574656c7531303a776f726c645175657374746936316569306569313030303631656475363a34303030303075323a32306574656c7531303a776f726c645175657374746936326569306569313030303632656475363a34303030303075323a32306574656c7531303a776f726c645175657374746936336569306569313030303633656475363a34303030303075323a32306574656c7531303a776f726c645175657374746936346569306569313030303634656475363a34303030303075323a32306574656c7531303a776f726c645175657374746936356569306569313030303635656475363a34303030303075323a32306574656c7531303a776f726c645175657374746936366569306569313030303636656475363a34303030303075323a32306574656c7531303a776f726c645175657374746936376569306569313030303637656475363a34303030303075323a32306574656c7531303a776f726c645175657374746936386569306569313030303638656475363a34303030303075323a32306574656c7531303a776f726c645175657374746936396569306569313030303639656475363a34303030303075323a32306574656c7531303a776f726c645175657374746937306569306569313030303730656475363a34303030303075323a32306574656c7531303a776f726c645175657374746937316569306569313030303731656475363a34303030303075323a32306574656c7531303a776f726c645175657374746937326569306569313030303732656475363a34303030303075323a32306574656c7531303a776f726c645175657374746937336569306569313030303733656475363a34303030303075323a32306574656c7531303a776f726c645175657374746937346569306569313030303734656475363a34303030303075323a32306574656c7531303a776f726c645175657374746937356569306569313030303735656475363a34303030303075323a32306574656c7531303a776f726c645175657374746937366569306569313030303736656475363a34303030303075323a32306574656c7531303a776f726c645175657374746937376569306569313030303737656475363a34303030303075323a32306574656c7531303a776f726c645175657374746937386569306569313030303738656475363a34303030303075323a32306574656c7531303a776f726c645175657374746937396569306569313030303739656475363a34303030303075323a32306574656c7531303a776f726c645175657374746938306569306569313030303830656475363a34303030303075323a323075363a35303030303075313a316574656c7531303a776f726c645175657374746938316569306569313030303831656475363a34303030303075323a32306574656c7531303a776f726c645175657374746938326569306569313030303832656475363a34303030303075323a32306574656c7531303a776f726c645175657374746938336569306569313030303833656475363a34303030303075323a32306574656c7531303a776f726c645175657374746938346569306569313030303834656475363a34303030303075323a32306574656c7531303a776f726c645175657374746938356569306569313030303835656475363a34303030303075323a32306574656c7531303a776f726c645175657374746938366569306569313030303836656475363a34303030303075323a32306574656c7531303a776f726c645175657374746938376569306569313030303837656475363a34303030303075323a32306574656c7531303a776f726c645175657374746938386569306569313030303838656475363a34303030303075323a32306574656c7531303a776f726c645175657374746938396569306569313030303839656475363a34303030303075323a32306574656c7531303a776f726c645175657374746939306569306569313030303930656475363a34303030303075323a32306574656c7531303a776f726c645175657374746939316569306569313030303931656475363a34303030303075323a32306574656c7531303a776f726c645175657374746939326569306569313030303932656475363a34303030303075323a32306574656c7531303a776f726c645175657374746939336569306569313030303933656475363a34303030303075323a32306574656c7531303a776f726c645175657374746939346569306569313030303934656475363a34303030303075323a32306574656c7531303a776f726c645175657374746939356569306569313030303935656475363a34303030303075323a32306574656c7531303a776f726c645175657374746939366569306569313030303936656475363a34303030303075323a32306574656c7531303a776f726c645175657374746939376569306569313030303937656475363a34303030303075323a32306574656c7531303a776f726c645175657374746939386569306569313030303938656475363a34303030303075323a32306574656c7531303a776f726c645175657374746939396569306569313030303939656475363a34303030303075323a323075363a35303030303075313a316574656c7531303a776f726c64517565737474693130306569306569313030313030656475363a33303430303175313a316574656c7531303a776f726c64517565737474693130316569306569313030313031656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693130326569306569313030313032656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693130336569306569313030313033656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693130346569306569313030313034656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693130356569306569313030313035656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693130366569306569313030313036656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693130376569306569313030313037656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693130386569306569313030313038656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693130396569306569313030313039656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693131306569306569313030313130656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693131316569306569313030313131656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693131326569306569313030313132656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693131336569306569313030313133656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693131346569306569313030313134656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693131356569306569313030313135656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693131366569306569313030313136656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693131376569306569313030313137656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693131386569306569313030313138656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693131396569306569313030313139656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693132306569306569313030313230656475363a34303030303075323a323075363a35303030303075313a316574656c7531303a776f726c64517565737474693132316569306569313030313231656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693132326569306569313030313232656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693132336569306569313030313233656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693132346569306569313030313234656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693132356569306569313030313235656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693132366569306569313030313236656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693132376569306569313030313237656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693132386569306569313030313238656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693132396569306569313030313239656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693133306569306569313030313330656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693133316569306569313030313331656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693133326569306569313030313332656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693133336569306569313030313333656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693133346569306569313030313334656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693133356569306569313030313335656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693133366569306569313030313336656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693133376569306569313030313337656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693133386569306569313030313338656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693133396569306569313030313339656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693134306569306569313030313430656475363a34303030303075323a323075363a35303030303075313a316574656c7531303a776f726c64517565737474693134316569306569313030313431656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693134326569306569313030313432656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693134336569306569313030313433656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693134346569306569313030313434656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693134356569306569313030313435656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693134366569306569313030313436656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693134376569306569313030313437656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693134386569306569313030313438656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693134396569306569313030313439656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693135306569306569313030313530656475363a33303430303075313a316574656c7531303a776f726c64517565737474693135316569306569313030313531656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693135326569306569313030313532656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693135336569306569313030313533656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693135346569306569313030313534656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693135356569306569313030313535656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693135366569306569313030313536656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693135376569306569313030313537656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693135386569306569313030313538656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693135396569306569313030313539656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693136306569306569313030313630656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693136316569306569313030313631656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693136326569306569313030313632656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693136336569306569313030313633656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693136346569306569313030313634656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693136356569306569313030313635656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693136366569306569313030313636656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693136376569306569313030313637656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693136386569306569313030313638656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693136396569306569313030313639656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693137306569306569313030313730656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693137316569306569313030313731656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693137326569306569313030313732656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693137336569306569313030313733656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693137346569306569313030313734656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693137356569306569313030313735656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693137366569306569313030313736656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693137376569306569313030313737656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693137386569306569313030313738656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693137396569306569313030313739656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693138306569306569313030313830656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693138316569306569313030313831656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693138326569306569313030313832656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693138336569306569313030313833656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693138346569306569313030313834656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693138356569306569313030313835656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693138366569306569313030313836656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693138376569306569313030313837656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693138386569306569313030313838656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693138396569306569313030313839656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693139306569306569313030313930656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693139316569306569313030313931656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693139326569306569313030313932656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693139336569306569313030313933656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693139346569306569313030313934656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693139356569306569313030313935656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693139366569306569313030313936656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693139376569306569313030313937656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693139386569306569313030313938656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693139396569306569313030313939656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693230306569306569313030323030656475363a33303430303375313a316574656c7531303a776f726c64517565737474693230316569306569313030323031656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693230326569306569313030323032656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693230336569306569313030323033656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693230346569306569313030323034656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693230356569306569313030323035656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693230366569306569313030323036656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693230376569306569313030323037656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693230386569306569313030323038656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693230396569306569313030323039656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693231306569306569313030323130656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693231316569306569313030323131656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693231326569306569313030323132656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693231336569306569313030323133656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693231346569306569313030323134656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693231356569306569313030323135656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693231366569306569313030323136656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693231376569306569313030323137656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693231386569306569313030323138656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693231396569306569313030323139656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693232306569306569313030323230656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693232316569306569313030323231656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693232326569306569313030323232656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693232336569306569313030323233656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693232346569306569313030323234656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693232356569306569313030323235656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693232366569306569313030323236656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693232376569306569313030323237656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693232386569306569313030323238656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693232396569306569313030323239656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693233306569306569313030323330656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693233316569306569313030323331656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693233326569306569313030323332656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693233336569306569313030323333656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693233346569306569313030323334656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693233356569306569313030323335656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693233366569306569313030323336656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693233376569306569313030323337656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693233386569306569313030323338656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693233396569306569313030323339656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693234306569306569313030323430656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693234316569306569313030323431656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693234326569306569313030323432656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693234336569306569313030323433656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693234346569306569313030323434656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693234356569306569313030323435656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693234366569306569313030323436656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693234376569306569313030323437656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693234386569306569313030323438656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693234396569306569313030323439656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693235306569306569313030323530656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693235316569306569313030323531656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693235326569306569313030323532656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693235336569306569313030323533656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693235346569306569313030323534656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693235356569306569313030323535656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693235366569306569313030323536656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693235376569306569313030323537656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693235386569306569313030323538656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693235396569306569313030323539656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693236306569306569313030323630656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693236316569306569313030323631656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693236326569306569313030323632656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693236336569306569313030323633656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693236346569306569313030323634656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693236356569306569313030323635656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693236366569306569313030323636656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693236376569306569313030323637656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693236386569306569313030323638656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693236396569306569313030323639656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693237306569306569313030323730656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693237316569306569313030323731656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693237326569306569313030323732656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693237336569306569313030323733656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693237346569306569313030323734656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693237356569306569313030323735656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693237366569306569313030323736656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693237376569306569313030323737656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693237386569306569313030323738656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693237396569306569313030323739656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693238306569306569313030323830656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693238316569306569313030323831656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693238326569306569313030323832656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693238336569306569313030323833656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693238346569306569313030323834656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693238356569306569313030323835656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693238366569306569313030323836656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693238376569306569313030323837656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693238386569306569313030323838656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693238396569306569313030323839656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693239306569306569313030323930656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693239316569306569313030323931656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693239326569306569313030323932656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693239336569306569313030323933656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693239346569306569313030323934656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693239356569306569313030323935656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693239366569306569313030323936656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693239376569306569313030323937656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693239386569306569313030323938656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693239396569306569313030323939656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693330306569306569313030333030656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693330316569306569313030333031656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693330326569306569313030333032656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693330336569306569313030333033656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693330346569306569313030333034656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693330356569306569313030333035656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693330366569306569313030333036656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693330376569306569313030333037656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693330386569306569313030333038656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693330396569306569313030333039656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693331306569306569313030333130656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693331316569306569313030333131656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693331326569306569313030333132656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693331336569306569313030333133656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693331346569306569313030333134656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693331356569306569313030333135656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693331366569306569313030333136656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693331376569306569313030333137656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693331386569306569313030333138656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693331396569306569313030333139656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693332306569306569313030333230656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693332316569306569313030333231656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693332326569306569313030333232656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693332336569306569313030333233656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693332346569306569313030333234656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693332356569306569313030333235656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693332366569306569313030333236656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693332376569306569313030333237656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693332386569306569313030333238656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693332396569306569313030333239656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693333306569306569313030333330656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693333316569306569313030333331656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693333326569306569313030333332656475363a34303030303075323a32306574656c7531303a776f726c64517565737466693333336569306569313030333333656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693333346569306569313030333334656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693333356569306569313030333335656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693333366569306569313030333336656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693333376569306569313030333337656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693333386569306569313030333338656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693333396569306569313030333339656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693334306569306569313030333430656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693334316569306569313030333431656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693334326569306569313030333432656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693334336569306569313030333433656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693334346569306569313030333434656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693334356569306569313030333435656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693334366569306569313030333436656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693334376569306569313030333437656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693334386569306569313030333438656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693334396569306569313030333439656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693335306569306569313030333530656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693335316569306569313030333531656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693335326569306569313030333532656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693335336569306569313030333533656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693335346569306569313030333534656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693335356569306569313030333535656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693335366569306569313030333536656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693335376569306569313030333537656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693335386569306569313030333538656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693335396569306569313030333539656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693336306569306569313030333630656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693336316569306569313030333631656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693336326569306569313030333632656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693336336569306569313030333633656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693336346569306569313030333634656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693336356569306569313030333635656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693336366569306569313030333636656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693336376569306569313030333637656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693336386569306569313030333638656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693336396569306569313030333639656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693337306569306569313030333730656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693337316569306569313030333731656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693337326569306569313030333732656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693337336569306569313030333733656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693337346569306569313030333734656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693337356569306569313030333735656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693337366569306569313030333736656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693337376569306569313030333737656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693337386569306569313030333738656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693337396569306569313030333739656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693338306569306569313030333830656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693338316569306569313030333831656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693338326569306569313030333832656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693338336569306569313030333833656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693338346569306569313030333834656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693338356569306569313030333835656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693338366569306569313030333836656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693338376569306569313030333837656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693338386569306569313030333838656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693338396569306569313030333839656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693339306569306569313030333930656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693339316569306569313030333931656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693339326569306569313030333932656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693339336569306569313030333933656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693339346569306569313030333934656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693339356569306569313030333935656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693339366569306569313030333936656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693339376569306569313030333937656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693339386569306569313030333938656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693339396569306569313030333939656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693430306569306569313030343030656475363a34303030303075333a3530306566656c7531323a636f6c6c65637451756573747469316569316569323030303031656475363a33303230303175313a3175363a33303230303275313a3165746932303130303065656c7531323a636f6c6c65637451756573747469316569316569323030303032656475363a33303230303475313a3275363a33303230303675313a3165746932303130303165656c7531323a636f6c6c65637451756573747469316569316569323030303033656475363a33303230303375313a3165746932303130303265656c7531323a636f6c6c65637451756573747469316569316569323030303034656475363a33303230303375313a3265746932303130303365656c7531323a636f6c6c65637451756573746669316569306569323030303035656475363a33303230303375313a3275363a33303230303575313a3265666932303130303465656c7531323a636f6c6c65637451756573747469316569316569323030303036656475363a33303230303375313a3165746932303130303565656c7531323a636f6c6c65637451756573747469316569316569323030303037656475363a33303230303375313a3265746932303130303665656c7531323a636f6c6c65637451756573746669316569306569323030303038656475363a33303230303075313a3275363a33303230303375313a3265666932303130303765656c7531323a636f6c6c65637451756573747469316569316569323030303039656475363a33303230303875313a3165746932303130303865656c7531323a636f6c6c65637451756573747469316569316569323030303130656475363a33303230303075313a3275363a33303230303875313a3265746932303130303965656c7531323a636f6c6c65637451756573747469316569316569323030303131656475363a33303230303975313a3165746932303130313065656c7531323a636f6c6c65637451756573747469316569316569323030303132656475363a33303230303875313a3165746932303130313165656c7531323a636f6c6c65637451756573747469316569316569323030303133656475363a33303230303575313a3275363a33303230303875313a3265746932303130313265656c7531323a636f6c6c65637451756573747469316569316569323030303134656475363a33303230303975313a3165746932303130313365656c7531363a636f6d62696e6174696f6e51756573747469316569316569333030303031656475363a33303230303175313a316574693265693665656c7531363a636f6d62696e6174696f6e51756573747469336569336569333030303032656475363a33303230303175313a316574693265693665656c7531363a636f6d62696e6174696f6e51756573747469356569356569333030303033656475363a33303230303175313a316574693265693665656c7531363a636f6d62696e6174696f6e517565737474693130656931306569333030303034656475363a33303230303175313a326574693265693665656c7531363a636f6d62696e6174696f6e517565737474693530656935306569333030303035656475363a33303230303175313a326574693265693665656c7531363a636f6d62696e6174696f6e51756573747469316569316569333030303036656475363a33303230303375313a316574693265693765656c7531363a636f6d62696e6174696f6e51756573747469336569336569333030303037656475363a33303230303375313a316574693265693765656c7531363a636f6d62696e6174696f6e51756573747469356569356569333030303038656475363a33303230303375313a316574693265693765656c7531363a636f6d62696e6174696f6e517565737474693130656931306569333030303039656475363a33303230303375313a326574693265693765656c7531363a636f6d62696e6174696f6e517565737474693530656935306569333030303130656475363a33303230303375313a326574693265693765656c7531363a636f6d62696e6174696f6e51756573747469316569316569333030303131656475363a33303230303575313a316574693265693865656c7531363a636f6d62696e6174696f6e51756573747469336569336569333030303132656475363a33303230303575313a316574693265693865656c7531363a636f6d62696e6174696f6e51756573747469356569356569333030303133656475363a33303230303575313a316574693265693865656c7531363a636f6d62696e6174696f6e517565737474693130656931306569333030303134656475363a33303230303575313a326574693265693865656c7531363a636f6d62696e6174696f6e517565737474693530656935306569333030303135656475363a33303230303575313a326574693265693865656c7531363a636f6d62696e6174696f6e51756573747469316569316569333030303136656475363a33303230303075313a316574693265693965656c7531363a636f6d62696e6174696f6e51756573747469336569336569333030303137656475363a33303230303075313a316574693265693965656c7531363a636f6d62696e6174696f6e51756573747469356569356569333030303138656475363a33303230303075313a316574693265693965656c7531363a636f6d62696e6174696f6e517565737474693130656931306569333030303139656475363a33303230303075313a326574693265693965656c7531363a636f6d62696e6174696f6e517565737474693530656935306569333030303230656475363a33303230303075313a326574693265693965656c7531363a636f6d62696e6174696f6e51756573747469316569316569333030303231656475363a33303230303175313a31657469326569313065656c7531363a636f6d62696e6174696f6e51756573747469336569336569333030303232656475363a33303230303175313a31657469326569313065656c7531363a636f6d62696e6174696f6e51756573747469356569356569333030303233656475363a33303230303175313a31657469326569313065656c7531363a636f6d62696e6174696f6e517565737474693130656931306569333030303234656475363a33303230303175313a32657469326569313065656c7531363a636f6d62696e6174696f6e517565737474693530656935306569333030303235656475363a33303230303175313a32657469326569313065656c7531363a636f6d62696e6174696f6e51756573747469316569316569333030303236656475363a33303230303375313a316574693065693065656c7531363a636f6d62696e6174696f6e517565737474693130656931306569333030303237656475363a33303230303375313a316574693065693065656c7531363a636f6d62696e6174696f6e517565737474693230656932306569333030303238656475363a33303230303375313a316574693065693065656c7531363a636f6d62696e6174696f6e517565737474693330656933306569333030303239656475363a33303230303375313a326574693065693065656c7531363a636f6d62696e6174696f6e517565737474693530656935306569333030303330656475363a33303230303375313a326574693065693065656c7531303a747261646551756573747469316569316569343030303031656475363a33303230303075313a326574693165656c7531303a7472616465517565737474693130656931306569343030303032656475363a33303230303075313a326574693165656c7531303a7472616465517565737474693530656935306569343030303033656475363a33303230303875313a326574693165656c7531303a74726164655175657374746931303065693130306569343030303034656475363a33303230303975313a326574693165656c7531303a747261646551756573747469316569316569343030303035656475363a33303230303575313a326574693065656c7531303a7472616465517565737474693130656931306569343030303036656475363a33303230303575313a326574693065656c7531303a7472616465517565737474693530656935306569343030303037656475363a33303230303875313a326574693065656c7531303a74726164655175657374746931303065693130306569343030303038656475363a33303230303975313a326574693065656c7531323a6d6f6e7374657251756573747469316569316569353030303031656475363a33303230303475313a3265746932303130303565656c7531323a6d6f6e7374657251756573747469316569316569353030303032656475363a33303230303475313a3275363a33303230303675313a3165746932303230303765656c7531323a6d6f6e7374657251756573747469316569316569353030303033656475363a33303230303875313a3265746932303330303765656c7531323a6d6f6e7374657251756573747469316569316569353030303034656475363a33303230303975313a3265746932303530303765656c7532303a6974656d456e68616e63656d656e7451756573747469336569316569363030303031656475363a33303230303275313a326574693165693165656c7532303a6974656d456e68616e63656d656e7451756573746669336569356569363030303032656475363a33303230303475313a326566693165693665656c7532303a6974656d456e68616e63656d656e7451756573747469366569316569363030303033656475363a33303230303475313a326574693265693165656c7532303a6974656d456e68616e63656d656e7451756573746669366569316569363030303034656475363a33303230303475313a3275363a33303230303675313a316566693265693665656c7532303a6974656d456e68616e63656d656e7451756573746669396569306569363030303035656475363a33303230303475313a3275363a33303230303675313a316566693365693165656c7532303a6974656d456e68616e63656d656e7451756573746669396569306569363030303036656475363a33303230303875313a326566693365693665656c7532303a6974656d456e68616e63656d656e7451756573746669396569306569363030303037656475363a33303230303975313a326566693465693165656c7532303a6974656d456e68616e63656d656e7451756573746669396569306569363030303038656475363a33303230303975313a326566693465693665656c7532303a6974656d456e68616e63656d656e7451756573746669396569306569363030303039656475363a33303230303975313a326566693565693165656c7532303a6974656d456e68616e63656d656e7451756573746669396569306569363030303130656475363a33303230303975313a326566693565693665656c7531323a67656e6572616c51756573747469316569316569373030303031656475363a33303230303275313a316574693165656c7531323a67656e6572616c517565737474693130656931306569373030303032656475363a33303230303275313a326574693165656c7531323a67656e6572616c517565737474693530656935306569373030303033656475363a33303230303275313a326574693165656c7531323a67656e6572616c517565737474693130656931306569373130303030656475363a33303230303275313a316574693265656c7531323a67656e6572616c517565737474693230656932306569373130303031656475363a33303230303275313a316574693265656c7531323a67656e6572616c517565737474693330656933306569373130303032656475363a33303230303375313a3275363a33303230303575313a326574693265656c7531323a67656e6572616c517565737474693530656935306569373130303033656475363a33303230303375313a3275363a33303230303575313a326574693265656c7531323a67656e6572616c517565737474693730656937306569373130303034656475363a33303230303475313a326574693265656c7531323a67656e6572616c517565737474693930656939306569373130303035656475363a33303230303475313a3275363a33303230303675313a316574693265656c7531323a67656e6572616c5175657374746931303065693130306569373130303036656475363a33303230303475313a3275363a33303230303675313a316574693265656c7531323a67656e6572616c5175657374746931323065693132306569373130303037656475363a33303230303475313a3275363a33303230303675313a316574693265656c7531323a67656e6572616c5175657374746931343065693134306569373130303038656475363a33303230303475313a3275363a33303230303675313a316574693265656c7531323a67656e6572616c5175657374746931363065693136306569373130303039656475363a33303230303475313a3275363a33303230303675313a316574693265656c7531323a67656e6572616c5175657374746931383065693138306569373130303130656475363a33303230303475313a3275363a33303230303675313a316574693265656c7531323a67656e6572616c5175657374746932303065693230306569373130303131656475363a33303230303475313a3275363a33303230303675313a316574693265656c7531323a67656e6572616c51756573747469316569316569373230303030656475363a33303230303275313a316574693365656c7531323a67656e6572616c517565737474693130656931306569373230303031656475363a33303230303275313a316574693365656c7531323a67656e6572616c517565737474693530656935306569373230303032656475363a33303230303275313a326574693365656c7531323a67656e6572616c5175657374746931303065693130306569373230303033656475363a33303230303275313a326574693365656c7531323a67656e6572616c517565737474693130656931316569373930303030656475363a33303230303375313a316574693465656c7531323a67656e6572616c517565737474693230656932306569373930303031656475363a33303230303375313a316574693465656c7531323a67656e6572616c517565737474693330656933316569373930303032656475363a33303230303375313a326574693465656c7531323a67656e6572616c517565737474693430656934306569373930303033656475363a33303230303375313a326574693465656c7531323a67656e6572616c517565737474693530656935306569373930303034656475363a33303230303375313a326574693465656c7531343a6974656d477261646551756573747469366569366569383030303030656475363a33303230303375313a3265746931656c69313031313030303065693130313131303030656931303231303030306569313032313130303065693130333130303030656931303431303030306565656c7531343a6974656d477261646551756573747469366569366569383030303031656475363a33303230303375313a3265746932656c69313031323030303065693130313231303030656931303132323030306569313032323030303065693130323231303030656931303332303030306565656c7531343a6974656d477261646551756573747469366569366569383030303032656475363a33303230303075313a3275363a33303230303375313a3265746933656c69313031333030303065693130313331303030656931303133333030306569313032333030303065693130323331303030656931303233313030316565656c7531343a6974656d477261646551756573747469366569366569383030303033656475363a33303230303875313a3265746934656c693230313030396569323031303132656931303334303030306569313033343130303065693130333434303030656931303434343030306565656c7531343a6974656d477261646551756573747469366569366569383030303034656475363a33303230303975313a3265746935656c693230313031306569323031303133656932303130313665693230313031396569323031303234656931303435323030316565656c7532303a6974656d54797065436f6c6c65637451756573747469356569356569393030303030656475363a33303230303375313a3165746c693330323030316569333033303030656933303331303065693330363034306569343030303030656575383a4d6174657269616c656c7532303a6974656d54797065436f6c6c656374517565737474693130656931306569393030303031656475363a33303230303075313a3275363a33303230303375313a3265746c69333032303031656933303230303265693330323030336569333032303035656933303330303065693330333130306569333033323030656933303630323365693330363034306569343030303030656575383a4d6174657269616c656c7532303a6974656d54797065436f6c6c656374517565737474693230656932306569393030303032656475363a33303230303075313a3275363a33303230303375313a3265746c693330323030306569333032303031656933303230303265693330323030336569333032303035656933303330303065693330333130306569333033323030656933303333303065693330333430306569333036303030656933303630303165693330363032336569333036303234656933303630323565693330363034306569333036303431656933303630343465693430303030306569353030303030656575383a4d6174657269616c656c7532303a6974656d54797065436f6c6c656374517565737474693330656933306569393030303033656475363a33303230303075313a3275363a33303230303375313a3265746c6933303230303065693330323030316569333032303032656933303230303365693330323030346569333032303035656933303230303665693330333030306569333033303031656933303331303065693330333130316569333033323030656933303332303165693330333330306569333033333031656933303334303065693330343030326569333036303030656933303630303165693330363030326569333036303039656933303630323365693330363032346569333036303235656933303630343065693330363034316569333036303433656933303630343465693430303030306569353030303030656575383a4d6174657269616c656c75393a476f6c6451756573747469313030656931353030656931303030303030656475363a33303230303375313a326574693065656c75393a476f6c645175657374746931303030656931353030656931303030303031656475363a33303230303475313a3275363a33303230303675313a316574693065656c75393a476f6c6451756573747469313030303065693138303732656931303030303033656475363a33303230303875313a326574693065656c75393a476f6c64517565737474693130306569313030656931303030303034656475363a33303230303075313a3275363a33303230303375313a326574693165656c75393a476f6c645175657374746931303030656931393330656931303030303035656475363a33303230303475313a3275363a33303230303675313a316574693165656c75393a476f6c6451756573747469313030303065693132353830656931303030303036656475363a33303230303875313a326574693165656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303031656475363a33303330303075313a31657475313a3175313a33656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303032656475363a33303330303075313a31657475313a3275323a3131656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303033656475363a33303330303075313a31657475313a3375323a3231656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303034656475363a33303330303075313a31657475313a3475323a3531656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303035656475363a33303330303075313a31657475313a3575323a3939656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303036656475363a33303330303175313a32657475313a3675323a3234656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303037656475363a33303330303175313a32657475313a3775323a3239656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303038656475363a33303330303175313a32657475313a3875323a3337656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303039656475363a33303330303175313a32657475313a3975333a313134656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303130656475363a33303330303175313a32657475323a313075333a313734656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303131656475363a33303330303275313a33657475323a313175323a3633656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303132656475363a33303330303275313a33657475323a313275323a3636656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303133656475363a33303330303275313a33657475323a313375323a3834656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303134656475363a33303330303275313a33657475323a313475333a313934656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303135656475363a33303330303275313a33657475323a313575333a323631656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303136656475363a33303330303275313a33657475323a313675333a313330656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303137656475363a33303330303275313a33657475323a313775333a313334656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303138656475363a33303330303275313a33657475323a313875333a313538656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303139656475363a33303330303275313a33657475323a313975333a323831656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303230656475363a33303330303275313a33657475323a323075333a333534656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303231656475363a33303330303375313a3465746932316575333a323136656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303232656475363a33303330303375313a34657475323a323275333a323231656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303233656475363a33303330303375313a3465666932336575333a323431656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303234656475363a33303330303375313a3465746932346575333a333837656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303235656475363a33303330303375313a3465666932356575333a353136656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303236656475363a33303330303375313a3465666932366575333a333031656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303237656475363a33303330303375313a3465746932376575333a333036656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303238656475363a33303330303375313a3465666932386575333a333330656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303239656475363a33303330303375313a3465666932396575333a353631656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303330656475363a33303330303375313a3465666933306575333a363736656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303331656475363a33303330303475313a3565666933316575333a343135656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303332656475363a33303330303475313a3565666933326575333a343232656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303333656475363a33303330303475313a3565666933336575333a343736656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303334656475363a33303330303475313a3565666933346575333a363936656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303335656475363a33303330303475313a3565666933356575333a373531656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303336656475363a33303330303475313a3565666933366575333a363036656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303337656475363a33303330303475313a3565666933376575333a363136656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303338656475363a33303330303475313a3565666933386575333a363536656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303339656475363a33303330303475313a3565666933396575333a383036656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303430656475363a33303330303475313a3565666934306575333a383330656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303431656475363a33303330303475313a3565666934316575333a383534656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303432656475363a33303331303075313a31657475323a343275313a36656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303433656475363a33303331303075313a31657475323a343375323a3133656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303434656475363a33303331303075313a31657475323a343475323a3232656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303435656475363a33303331303075313a31657475323a343575323a3539656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303436656475363a33303331303075313a31657475323a343675333a313131656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303437656475363a33303331303175313a32657475323a343775323a3333656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303438656475363a33303331303175313a32657475323a343875323a3335656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303439656475363a33303331303175313a32657475323a343975323a3435656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303530656475363a33303331303175313a32657475323a353075333a313236656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303531656475363a33303331303175313a32657475323a353175333a313832656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303532656475363a33303331303275313a33657475323a353275323a3735656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303533656475363a33303331303275313a33657475323a353375323a3738656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303534656475363a33303331303275313a33657475323a353475323a3936656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303535656475363a33303331303275313a33657475323a353575333a323032656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303536656475363a33303331303275313a33657475323a353675333a323736656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303537656475363a33303331303275313a33657475323a353775333a313436656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303538656475363a33303331303275313a33657475323a353875333a313530656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303539656475363a33303331303275313a33657475323a353975333a313636656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303630656475363a33303331303275313a33657475323a363075333a323931656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303631656475363a33303331303275313a3365666936316575333a333733656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303632656475363a33303331303375313a3465666936326575333a323331656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303633656475363a33303331303375313a3465746936336575333a323336656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303634656475363a33303331303375313a3465666936346575333a323536656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303635656475363a33303331303375313a3465746936356575333a343038656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303636656475363a33303331303375313a3465666936366575333a353433656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303637656475363a33303331303375313a3465666936376575333a333138656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303638656475363a33303331303375313a3465666936386575333a333234656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303639656475363a33303331303375313a3465746936396575333a333432656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303730656475363a33303331303375313a3465666937306575333a353838656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303731656475363a33303331303375313a3465666937316575333a363836656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303732656475363a33303331303475313a3565666937326575333a343532656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303733656475363a33303331303475313a3565666937336575333a343630656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303734656475363a33303331303475313a3565666937346575333a353030656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303735656475363a33303331303475313a3565666937356575333a373037656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303736656475363a33303331303475313a3565666937366575333a373632656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303737656475363a33303331303475313a3565666937376575333a363336656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303738656475363a33303331303475313a3565666937386575333a363436656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303739656475363a33303331303475313a3565666937396575333a363636656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303830656475363a33303331303475313a3565666938306575333a383138656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303831656475363a33303331303475313a3565666938316575333a383432656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303832656475363a33303331303475313a3565666938326575333a383636656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303833656475363a33303332303075313a31657475323a383375313a39656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303834656475363a33303332303075313a31657475323a383475323a3137656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303835656475363a33303332303075313a31657475323a383575323a3235656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303836656475363a33303332303075313a31657475323a383675323a3639656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303837656475363a33303332303075313a31657475323a383775333a313338656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303838656475363a33303332303175313a32657475323a383875323a3339656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303839656475363a33303332303175313a32657475323a383975323a3431656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303930656475363a33303332303175313a32657475323a393075323a3533656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303931656475363a33303332303175313a32657475323a393175333a313632656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303932656475363a33303332303175313a3265666939326575333a323731656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303933656475363a33303332303275313a33657475323a393375323a3837656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303934656475363a33303332303275313a33657475323a393475323a3930656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303935656475363a33303332303275313a33657475323a393575333a313038656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303936656475363a33303332303275313a33657475323a393675333a333132656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303937656475363a33303332303275313a3365666939376575333a343834656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303938656475363a33303332303375313a34657475323a393875333a313836656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303939656475363a33303332303375313a34657475323a393975333a313930656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313030656475363a33303332303375313a346566693130306575333a323236656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313031656475363a33303332303375313a346566693130316575333a353235656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313032656475363a33303332303375313a346566693130326575333a353730656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313033656475363a33303332303475313a356566693130336575333a333630656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313034656475363a33303332303475313a356566693130346575333a333636656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313035656475363a33303332303475313a356566693130356575333a343434656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313036656475363a33303332303475313a356574693130366575333a373138656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313037656475363a33303332303475313a356574693130376575333a373733656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313038656475363a33303333303075313a31657475333a31303875323a3135656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313039656475363a33303333303075313a31657475333a31303975323a3139656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313130656475363a33303333303075313a31657475333a31313075323a3331656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313131656475363a33303333303075313a31657475333a31313175323a3831656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313132656475363a33303333303075313a31657475333a31313275333a313534656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313133656475363a33303333303175313a32657475333a31313375323a3437656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313134656475363a33303333303175313a32657475333a31313475323a3439656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313135656475363a33303333303175313a32657475333a31313575323a3631656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313136656475363a33303333303175313a32657475333a31313675333a313738656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313137656475363a33303333303175313a326566693131376575333a323936656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313138656475363a33303333303275313a33657475333a31313875333a313032656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313139656475363a33303333303275313a33657475333a31313975333a313035656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313230656475363a33303333303275313a33657475333a31323075333a313233656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313231656475363a33303333303275313a33657475333a31323175333a333438656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313232656475363a33303333303275313a336566693132326575333a353038656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313233656475363a33303333303375313a34657475333a31323375333a323036656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313234656475363a33303333303375313a346566693132346575333a323131656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313235656475363a33303333303375313a346566693132356575333a323636656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313236656475363a33303333303375313a346566693132366575333a353532656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313237656475363a33303333303375313a346566693132376575333a353937656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313238656475363a33303333303475313a356566693132386575333a333934656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313239656475363a33303333303475313a35657475333a31323975333a343031656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313330656475363a33303333303475313a356566693133306575333a343638656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313331656475363a33303333303475313a356574693133316575333a373239656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313332656475363a33303333303475313a356574693133326575333a373834656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313333656475363a33303334303075313a31657475333a31333375323a3230656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313334656475363a33303334303075313a31657475333a31333475323a3237656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313335656475363a33303334303075313a31657475333a31333575323a3433656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313336656475363a33303334303075313a31657475333a31333675323a3933656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313337656475363a33303334303075313a31657475333a31333775333a313730656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313338656475363a33303334303175313a32657475333a31333875323a3535656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313339656475363a33303334303175313a32657475333a31333975323a3537656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313430656475363a33303334303175313a32657475333a31343075323a3732656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313431656475363a33303334303175313a32657475333a31343175333a313938656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313432656475363a33303334303175313a32657475333a31343275333a333336656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313433656475363a33303334303275313a33657475333a31343375333a313137656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313434656475363a33303334303275313a33657475333a31343475333a313230656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313435656475363a33303334303275313a33657475333a31343575333a313432656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313436656475363a33303334303275313a336566693134366575333a333830656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313437656475363a33303334303275313a33657475333a31343775333a353334656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313438656475363a33303334303375313a346574693134386575333a323436656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313439656475363a33303334303375313a346566693134396575333a323531656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313530656475363a33303334303375313a346566693135306575333a323836656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313531656475363a33303334303375313a346574693135316575333a353739656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313532656475363a33303334303375313a346574693135326575333a363236656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313533656475363a33303334303475313a356566693135336575333a343239656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313534656475363a33303334303475313a356574693135346575333a343336656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313535656475363a33303334303475313a356566693135356575333a343932656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313536656475363a33303334303475313a356566693135366575333a373430656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313537656475363a33303334303475313a356566693135376575333a373935656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313538656475363a33303332303475323a31326566693136316575333a333330656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313539656475363a33303332303475323a31326574693136326575333a333130656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313630656475363a33303332303475323a31326566693136336575333a333130656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313631656475363a33303332303475323a31326566693136346575333a333330656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313632656475363a33303332303475323a31326574693136356575333a333330656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313633656475363a33303333303475323a31336566693136366575333a333335656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313634656475363a33303333303475323a31336574693136376575333a333230656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313635656475363a33303333303475323a31336574693136386575333a333230656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313636656475363a33303333303475323a31336566693136396575333a333335656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313637656475363a33303333303475323a31336566693137306575333a333335656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313638656475363a33303330303575323a3530656669313839656933383065656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313639656475363a33303330303575323a3530656669313930656933353565656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313730656475363a33303330303575323a3530656669313931656933353565656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313731656475363a33303330303575323a3530656669313932656933383065656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313732656475363a33303330303575323a3530656669313933656934303065656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313733656475363a33303331303575323a3530656669313934656933383565656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313734656475363a33303331303575323a3530656669313935656933363565656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313735656475363a33303331303575323a3530656669313936656933363565656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313736656475363a33303331303575323a3530656669313937656933383565656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313737656475363a33303331303575323a3530656669313938656933393865656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313738656475363a33303332303575323a3530656669313939656933383065656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313739656475363a33303332303575323a3530656669323030656933363065656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313830656475363a33303332303575323a3530656669323031656933363065656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313831656475363a33303332303575323a3530656669323032656933383065656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313832656475363a33303332303575323a3530656669323033656933393265656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313833656475363a33303333303575323a3530656669323034656933383565656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313834656475363a33303333303575323a3530656669323035656933373065656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313835656475363a33303333303575323a3530656669323036656933373065656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313836656475363a33303333303575323a3530656669323037656933383565656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313837656475363a33303333303575323a3530656669323038656933393465656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313838656475363a33303334303575323a3530656669323039656933393065656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313839656475363a33303334303575323a3530656669323130656933373565656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313930656475363a33303334303575323a3530656669323131656933373565656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313931656475363a33303334303575323a3530656669323132656933393065656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313932656475363a33303334303575323a353065666932313365693339366565656c69313030333332656565"))); - var worldState = new World(MockUtil.MockModernWorldState) - .SetAvatarState(avatarAddress, avatarState); - var stateRootHash = worldState.Trie.Hash; - var tip = new Domain.Model.BlockChain.Block( - BlockHash.FromString("613dfa26e104465790625ae7bc03fc27a64947c02a9377565ec190405ef7154b"), - BlockHash.FromString("36456be15af9a5b9b13a02c7ce1e849ae9cba8781ec309010499cdb93e29237d"), - default(Address), - 0, - Timestamp: DateTimeOffset.UtcNow, - StateRootHash: stateRootHash, - Transactions: ImmutableArray.Empty - ); - BlockChainRepository.Setup(repository => repository.GetTip()) - .Returns(tip); - WorldStateRepository.Setup(repository => repository.GetWorldState(stateRootHash)) - .Returns(worldState); + SetupStatesOnTip(world => world + .SetAvatarState(avatarAddress, avatarState)); string query = $@"query {{ stateQuery {{ @@ -907,24 +825,8 @@ public async Task ActivationKeyNonce(bool trim) random.NextBytes(nonce); var (activationKey, pendingActivationState) = ActivationKey.Create(privateKey, nonce); - var worldState = new World(MockUtil.MockModernWorldState) - .SetLegacyState(activationKey.PendingAddress, pendingActivationState.Serialize()); - var stateRootHash = worldState.Trie.Hash; - - var tip = new Domain.Model.BlockChain.Block( - BlockHash.FromString("613dfa26e104465790625ae7bc03fc27a64947c02a9377565ec190405ef7154b"), - BlockHash.FromString("36456be15af9a5b9b13a02c7ce1e849ae9cba8781ec309010499cdb93e29237d"), - default(Address), - 0, - Timestamp: DateTimeOffset.UtcNow, - StateRootHash: stateRootHash, - Transactions: ImmutableArray.Empty - ); - - BlockChainRepository.Setup(repo => repo.GetTip()) - .Returns(tip); - WorldStateRepository.Setup(repo => repo.GetWorldState(stateRootHash)) - .Returns(worldState); + SetupStatesOnTip(world => world + .SetLegacyState(activationKey.PendingAddress, pendingActivationState.Serialize())); var code = activationKey.Encode(); if (trim) @@ -956,24 +858,8 @@ public async Task ActivationKeyNonce_ThrowError_WithOutdatedCode(string code, st { var activationKey = ActivationKey.Decode(code); - var worldState = new World(MockUtil.MockModernWorldState) - .SetLegacyState(activationKey.PendingAddress, Bencodex.Types.Null.Value); - var stateRootHash = worldState.Trie.Hash; - - var tip = new Domain.Model.BlockChain.Block( - BlockHash.FromString("613dfa26e104465790625ae7bc03fc27a64947c02a9377565ec190405ef7154b"), - BlockHash.FromString("36456be15af9a5b9b13a02c7ce1e849ae9cba8781ec309010499cdb93e29237d"), - default(Address), - 0, - Timestamp: DateTimeOffset.UtcNow, - StateRootHash: stateRootHash, - Transactions: ImmutableArray.Empty - ); - - BlockChainRepository.Setup(repo => repo.GetTip()) - .Returns(tip); - WorldStateRepository.Setup(repo => repo.GetWorldState(stateRootHash)) - .Returns(worldState); + SetupStatesOnTip(world => world + .SetLegacyState(activationKey.PendingAddress, Bencodex.Types.Null.Value)); var query = $"query {{ activationKeyNonce(invitationCode: \"{code}\") }}"; var queryResult = await ExecuteQueryAsync(query); @@ -986,23 +872,8 @@ public async Task ActivationKeyNonce_ThrowError_WithOutdatedCode(string code, st public async Task Balance() { var address = new PrivateKey().Address; - var worldState = new World(MockUtil.MockModernWorldState); - var stateRootHash = worldState.Trie.Hash; - - var tip = new Domain.Model.BlockChain.Block( - BlockHash.FromString("613dfa26e104465790625ae7bc03fc27a64947c02a9377565ec190405ef7154b"), - BlockHash.FromString("36456be15af9a5b9b13a02c7ce1e849ae9cba8781ec309010499cdb93e29237d"), - default(Address), - 0, - Timestamp: DateTimeOffset.UtcNow, - StateRootHash: stateRootHash, - Transactions: ImmutableArray.Empty - ); - BlockChainRepository.Setup(repo => repo.GetTip()) - .Returns(tip); - WorldStateRepository.Setup(repo => repo.GetWorldState(stateRootHash)) - .Returns(worldState); + SetupStatesOnTip(world => world); var query = $@"query {{ stateQuery {{ From 02a14064160f9d538281edd9046a5c6dfb37f387 Mon Sep 17 00:00:00 2001 From: moreal Date: Thu, 5 Sep 2024 23:46:45 +0900 Subject: [PATCH 58/72] Create `AvatarState` instance with code instead decoding from binary --- .../GraphTypes/StandaloneQueryTest.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/NineChronicles.Headless.Tests/GraphTypes/StandaloneQueryTest.cs b/NineChronicles.Headless.Tests/GraphTypes/StandaloneQueryTest.cs index 019b1762d..43385b869 100644 --- a/NineChronicles.Headless.Tests/GraphTypes/StandaloneQueryTest.cs +++ b/NineChronicles.Headless.Tests/GraphTypes/StandaloneQueryTest.cs @@ -793,13 +793,12 @@ public async Task Avatar() { var agentAddress = new Address("f189c04126e2e708cd7d17cd68a7b7f10bbb6f16"); var avatarAddress = new Address("f1a005c01e683dbcab9a306d5cc70d5e57fccfa9"); - var avatarState = new AvatarState((List)new Codec().Decode(Convert.FromHexString( - "6c6c32303af1a005c01e683dbcab9a306d5cc70d5e57fccfa96569326575353a6261447561693130303031306569333336656937313231346575383a313134393233323632303af189c04126e2e708cd7d17cd68a7b7f10bbb6f166c647531303a6174746163686d656e74647531313a616374696f6e506f696e7475313a3075313a636c647531333a646563696d616c506c61636573313a1275373a6d696e746572736e75363a7469636b657275373a4352595354414c65693065657531373a656e68616e63656d656e74526573756c7475373a5375636365737375343a676f6c6469306575323a696431363a17b05d00fea9864c901ede7c9f4d31bb7531303a6974656d557361626c65647531303a62756666536b696c6c736c657531343a656c656d656e74616c5f7479706575343a4c616e6475363a65715f65787075323a333275383a65717569707065646675353a677261646575313a3175323a696475383a313034313330303075363a6974656d496431363a788c0c286da7c14abde5ded62de0f44d7531333a6974656d5f7375625f7479706575383a4e65636b6c61636575393a6974656d5f7479706575393a45717569706d656e7475353a6c6576656c75313a3275323a6f6375313a337531383a7265717569726564426c6f636b496e64657875383a313134393232363775363a7365745f696475313a3475363a736b696c6c736c6475363a6368616e636575313a3875353a706f77657275313a3075383a736b696c6c526f776475353a636f6d626f6675383a636f6f6c646f776e693235657531343a656c656d656e74616c5f7479706575363a4e6f726d616c75393a6869745f636f756e7469316575323a696469323430303030657531343a736b696c6c5f63617465676f727975373a486974427566667531373a736b696c6c5f7461726765745f7479706575343a53656c667531303a736b696c6c5f7479706575343a427566666565657531393a7370696e655f7265736f757263655f7061746875383a313034313330303075343a737461746475343a74797065343a0500000075353a76616c756575333a3335376575383a73746174734d617064343a03000000647531353a6164646974696f6e616c56616c75657531313a33312e303030303030303075383a7374617454797065343a0300000075353a76616c756575313a3065343a05000000647531353a6164646974696f6e616c56616c75657531323a3130362e303030303030303075383a7374617454797065343a0500000075353a76616c756575383a3434322e323133316565657531383a6d6174657269616c4974656d49644c6973746c31363ad5f36402d57e214691607fa35606e52931363a7f45c50e8c9cdc48b87b1c28af35597031363a11eaf70e63890447894dacb39c8402d0657531333a7072654974656d557361626c65647531303a62756666536b696c6c736c657531343a656c656d656e74616c5f7479706575343a4c616e6475363a65715f65787075313a3875383a65717569707065646675353a677261646575313a3175323a696475383a313034313330303075363a6974656d496431363a788c0c286da7c14abde5ded62de0f44d7531333a6974656d5f7375625f7479706575383a4e65636b6c61636575393a6974656d5f7479706575393a45717569706d656e7475353a6c6576656c75313a3075323a6f6375313a337531383a7265717569726564426c6f636b496e64657875383a313134383936323075363a7365745f696475313a3475363a736b696c6c736c6475363a6368616e636575313a3875353a706f77657275313a3075383a736b696c6c526f776475353a636f6d626f6675383a636f6f6c646f776e693235657531343a656c656d656e74616c5f7479706575363a4e6f726d616c75393a6869745f636f756e7469316575323a696469323430303030657531343a736b696c6c5f63617465676f727975373a486974427566667531373a736b696c6c5f7461726765745f7479706575343a53656c667531303a736b696c6c5f7479706575343a427566666565657531393a7370696e655f7265736f757263655f7061746875383a313034313330303075343a737461746475343a74797065343a0500000075353a76616c756575333a3335376575383a73746174734d617064343a03000000647531353a6164646974696f6e616c56616c756575323a333175383a7374617454797065343a0300000075353a76616c756575313a3065343a05000000647531353a6164646974696f6e616c56616c756575333a31303675383a7374617454797065343a0500000075353a76616c756575333a33353765656575363a7479706549647532353a6974656d5f656e68616e63656d656e7431332e726573756c74657531303a626c6f636b496e64657875383a313134393232323775323a696431363a17b05d00fea9864c901ede7c9f4d31bb7531383a7265717569726564426c6f636b496e64657875383a313134393232363775363a7479706549647531313a6974656d456e68616e636565647531303a626c6f636b496e64657875383a313134373830303375323a696431363af4bef400ccc4624da8f69f1e78a0478375323a706931363af4bef400ccc4624da8f69f1e78a047837531383a7265717569726564426c6f636b496e64657875383a313134373830303375363a7479706549647531373a50726f6475637453656c6c65724d61696c65647531303a626c6f636b496e64657875383a313134383035363375323a696431363adc9740029e56f544bcde568ecce9adbf75323a706931363adc9740029e56f544bcde568ecce9adbf7531383a7265717569726564426c6f636b496e64657875383a313134383035363375363a7479706549647531373a50726f6475637453656c6c65724d61696c65647531303a6174746163686d656e74647531313a616374696f6e506f696e7475313a3075343a676f6c6469306575323a696431363a070d1d1d75c4a849a6ee8e626b08542e7531303a6974656d557361626c65647531303a62756666536b696c6c736c657531343a656c656d656e74616c5f7479706575343a4c616e6475363a65715f65787075313a3875383a65717569707065646675353a677261646575313a3175323a696475383a313034313330303075363a6974656d496431363a080f06a366c6e84c993ac8525b1d6cf27531333a6974656d5f7375625f7479706575383a4e65636b6c61636575393a6974656d5f7479706575393a45717569706d656e7475353a6c6576656c75313a3075323a6f6375313a337531383a7265717569726564426c6f636b496e64657875383a313134393033323275363a7365745f696475313a3475363a736b696c6c736c657531393a7370696e655f7265736f757263655f7061746875383a313034313330303075343a737461746475343a74797065343a0500000075353a76616c756575333a3335376575383a73746174734d617064343a03000000647531353a6164646974696f6e616c56616c756575323a323675383a7374617454797065343a0300000075353a76616c756575313a3065343a05000000647531353a6164646974696f6e616c56616c756575333a31373175383a7374617454797065343a0500000075353a76616c756575333a33353765656575393a6d6174657269616c736c6475353a636f756e7475323a313575383a6d6174657269616c647531343a656c656d656e74616c5f7479706575363a4e6f726d616c75353a677261646575313a3175323a696475363a33303333303075373a6974656d5f696433323a1bd96c8d5bce17827b894e01d4eb87bd853bc6a48baee9e6151ce568ae43ad397531333a6974656d5f7375625f747970657531373a45717569706d656e744d6174657269616c75393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323075383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630303975373a6974656d5f696433323a67f6ff0b0e20202a8e63742adf804355ceaee3ab636ed3065bd535985e7109a87531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323975383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630313075373a6974656d5f696433323ae0e69c7f4f16174438570e79ef52f5091ff761615a29dc70d3babbb4a099ce337531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323075383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630313175373a6974656d5f696433323a2d85afe3aa2e0ebc49df0149cf939feeddbfb9049a1e0c3bd7d8c00a948fece67531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656575383a726563697065496475333a3131317531313a737562526563697065496475333a32363075363a7479706549647532343a636f6d62696e6174696f6e2e726573756c742d6d6f64656c657531303a626c6f636b496e64657875383a313134383935393875323a696431363a070d1d1d75c4a849a6ee8e626b08542e7531383a7265717569726564426c6f636b496e64657875383a313134393033323275363a7479706549647531353a636f6d62696e6174696f6e4d61696c65647531303a626c6f636b496e64657875383a313134373837373975313a666c6c647531333a646563696d616c506c61636573313a1275373a6d696e746572736e75363a7469636b657275373a4352595354414c65693234303030303030303030303030303030303030303065656575313a696c6c693830303230316569313265656575323a696431363a5580de2c0e57bc4a936439bd3e0e548275313a6d7536303a706174726f6c207265776172642046314130303543303145363833644263416239413330366435634337304435453537666363466139202f203331327531383a7265717569726564426c6f636b496e64657875383a313134373837373975363a7479706549647531343a436c61696d4974656d734d61696c65647531303a6174746163686d656e74647531313a616374696f6e506f696e7475313a3075343a676f6c6469306575323a696431363a91fe9e33e696034cae9720cea467aaed7531303a6974656d557361626c65647531303a62756666536b696c6c736c657531343a656c656d656e74616c5f7479706575343a57696e6475363a65715f65787075323a313075383a65717569707065646675353a677261646575313a3175323a696475383a313035313430303075363a6974656d496431363afc0b4deaa2aa1342910de9bb0f4e868f7531333a6974656d5f7375625f7479706575343a52696e6775393a6974656d5f7479706575393a45717569706d656e7475353a6c6576656c75313a3075323a6f6375313a337531383a7265717569726564426c6f636b496e64657875383a313135303236383775363a7365745f696475313a3575363a736b696c6c736c657531393a7370696e655f7265736f757263655f7061746875383a313035313430303075343a737461746475343a74797065343a0300000075353a76616c756575333a3130376575383a73746174734d617064343a03000000647531353a6164646974696f6e616c56616c756575323a393275383a7374617454797065343a0300000075353a76616c756575333a31303765343a06000000647531353a6164646974696f6e616c56616c756575333a34323075383a7374617454797065343a0600000075353a76616c756575313a3065656575393a6d6174657269616c736c6475353a636f756e7475323a323475383a6d6174657269616c647531343a656c656d656e74616c5f7479706575363a4e6f726d616c75353a677261646575313a3175323a696475363a33303334303075373a6974656d5f696433323a45c8a87009caf8f9d3ecf58618fa6e2b14fe0edb2283d373e3c190c56eb96d8a7531333a6974656d5f7375625f747970657531373a45717569706d656e744d6174657269616c75393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a313275383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a57696e6475353a677261646575313a3175323a696475363a33303630343275373a6974656d5f696433323a31f48810fa91236281c165659d65003cfb611205a52c1ff6e02c019b86625dda7531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a343775383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a57696e6475353a677261646575313a3275323a696475363a33303630353075373a6974656d5f696433323adf0c212eb56526891629367fe889cfce0ea89a04e21d11a05b19ff9231802b4c7531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a373075383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a57696e6475353a677261646575313a3275323a696475363a33303630353175373a6974656d5f696433323a5eac6f2b799a1fc20a50f005f2df8783fefec63595787804b4418ece2b3d07177531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656575383a726563697065496475333a3133377531313a737562526563697065496475333a33323375363a7479706549647532343a636f6d62696e6174696f6e2e726573756c742d6d6f64656c657531303a626c6f636b496e64657875383a313134393232333075323a696431363a91fe9e33e696034cae9720cea467aaed7531383a7265717569726564426c6f636b496e64657875383a313135303236383775363a7479706549647531353a636f6d62696e6174696f6e4d61696c65647531303a6174746163686d656e74647531313a616374696f6e506f696e7475313a3075343a676f6c6469306575323a696431363aa09bb5427904a84db14bf0e004729f247531303a6974656d557361626c65647531303a62756666536b696c6c736c657531343a656c656d656e74616c5f7479706575363a4e6f726d616c75363a65715f65787075313a3575383a65717569707065646675353a677261646575313a3175323a696475383a313035313030303075363a6974656d496431363a31541a02030725409e67ad7b14fd1d807531333a6974656d5f7375625f7479706575343a52696e6775393a6974656d5f7479706575393a45717569706d656e7475353a6c6576656c75313a3075323a6f6375313a337531383a7265717569726564426c6f636b496e64657875383a313134383334363275363a7365745f696475313a3175363a736b696c6c736c657531393a7370696e655f7265736f757263655f7061746875383a313035313030303075343a737461746475343a74797065343a0300000075353a76616c756575313a386575383a73746174734d617064343a02000000647531353a6164646974696f6e616c56616c756575313a3675383a7374617454797065343a0200000075353a76616c756575313a3065343a03000000647531353a6164646974696f6e616c56616c756575313a3775383a7374617454797065343a0300000075353a76616c756575313a3865656575393a6d6174657269616c736c6475353a636f756e7475313a3275383a6d6174657269616c647531343a656c656d656e74616c5f7479706575363a4e6f726d616c75353a677261646575313a3175323a696475363a33303334303075373a6974656d5f696433323a45c8a87009caf8f9d3ecf58618fa6e2b14fe0edb2283d373e3c190c56eb96d8a7531333a6974656d5f7375625f747970657531373a45717569706d656e744d6174657269616c75393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475313a3275383a6d6174657269616c647531343a656c656d656e74616c5f7479706575353a576174657275353a677261646575313a3175323a696475363a33303630303175373a6974656d5f696433323a77cfad5273885820b69e61c2106ae06583f69c7f6d82a229b59e5f1b984164be7531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475313a3275383a6d6174657269616c647531343a656c656d656e74616c5f7479706575353a576174657275353a677261646575313a3175323a696475363a33303630303275373a6974656d5f696433323a28a2c38b0934225a8f2327b9bd8cf7c7eaf3551bde8203f44248c011938e97707531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475313a3175383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4669726575353a677261646575313a3175323a696475363a33303630323375373a6974656d5f696433323a1af5e747fc81a7f3149af024db2e5025b6749a000d66b22e665acdd45b8dbd177531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656575383a726563697065496475333a3133337531313a737562526563697065496475333a34353875363a7479706549647532343a636f6d62696e6174696f6e2e726573756c742d6d6f64656c657531303a626c6f636b496e64657875383a313134383334353475323a696431363aa09bb5427904a84db14bf0e004729f247531383a7265717569726564426c6f636b496e64657875383a313134383334363275363a7479706549647531353a636f6d62696e6174696f6e4d61696c65647531303a626c6f636b496e64657875383a313134383132393975313a696c6c6936303032303165693565656575323a696431363aecaa0b486ea7564da3971e00d5fb8b9d75313a6d7535313a7b22736561736f6e5f70617373223a207b226e223a205b32315d2c202270223a205b5d2c202274223a2022636c61696d227d7d7531383a7265717569726564426c6f636b496e64657875383a313134383132393975363a7479706549647531343a436c61696d4974656d734d61696c65647531303a626c6f636b496e64657875383a313134383934363675313a666c6c647531333a646563696d616c506c61636573313a1275373a6d696e746572736e75363a7469636b657275373a4352595354414c65693234303030303030303030303030303030303030303065656575313a696c6c693830303230316569313265656575323a696431363a5f21e54bd0119549a07713182f22ee7a75313a6d7536303a706174726f6c207265776172642046314130303543303145363833644263416239413330366435634337304435453537666363466139202f203331337531383a7265717569726564426c6f636b496e64657875383a313134383934363675363a7479706549647531343a436c61696d4974656d734d61696c65647531303a6174746163686d656e74647531313a616374696f6e506f696e7475313a3075343a676f6c6469306575323a696431363a48e84158fc051044a7316a5a8e3fed177531303a6974656d557361626c65647531303a62756666536b696c6c736c657531343a656c656d656e74616c5f7479706575343a4c616e6475363a65715f65787075313a3875383a65717569707065646675353a677261646575313a3175323a696475383a313034313330303075363a6974656d496431363af62bd25f4b3e964682fee972bdf6174f7531333a6974656d5f7375625f7479706575383a4e65636b6c61636575393a6974656d5f7479706575393a45717569706d656e7475353a6c6576656c75313a3075323a6f6375313a337531383a7265717569726564426c6f636b496e64657875383a313134383334363975363a7365745f696475313a3475363a736b696c6c736c6475363a6368616e636575313a3875353a706f77657275313a3075383a736b696c6c526f776475353a636f6d626f6675383a636f6f6c646f776e693235657531343a656c656d656e74616c5f7479706575363a4e6f726d616c75393a6869745f636f756e7469316575323a696469323430303030657531343a736b696c6c5f63617465676f727975373a486974427566667531373a736b696c6c5f7461726765745f7479706575343a53656c667531303a736b696c6c5f7479706575343a427566666565657531393a7370696e655f7265736f757263655f7061746875383a313034313330303075343a737461746475343a74797065343a0500000075353a76616c756575333a3335376575383a73746174734d617064343a03000000647531353a6164646974696f6e616c56616c756575323a333075383a7374617454797065343a0300000075353a76616c756575313a3065343a05000000647531353a6164646974696f6e616c56616c756575323a393975383a7374617454797065343a0500000075353a76616c756575333a33353765656575393a6d6174657269616c736c6475353a636f756e7475323a313575383a6d6174657269616c647531343a656c656d656e74616c5f7479706575363a4e6f726d616c75353a677261646575313a3175323a696475363a33303333303075373a6974656d5f696433323a1bd96c8d5bce17827b894e01d4eb87bd853bc6a48baee9e6151ce568ae43ad397531333a6974656d5f7375625f747970657531373a45717569706d656e744d6174657269616c75393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323075383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630303975373a6974656d5f696433323a67f6ff0b0e20202a8e63742adf804355ceaee3ab636ed3065bd535985e7109a87531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323975383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630313075373a6974656d5f696433323ae0e69c7f4f16174438570e79ef52f5091ff761615a29dc70d3babbb4a099ce337531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323075383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630313175373a6974656d5f696433323a2d85afe3aa2e0ebc49df0149cf939feeddbfb9049a1e0c3bd7d8c00a948fece67531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656575383a726563697065496475333a3131317531313a737562526563697065496475333a32363075363a7479706549647532343a636f6d62696e6174696f6e2e726573756c742d6d6f64656c657531303a626c6f636b496e64657875383a313134383334343975323a696431363a48e84158fc051044a7316a5a8e3fed177531383a7265717569726564426c6f636b496e64657875383a313134383334363975363a7479706549647531353a636f6d62696e6174696f6e4d61696c65647531303a626c6f636b496e64657875383a313134383035363375323a696431363a3c5cc35a76d6b9459e6edcac8ae2539575323a706931363a3c5cc35a76d6b9459e6edcac8ae253957531383a7265717569726564426c6f636b496e64657875383a313134383035363375363a7479706549647531373a50726f6475637453656c6c65724d61696c65647531303a6174746163686d656e74647531313a616374696f6e506f696e7475313a3075343a676f6c6469306575323a696431363a5978fb5b2ec75949aec15d76f13d87827531303a6974656d557361626c65647531303a62756666536b696c6c736c657531343a656c656d656e74616c5f7479706575363a4e6f726d616c75363a65715f65787075313a3575383a65717569707065646675353a677261646575313a3175323a696475383a313035313030303075363a6974656d496431363a83c590459b76b6418b041f9f372544ca7531333a6974656d5f7375625f7479706575343a52696e6775393a6974656d5f7479706575393a45717569706d656e7475353a6c6576656c75313a3075323a6f6375313a347531383a7265717569726564426c6f636b496e64657875383a313134383937353675363a7365745f696475313a3175363a736b696c6c736c6475363a6368616e636575313a3875353a706f77657275313a3075383a736b696c6c526f776475353a636f6d626f6675383a636f6f6c646f776e693235657531343a656c656d656e74616c5f7479706575363a4e6f726d616c75393a6869745f636f756e7469316575323a696469323130303030657531343a736b696c6c5f63617465676f72797531303a41747461636b427566667531373a736b696c6c5f7461726765745f7479706575343a53656c667531303a736b696c6c5f7479706575343a427566666565657531393a7370696e655f7265736f757263655f7061746875383a313035313030303075343a737461746475343a74797065343a0300000075353a76616c756575313a386575383a73746174734d617064343a02000000647531353a6164646974696f6e616c56616c756575313a3475383a7374617454797065343a0200000075353a76616c756575313a3065343a03000000647531353a6164646974696f6e616c56616c756575313a3875383a7374617454797065343a0300000075353a76616c756575313a3865656575393a6d6174657269616c736c6475353a636f756e7475313a3275383a6d6174657269616c647531343a656c656d656e74616c5f7479706575363a4e6f726d616c75353a677261646575313a3175323a696475363a33303334303075373a6974656d5f696433323a45c8a87009caf8f9d3ecf58618fa6e2b14fe0edb2283d373e3c190c56eb96d8a7531333a6974656d5f7375625f747970657531373a45717569706d656e744d6174657269616c75393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475313a3275383a6d6174657269616c647531343a656c656d656e74616c5f7479706575353a576174657275353a677261646575313a3175323a696475363a33303630303175373a6974656d5f696433323a77cfad5273885820b69e61c2106ae06583f69c7f6d82a229b59e5f1b984164be7531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475313a3275383a6d6174657269616c647531343a656c656d656e74616c5f7479706575353a576174657275353a677261646575313a3175323a696475363a33303630303275373a6974656d5f696433323a28a2c38b0934225a8f2327b9bd8cf7c7eaf3551bde8203f44248c011938e97707531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475313a3175383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4669726575353a677261646575313a3175323a696475363a33303630323375373a6974656d5f696433323a1af5e747fc81a7f3149af024db2e5025b6749a000d66b22e665acdd45b8dbd177531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656575383a726563697065496475333a3133337531313a737562526563697065496475333a34353875363a7479706549647532343a636f6d62696e6174696f6e2e726573756c742d6d6f64656c657531303a626c6f636b496e64657875383a313134383937333675323a696431363a5978fb5b2ec75949aec15d76f13d87827531383a7265717569726564426c6f636b496e64657875383a313134383937353675363a7479706549647531353a636f6d62696e6174696f6e4d61696c65647531303a626c6f636b496e64657875383a313134383035363375323a696431363a75ff80623e199846804b450232e452dd75323a706931363a75ff80623e199846804b450232e452dd7531383a7265717569726564426c6f636b496e64657875383a313134383035363375363a7479706549647531373a50726f6475637453656c6c65724d61696c65647531303a626c6f636b496e64657875383a313134383035363375323a696431363a5797bc645cc0f045b117e4e133e323bb75323a706931363a5797bc645cc0f045b117e4e133e323bb7531383a7265717569726564426c6f636b496e64657875383a313134383035363375363a7479706549647531373a50726f6475637453656c6c65724d61696c65647531303a6174746163686d656e74647531313a616374696f6e506f696e7475313a3075343a676f6c6469306575323a696431363aeb3383670cd49a41aa6a956fb38caa267531303a6974656d557361626c65647531303a62756666536b696c6c736c657531343a656c656d656e74616c5f7479706575343a57696e6475363a65715f65787075323a313075383a65717569707065646675353a677261646575313a3175323a696475383a313035313430303075363a6974656d496431363aa8f4c138733f0e4f851abb2a7552555b7531333a6974656d5f7375625f7479706575343a52696e6775393a6974656d5f7479706575393a45717569706d656e7475353a6c6576656c75313a3075323a6f6375313a347531383a7265717569726564426c6f636b496e64657875383a313134393233343475363a7365745f696475313a3575363a736b696c6c736c6475363a6368616e636575313a3975353a706f77657275343a3334323875383a736b696c6c526f776475353a636f6d626f6675383a636f6f6c646f776e693133657531343a656c656d656e74616c5f7479706575343a57696e6475393a6869745f636f756e7469356575323a696469313430303035657531343a736b696c6c5f63617465676f72797531303a4172656141747461636b7531373a736b696c6c5f7461726765745f7479706575373a456e656d6965737531303a736b696c6c5f7479706575363a41747461636b6565657531393a7370696e655f7265736f757263655f7061746875383a313035313430303075343a737461746475343a74797065343a0300000075353a76616c756575333a3130376575383a73746174734d617064343a03000000647531353a6164646974696f6e616c56616c756575323a393175383a7374617454797065343a0300000075353a76616c756575333a31303765343a06000000647531353a6164646974696f6e616c56616c756575333a34303175383a7374617454797065343a0600000075353a76616c756575313a3065656575393a6d6174657269616c736c6475353a636f756e7475323a323475383a6d6174657269616c647531343a656c656d656e74616c5f7479706575363a4e6f726d616c75353a677261646575313a3175323a696475363a33303334303075373a6974656d5f696433323a45c8a87009caf8f9d3ecf58618fa6e2b14fe0edb2283d373e3c190c56eb96d8a7531333a6974656d5f7375625f747970657531373a45717569706d656e744d6174657269616c75393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a313275383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a57696e6475353a677261646575313a3175323a696475363a33303630343275373a6974656d5f696433323a31f48810fa91236281c165659d65003cfb611205a52c1ff6e02c019b86625dda7531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a343775383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a57696e6475353a677261646575313a3275323a696475363a33303630353075373a6974656d5f696433323adf0c212eb56526891629367fe889cfce0ea89a04e21d11a05b19ff9231802b4c7531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a373075383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a57696e6475353a677261646575313a3275323a696475363a33303630353175373a6974656d5f696433323a5eac6f2b799a1fc20a50f005f2df8783fefec63595787804b4418ece2b3d07177531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656575383a726563697065496475333a3133377531313a737562526563697065496475333a33323375363a7479706549647532343a636f6d62696e6174696f6e2e726573756c742d6d6f64656c657531303a626c6f636b496e64657875383a313134393233323475323a696431363aeb3383670cd49a41aa6a956fb38caa267531383a7265717569726564426c6f636b496e64657875383a313134393233343475363a7479706549647531353a636f6d62696e6174696f6e4d61696c65647531303a626c6f636b496e64657875383a313134383035363375323a696431363a1463b76e102ce24e841f3f88020aa05275323a706931363a1463b76e102ce24e841f3f88020aa0527531383a7265717569726564426c6f636b496e64657875383a313134383035363375363a7479706549647531373a50726f6475637453656c6c65724d61696c65647531303a626c6f636b496e64657875383a313134393232343275313a666c6c647531333a646563696d616c506c61636573313a1275373a6d696e746572736e75363a7469636b657275373a4352595354414c656931353030303030303030303030303030303030303030303065656575323a696431363afa061a8852396448896835e2906fe61175313a6d7535313a7b22736561736f6e5f70617373223a207b226e223a205b32325d2c202270223a205b5d2c202274223a2022636c61696d227d7d7531383a7265717569726564426c6f636b496e64657875383a313134393232343275363a7479706549647531343a436c61696d4974656d734d61696c65647531303a626c6f636b496e64657875383a313134383035363375323a696431363ab966678b92d4424d99fde7bd69d2148775323a706931363ab966678b92d4424d99fde7bd69d214877531383a7265717569726564426c6f636b496e64657875383a313134383035363375363a7479706549647531373a50726f6475637453656c6c65724d61696c65647531303a626c6f636b496e64657875383a313134383035363375323a696431363ad88ca59d18c2ad409e257322e0e3f33475323a706931363ad88ca59d18c2ad409e257322e0e3f3347531383a7265717569726564426c6f636b496e64657875383a313134383035363375363a7479706549647531373a50726f6475637453656c6c65724d61696c65647531303a626c6f636b496e64657875383a313134373836333675323a696431363a05c08f9e2558b849be91dcea16e6d8a475323a706931363a05c08f9e2558b849be91dcea16e6d8a47531383a7265717569726564426c6f636b496e64657875383a313134373836333675363a7479706549647531373a50726f6475637453656c6c65724d61696c65647531303a6174746163686d656e74647531313a616374696f6e506f696e7475313a3075343a676f6c6469306575323a696431363a99257ba2c86ea4449a8ca8132be300f37531303a6974656d557361626c65647531303a62756666536b696c6c736c657531343a656c656d656e74616c5f7479706575343a57696e6475363a65715f65787075323a313075383a65717569707065646675353a677261646575313a3175323a696475383a313035313430303075363a6974656d496431363af2b0e55aa26e454984c09067ce4162827531333a6974656d5f7375625f7479706575343a52696e6775393a6974656d5f7479706575393a45717569706d656e7475353a6c6576656c75313a3075323a6f6375313a337531383a7265717569726564426c6f636b496e64657875383a313135303236383675363a7365745f696475313a3575363a736b696c6c736c657531393a7370696e655f7265736f757263655f7061746875383a313035313430303075343a737461746475343a74797065343a0300000075353a76616c756575333a3130376575383a73746174734d617064343a03000000647531353a6164646974696f6e616c56616c756575323a393475383a7374617454797065343a0300000075353a76616c756575333a31303765343a06000000647531353a6164646974696f6e616c56616c756575333a33393675383a7374617454797065343a0600000075353a76616c756575313a3065656575393a6d6174657269616c736c6475353a636f756e7475323a323475383a6d6174657269616c647531343a656c656d656e74616c5f7479706575363a4e6f726d616c75353a677261646575313a3175323a696475363a33303334303075373a6974656d5f696433323a45c8a87009caf8f9d3ecf58618fa6e2b14fe0edb2283d373e3c190c56eb96d8a7531333a6974656d5f7375625f747970657531373a45717569706d656e744d6174657269616c75393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a313275383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a57696e6475353a677261646575313a3175323a696475363a33303630343275373a6974656d5f696433323a31f48810fa91236281c165659d65003cfb611205a52c1ff6e02c019b86625dda7531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a343775383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a57696e6475353a677261646575313a3275323a696475363a33303630353075373a6974656d5f696433323adf0c212eb56526891629367fe889cfce0ea89a04e21d11a05b19ff9231802b4c7531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a373075383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a57696e6475353a677261646575313a3275323a696475363a33303630353175373a6974656d5f696433323a5eac6f2b799a1fc20a50f005f2df8783fefec63595787804b4418ece2b3d07177531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656575383a726563697065496475333a3133377531313a737562526563697065496475333a33323375363a7479706549647532343a636f6d62696e6174696f6e2e726573756c742d6d6f64656c657531303a626c6f636b496e64657875383a313134393232323975323a696431363a99257ba2c86ea4449a8ca8132be300f37531383a7265717569726564426c6f636b496e64657875383a313135303236383675363a7479706549647531353a636f6d62696e6174696f6e4d61696c65647531303a6174746163686d656e74647531313a616374696f6e506f696e7475313a3075343a676f6c6469306575323a696431363a6f177dabab873a4397f195fad7011e067531303a6974656d557361626c65647531303a62756666536b696c6c736c657531343a656c656d656e74616c5f7479706575343a4c616e6475363a65715f65787075313a3875383a65717569707065646675353a677261646575313a3175323a696475383a313034313330303075363a6974656d496431363ab84219dad196ff44a8f53e9bf494a01b7531333a6974656d5f7375625f7479706575383a4e65636b6c61636575393a6974656d5f7479706575393a45717569706d656e7475353a6c6576656c75313a3075323a6f6375313a337531383a7265717569726564426c6f636b496e64657875383a313134393033323175363a7365745f696475313a3475363a736b696c6c736c657531393a7370696e655f7265736f757263655f7061746875383a313034313330303075343a737461746475343a74797065343a0500000075353a76616c756575333a3335376575383a73746174734d617064343a03000000647531353a6164646974696f6e616c56616c756575323a323375383a7374617454797065343a0300000075353a76616c756575313a3065343a05000000647531353a6164646974696f6e616c56616c756575333a31373275383a7374617454797065343a0500000075353a76616c756575333a33353765656575393a6d6174657269616c736c6475353a636f756e7475323a313575383a6d6174657269616c647531343a656c656d656e74616c5f7479706575363a4e6f726d616c75353a677261646575313a3175323a696475363a33303333303075373a6974656d5f696433323a1bd96c8d5bce17827b894e01d4eb87bd853bc6a48baee9e6151ce568ae43ad397531333a6974656d5f7375625f747970657531373a45717569706d656e744d6174657269616c75393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323075383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630303975373a6974656d5f696433323a67f6ff0b0e20202a8e63742adf804355ceaee3ab636ed3065bd535985e7109a87531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323975383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630313075373a6974656d5f696433323ae0e69c7f4f16174438570e79ef52f5091ff761615a29dc70d3babbb4a099ce337531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323075383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630313175373a6974656d5f696433323a2d85afe3aa2e0ebc49df0149cf939feeddbfb9049a1e0c3bd7d8c00a948fece67531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656575383a726563697065496475333a3131317531313a737562526563697065496475333a32363075363a7479706549647532343a636f6d62696e6174696f6e2e726573756c742d6d6f64656c657531303a626c6f636b496e64657875383a313134383935393775323a696431363a6f177dabab873a4397f195fad7011e067531383a7265717569726564426c6f636b496e64657875383a313134393033323175363a7479706549647531353a636f6d62696e6174696f6e4d61696c65647531303a6174746163686d656e74647531313a616374696f6e506f696e7475313a3075343a676f6c6469306575323a696431363af3c9f6b3f36aa0488c73dc597a06b36c7531303a6974656d557361626c65647531303a62756666536b696c6c736c657531343a656c656d656e74616c5f7479706575343a4c616e6475363a65715f65787075313a3875383a65717569707065646675353a677261646575313a3175323a696475383a313034313330303075363a6974656d496431363a788c0c286da7c14abde5ded62de0f44d7531333a6974656d5f7375625f7479706575383a4e65636b6c61636575393a6974656d5f7479706575393a45717569706d656e7475353a6c6576656c75313a3075323a6f6375313a337531383a7265717569726564426c6f636b496e64657875383a313134383936323075363a7365745f696475313a3475363a736b696c6c736c6475363a6368616e636575313a3875353a706f77657275313a3075383a736b696c6c526f776475353a636f6d626f6675383a636f6f6c646f776e693235657531343a656c656d656e74616c5f7479706575363a4e6f726d616c75393a6869745f636f756e7469316575323a696469323430303030657531343a736b696c6c5f63617465676f727975373a486974427566667531373a736b696c6c5f7461726765745f7479706575343a53656c667531303a736b696c6c5f7479706575343a427566666565657531393a7370696e655f7265736f757263655f7061746875383a313034313330303075343a737461746475343a74797065343a0500000075353a76616c756575333a3335376575383a73746174734d617064343a03000000647531353a6164646974696f6e616c56616c756575323a333175383a7374617454797065343a0300000075353a76616c756575313a3065343a05000000647531353a6164646974696f6e616c56616c756575333a31303675383a7374617454797065343a0500000075353a76616c756575333a33353765656575393a6d6174657269616c736c6475353a636f756e7475323a313575383a6d6174657269616c647531343a656c656d656e74616c5f7479706575363a4e6f726d616c75353a677261646575313a3175323a696475363a33303333303075373a6974656d5f696433323a1bd96c8d5bce17827b894e01d4eb87bd853bc6a48baee9e6151ce568ae43ad397531333a6974656d5f7375625f747970657531373a45717569706d656e744d6174657269616c75393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323075383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630303975373a6974656d5f696433323a67f6ff0b0e20202a8e63742adf804355ceaee3ab636ed3065bd535985e7109a87531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323975383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630313075373a6974656d5f696433323ae0e69c7f4f16174438570e79ef52f5091ff761615a29dc70d3babbb4a099ce337531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323075383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630313175373a6974656d5f696433323a2d85afe3aa2e0ebc49df0149cf939feeddbfb9049a1e0c3bd7d8c00a948fece67531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656575383a726563697065496475333a3131317531313a737562526563697065496475333a32363075363a7479706549647532343a636f6d62696e6174696f6e2e726573756c742d6d6f64656c657531303a626c6f636b496e64657875383a313134383936303075323a696431363af3c9f6b3f36aa0488c73dc597a06b36c7531383a7265717569726564426c6f636b496e64657875383a313134383936323075363a7479706549647531353a636f6d62696e6174696f6e4d61696c65647531303a6174746163686d656e74647531313a616374696f6e506f696e7475313a3075313a636c647531333a646563696d616c506c61636573313a1275373a6d696e746572736e75363a7469636b657275373a4352595354414c65693065657531373a656e68616e63656d656e74526573756c7475373a5375636365737375343a676f6c6469306575323a696431363a360225bce61f584cb67a5f45441797eb7531303a6974656d557361626c65647531303a62756666536b696c6c736c657531343a656c656d656e74616c5f7479706575343a57696e6475363a65715f65787075333a36343075383a65717569707065646675353a677261646575313a3275323a696475383a313031323430303075363a6974656d496431363abb94ea9d0a698e4581e9e177e9efbd017531333a6974656d5f7375625f7479706575363a576561706f6e75393a6974656d5f7479706575393a45717569706d656e7475353a6c6576656c75313a3275323a6f6375313a337531383a7265717569726564426c6f636b496e64657875383a313134383134353275363a7365745f696475323a313075363a736b696c6c736c6475363a6368616e636575323a323875353a706f77657275343a3336353775383a736b696c6c526f776475353a636f6d626f6675383a636f6f6c646f776e6933657531343a656c656d656e74616c5f7479706575343a57696e6475393a6869745f636f756e7469326575323a696469313430303033657531343a736b696c6c5f63617465676f72797531323a446f75626c6541747461636b7531373a736b696c6c5f7461726765745f7479706575353a456e656d797531303a736b696c6c5f7479706575363a41747461636b6565657531393a7370696e655f7265736f757263655f7061746875383a313031323430303075343a737461746475343a74797065343a0200000075353a76616c756575333a3332376575383a73746174734d617064343a02000000647531353a6164646974696f6e616c56616c75657531323a3131372e303030303030303075383a7374617454797065343a0200000075353a76616c756575383a3339302e3533373665343a06000000647531353a6164646974696f6e616c56616c75657531323a3439382e303030303030303075383a7374617454797065343a0600000075353a76616c756575313a306565657531383a6d6174657269616c4974656d49644c6973746c31363aa30c9f43ac29414abdc8e2e2cac3a6e131363ac2746f747d8e964791104ce99ccc779931363a71acadf8602fbf4ab80c58f1c1329c33657531333a7072654974656d557361626c65647531303a62756666536b696c6c736c657531343a656c656d656e74616c5f7479706575343a57696e6475363a65715f65787075333a31383075383a65717569707065646675353a677261646575313a3275323a696475383a313031323430303075363a6974656d496431363abb94ea9d0a698e4581e9e177e9efbd017531333a6974656d5f7375625f7479706575363a576561706f6e75393a6974656d5f7479706575393a45717569706d656e7475353a6c6576656c75313a3075323a6f6375313a337531383a7265717569726564426c6f636b496e64657875383a313134363938333075363a7365745f696475323a313075363a736b696c6c736c6475363a6368616e636575323a323875353a706f77657275343a3336353775383a736b696c6c526f776475353a636f6d626f6675383a636f6f6c646f776e6933657531343a656c656d656e74616c5f7479706575343a57696e6475393a6869745f636f756e7469326575323a696469313430303033657531343a736b696c6c5f63617465676f72797531323a446f75626c6541747461636b7531373a736b696c6c5f7461726765745f7479706575353a456e656d797531303a736b696c6c5f7479706575363a41747461636b6565657531393a7370696e655f7265736f757263655f7061746875383a313031323430303075343a737461746475343a74797065343a0200000075353a76616c756575333a3332376575383a73746174734d617064343a02000000647531353a6164646974696f6e616c56616c756575333a31313775383a7374617454797065343a0200000075353a76616c756575333a33323765343a06000000647531353a6164646974696f6e616c56616c756575333a34393875383a7374617454797065343a0600000075353a76616c756575313a3065656575363a7479706549647532353a6974656d5f656e68616e63656d656e7431332e726573756c74657531303a626c6f636b496e64657875383a313134383133303275323a696431363a360225bce61f584cb67a5f45441797eb7531383a7265717569726564426c6f636b496e64657875383a313134383134353275363a7479706549647531313a6974656d456e68616e636565647531303a6174746163686d656e74647531313a616374696f6e506f696e7475313a3075343a676f6c6469306575323a696431363a83ca3ec0f936834b8e68d82f1a74023e7531303a6974656d557361626c65647531303a62756666536b696c6c736c657531343a656c656d656e74616c5f7479706575343a57696e6475363a65715f65787075323a313075383a65717569707065646675353a677261646575313a3175323a696475383a313035313430303075363a6974656d496431363a171b65986137df448b463fd62824e4997531333a6974656d5f7375625f7479706575343a52696e6775393a6974656d5f7479706575393a45717569706d656e7475353a6c6576656c75313a3075323a6f6375313a337531383a7265717569726564426c6f636b496e64657875383a313135303032313975363a7365745f696475313a3575363a736b696c6c736c657531393a7370696e655f7265736f757263655f7061746875383a313035313430303075343a737461746475343a74797065343a0300000075353a76616c756575333a3130376575383a73746174734d617064343a03000000647531353a6164646974696f6e616c56616c756575323a393475383a7374617454797065343a0300000075353a76616c756575333a31303765343a06000000647531353a6164646974696f6e616c56616c756575333a33373475383a7374617454797065343a0600000075353a76616c756575313a3065656575393a6d6174657269616c736c6475353a636f756e7475323a323475383a6d6174657269616c647531343a656c656d656e74616c5f7479706575363a4e6f726d616c75353a677261646575313a3175323a696475363a33303334303075373a6974656d5f696433323a45c8a87009caf8f9d3ecf58618fa6e2b14fe0edb2283d373e3c190c56eb96d8a7531333a6974656d5f7375625f747970657531373a45717569706d656e744d6174657269616c75393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a313275383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a57696e6475353a677261646575313a3175323a696475363a33303630343275373a6974656d5f696433323a31f48810fa91236281c165659d65003cfb611205a52c1ff6e02c019b86625dda7531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a343775383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a57696e6475353a677261646575313a3275323a696475363a33303630353075373a6974656d5f696433323adf0c212eb56526891629367fe889cfce0ea89a04e21d11a05b19ff9231802b4c7531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a373075383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a57696e6475353a677261646575313a3275323a696475363a33303630353175373a6974656d5f696433323a5eac6f2b799a1fc20a50f005f2df8783fefec63595787804b4418ece2b3d07177531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656575383a726563697065496475333a3133377531313a737562526563697065496475333a33323375363a7479706549647532343a636f6d62696e6174696f6e2e726573756c742d6d6f64656c657531303a626c6f636b496e64657875383a313134383937363275323a696431363a83ca3ec0f936834b8e68d82f1a74023e7531383a7265717569726564426c6f636b496e64657875383a313135303032313975363a7479706549647531353a636f6d62696e6174696f6e4d61696c65647531303a6174746163686d656e74647531313a616374696f6e506f696e7475313a3075343a676f6c6469306575323a696431363a410bdbc1e7784944a326a7c33283949c7531303a6974656d557361626c65647531303a62756666536b696c6c736c657531343a656c656d656e74616c5f7479706575343a4c616e6475363a65715f65787075313a3875383a65717569707065646675353a677261646575313a3175323a696475383a313034313330303075363a6974656d496431363a11eaf70e63890447894dacb39c8402d07531333a6974656d5f7375625f7479706575383a4e65636b6c61636575393a6974656d5f7479706575393a45717569706d656e7475353a6c6576656c75313a3075323a6f6375313a327531383a7265717569726564426c6f636b496e64657875383a313134383139313675363a7365745f696475313a3475363a736b696c6c736c657531393a7370696e655f7265736f757263655f7061746875383a313034313330303075343a737461746475343a74797065343a0500000075353a76616c756575333a3335376575383a73746174734d617064343a03000000647531353a6164646974696f6e616c56616c756575323a323875383a7374617454797065343a0300000075353a76616c756575313a3065343a05000000647531353a6164646974696f6e616c56616c756575333a31313075383a7374617454797065343a0500000075353a76616c756575333a33353765656575393a6d6174657269616c736c6475353a636f756e7475323a313575383a6d6174657269616c647531343a656c656d656e74616c5f7479706575363a4e6f726d616c75353a677261646575313a3175323a696475363a33303333303075373a6974656d5f696433323a1bd96c8d5bce17827b894e01d4eb87bd853bc6a48baee9e6151ce568ae43ad397531333a6974656d5f7375625f747970657531373a45717569706d656e744d6174657269616c75393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323075383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630303975373a6974656d5f696433323a67f6ff0b0e20202a8e63742adf804355ceaee3ab636ed3065bd535985e7109a87531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323975383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630313075373a6974656d5f696433323ae0e69c7f4f16174438570e79ef52f5091ff761615a29dc70d3babbb4a099ce337531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323075383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630313175373a6974656d5f696433323a2d85afe3aa2e0ebc49df0149cf939feeddbfb9049a1e0c3bd7d8c00a948fece67531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656575383a726563697065496475333a3131317531313a737562526563697065496475333a32363075363a7479706549647532343a636f6d62696e6174696f6e2e726573756c742d6d6f64656c657531303a626c6f636b496e64657875383a313134383133303775323a696431363a410bdbc1e7784944a326a7c33283949c7531383a7265717569726564426c6f636b496e64657875383a313134383139313675363a7479706549647531353a636f6d62696e6174696f6e4d61696c65647531303a6174746163686d656e74647531313a616374696f6e506f696e7475313a3075343a676f6c6469306575323a696431363a70fe8ac41b84c746859508c0892a6c907531303a6974656d557361626c65647531303a62756666536b696c6c736c657531343a656c656d656e74616c5f7479706575363a4e6f726d616c75363a65715f65787075313a3575383a65717569707065646675353a677261646575313a3175323a696475383a313035313030303075363a6974656d496431363aa0490f2ce8a1cd47ad9d579a9e9304a07531333a6974656d5f7375625f7479706575343a52696e6775393a6974656d5f7479706575393a45717569706d656e7475353a6c6576656c75313a3075323a6f6375313a337531383a7265717569726564426c6f636b496e64657875383a313134383334363175363a7365745f696475313a3175363a736b696c6c736c657531393a7370696e655f7265736f757263655f7061746875383a313035313030303075343a737461746475343a74797065343a0300000075353a76616c756575313a386575383a73746174734d617064343a02000000647531353a6164646974696f6e616c56616c756575313a3775383a7374617454797065343a0200000075353a76616c756575313a3065343a03000000647531353a6164646974696f6e616c56616c756575313a3675383a7374617454797065343a0300000075353a76616c756575313a3865656575393a6d6174657269616c736c6475353a636f756e7475313a3275383a6d6174657269616c647531343a656c656d656e74616c5f7479706575363a4e6f726d616c75353a677261646575313a3175323a696475363a33303334303075373a6974656d5f696433323a45c8a87009caf8f9d3ecf58618fa6e2b14fe0edb2283d373e3c190c56eb96d8a7531333a6974656d5f7375625f747970657531373a45717569706d656e744d6174657269616c75393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475313a3275383a6d6174657269616c647531343a656c656d656e74616c5f7479706575353a576174657275353a677261646575313a3175323a696475363a33303630303175373a6974656d5f696433323a77cfad5273885820b69e61c2106ae06583f69c7f6d82a229b59e5f1b984164be7531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475313a3275383a6d6174657269616c647531343a656c656d656e74616c5f7479706575353a576174657275353a677261646575313a3175323a696475363a33303630303275373a6974656d5f696433323a28a2c38b0934225a8f2327b9bd8cf7c7eaf3551bde8203f44248c011938e97707531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475313a3175383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4669726575353a677261646575313a3175323a696475363a33303630323375373a6974656d5f696433323a1af5e747fc81a7f3149af024db2e5025b6749a000d66b22e665acdd45b8dbd177531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656575383a726563697065496475333a3133337531313a737562526563697065496475333a34353875363a7479706549647532343a636f6d62696e6174696f6e2e726573756c742d6d6f64656c657531303a626c6f636b496e64657875383a313134383334353375323a696431363a70fe8ac41b84c746859508c0892a6c907531383a7265717569726564426c6f636b496e64657875383a313134383334363175363a7479706549647531353a636f6d62696e6174696f6e4d61696c65647531303a6174746163686d656e74647531313a616374696f6e506f696e7475313a3075343a676f6c6469306575323a696431363ac11851cdf4576d49a113d7d756ed35897531303a6974656d557361626c65647531303a62756666536b696c6c736c657531343a656c656d656e74616c5f7479706575343a4c616e6475363a65715f65787075313a3875383a65717569707065646675353a677261646575313a3175323a696475383a313034313330303075363a6974656d496431363a7f45c50e8c9cdc48b87b1c28af3559707531333a6974656d5f7375625f7479706575383a4e65636b6c61636575393a6974656d5f7479706575393a45717569706d656e7475353a6c6576656c75313a3075323a6f6375313a337531383a7265717569726564426c6f636b496e64657875383a313134383230333275363a7365745f696475313a3475363a736b696c6c736c657531393a7370696e655f7265736f757263655f7061746875383a313034313330303075343a737461746475343a74797065343a0500000075353a76616c756575333a3335376575383a73746174734d617064343a03000000647531353a6164646974696f6e616c56616c756575323a323875383a7374617454797065343a0300000075353a76616c756575313a3065343a05000000647531353a6164646974696f6e616c56616c756575333a31383475383a7374617454797065343a0500000075353a76616c756575333a33353765656575393a6d6174657269616c736c6475353a636f756e7475323a313575383a6d6174657269616c647531343a656c656d656e74616c5f7479706575363a4e6f726d616c75353a677261646575313a3175323a696475363a33303333303075373a6974656d5f696433323a1bd96c8d5bce17827b894e01d4eb87bd853bc6a48baee9e6151ce568ae43ad397531333a6974656d5f7375625f747970657531373a45717569706d656e744d6174657269616c75393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323075383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630303975373a6974656d5f696433323a67f6ff0b0e20202a8e63742adf804355ceaee3ab636ed3065bd535985e7109a87531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323975383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630313075373a6974656d5f696433323ae0e69c7f4f16174438570e79ef52f5091ff761615a29dc70d3babbb4a099ce337531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323075383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630313175373a6974656d5f696433323a2d85afe3aa2e0ebc49df0149cf939feeddbfb9049a1e0c3bd7d8c00a948fece67531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656575383a726563697065496475333a3131317531313a737562526563697065496475333a32363075363a7479706549647532343a636f6d62696e6174696f6e2e726573756c742d6d6f64656c657531303a626c6f636b496e64657875383a313134383133303875323a696431363ac11851cdf4576d49a113d7d756ed35897531383a7265717569726564426c6f636b496e64657875383a313134383230333275363a7479706549647531353a636f6d62696e6174696f6e4d61696c65647531303a6174746163686d656e74647531313a616374696f6e506f696e7475313a3075343a676f6c6469306575323a696431363ab21cf1d3f2538e4c9496080cb00216657531303a6974656d557361626c65647531303a62756666536b696c6c736c657531343a656c656d656e74616c5f7479706575343a4c616e6475363a65715f65787075313a3875383a65717569707065646675353a677261646575313a3175323a696475383a313034313330303075363a6974656d496431363ad5f36402d57e214691607fa35606e5297531333a6974656d5f7375625f7479706575383a4e65636b6c61636575393a6974656d5f7479706575393a45717569706d656e7475353a6c6576656c75313a3075323a6f6375313a327531383a7265717569726564426c6f636b496e64657875383a313134383139313575363a7365745f696475313a3475363a736b696c6c736c657531393a7370696e655f7265736f757263655f7061746875383a313034313330303075343a737461746475343a74797065343a0500000075353a76616c756575333a3335376575383a73746174734d617064343a03000000647531353a6164646974696f6e616c56616c756575323a333075383a7374617454797065343a0300000075353a76616c756575313a3065343a05000000647531353a6164646974696f6e616c56616c756575333a31313675383a7374617454797065343a0500000075353a76616c756575333a33353765656575393a6d6174657269616c736c6475353a636f756e7475323a313575383a6d6174657269616c647531343a656c656d656e74616c5f7479706575363a4e6f726d616c75353a677261646575313a3175323a696475363a33303333303075373a6974656d5f696433323a1bd96c8d5bce17827b894e01d4eb87bd853bc6a48baee9e6151ce568ae43ad397531333a6974656d5f7375625f747970657531373a45717569706d656e744d6174657269616c75393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323075383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630303975373a6974656d5f696433323a67f6ff0b0e20202a8e63742adf804355ceaee3ab636ed3065bd535985e7109a87531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323975383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630313075373a6974656d5f696433323ae0e69c7f4f16174438570e79ef52f5091ff761615a29dc70d3babbb4a099ce337531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a323075383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a4c616e6475353a677261646575313a3275323a696475363a33303630313175373a6974656d5f696433323a2d85afe3aa2e0ebc49df0149cf939feeddbfb9049a1e0c3bd7d8c00a948fece67531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656575383a726563697065496475333a3131317531313a737562526563697065496475333a32363075363a7479706549647532343a636f6d62696e6174696f6e2e726573756c742d6d6f64656c657531303a626c6f636b496e64657875383a313134383133303675323a696431363ab21cf1d3f2538e4c9496080cb00216657531383a7265717569726564426c6f636b496e64657875383a313134383139313575363a7479706549647531353a636f6d62696e6174696f6e4d61696c65647531303a6174746163686d656e74647531313a616374696f6e506f696e7475313a3075343a676f6c6469306575323a696431363a885a5cdfbb73604e99edf84bb44705387531303a6974656d557361626c65647531303a62756666536b696c6c736c657531343a656c656d656e74616c5f7479706575343a57696e6475363a65715f65787075323a313075383a65717569707065646675353a677261646575313a3175323a696475383a313035313430303075363a6974656d496431363af48685a80203184fb5b78808f005198e7531333a6974656d5f7375625f7479706575343a52696e6775393a6974656d5f7479706575393a45717569706d656e7475353a6c6576656c75313a3075323a6f6375313a327531383a7265717569726564426c6f636b496e64657875383a313134393138323175363a7365745f696475313a3575363a736b696c6c736c657531393a7370696e655f7265736f757263655f7061746875383a313035313430303075343a737461746475343a74797065343a0300000075353a76616c756575333a3130376575383a73746174734d617064343a03000000647531353a6164646974696f6e616c56616c756575323a343775383a7374617454797065343a0300000075353a76616c756575333a31303765343a06000000647531353a6164646974696f6e616c56616c756575333a34343275383a7374617454797065343a0600000075353a76616c756575313a3065656575393a6d6174657269616c736c6475353a636f756e7475323a323475383a6d6174657269616c647531343a656c656d656e74616c5f7479706575363a4e6f726d616c75353a677261646575313a3175323a696475363a33303334303075373a6974656d5f696433323a45c8a87009caf8f9d3ecf58618fa6e2b14fe0edb2283d373e3c190c56eb96d8a7531333a6974656d5f7375625f747970657531373a45717569706d656e744d6174657269616c75393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a313275383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a57696e6475353a677261646575313a3175323a696475363a33303630343275373a6974656d5f696433323a31f48810fa91236281c165659d65003cfb611205a52c1ff6e02c019b86625dda7531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a343775383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a57696e6475353a677261646575313a3275323a696475363a33303630353075373a6974656d5f696433323adf0c212eb56526891629367fe889cfce0ea89a04e21d11a05b19ff9231802b4c7531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656475353a636f756e7475323a373075383a6d6174657269616c647531343a656c656d656e74616c5f7479706575343a57696e6475353a677261646575313a3275323a696475363a33303630353175373a6974656d5f696433323a5eac6f2b799a1fc20a50f005f2df8783fefec63595787804b4418ece2b3d07177531333a6974656d5f7375625f747970657531313a4d6f6e737465725061727475393a6974656d5f7479706575383a4d6174657269616c65656575383a726563697065496475333a3133377531313a737562526563697065496475333a33323375363a7479706549647532343a636f6d62696e6174696f6e2e726573756c742d6d6f64656c657531303a626c6f636b496e64657875383a313134383334353575323a696431363a885a5cdfbb73604e99edf84bb44705387531383a7265717569726564426c6f636b496e64657875383a313134393138323175363a7479706549647531353a636f6d62696e6174696f6e4d61696c6565693131343932333234656939383832333735656930656475313a3175313a3175323a313075313a3175333a31303075333a32303375333a31303175313a3175333a31303275333a31343875333a31303375323a313175333a31303475313a3575333a31303575313a3275333a31303675313a3175333a31303775313a3275333a31303875313a3175333a31303975323a313075323a313175313a3175333a31313075323a313175333a31313175313a3975333a31313275313a3175333a31313375313a3175333a31313475313a3175333a31313575313a3175333a31313675313a3175333a31313775313a3175333a31313875313a3175333a31313975313a3175323a313275313a3175333a31323075313a3175333a31323175313a3175333a31323275313a3175333a31323375313a3175333a31323475313a3175333a31323575313a3175333a31323675313a3175333a31323775313a3175333a31323875313a3175333a31323975313a3175323a313375313a3175333a31333075313a3175333a31333175313a3175333a31333275313a3175333a31333375313a3175333a31333475313a3175333a31333575313a3175333a31333675313a3175333a31333775313a3175333a31333875313a3175333a31333975313a3175323a313475313a3175333a31343075313a3175333a31343175313a3175333a31343275313a3175333a31343375313a3175333a31343475313a3175333a31343575313a3175333a31343675313a3175333a31343775313a3175333a31343875313a3275333a31343975313a3475323a313575323a313275333a31353075323a333475333a31353175343a3130373275333a31353275313a3175333a31353375313a3275333a31353475313a3175333a31353575313a3175333a31353675323a313175333a31353775313a3275333a31353875313a3175333a31353975323a313975323a313675313a3175333a31363075313a3175333a31363175313a3275333a31363275323a313875333a31363375313a3175333a31363475313a3175333a31363575313a3175333a31363675313a3175333a31363775323a313575333a31363875313a3375333a31363975313a3275323a313775313a3175333a31373075323a313275333a31373175323a333275333a31373275313a3175333a31373375333a37383775333a31373475333a31373375333a31373575333a32303475333a31373675313a3775333a31373775313a3775333a31373875313a3275333a31373975313a3175323a313875313a3675333a31383075323a313075333a31383175323a313875333a31383275323a323575333a31383375313a3175333a31383475313a3175333a31383575313a3175333a31383675313a3175333a31383775313a3175333a31383875313a3175333a31383975313a3175323a313975313a3175333a31393075313a3175333a31393175313a3175333a31393275313a3175333a31393375313a3175333a31393475313a3175333a31393575323a323375333a31393675323a323475333a31393775313a3175333a31393875313a3175333a31393975313a3175313a3275313a3175323a323075313a3175333a32303075313a3275333a32303175313a3175333a32303275313a3175333a32303375313a3175333a32303475313a3175333a32303575313a3175333a32303675313a3175333a32303775313a3275333a32303875323a323175333a32303975313a3175323a323175313a3275333a32313075313a3175333a32313175313a3175333a32313275313a3175333a32313375313a3175333a32313475313a3175333a32313575313a3175333a32313675313a3175333a32313775323a313275333a32313875313a3175333a32313975313a3975323a323275313a3175333a32323075313a3375333a32323175313a3175333a32323275313a3175333a32323375313a3175333a32323475313a3175333a32323575313a3175333a32323675313a3175333a32323775313a3175333a32323875313a3175333a32323975313a3175323a323375313a3375333a32333075313a3275333a32333175313a3175333a32333275313a3175333a32333375313a3175333a32333475313a3175333a32333575313a3175333a32333675313a3175333a32333775313a3175333a32333875313a3175333a32333975313a3175323a323475313a3475333a32343075313a3175333a32343175313a3175333a32343275313a3175333a32343375313a3175333a32343475313a3175333a32343575313a3175333a32343675313a3175333a32343775313a3175333a32343875313a3175333a32343975313a3275323a323575313a3175333a32353075313a3175333a32353175313a3175333a32353275313a3175333a32353375313a3175333a32353475323a313675333a32353575313a3175333a32353675313a3175333a32353775313a3175333a32353875313a3175333a32353975313a3175323a323675313a3175333a32363075313a3175333a32363175313a3175333a32363275313a3175333a32363375313a3175333a32363475313a3175333a32363575313a3175333a32363675313a3175333a32363775313a3175333a32363875313a3175333a32363975313a3175323a323775323a343075333a32373075313a3175333a32373175313a3175333a32373275313a3175333a32373375313a3175333a32373475313a3175333a32373575313a3175333a32373675313a3175333a32373775313a3175333a32373875313a3175333a32373975313a3175323a323875323a333075333a32383075323a313275333a32383175313a3175333a32383275313a3175333a32383375313a3175333a32383475313a3175333a32383575313a3175333a32383675313a3175333a32383775313a3175333a32383875313a3175333a32383975323a333075323a323975313a3175333a32393075313a3175333a32393175313a3175333a32393275313a3175333a32393375313a3175333a32393475313a3175333a32393575323a313975333a32393675313a3775333a32393775313a3175333a32393875313a3775333a32393975313a3175313a3375313a3175323a333075313a3175333a33303075313a3875333a33303175313a3175333a33303275313a3175333a33303375313a3175333a33303475313a3175333a33303575313a3175333a33303675313a3175333a33303775313a3175333a33303875313a3175333a33303975313a3175323a333175313a3375333a33313075313a3175333a33313175313a3175333a33313275313a3175333a33313375313a3175333a33313475313a3175333a33313575313a3175333a33313675313a3175333a33313775313a3175333a33313875313a3175333a33313975313a3175323a333275313a3775333a33323075313a3175333a33323175313a3175333a33323275313a3175333a33323375313a3175333a33323475313a3175333a33323575313a3275333a33323675313a3175333a33323775313a3175333a33323875313a3175333a33323975313a3175323a333375313a3175333a33333075313a3175333a33333175313a3375333a33333275313a3175323a333475313a3375323a333575313a3175323a333675313a3875323a333775313a3375323a333875313a3975323a333975313a3175313a3475313a3175323a343075313a3175323a343175313a3175323a343275313a3175323a343375313a3375323a343475313a3275323a343575313a3175323a343675313a3175323a343775313a3175323a343875313a3175323a343975313a3275313a3575313a3175323a353075313a3175323a353175313a3675323a353275333a31373375323a353375333a34323175323a353475313a3375323a353575333a31353775323a353675313a3775323a353775323a323275323a353875313a3275323a353975313a3275313a3675313a3175323a363075313a3175323a363175313a3175323a363275313a3175323a363375333a31363775323a363475323a353675323a363575323a343175323a363675323a313775323a363775323a323075323a363875323a353775323a363975313a3875313a3775313a3175323a373075323a323275323a373175313a3875323a373275323a323775323a373375333a32313075323a373475323a383275323a373575333a31353275323a373675323a323875323a373775323a343575323a373875323a323175323a373975323a313575313a3875313a3175323a383075323a313475323a383175323a323275323a383275323a313175323a383375323a373275323a383475313a3775323a383575323a313475323a383675313a3675323a383775313a3375323a383875313a3275323a383975313a3275313a3975313a3275323a393075313a3275323a393175313a3275323a393275313a3275323a393375313a3175323a393475313a3175323a393575313a3275323a393675313a3175323a393775313a3975323a393875313a3475323a393975313a33656475363a32303130303075333a36333975363a32303130303175333a31383575363a32303130303275333a32343075363a32303130303375323a393875363a32303130303475333a31353775363a32303130303575313a3175363a32303130303675313a3775363a32303130303775323a323075363a32303130303875323a313575363a32303230303075343a3531373675363a32303230303175343a3432303375363a32303230303275343a3135393575363a32303230303375333a34343775363a32303230303475333a34353975363a32303230303575343a3133303875363a32303230303675323a323075363a32303230303775333a32303375363a32303330303075343a3138303675363a32303330303175333a33333275363a32303330303275333a33383375363a32303330303375323a353675363a32303330303475323a333975363a32303330303575323a323475363a32303330303675323a313075363a32303330303775323a333475363a32303430303075343a3530333075363a32303430303175333a33383775363a32303430303275343a3133363475363a32303430313075343a3237303475363a32303430313175333a39373775363a32303430313275343a3331373575363a32303430313375343a3433313475363a32303430323075343a3138333475363a32303430323175333a32343375363a32303430323275333a33323275363a32303430323375343a3133303275363a32303530303075343a3833353375363a32303530303175353a313038373775363a32303530303275343a3237363975363a32303530303375333a37303875363a32303530303475323a363075363a32303530303575333a38393475363a32303530303675323a333075363a32303530303775313a3275363a32303630303075343a3136383675363a32303630303175343a3135393775363a32303630303275333a36363775363a32303630303375333a31373175363a32303630303475333a31333675363a32303630303575323a373575363a32303630303675313a3675363a32303630303775313a3175363a32303730303075343a3135353875363a32303730303175343a3131343575363a32303730303275333a36343475363a32303730303375333a38393775363a32303730303475333a33353075363a32303730303575333a32313475363a32303730303675323a323375363a32303730303775313a3875363a32303830303075343a3231353375363a32303830303175343a3135373775363a32303830303275343a3233323775363a32303830303375333a35353275363a32303830303475333a33393375363a32303830303575313a32656475383a313031313030303075323a313375383a313031313130303075313a3375383a313031313230303075313a3275383a313031313330303075313a3175383a313031313430303075323a313275383a313031323030303075323a333475383a313031323130303075313a3775383a313031323230303075313a3875383a313031323330303075313a3175383a313031323430303075323a373475383a313031333030303075333a34333675383a313031333030303175323a313875383a313031333130303075313a3975383a313031333130303175313a3175383a313031333230303075313a3575383a313031333230303175323a313675383a313031333330303075323a313475383a313031333330303175323a313375383a313031333430303075313a3875383a313031333430303175313a3475383a313031343030303075313a3175383a313031343130303075323a313375383a313031343330303075313a3875383a313031353130303075313a3475383a313032313030303075313a3375383a313032313130303075323a313475383a313032313230303075323a313675383a313032313330303075313a3375383a313032313430303075313a3475383a313032323030303075333a31303975383a313032323130303075323a313175383a313032323230303075313a3775383a313032323330303075313a3175383a313032323430303075323a353875383a313032333030303075323a313675383a313032333030303175313a3375383a313032333130303075313a3175383a313032333130303175323a313475383a313032333230303075313a3175383a313032333230303175323a313775383a313032333330303075313a3375383a313032333330303175313a3975383a313032333430303075313a3575383a313032343130303075313a3375383a313032343330303075313a3475383a313032353230303175313a3475383a313033313030303075313a3175383a313033313130303075313a3375383a313033313230303075313a3375383a313033313330303075313a3775383a313033313430303075313a3675383a313033323030303075323a313075383a313033323130303075313a3275383a313033323230303075313a3375383a313033323330303075323a323475383a313033323430303075313a3175383a313033333030303075323a313075383a313033333130303075323a313675383a313033333230303075313a3475383a313033333330303075313a3475383a313033333430303075313a3375383a313033343030303075333a31333775383a313033343130303075313a3775383a313033343330303075313a3175383a313033343430303075313a3175383a313033353130303175313a3475383a313033353330303075313a3275383a313033353430303075313a3175383a313033353430303175313a3275383a313034313030303075313a3175383a313034313130303075313a3775383a313034313230303075313a3275383a313034313330303075323a313075383a313034313430303075313a3175383a313034323030303075323a383775383a313034323130303075323a313175383a313034323230303075313a3775383a313034323330303075323a323575383a313034333030303075323a383375383a313034333130303075313a3175383a313034333230303075323a313875383a313034333330303075313a3875383a313034343030303075313a3275383a313034343430303075313a3175383a313034353130303075323a313075383a313034353130303175313a3275383a313034353230303175313a3175383a313034353330303075313a3175383a313034353430303075313a3175383a313035313030303075323a313775383a313035313130303075313a3375383a313035313230303075313a3275383a313035313330303075313a3175383a313035313430303075323a353875383a313035323030303075323a323975383a313035323130303075323a313075383a313035323230303075323a313275383a313035323330303075313a3875383a313035323430303075323a313575383a313035333030303075333a31333375383a313035333130303075313a3775383a313035333230303075323a313275383a313035333330303075313a3875383a313035333430303075313a3375383a313035343030303075313a3175383a313035343330303075313a3175383a313035343430303075323a313675383a313035353130303075313a3275383a313036313030303075333a34383375383a313036323030303075333a32343275383a313036323030303175323a323675383a313036323030303275323a323075383a313036323030303375323a313675383a313036333030303075323a323975383a313036333030303175313a3775383a313036333030303275313a3975383a313036333030303375323a313075383a313036343030303275313a3175383a313230303130303175323a323475383a313230303130303275323a313275383a313230303130303375313a3675363a32303130303075313a3975363a32303130303175323a363775363a32303130303275313a3475363a32303130303375323a313075363a32303130303575323a313375363a32303130303675313a3675363a32303130303875313a3875363a32303130303975313a3775363a32303130313075313a3975363a32303130313175313a3475363a32303130313275313a3375363a32303130313375313a3275363a32303130313575323a343275363a32303130313675313a3575363a32303130313875323a373475363a32303130313975313a3575363a32303130323175323a383775363a32303130323275323a323575363a32303130323375313a3575363a32303130323475313a3775363a32303130323575323a343675363a32303130323675313a3575363a32303130323775313a3775363a33303230303075323a323375363a33303230303175323a313575363a33303230303275323a313675363a33303230303375323a343975363a33303230303475323a323875363a33303230303575323a313775363a33303230303675323a313175363a33303230303875323a313875363a33303230303975323a313075363a33303330303075323a373675363a33303330303175333a35373175363a33303330303275343a3230373575363a33303330303375333a32373775363a33303330303475333a31383675363a33303331303075323a323475363a33303331303175333a34323775363a33303331303275333a38393375363a33303331303375323a393975363a33303331303475313a3775363a33303332303075323a343275363a33303332303175333a32313575363a33303332303275343a3135303575363a33303332303375333a31363275363a33303332303475333a31323975363a33303333303075323a343175363a33303333303175333a33373675363a33303333303275333a35363675363a33303333303375323a353975363a33303333303475323a343775363a33303334303075333a32373375363a33303334303175333a33333775363a33303334303275343a3136363575363a33303334303375333a32313075363a33303334303475323a333475363a33303430303075313a3175363a33303430303175313a3175363a33303430303275313a3175363a33303430303375313a3175363a33303630303075333a31343775363a33303630303175333a31313075363a33303630303275323a373775363a33303630303375333a31343575363a33303630303475333a31353975363a33303630303575323a373075363a33303630303675333a31383775363a33303630303775323a393775363a33303630303875343a3130393475363a33303630303975333a31343975363a33303630313075333a33393675363a33303630313175323a363775363a33303630313275333a33333275363a33303630313375333a33303975363a33303630313475333a31343575363a33303630313575343a3138303275363a33303630313675333a31303575363a33303630313775333a31303175363a33303630323375333a33303175363a33303630323475333a32313775363a33303630323575333a31343175363a33303630323675333a33353475363a33303630323775333a32313675363a33303630323875333a31363075363a33303630323975333a34383375363a33303630333075333a32313275363a33303630333175323a353275363a33303630333575343a3135333575363a33303630333675333a31373375363a33303630333775333a37313775363a33303630333875333a32373175363a33303630333975333a32353975363a33303630343075343a3334363975363a33303630343175333a38303375363a33303630343275343a3232333375363a33303630343375333a35373575363a33303630343475333a34303075363a33303630343575323a393475363a33303630343675323a323375363a33303630343775313a3275363a33303630343875323a313675363a33303630343975313a3975363a33303630353075343a3136323575363a33303630353175343a3132383175363a33303630353275333a36353975363a33303630353375333a37323275363a33303630353475333a36353375363a33303630353575333a34313475363a33303630373075333a31303675363a33303630373275313a3175363a33303630373375323a343175363a33303630373475313a3575363a33303630373575313a3675363a33303630373675313a3575363a33303630373775313a3475363a33303630373875313a3875363a33303630373975323a373875363a33303630383075333a37393775363a33303630383175333a33313575363a34303030303075373a3132303738343075363a35303030303075343a3635363875363a36303031303175313a3275363a36303031303275313a33656475313a3075313a3175313a3175333a34343775313a3275333a32333475313a3375343a3438393375313a3475333a35323975313a3575343a3231303875313a3675333a343530656931656931656939656937656c32303a25ff1be7d26b566a17a406ae8825de3a52034b1132303a68f8b334d7429661c95cb2283628c14da722be7d32303a74573255a354a272c5650b58645427a00ce7e1f132303af69af3454d83ea6f512a8398aac66e2c17ec07ff6532303aae75ca68c5bb8583c379348de5e562933d2b4cee65"))); + var worldInformation = new WorldInformation(Dictionary.Empty); + var questList = new QuestList(new List((Integer)0, List.Empty, List.Empty)); + var avatarState = new AvatarState( + agentAddress, avatarAddress, 0, questList, worldInformation, default, "name"); avatarState.inventory = new Inventory(); - avatarState.worldInformation = new WorldInformation((Dictionary)new Codec().Decode(Convert.FromHexString( - "6475313a316475323a496475313a3175343a4e616d6575393a59676764726173696c7531303a5374616765426567696e75313a317532323a5374616765436c6561726564426c6f636b496e64657875363a3437323632387531343a5374616765436c6561726564496475323a353075383a5374616765456e6475323a35307531383a556e6c6f636b6564426c6f636b496e64657875363a3434343436366575353a31303030316475323a496475353a313030303175343a4e616d657531313a4d696d69736272756e6e727531303a5374616765426567696e75383a31303030303030317532323a5374616765436c6561726564426c6f636b496e64657875323a2d317531343a5374616765436c6561726564496475323a2d3175383a5374616765456e6475383a31303030303032307531383a556e6c6f636b6564426c6f636b496e64657875363a3438373734336575313a326475323a496475313a3275343a4e616d6575373a416c666865696d7531303a5374616765426567696e75323a35317532323a5374616765436c6561726564426c6f636b496e64657875363a3438373734337531343a5374616765436c6561726564496475333a31303075383a5374616765456e6475333a3130307531383a556e6c6f636b6564426c6f636b496e64657875363a3437323632386575313a336475323a496475313a3375343a4e616d657531323a5376617274616c666865696d7531303a5374616765426567696e75333a3130317532323a5374616765436c6561726564426c6f636b496e64657875363a3530343031387531343a5374616765436c6561726564496475333a31353075383a5374616765456e6475333a3135307531383a556e6c6f636b6564426c6f636b496e64657875363a3438373734336575313a346475323a496475313a3475343a4e616d6575363a4173676172647531303a5374616765426567696e75333a3135317532323a5374616765436c6561726564426c6f636b496e64657875373a343839313637337531343a5374616765436c6561726564496475333a32303075383a5374616765456e6475333a3230307531383a556e6c6f636b6564426c6f636b496e64657875363a3530343031386575313a356475323a496475313a3575343a4e616d657531303a4d757370656c6865696d7531303a5374616765426567696e75333a3230317532323a5374616765436c6561726564426c6f636b496e64657875373a373132353232397531343a5374616765436c6561726564496475333a32353075383a5374616765456e6475333a3235307531383a556e6c6f636b6564426c6f636b496e64657875373a343839313637336575313a366475323a496475313a3675343a4e616d6575393a4a6f74756e6865696d7531303a5374616765426567696e75333a3235317532323a5374616765436c6561726564426c6f636b496e64657875383a31313237353837337531343a5374616765436c6561726564496475333a33303075383a5374616765456e6475333a3330307531383a556e6c6f636b6564426c6f636b496e64657875373a373132353232396575313a376475323a496475313a3775343a4e616d6575383a4e69666c6865696d7531303a5374616765426567696e75333a3330317532323a5374616765436c6561726564426c6f636b496e64657875383a31313439323332367531343a5374616765436c6561726564496475333a33333275383a5374616765456e6475333a3335307531383a556e6c6f636b6564426c6f636b496e64657875383a31313237353837336565"))); - avatarState.questList = new QuestList((List)new Codec().Decode(Convert.FromHexString( - "6c6935656c6c7531303a776f726c6451756573747469316569306569313030303031656475363a34303030303075323a32306574656c7531303a776f726c6451756573747469326569306569313030303032656475363a34303030303075323a32306574656c7531303a776f726c6451756573747469336569306569313030303033656475363a33303330303075313a3175363a34303030303075333a3430306574656c7531303a776f726c6451756573747469346569306569313030303034656475363a33303630343075313a376574656c7531303a776f726c6451756573747469356569306569313030303035656475363a34303030303075323a32306574656c7531303a776f726c6451756573747469366569306569313030303036656475363a33303331303075313a316574656c7531303a776f726c6451756573747469376569306569313030303037656475363a34303030303075323a32306574656c7531303a776f726c6451756573747469386569306569313030303038656475363a34303030303075323a32306574656c7531303a776f726c6451756573747469396569306569313030303039656475363a33303332303075313a316574656c7531303a776f726c645175657374746931306569306569313030303130656475363a34303030303075323a32306574656c7531303a776f726c645175657374746931316569306569313030303131656475363a33303630323375313a3175363a33303630343175313a326574656c7531303a776f726c645175657374746931326569306569313030303132656475363a34303030303075323a32306574656c7531303a776f726c645175657374746931336569306569313030303133656475363a33303630323575313a3375363a33303630343175313a326574656c7531303a776f726c645175657374746931346569306569313030303134656475363a34303030303075323a32306574656c7531303a776f726c645175657374746931356569306569313030303135656475363a33303333303075313a316574656c7531303a776f726c645175657374746931366569306569313030303136656475363a34303030303075323a32306574656c7531303a776f726c645175657374746931376569306569313030303137656475363a34303030303075323a32306574656c7531303a776f726c645175657374746931386569306569313030303138656475363a34303030303075323a32306574656c7531303a776f726c645175657374746931396569306569313030303139656475363a34303030303075323a323075363a35303030303075313a316574656c7531303a776f726c645175657374746932306569306569313030303230656475363a33303334303075313a316574656c7531303a776f726c645175657374746932316569306569313030303231656475363a33303630303175313a3175363a33303630343475313a316574656c7531303a776f726c645175657374746932326569306569313030303232656475363a33303630303075313a3175363a33303630303275313a316574656c7531303a776f726c645175657374746932336569306569313030303233656475363a34303030303075323a32306574656c7531303a776f726c645175657374746932346569306569313030303234656475363a33303330303175313a326574656c7531303a776f726c645175657374746932356569306569313030303235656475363a33303630303075313a3175363a33303630303175313a316574656c7531303a776f726c645175657374746932366569306569313030303236656475363a34303030303075323a32306574656c7531303a776f726c645175657374746932376569306569313030303237656475363a34303030303075323a32306574656c7531303a776f726c645175657374746932386569306569313030303238656475363a34303030303075323a32306574656c7531303a776f726c645175657374746932396569306569313030303239656475363a34303030303075323a32306574656c7531303a776f726c645175657374746933306569306569313030303330656475363a34303030303075323a32306574656c7531303a776f726c645175657374746933316569306569313030303331656475363a34303030303075323a32306574656c7531303a776f726c645175657374746933326569306569313030303332656475363a34303030303075323a32306574656c7531303a776f726c645175657374746933336569306569313030303333656475363a34303030303075323a32306574656c7531303a776f726c645175657374746933346569306569313030303334656475363a34303030303075323a32306574656c7531303a776f726c645175657374746933356569306569313030303335656475363a34303030303075323a32306574656c7531303a776f726c645175657374746933366569306569313030303336656475363a34303030303075323a32306574656c7531303a776f726c645175657374746933376569306569313030303337656475363a34303030303075323a32306574656c7531303a776f726c645175657374746933386569306569313030303338656475363a34303030303075323a32306574656c7531303a776f726c645175657374746933396569306569313030303339656475363a34303030303075323a32306574656c7531303a776f726c645175657374746934306569306569313030303430656475363a34303030303075323a323075363a35303030303075313a316574656c7531303a776f726c645175657374746934316569306569313030303431656475363a34303030303075323a32306574656c7531303a776f726c645175657374746934326569306569313030303432656475363a34303030303075323a32306574656c7531303a776f726c645175657374746934336569306569313030303433656475363a34303030303075323a32306574656c7531303a776f726c645175657374746934346569306569313030303434656475363a34303030303075323a32306574656c7531303a776f726c645175657374746934356569306569313030303435656475363a34303030303075323a32306574656c7531303a776f726c645175657374746934366569306569313030303436656475363a34303030303075323a32306574656c7531303a776f726c645175657374746934376569306569313030303437656475363a34303030303075323a32306574656c7531303a776f726c645175657374746934386569306569313030303438656475363a34303030303075323a32306574656c7531303a776f726c645175657374746934396569306569313030303439656475363a34303030303075323a32306574656c7531303a776f726c645175657374746935306569306569313030303530656475363a33303430303275313a316574656c7531303a776f726c645175657374746935316569306569313030303531656475363a34303030303075323a32306574656c7531303a776f726c645175657374746935326569306569313030303532656475363a34303030303075323a32306574656c7531303a776f726c645175657374746935336569306569313030303533656475363a34303030303075323a32306574656c7531303a776f726c645175657374746935346569306569313030303534656475363a34303030303075323a32306574656c7531303a776f726c645175657374746935356569306569313030303535656475363a34303030303075323a32306574656c7531303a776f726c645175657374746935366569306569313030303536656475363a34303030303075323a32306574656c7531303a776f726c645175657374746935376569306569313030303537656475363a34303030303075323a32306574656c7531303a776f726c645175657374746935386569306569313030303538656475363a34303030303075323a32306574656c7531303a776f726c645175657374746935396569306569313030303539656475363a34303030303075323a32306574656c7531303a776f726c645175657374746936306569306569313030303630656475363a34303030303075323a323075363a35303030303075313a316574656c7531303a776f726c645175657374746936316569306569313030303631656475363a34303030303075323a32306574656c7531303a776f726c645175657374746936326569306569313030303632656475363a34303030303075323a32306574656c7531303a776f726c645175657374746936336569306569313030303633656475363a34303030303075323a32306574656c7531303a776f726c645175657374746936346569306569313030303634656475363a34303030303075323a32306574656c7531303a776f726c645175657374746936356569306569313030303635656475363a34303030303075323a32306574656c7531303a776f726c645175657374746936366569306569313030303636656475363a34303030303075323a32306574656c7531303a776f726c645175657374746936376569306569313030303637656475363a34303030303075323a32306574656c7531303a776f726c645175657374746936386569306569313030303638656475363a34303030303075323a32306574656c7531303a776f726c645175657374746936396569306569313030303639656475363a34303030303075323a32306574656c7531303a776f726c645175657374746937306569306569313030303730656475363a34303030303075323a32306574656c7531303a776f726c645175657374746937316569306569313030303731656475363a34303030303075323a32306574656c7531303a776f726c645175657374746937326569306569313030303732656475363a34303030303075323a32306574656c7531303a776f726c645175657374746937336569306569313030303733656475363a34303030303075323a32306574656c7531303a776f726c645175657374746937346569306569313030303734656475363a34303030303075323a32306574656c7531303a776f726c645175657374746937356569306569313030303735656475363a34303030303075323a32306574656c7531303a776f726c645175657374746937366569306569313030303736656475363a34303030303075323a32306574656c7531303a776f726c645175657374746937376569306569313030303737656475363a34303030303075323a32306574656c7531303a776f726c645175657374746937386569306569313030303738656475363a34303030303075323a32306574656c7531303a776f726c645175657374746937396569306569313030303739656475363a34303030303075323a32306574656c7531303a776f726c645175657374746938306569306569313030303830656475363a34303030303075323a323075363a35303030303075313a316574656c7531303a776f726c645175657374746938316569306569313030303831656475363a34303030303075323a32306574656c7531303a776f726c645175657374746938326569306569313030303832656475363a34303030303075323a32306574656c7531303a776f726c645175657374746938336569306569313030303833656475363a34303030303075323a32306574656c7531303a776f726c645175657374746938346569306569313030303834656475363a34303030303075323a32306574656c7531303a776f726c645175657374746938356569306569313030303835656475363a34303030303075323a32306574656c7531303a776f726c645175657374746938366569306569313030303836656475363a34303030303075323a32306574656c7531303a776f726c645175657374746938376569306569313030303837656475363a34303030303075323a32306574656c7531303a776f726c645175657374746938386569306569313030303838656475363a34303030303075323a32306574656c7531303a776f726c645175657374746938396569306569313030303839656475363a34303030303075323a32306574656c7531303a776f726c645175657374746939306569306569313030303930656475363a34303030303075323a32306574656c7531303a776f726c645175657374746939316569306569313030303931656475363a34303030303075323a32306574656c7531303a776f726c645175657374746939326569306569313030303932656475363a34303030303075323a32306574656c7531303a776f726c645175657374746939336569306569313030303933656475363a34303030303075323a32306574656c7531303a776f726c645175657374746939346569306569313030303934656475363a34303030303075323a32306574656c7531303a776f726c645175657374746939356569306569313030303935656475363a34303030303075323a32306574656c7531303a776f726c645175657374746939366569306569313030303936656475363a34303030303075323a32306574656c7531303a776f726c645175657374746939376569306569313030303937656475363a34303030303075323a32306574656c7531303a776f726c645175657374746939386569306569313030303938656475363a34303030303075323a32306574656c7531303a776f726c645175657374746939396569306569313030303939656475363a34303030303075323a323075363a35303030303075313a316574656c7531303a776f726c64517565737474693130306569306569313030313030656475363a33303430303175313a316574656c7531303a776f726c64517565737474693130316569306569313030313031656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693130326569306569313030313032656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693130336569306569313030313033656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693130346569306569313030313034656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693130356569306569313030313035656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693130366569306569313030313036656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693130376569306569313030313037656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693130386569306569313030313038656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693130396569306569313030313039656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693131306569306569313030313130656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693131316569306569313030313131656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693131326569306569313030313132656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693131336569306569313030313133656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693131346569306569313030313134656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693131356569306569313030313135656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693131366569306569313030313136656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693131376569306569313030313137656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693131386569306569313030313138656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693131396569306569313030313139656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693132306569306569313030313230656475363a34303030303075323a323075363a35303030303075313a316574656c7531303a776f726c64517565737474693132316569306569313030313231656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693132326569306569313030313232656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693132336569306569313030313233656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693132346569306569313030313234656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693132356569306569313030313235656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693132366569306569313030313236656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693132376569306569313030313237656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693132386569306569313030313238656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693132396569306569313030313239656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693133306569306569313030313330656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693133316569306569313030313331656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693133326569306569313030313332656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693133336569306569313030313333656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693133346569306569313030313334656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693133356569306569313030313335656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693133366569306569313030313336656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693133376569306569313030313337656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693133386569306569313030313338656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693133396569306569313030313339656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693134306569306569313030313430656475363a34303030303075323a323075363a35303030303075313a316574656c7531303a776f726c64517565737474693134316569306569313030313431656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693134326569306569313030313432656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693134336569306569313030313433656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693134346569306569313030313434656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693134356569306569313030313435656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693134366569306569313030313436656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693134376569306569313030313437656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693134386569306569313030313438656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693134396569306569313030313439656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693135306569306569313030313530656475363a33303430303075313a316574656c7531303a776f726c64517565737474693135316569306569313030313531656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693135326569306569313030313532656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693135336569306569313030313533656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693135346569306569313030313534656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693135356569306569313030313535656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693135366569306569313030313536656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693135376569306569313030313537656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693135386569306569313030313538656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693135396569306569313030313539656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693136306569306569313030313630656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693136316569306569313030313631656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693136326569306569313030313632656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693136336569306569313030313633656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693136346569306569313030313634656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693136356569306569313030313635656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693136366569306569313030313636656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693136376569306569313030313637656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693136386569306569313030313638656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693136396569306569313030313639656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693137306569306569313030313730656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693137316569306569313030313731656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693137326569306569313030313732656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693137336569306569313030313733656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693137346569306569313030313734656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693137356569306569313030313735656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693137366569306569313030313736656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693137376569306569313030313737656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693137386569306569313030313738656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693137396569306569313030313739656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693138306569306569313030313830656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693138316569306569313030313831656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693138326569306569313030313832656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693138336569306569313030313833656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693138346569306569313030313834656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693138356569306569313030313835656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693138366569306569313030313836656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693138376569306569313030313837656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693138386569306569313030313838656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693138396569306569313030313839656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693139306569306569313030313930656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693139316569306569313030313931656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693139326569306569313030313932656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693139336569306569313030313933656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693139346569306569313030313934656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693139356569306569313030313935656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693139366569306569313030313936656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693139376569306569313030313937656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693139386569306569313030313938656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693139396569306569313030313939656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693230306569306569313030323030656475363a33303430303375313a316574656c7531303a776f726c64517565737474693230316569306569313030323031656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693230326569306569313030323032656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693230336569306569313030323033656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693230346569306569313030323034656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693230356569306569313030323035656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693230366569306569313030323036656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693230376569306569313030323037656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693230386569306569313030323038656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693230396569306569313030323039656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693231306569306569313030323130656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693231316569306569313030323131656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693231326569306569313030323132656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693231336569306569313030323133656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693231346569306569313030323134656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693231356569306569313030323135656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693231366569306569313030323136656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693231376569306569313030323137656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693231386569306569313030323138656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693231396569306569313030323139656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693232306569306569313030323230656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693232316569306569313030323231656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693232326569306569313030323232656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693232336569306569313030323233656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693232346569306569313030323234656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693232356569306569313030323235656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693232366569306569313030323236656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693232376569306569313030323237656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693232386569306569313030323238656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693232396569306569313030323239656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693233306569306569313030323330656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693233316569306569313030323331656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693233326569306569313030323332656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693233336569306569313030323333656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693233346569306569313030323334656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693233356569306569313030323335656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693233366569306569313030323336656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693233376569306569313030323337656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693233386569306569313030323338656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693233396569306569313030323339656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693234306569306569313030323430656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693234316569306569313030323431656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693234326569306569313030323432656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693234336569306569313030323433656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693234346569306569313030323434656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693234356569306569313030323435656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693234366569306569313030323436656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693234376569306569313030323437656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693234386569306569313030323438656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693234396569306569313030323439656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693235306569306569313030323530656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693235316569306569313030323531656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693235326569306569313030323532656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693235336569306569313030323533656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693235346569306569313030323534656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693235356569306569313030323535656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693235366569306569313030323536656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693235376569306569313030323537656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693235386569306569313030323538656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693235396569306569313030323539656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693236306569306569313030323630656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693236316569306569313030323631656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693236326569306569313030323632656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693236336569306569313030323633656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693236346569306569313030323634656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693236356569306569313030323635656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693236366569306569313030323636656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693236376569306569313030323637656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693236386569306569313030323638656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693236396569306569313030323639656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693237306569306569313030323730656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693237316569306569313030323731656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693237326569306569313030323732656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693237336569306569313030323733656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693237346569306569313030323734656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693237356569306569313030323735656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693237366569306569313030323736656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693237376569306569313030323737656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693237386569306569313030323738656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693237396569306569313030323739656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693238306569306569313030323830656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693238316569306569313030323831656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693238326569306569313030323832656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693238336569306569313030323833656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693238346569306569313030323834656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693238356569306569313030323835656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693238366569306569313030323836656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693238376569306569313030323837656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693238386569306569313030323838656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693238396569306569313030323839656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693239306569306569313030323930656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693239316569306569313030323931656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693239326569306569313030323932656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693239336569306569313030323933656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693239346569306569313030323934656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693239356569306569313030323935656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693239366569306569313030323936656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693239376569306569313030323937656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693239386569306569313030323938656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693239396569306569313030323939656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693330306569306569313030333030656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693330316569306569313030333031656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693330326569306569313030333032656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693330336569306569313030333033656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693330346569306569313030333034656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693330356569306569313030333035656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693330366569306569313030333036656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693330376569306569313030333037656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693330386569306569313030333038656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693330396569306569313030333039656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693331306569306569313030333130656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693331316569306569313030333131656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693331326569306569313030333132656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693331336569306569313030333133656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693331346569306569313030333134656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693331356569306569313030333135656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693331366569306569313030333136656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693331376569306569313030333137656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693331386569306569313030333138656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693331396569306569313030333139656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693332306569306569313030333230656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693332316569306569313030333231656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693332326569306569313030333232656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693332336569306569313030333233656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693332346569306569313030333234656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693332356569306569313030333235656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693332366569306569313030333236656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693332376569306569313030333237656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693332386569306569313030333238656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693332396569306569313030333239656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693333306569306569313030333330656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693333316569306569313030333331656475363a34303030303075323a32306574656c7531303a776f726c64517565737474693333326569306569313030333332656475363a34303030303075323a32306574656c7531303a776f726c64517565737466693333336569306569313030333333656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693333346569306569313030333334656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693333356569306569313030333335656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693333366569306569313030333336656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693333376569306569313030333337656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693333386569306569313030333338656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693333396569306569313030333339656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693334306569306569313030333430656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693334316569306569313030333431656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693334326569306569313030333432656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693334336569306569313030333433656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693334346569306569313030333434656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693334356569306569313030333435656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693334366569306569313030333436656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693334376569306569313030333437656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693334386569306569313030333438656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693334396569306569313030333439656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693335306569306569313030333530656475363a34303030303075323a32306566656c7531303a776f726c64517565737466693335316569306569313030333531656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693335326569306569313030333532656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693335336569306569313030333533656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693335346569306569313030333534656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693335356569306569313030333535656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693335366569306569313030333536656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693335376569306569313030333537656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693335386569306569313030333538656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693335396569306569313030333539656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693336306569306569313030333630656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693336316569306569313030333631656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693336326569306569313030333632656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693336336569306569313030333633656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693336346569306569313030333634656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693336356569306569313030333635656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693336366569306569313030333636656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693336376569306569313030333637656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693336386569306569313030333638656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693336396569306569313030333639656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693337306569306569313030333730656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693337316569306569313030333731656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693337326569306569313030333732656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693337336569306569313030333733656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693337346569306569313030333734656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693337356569306569313030333735656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693337366569306569313030333736656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693337376569306569313030333737656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693337386569306569313030333738656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693337396569306569313030333739656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693338306569306569313030333830656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693338316569306569313030333831656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693338326569306569313030333832656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693338336569306569313030333833656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693338346569306569313030333834656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693338356569306569313030333835656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693338366569306569313030333836656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693338376569306569313030333837656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693338386569306569313030333838656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693338396569306569313030333839656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693339306569306569313030333930656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693339316569306569313030333931656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693339326569306569313030333932656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693339336569306569313030333933656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693339346569306569313030333934656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693339356569306569313030333935656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693339366569306569313030333936656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693339376569306569313030333937656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693339386569306569313030333938656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693339396569306569313030333939656475363a34303030303075333a3530306566656c7531303a776f726c64517565737466693430306569306569313030343030656475363a34303030303075333a3530306566656c7531323a636f6c6c65637451756573747469316569316569323030303031656475363a33303230303175313a3175363a33303230303275313a3165746932303130303065656c7531323a636f6c6c65637451756573747469316569316569323030303032656475363a33303230303475313a3275363a33303230303675313a3165746932303130303165656c7531323a636f6c6c65637451756573747469316569316569323030303033656475363a33303230303375313a3165746932303130303265656c7531323a636f6c6c65637451756573747469316569316569323030303034656475363a33303230303375313a3265746932303130303365656c7531323a636f6c6c65637451756573746669316569306569323030303035656475363a33303230303375313a3275363a33303230303575313a3265666932303130303465656c7531323a636f6c6c65637451756573747469316569316569323030303036656475363a33303230303375313a3165746932303130303565656c7531323a636f6c6c65637451756573747469316569316569323030303037656475363a33303230303375313a3265746932303130303665656c7531323a636f6c6c65637451756573746669316569306569323030303038656475363a33303230303075313a3275363a33303230303375313a3265666932303130303765656c7531323a636f6c6c65637451756573747469316569316569323030303039656475363a33303230303875313a3165746932303130303865656c7531323a636f6c6c65637451756573747469316569316569323030303130656475363a33303230303075313a3275363a33303230303875313a3265746932303130303965656c7531323a636f6c6c65637451756573747469316569316569323030303131656475363a33303230303975313a3165746932303130313065656c7531323a636f6c6c65637451756573747469316569316569323030303132656475363a33303230303875313a3165746932303130313165656c7531323a636f6c6c65637451756573747469316569316569323030303133656475363a33303230303575313a3275363a33303230303875313a3265746932303130313265656c7531323a636f6c6c65637451756573747469316569316569323030303134656475363a33303230303975313a3165746932303130313365656c7531363a636f6d62696e6174696f6e51756573747469316569316569333030303031656475363a33303230303175313a316574693265693665656c7531363a636f6d62696e6174696f6e51756573747469336569336569333030303032656475363a33303230303175313a316574693265693665656c7531363a636f6d62696e6174696f6e51756573747469356569356569333030303033656475363a33303230303175313a316574693265693665656c7531363a636f6d62696e6174696f6e517565737474693130656931306569333030303034656475363a33303230303175313a326574693265693665656c7531363a636f6d62696e6174696f6e517565737474693530656935306569333030303035656475363a33303230303175313a326574693265693665656c7531363a636f6d62696e6174696f6e51756573747469316569316569333030303036656475363a33303230303375313a316574693265693765656c7531363a636f6d62696e6174696f6e51756573747469336569336569333030303037656475363a33303230303375313a316574693265693765656c7531363a636f6d62696e6174696f6e51756573747469356569356569333030303038656475363a33303230303375313a316574693265693765656c7531363a636f6d62696e6174696f6e517565737474693130656931306569333030303039656475363a33303230303375313a326574693265693765656c7531363a636f6d62696e6174696f6e517565737474693530656935306569333030303130656475363a33303230303375313a326574693265693765656c7531363a636f6d62696e6174696f6e51756573747469316569316569333030303131656475363a33303230303575313a316574693265693865656c7531363a636f6d62696e6174696f6e51756573747469336569336569333030303132656475363a33303230303575313a316574693265693865656c7531363a636f6d62696e6174696f6e51756573747469356569356569333030303133656475363a33303230303575313a316574693265693865656c7531363a636f6d62696e6174696f6e517565737474693130656931306569333030303134656475363a33303230303575313a326574693265693865656c7531363a636f6d62696e6174696f6e517565737474693530656935306569333030303135656475363a33303230303575313a326574693265693865656c7531363a636f6d62696e6174696f6e51756573747469316569316569333030303136656475363a33303230303075313a316574693265693965656c7531363a636f6d62696e6174696f6e51756573747469336569336569333030303137656475363a33303230303075313a316574693265693965656c7531363a636f6d62696e6174696f6e51756573747469356569356569333030303138656475363a33303230303075313a316574693265693965656c7531363a636f6d62696e6174696f6e517565737474693130656931306569333030303139656475363a33303230303075313a326574693265693965656c7531363a636f6d62696e6174696f6e517565737474693530656935306569333030303230656475363a33303230303075313a326574693265693965656c7531363a636f6d62696e6174696f6e51756573747469316569316569333030303231656475363a33303230303175313a31657469326569313065656c7531363a636f6d62696e6174696f6e51756573747469336569336569333030303232656475363a33303230303175313a31657469326569313065656c7531363a636f6d62696e6174696f6e51756573747469356569356569333030303233656475363a33303230303175313a31657469326569313065656c7531363a636f6d62696e6174696f6e517565737474693130656931306569333030303234656475363a33303230303175313a32657469326569313065656c7531363a636f6d62696e6174696f6e517565737474693530656935306569333030303235656475363a33303230303175313a32657469326569313065656c7531363a636f6d62696e6174696f6e51756573747469316569316569333030303236656475363a33303230303375313a316574693065693065656c7531363a636f6d62696e6174696f6e517565737474693130656931306569333030303237656475363a33303230303375313a316574693065693065656c7531363a636f6d62696e6174696f6e517565737474693230656932306569333030303238656475363a33303230303375313a316574693065693065656c7531363a636f6d62696e6174696f6e517565737474693330656933306569333030303239656475363a33303230303375313a326574693065693065656c7531363a636f6d62696e6174696f6e517565737474693530656935306569333030303330656475363a33303230303375313a326574693065693065656c7531303a747261646551756573747469316569316569343030303031656475363a33303230303075313a326574693165656c7531303a7472616465517565737474693130656931306569343030303032656475363a33303230303075313a326574693165656c7531303a7472616465517565737474693530656935306569343030303033656475363a33303230303875313a326574693165656c7531303a74726164655175657374746931303065693130306569343030303034656475363a33303230303975313a326574693165656c7531303a747261646551756573747469316569316569343030303035656475363a33303230303575313a326574693065656c7531303a7472616465517565737474693130656931306569343030303036656475363a33303230303575313a326574693065656c7531303a7472616465517565737474693530656935306569343030303037656475363a33303230303875313a326574693065656c7531303a74726164655175657374746931303065693130306569343030303038656475363a33303230303975313a326574693065656c7531323a6d6f6e7374657251756573747469316569316569353030303031656475363a33303230303475313a3265746932303130303565656c7531323a6d6f6e7374657251756573747469316569316569353030303032656475363a33303230303475313a3275363a33303230303675313a3165746932303230303765656c7531323a6d6f6e7374657251756573747469316569316569353030303033656475363a33303230303875313a3265746932303330303765656c7531323a6d6f6e7374657251756573747469316569316569353030303034656475363a33303230303975313a3265746932303530303765656c7532303a6974656d456e68616e63656d656e7451756573747469336569316569363030303031656475363a33303230303275313a326574693165693165656c7532303a6974656d456e68616e63656d656e7451756573746669336569356569363030303032656475363a33303230303475313a326566693165693665656c7532303a6974656d456e68616e63656d656e7451756573747469366569316569363030303033656475363a33303230303475313a326574693265693165656c7532303a6974656d456e68616e63656d656e7451756573746669366569316569363030303034656475363a33303230303475313a3275363a33303230303675313a316566693265693665656c7532303a6974656d456e68616e63656d656e7451756573746669396569306569363030303035656475363a33303230303475313a3275363a33303230303675313a316566693365693165656c7532303a6974656d456e68616e63656d656e7451756573746669396569306569363030303036656475363a33303230303875313a326566693365693665656c7532303a6974656d456e68616e63656d656e7451756573746669396569306569363030303037656475363a33303230303975313a326566693465693165656c7532303a6974656d456e68616e63656d656e7451756573746669396569306569363030303038656475363a33303230303975313a326566693465693665656c7532303a6974656d456e68616e63656d656e7451756573746669396569306569363030303039656475363a33303230303975313a326566693565693165656c7532303a6974656d456e68616e63656d656e7451756573746669396569306569363030303130656475363a33303230303975313a326566693565693665656c7531323a67656e6572616c51756573747469316569316569373030303031656475363a33303230303275313a316574693165656c7531323a67656e6572616c517565737474693130656931306569373030303032656475363a33303230303275313a326574693165656c7531323a67656e6572616c517565737474693530656935306569373030303033656475363a33303230303275313a326574693165656c7531323a67656e6572616c517565737474693130656931306569373130303030656475363a33303230303275313a316574693265656c7531323a67656e6572616c517565737474693230656932306569373130303031656475363a33303230303275313a316574693265656c7531323a67656e6572616c517565737474693330656933306569373130303032656475363a33303230303375313a3275363a33303230303575313a326574693265656c7531323a67656e6572616c517565737474693530656935306569373130303033656475363a33303230303375313a3275363a33303230303575313a326574693265656c7531323a67656e6572616c517565737474693730656937306569373130303034656475363a33303230303475313a326574693265656c7531323a67656e6572616c517565737474693930656939306569373130303035656475363a33303230303475313a3275363a33303230303675313a316574693265656c7531323a67656e6572616c5175657374746931303065693130306569373130303036656475363a33303230303475313a3275363a33303230303675313a316574693265656c7531323a67656e6572616c5175657374746931323065693132306569373130303037656475363a33303230303475313a3275363a33303230303675313a316574693265656c7531323a67656e6572616c5175657374746931343065693134306569373130303038656475363a33303230303475313a3275363a33303230303675313a316574693265656c7531323a67656e6572616c5175657374746931363065693136306569373130303039656475363a33303230303475313a3275363a33303230303675313a316574693265656c7531323a67656e6572616c5175657374746931383065693138306569373130303130656475363a33303230303475313a3275363a33303230303675313a316574693265656c7531323a67656e6572616c5175657374746932303065693230306569373130303131656475363a33303230303475313a3275363a33303230303675313a316574693265656c7531323a67656e6572616c51756573747469316569316569373230303030656475363a33303230303275313a316574693365656c7531323a67656e6572616c517565737474693130656931306569373230303031656475363a33303230303275313a316574693365656c7531323a67656e6572616c517565737474693530656935306569373230303032656475363a33303230303275313a326574693365656c7531323a67656e6572616c5175657374746931303065693130306569373230303033656475363a33303230303275313a326574693365656c7531323a67656e6572616c517565737474693130656931316569373930303030656475363a33303230303375313a316574693465656c7531323a67656e6572616c517565737474693230656932306569373930303031656475363a33303230303375313a316574693465656c7531323a67656e6572616c517565737474693330656933316569373930303032656475363a33303230303375313a326574693465656c7531323a67656e6572616c517565737474693430656934306569373930303033656475363a33303230303375313a326574693465656c7531323a67656e6572616c517565737474693530656935306569373930303034656475363a33303230303375313a326574693465656c7531343a6974656d477261646551756573747469366569366569383030303030656475363a33303230303375313a3265746931656c69313031313030303065693130313131303030656931303231303030306569313032313130303065693130333130303030656931303431303030306565656c7531343a6974656d477261646551756573747469366569366569383030303031656475363a33303230303375313a3265746932656c69313031323030303065693130313231303030656931303132323030306569313032323030303065693130323231303030656931303332303030306565656c7531343a6974656d477261646551756573747469366569366569383030303032656475363a33303230303075313a3275363a33303230303375313a3265746933656c69313031333030303065693130313331303030656931303133333030306569313032333030303065693130323331303030656931303233313030316565656c7531343a6974656d477261646551756573747469366569366569383030303033656475363a33303230303875313a3265746934656c693230313030396569323031303132656931303334303030306569313033343130303065693130333434303030656931303434343030306565656c7531343a6974656d477261646551756573747469366569366569383030303034656475363a33303230303975313a3265746935656c693230313031306569323031303133656932303130313665693230313031396569323031303234656931303435323030316565656c7532303a6974656d54797065436f6c6c65637451756573747469356569356569393030303030656475363a33303230303375313a3165746c693330323030316569333033303030656933303331303065693330363034306569343030303030656575383a4d6174657269616c656c7532303a6974656d54797065436f6c6c656374517565737474693130656931306569393030303031656475363a33303230303075313a3275363a33303230303375313a3265746c69333032303031656933303230303265693330323030336569333032303035656933303330303065693330333130306569333033323030656933303630323365693330363034306569343030303030656575383a4d6174657269616c656c7532303a6974656d54797065436f6c6c656374517565737474693230656932306569393030303032656475363a33303230303075313a3275363a33303230303375313a3265746c693330323030306569333032303031656933303230303265693330323030336569333032303035656933303330303065693330333130306569333033323030656933303333303065693330333430306569333036303030656933303630303165693330363032336569333036303234656933303630323565693330363034306569333036303431656933303630343465693430303030306569353030303030656575383a4d6174657269616c656c7532303a6974656d54797065436f6c6c656374517565737474693330656933306569393030303033656475363a33303230303075313a3275363a33303230303375313a3265746c6933303230303065693330323030316569333032303032656933303230303365693330323030346569333032303035656933303230303665693330333030306569333033303031656933303331303065693330333130316569333033323030656933303332303165693330333330306569333033333031656933303334303065693330343030326569333036303030656933303630303165693330363030326569333036303039656933303630323365693330363032346569333036303235656933303630343065693330363034316569333036303433656933303630343465693430303030306569353030303030656575383a4d6174657269616c656c75393a476f6c6451756573747469313030656931353030656931303030303030656475363a33303230303375313a326574693065656c75393a476f6c645175657374746931303030656931353030656931303030303031656475363a33303230303475313a3275363a33303230303675313a316574693065656c75393a476f6c6451756573747469313030303065693138303732656931303030303033656475363a33303230303875313a326574693065656c75393a476f6c64517565737474693130306569313030656931303030303034656475363a33303230303075313a3275363a33303230303375313a326574693165656c75393a476f6c645175657374746931303030656931393330656931303030303035656475363a33303230303475313a3275363a33303230303675313a316574693165656c75393a476f6c6451756573747469313030303065693132353830656931303030303036656475363a33303230303875313a326574693165656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303031656475363a33303330303075313a31657475313a3175313a33656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303032656475363a33303330303075313a31657475313a3275323a3131656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303033656475363a33303330303075313a31657475313a3375323a3231656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303034656475363a33303330303075313a31657475313a3475323a3531656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303035656475363a33303330303075313a31657475313a3575323a3939656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303036656475363a33303330303175313a32657475313a3675323a3234656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303037656475363a33303330303175313a32657475313a3775323a3239656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303038656475363a33303330303175313a32657475313a3875323a3337656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303039656475363a33303330303175313a32657475313a3975333a313134656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303130656475363a33303330303175313a32657475323a313075333a313734656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303131656475363a33303330303275313a33657475323a313175323a3633656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303132656475363a33303330303275313a33657475323a313275323a3636656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303133656475363a33303330303275313a33657475323a313375323a3834656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303134656475363a33303330303275313a33657475323a313475333a313934656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303135656475363a33303330303275313a33657475323a313575333a323631656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303136656475363a33303330303275313a33657475323a313675333a313330656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303137656475363a33303330303275313a33657475323a313775333a313334656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303138656475363a33303330303275313a33657475323a313875333a313538656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303139656475363a33303330303275313a33657475323a313975333a323831656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303230656475363a33303330303275313a33657475323a323075333a333534656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303231656475363a33303330303375313a3465746932316575333a323136656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303232656475363a33303330303375313a34657475323a323275333a323231656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303233656475363a33303330303375313a3465666932336575333a323431656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303234656475363a33303330303375313a3465746932346575333a333837656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303235656475363a33303330303375313a3465666932356575333a353136656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303236656475363a33303330303375313a3465666932366575333a333031656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303237656475363a33303330303375313a3465746932376575333a333036656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303238656475363a33303330303375313a3465666932386575333a333330656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303239656475363a33303330303375313a3465666932396575333a353631656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303330656475363a33303330303375313a3465666933306575333a363736656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303331656475363a33303330303475313a3565666933316575333a343135656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303332656475363a33303330303475313a3565666933326575333a343232656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303333656475363a33303330303475313a3565666933336575333a343736656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303334656475363a33303330303475313a3565666933346575333a363936656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303335656475363a33303330303475313a3565666933356575333a373531656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303336656475363a33303330303475313a3565666933366575333a363036656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303337656475363a33303330303475313a3565666933376575333a363136656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303338656475363a33303330303475313a3565666933386575333a363536656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303339656475363a33303330303475313a3565666933396575333a383036656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303430656475363a33303330303475313a3565666934306575333a383330656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303431656475363a33303330303475313a3565666934316575333a383534656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303432656475363a33303331303075313a31657475323a343275313a36656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303433656475363a33303331303075313a31657475323a343375323a3133656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303434656475363a33303331303075313a31657475323a343475323a3232656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303435656475363a33303331303075313a31657475323a343575323a3539656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303436656475363a33303331303075313a31657475323a343675333a313131656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303437656475363a33303331303175313a32657475323a343775323a3333656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303438656475363a33303331303175313a32657475323a343875323a3335656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303439656475363a33303331303175313a32657475323a343975323a3435656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303530656475363a33303331303175313a32657475323a353075333a313236656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303531656475363a33303331303175313a32657475323a353175333a313832656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303532656475363a33303331303275313a33657475323a353275323a3735656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303533656475363a33303331303275313a33657475323a353375323a3738656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303534656475363a33303331303275313a33657475323a353475323a3936656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303535656475363a33303331303275313a33657475323a353575333a323032656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303536656475363a33303331303275313a33657475323a353675333a323736656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303537656475363a33303331303275313a33657475323a353775333a313436656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303538656475363a33303331303275313a33657475323a353875333a313530656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303539656475363a33303331303275313a33657475323a353975333a313636656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303630656475363a33303331303275313a33657475323a363075333a323931656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303631656475363a33303331303275313a3365666936316575333a333733656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303632656475363a33303331303375313a3465666936326575333a323331656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303633656475363a33303331303375313a3465746936336575333a323336656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303634656475363a33303331303375313a3465666936346575333a323536656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303635656475363a33303331303375313a3465746936356575333a343038656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303636656475363a33303331303375313a3465666936366575333a353433656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303637656475363a33303331303375313a3465666936376575333a333138656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303638656475363a33303331303375313a3465666936386575333a333234656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303639656475363a33303331303375313a3465746936396575333a333432656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303730656475363a33303331303375313a3465666937306575333a353838656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303731656475363a33303331303375313a3465666937316575333a363836656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303732656475363a33303331303475313a3565666937326575333a343532656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303733656475363a33303331303475313a3565666937336575333a343630656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303734656475363a33303331303475313a3565666937346575333a353030656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303735656475363a33303331303475313a3565666937356575333a373037656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303736656475363a33303331303475313a3565666937366575333a373632656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303737656475363a33303331303475313a3565666937376575333a363336656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303738656475363a33303331303475313a3565666937386575333a363436656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303739656475363a33303331303475313a3565666937396575333a363636656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303830656475363a33303331303475313a3565666938306575333a383138656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303831656475363a33303331303475313a3565666938316575333a383432656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303832656475363a33303331303475313a3565666938326575333a383636656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303833656475363a33303332303075313a31657475323a383375313a39656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303834656475363a33303332303075313a31657475323a383475323a3137656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303835656475363a33303332303075313a31657475323a383575323a3235656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303836656475363a33303332303075313a31657475323a383675323a3639656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303837656475363a33303332303075313a31657475323a383775333a313338656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303838656475363a33303332303175313a32657475323a383875323a3339656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303839656475363a33303332303175313a32657475323a383975323a3431656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303930656475363a33303332303175313a32657475323a393075323a3533656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303931656475363a33303332303175313a32657475323a393175333a313632656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303932656475363a33303332303175313a3265666939326575333a323731656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303933656475363a33303332303275313a33657475323a393375323a3837656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303934656475363a33303332303275313a33657475323a393475323a3930656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303935656475363a33303332303275313a33657475323a393575333a313038656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303936656475363a33303332303275313a33657475323a393675333a333132656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030303937656475363a33303332303275313a3365666939376575333a343834656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303938656475363a33303332303375313a34657475323a393875333a313836656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030303939656475363a33303332303375313a34657475323a393975333a313930656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313030656475363a33303332303375313a346566693130306575333a323236656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313031656475363a33303332303375313a346566693130316575333a353235656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313032656475363a33303332303375313a346566693130326575333a353730656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313033656475363a33303332303475313a356566693130336575333a333630656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313034656475363a33303332303475313a356566693130346575333a333636656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313035656475363a33303332303475313a356566693130356575333a343434656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313036656475363a33303332303475313a356574693130366575333a373138656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313037656475363a33303332303475313a356574693130376575333a373733656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313038656475363a33303333303075313a31657475333a31303875323a3135656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313039656475363a33303333303075313a31657475333a31303975323a3139656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313130656475363a33303333303075313a31657475333a31313075323a3331656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313131656475363a33303333303075313a31657475333a31313175323a3831656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313132656475363a33303333303075313a31657475333a31313275333a313534656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313133656475363a33303333303175313a32657475333a31313375323a3437656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313134656475363a33303333303175313a32657475333a31313475323a3439656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313135656475363a33303333303175313a32657475333a31313575323a3631656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313136656475363a33303333303175313a32657475333a31313675333a313738656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313137656475363a33303333303175313a326566693131376575333a323936656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313138656475363a33303333303275313a33657475333a31313875333a313032656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313139656475363a33303333303275313a33657475333a31313975333a313035656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313230656475363a33303333303275313a33657475333a31323075333a313233656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313231656475363a33303333303275313a33657475333a31323175333a333438656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313232656475363a33303333303275313a336566693132326575333a353038656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313233656475363a33303333303375313a34657475333a31323375333a323036656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313234656475363a33303333303375313a346566693132346575333a323131656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313235656475363a33303333303375313a346566693132356575333a323636656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313236656475363a33303333303375313a346566693132366575333a353532656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313237656475363a33303333303375313a346566693132376575333a353937656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313238656475363a33303333303475313a356566693132386575333a333934656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313239656475363a33303333303475313a35657475333a31323975333a343031656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313330656475363a33303333303475313a356566693133306575333a343638656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313331656475363a33303333303475313a356574693133316575333a373239656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313332656475363a33303333303475313a356574693133326575333a373834656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313333656475363a33303334303075313a31657475333a31333375323a3230656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313334656475363a33303334303075313a31657475333a31333475323a3237656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313335656475363a33303334303075313a31657475333a31333575323a3433656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313336656475363a33303334303075313a31657475333a31333675323a3933656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313337656475363a33303334303075313a31657475333a31333775333a313730656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313338656475363a33303334303175313a32657475333a31333875323a3535656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313339656475363a33303334303175313a32657475333a31333975323a3537656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313430656475363a33303334303175313a32657475333a31343075323a3732656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313431656475363a33303334303175313a32657475333a31343175333a313938656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313432656475363a33303334303175313a32657475333a31343275333a333336656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313433656475363a33303334303275313a33657475333a31343375333a313137656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313434656475363a33303334303275313a33657475333a31343475333a313230656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313435656475363a33303334303275313a33657475333a31343575333a313432656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313436656475363a33303334303275313a336566693134366575333a333830656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313437656475363a33303334303275313a33657475333a31343775333a353334656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313438656475363a33303334303375313a346574693134386575333a323436656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313439656475363a33303334303375313a346566693134396575333a323531656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313530656475363a33303334303375313a346566693135306575333a323836656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313531656475363a33303334303375313a346574693135316575333a353739656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313532656475363a33303334303375313a346574693135326575333a363236656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313533656475363a33303334303475313a356566693135336575333a343239656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313534656475363a33303334303475313a356574693135346575333a343336656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313535656475363a33303334303475313a356566693135356575333a343932656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313536656475363a33303334303475313a356566693135366575333a373430656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313537656475363a33303334303475313a356566693135376575333a373935656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313538656475363a33303332303475323a31326566693136316575333a333330656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313539656475363a33303332303475323a31326574693136326575333a333130656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313630656475363a33303332303475323a31326566693136336575333a333130656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313631656475363a33303332303475323a31326566693136346575333a333330656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313632656475363a33303332303475323a31326574693136356575333a333330656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313633656475363a33303333303475323a31336566693136366575333a333335656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313634656475363a33303333303475323a31336574693136376575333a333230656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374746931656931656931313030313635656475363a33303333303475323a31336574693136386575333a333230656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313636656475363a33303333303475323a31336566693136396575333a333335656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313637656475363a33303333303475323a31336566693137306575333a333335656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313638656475363a33303330303575323a3530656669313839656933383065656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313639656475363a33303330303575323a3530656669313930656933353565656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313730656475363a33303330303575323a3530656669313931656933353565656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313731656475363a33303330303575323a3530656669313932656933383065656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313732656475363a33303330303575323a3530656669313933656934303065656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313733656475363a33303331303575323a3530656669313934656933383565656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313734656475363a33303331303575323a3530656669313935656933363565656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313735656475363a33303331303575323a3530656669313936656933363565656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313736656475363a33303331303575323a3530656669313937656933383565656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313737656475363a33303331303575323a3530656669313938656933393865656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313738656475363a33303332303575323a3530656669313939656933383065656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313739656475363a33303332303575323a3530656669323030656933363065656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313830656475363a33303332303575323a3530656669323031656933363065656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313831656475363a33303332303575323a3530656669323032656933383065656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313832656475363a33303332303575323a3530656669323033656933393265656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313833656475363a33303333303575323a3530656669323034656933383565656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313834656475363a33303333303575323a3530656669323035656933373065656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313835656475363a33303333303575323a3530656669323036656933373065656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313836656475363a33303333303575323a3530656669323037656933383565656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313837656475363a33303333303575323a3530656669323038656933393465656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313838656475363a33303334303575323a3530656669323039656933393065656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313839656475363a33303334303575323a3530656669323130656933373565656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313930656475363a33303334303575323a3530656669323131656933373565656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313931656475363a33303334303575323a3530656669323132656933393065656c7532353a636f6d62696e6174696f6e45717569706d656e745175657374666931656930656931313030313932656475363a33303334303575323a353065666932313365693339366565656c69313030333332656565"))); + SetupStatesOnTip(world => world .SetAvatarState(avatarAddress, avatarState)); From 64b3f537b9af539a6d89e156924c9ce0694ae0bf Mon Sep 17 00:00:00 2001 From: moreal Date: Fri, 20 Sep 2024 15:44:38 +0900 Subject: [PATCH 59/72] Track Discord users from README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 85929efb2..31015c9a5 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # NineChronicles Headless -[![Planetarium Discord invite](https://img.shields.io/discord/539405872346955788?color=6278DA&label=Planetarium&logo=discord&logoColor=white)](https://discord.gg/JyujU8E4SD) -[![Planetarium-Dev Discord Invite](https://img.shields.io/discord/928926944937013338?color=6278DA&label=Planetarium-dev&logo=discord&logoColor=white)](https://discord.gg/RYJDyFRYY7) +[![Planetarium Discord invite](https://img.shields.io/discord/539405872346955788?color=6278DA&label=Planetarium&logo=discord&logoColor=white)](https://bit.ly/47AtJHp) +[![Planetarium-Dev Discord Invite](https://img.shields.io/discord/928926944937013338?color=6278DA&label=Planetarium-dev&logo=discord&logoColor=white)](https://bit.ly/3TEOU59) > [!TIP] > If you're new to Nine Chronicles, try to visit our **Developer Portal**! From d29f47dc3d42626b5014ea4c9d203d3324f8b9b5 Mon Sep 17 00:00:00 2001 From: Moreal Date: Mon, 23 Sep 2024 10:43:03 +0900 Subject: [PATCH 60/72] Remove `activationStatus` mutation --- .../GraphTypes/ActivationStatusMutation.cs | 75 ------------------- .../GraphTypes/StandaloneMutation.cs | 5 -- 2 files changed, 80 deletions(-) delete mode 100644 NineChronicles.Headless/GraphTypes/ActivationStatusMutation.cs diff --git a/NineChronicles.Headless/GraphTypes/ActivationStatusMutation.cs b/NineChronicles.Headless/GraphTypes/ActivationStatusMutation.cs deleted file mode 100644 index 4575105f5..000000000 --- a/NineChronicles.Headless/GraphTypes/ActivationStatusMutation.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System; -using Bencodex.Types; -using GraphQL; -using GraphQL.Types; -using Libplanet.Action; -using Nekoyume.Action; -using Nekoyume.Model; -using Nekoyume.Model.State; -using Nekoyume.Module; - -namespace NineChronicles.Headless.GraphTypes -{ - public class ActivationStatusMutation : ObjectGraphType - { - public ActivationStatusMutation(NineChroniclesNodeService service) - { - DeprecationReason = "Since NCIP-15, it doesn't care account activation."; - - Field>("activateAccount", - deprecationReason: "Since NCIP-15, it doesn't care account activation.", - arguments: new QueryArguments( - new QueryArgument> - { - Name = "encodedActivationKey", - }), - resolve: context => - { - try - { - string encodedActivationKey = - context.GetArgument("encodedActivationKey"); - // FIXME: Private key may not exists at this moment. - if (!(service.MinerPrivateKey is { } privateKey)) - { - throw new InvalidOperationException($"{nameof(privateKey)} is null."); - } - - ActivationKey activationKey = ActivationKey.Decode(encodedActivationKey); - if (!(service.Swarm?.BlockChain is { } blockChain)) - { - throw new InvalidOperationException($"{nameof(blockChain)} is null."); - } - - IValue state = blockChain.GetWorldState().GetLegacyState(activationKey.PendingAddress); - - if (!(state is Bencodex.Types.Dictionary asDict)) - { - context.Errors.Add(new ExecutionError("The given key was already expired.")); - return false; - } - - var pendingActivationState = new PendingActivationState(asDict); - ActivateAccount action = activationKey.CreateActivateAccount( - pendingActivationState.Nonce); - - var actions = new IAction[] { action }; - blockChain.MakeTransaction(privateKey, actions); - } - catch (ArgumentException ae) - { - context.Errors.Add(new ExecutionError("The given key isn't in the correct format.", ae)); - return false; - } - catch (Exception e) - { - var msg = "Unexpected exception occurred during ActivatedAccountsMutation: {e}"; - context.Errors.Add(new ExecutionError(msg, e)); - return false; - } - - return true; - }); - } - } -} diff --git a/NineChronicles.Headless/GraphTypes/StandaloneMutation.cs b/NineChronicles.Headless/GraphTypes/StandaloneMutation.cs index 6285a00e1..826e9bb42 100644 --- a/NineChronicles.Headless/GraphTypes/StandaloneMutation.cs +++ b/NineChronicles.Headless/GraphTypes/StandaloneMutation.cs @@ -42,11 +42,6 @@ IConfiguration configuration deprecationReason: "Use `planet key` command instead. https://www.npmjs.com/package/@planetarium/cli", resolve: context => standaloneContext.KeyStore); - Field( - name: "activationStatus", - resolve: _ => new ActivationStatusMutation(nodeService), - deprecationReason: "Since NCIP-15, it doesn't care account activation."); - Field( name: "action", resolve: _ => new ActionMutation(nodeService)); From 8640b538f2293e222c21eff3ad4ccca3b9c8b944 Mon Sep 17 00:00:00 2001 From: Moreal Date: Mon, 23 Sep 2024 10:43:58 +0900 Subject: [PATCH 61/72] Remove `actionQuery.activateAccount` field --- .../GraphTypes/ActionQuery.cs | 29 ------------------- 1 file changed, 29 deletions(-) diff --git a/NineChronicles.Headless/GraphTypes/ActionQuery.cs b/NineChronicles.Headless/GraphTypes/ActionQuery.cs index 4c2c6fc0d..4462dcbf2 100644 --- a/NineChronicles.Headless/GraphTypes/ActionQuery.cs +++ b/NineChronicles.Headless/GraphTypes/ActionQuery.cs @@ -424,35 +424,6 @@ public ActionQuery(StandaloneContext standaloneContext) return Encode(context, action); } ); - Field>( - "activateAccount", - deprecationReason: "Since NCIP-15, it doesn't care account activation.", - arguments: new QueryArguments( - new QueryArgument> - { - Name = "activationCode", - Description = "Activation code that you've get." - } - ), - resolve: context => - { - var activationCode = context.GetArgument("activationCode"); - var activationKey = ActivationKey.Decode(activationCode); - if (standaloneContext.BlockChain!.GetWorldState().GetLegacyState(activationKey.PendingAddress) is Dictionary dictionary) - { - var pending = new PendingActivationState(dictionary); - var action = activationKey.CreateActivateAccount(pending.Nonce); - if (pending.Verify(action)) - { - return Encode(context, action); - } - - throw new ExecutionError("Failed to verify activateAccount action."); - } - - throw new InvalidOperationException("BlockChain not found in the context"); - } - ); Field>( "createAvatar", arguments: new QueryArguments( From ab034a2cdf40ec75f15720491856c84671a982c2 Mon Sep 17 00:00:00 2001 From: Moreal Date: Mon, 23 Sep 2024 11:16:58 +0900 Subject: [PATCH 62/72] Remove `ActivateAccount` support of `tx sign` command --- .../Commands/TxCommandTest.cs | 14 -------------- .../Commands/TxCommand.cs | 1 - 2 files changed, 15 deletions(-) diff --git a/NineChronicles.Headless.Executable.Tests/Commands/TxCommandTest.cs b/NineChronicles.Headless.Executable.Tests/Commands/TxCommandTest.cs index dc09855de..ab3a1f487 100644 --- a/NineChronicles.Headless.Executable.Tests/Commands/TxCommandTest.cs +++ b/NineChronicles.Headless.Executable.Tests/Commands/TxCommandTest.cs @@ -31,20 +31,6 @@ public TxCommandTest() _blockHash = BlockHash.FromHashDigest(default); } - [Theory] - [InlineData(1)] - [InlineData(2)] - public void Sign_ActivateAccount(int txNonce) - { - var nonce = new byte[] { 0x00, 0x01, 0x02, 0x03 }; - (ActivationKey activationKey, PendingActivationState _) = - ActivationKey.Create(_privateKey, nonce); - var filePath = Path.Combine(Path.GetTempPath(), Path.GetTempFileName()); - var actionCommand = new ActionCommand(_console); - actionCommand.ActivateAccount(activationKey.Encode(), ByteUtil.Hex(nonce), filePath); - Assert_Tx(txNonce, filePath, false); - } - [Theory] [InlineData(1, false)] [InlineData(10, true)] diff --git a/NineChronicles.Headless.Executable/Commands/TxCommand.cs b/NineChronicles.Headless.Executable/Commands/TxCommand.cs index 6c6ddaf94..a4dfb1bc2 100644 --- a/NineChronicles.Headless.Executable/Commands/TxCommand.cs +++ b/NineChronicles.Headless.Executable/Commands/TxCommand.cs @@ -65,7 +65,6 @@ public void Sign( ActionBase action = type switch { - nameof(ActivateAccount) => new ActivateAccount(), nameof(Stake) => new Stake(), nameof(ClaimStakeReward) => new ClaimStakeReward(), nameof(TransferAsset) => new TransferAsset(), From e3953c5ce744f61ce33d8c4bf626dc466920b5c4 Mon Sep 17 00:00:00 2001 From: Moreal Date: Mon, 23 Sep 2024 11:17:43 +0900 Subject: [PATCH 63/72] Remove `action activate-account` command --- .../Commands/ActionCommandTest.cs | 32 -------------- .../Commands/ActionCommand.cs | 43 ------------------- 2 files changed, 75 deletions(-) diff --git a/NineChronicles.Headless.Executable.Tests/Commands/ActionCommandTest.cs b/NineChronicles.Headless.Executable.Tests/Commands/ActionCommandTest.cs index 29eade8fb..130b74caa 100644 --- a/NineChronicles.Headless.Executable.Tests/Commands/ActionCommandTest.cs +++ b/NineChronicles.Headless.Executable.Tests/Commands/ActionCommandTest.cs @@ -26,38 +26,6 @@ public ActionCommandTest() _command = new ActionCommand(_console); } - [Theory] - [InlineData(true, -1)] - [InlineData(false, 0)] - public void ActivateAccount(bool invalid, int expectedCode) - { - var nonce = new byte[] { 0x00, 0x01, 0x02, 0x03 }; - var privateKey = new PrivateKey(); - (ActivationKey activationKey, PendingActivationState _) = ActivationKey.Create(privateKey, nonce); - string invitationCode = invalid ? "invalid_code" : activationKey.Encode(); - var filePath = Path.Combine(Path.GetTempPath(), Path.GetTempFileName()); - var resultCode = _command.ActivateAccount(invitationCode, ByteUtil.Hex(nonce), filePath); - Assert.Equal(expectedCode, resultCode); - - if (resultCode == 0) - { - var rawAction = Convert.FromBase64String(File.ReadAllText(filePath)); - var decoded = (List)_codec.Decode(rawAction); - string type = (Text)decoded[0]; - Assert.Equal(nameof(Nekoyume.Action.ActivateAccount), type); - - Dictionary plainValue = (Dictionary)decoded[1]; - var action = new ActivateAccount(); - action.LoadPlainValue(plainValue); - Assert.Equal(activationKey.PrivateKey.Sign(nonce), action.Signature); - Assert.Equal(activationKey.PendingAddress, action.PendingAddress); - } - else - { - Assert.Contains("hexWithSlash seems invalid. [invalid_code]", _console.Error.ToString()); - } - } - [Theory] [InlineData(10, 0, "transfer asset test1.")] [InlineData(100, 0, "transfer asset test2.")] diff --git a/NineChronicles.Headless.Executable/Commands/ActionCommand.cs b/NineChronicles.Headless.Executable/Commands/ActionCommand.cs index 1ddabd47c..ca0752db6 100644 --- a/NineChronicles.Headless.Executable/Commands/ActionCommand.cs +++ b/NineChronicles.Headless.Executable/Commands/ActionCommand.cs @@ -33,49 +33,6 @@ public void Help([FromService] ICoconaHelpMessageBuilder helpMessageBuilder) _console.Error.WriteLine(helpMessageBuilder.BuildAndRenderForCurrentContext()); } - [Command(Description = "Create ActivateAccount action.")] - public int ActivateAccount( - [Argument("INVITATION-CODE", Description = "An invitation code.")] - string invitationCode, - [Argument("NONCE", Description = "A hex-encoded nonce for activation.")] - string nonceEncoded, - [Argument("PATH", Description = "A file path of base64 encoded action.")] - string? filePath = null - ) - { - try - { - ActivationKey activationKey = ActivationKey.Decode(invitationCode); - byte[] nonce = ByteUtil.ParseHex(nonceEncoded); - Nekoyume.Action.ActivateAccount action = activationKey.CreateActivateAccount(nonce); - var list = new List( - new[] - { - (Text) nameof(Nekoyume.Action.ActivateAccount), - action.PlainValue - } - ); - - byte[] raw = Codec.Encode(list); - string encoded = Convert.ToBase64String(raw); - if (filePath is null) - { - _console.Out.Write(encoded); - } - else - { - File.WriteAllText(filePath, encoded); - } - - return 0; - } - catch (Exception e) - { - _console.Error.WriteLine(e); - return -1; - } - } - [Command(Description = "Lists all actions' type ids.")] public IOrderedEnumerable List( [Option( From aa57f5085fdb9f6b816fbb0fdcaf6fbbc89ac508 Mon Sep 17 00:00:00 2001 From: Moreal Date: Mon, 23 Sep 2024 10:41:54 +0900 Subject: [PATCH 64/72] Bump lib9c submodule --- Lib9c | 2 +- .../GraphTypes/ActionQueryTest.cs | 19 --- .../GraphTypes/StandaloneMutationTest.cs | 39 ------ .../GraphTypes/StandaloneQueryTest.cs | 127 +----------------- .../GraphTypes/ActivationStatusQuery.cs | 56 -------- .../GraphTypes/StandaloneQuery.cs | 4 +- 6 files changed, 4 insertions(+), 243 deletions(-) diff --git a/Lib9c b/Lib9c index 31cbd41a9..a34287b88 160000 --- a/Lib9c +++ b/Lib9c @@ -1 +1 @@ -Subproject commit 31cbd41a99ed7b17a33fd1ea2597600dfd9b9906 +Subproject commit a34287b886cc6791598decfd2d3888888df60018 diff --git a/NineChronicles.Headless.Tests/GraphTypes/ActionQueryTest.cs b/NineChronicles.Headless.Tests/GraphTypes/ActionQueryTest.cs index 8b4b1a2e5..7953d2bdb 100644 --- a/NineChronicles.Headless.Tests/GraphTypes/ActionQueryTest.cs +++ b/NineChronicles.Headless.Tests/GraphTypes/ActionQueryTest.cs @@ -582,25 +582,6 @@ public async Task TransferAssets(bool exc) } } - [Fact] - public async Task ActivateAccount() - { - var activationCode = _activationKey.Encode(); - var signature = _activationKey.PrivateKey.Sign(_nonce); - - var query = $"{{ activateAccount(activationCode: \"{activationCode}\") }}"; - var queryResult = await ExecuteQueryAsync(query, standaloneContext: _standaloneContext); - - Assert.Null(queryResult.Errors); - var data = (Dictionary)((ExecutionNode)queryResult.Data!).ToValue()!; - var plainValue = _codec.Decode(ByteUtil.ParseHex((string)data["activateAccount"])); - Assert.IsType(plainValue); - var actionBase = DeserializeNCAction(plainValue); - var action = Assert.IsType(actionBase); - - Assert.Equal(signature, action.Signature); - } - [Theory] [InlineData(-1, "ab", null, null, null, null, false)] [InlineData(0, "ab", null, null, null, null, true)] diff --git a/NineChronicles.Headless.Tests/GraphTypes/StandaloneMutationTest.cs b/NineChronicles.Headless.Tests/GraphTypes/StandaloneMutationTest.cs index 556a0deaa..2d8854eda 100644 --- a/NineChronicles.Headless.Tests/GraphTypes/StandaloneMutationTest.cs +++ b/NineChronicles.Headless.Tests/GraphTypes/StandaloneMutationTest.cs @@ -846,45 +846,6 @@ public async Task Tx_V2() Assert.Null(result.Errors); } - [Fact] - public async Task Tx_ActivateAccount() - { - var nonce = new byte[] { 0x00, 0x01, 0x02, 0x03 }; - var privateKey = new PrivateKey(); - (ActivationKey activationKey, PendingActivationState pendingActivation) = - ActivationKey.Create(privateKey, nonce); - ActionBase action = new CreatePendingActivation(pendingActivation); - BlockChain.MakeTransaction(AdminPrivateKey, new[] { action }); - Block block = BlockChain.ProposeBlock( - ProposerPrivateKey, - lastCommit: GenerateBlockCommit(BlockChain.Tip.Index, BlockChain.Tip.Hash, GenesisValidators)); - BlockChain.Append(block, GenerateBlockCommit(block.Index, block.Hash, GenesisValidators)); - AppendEmptyBlock(GenesisValidators); - var encodedActivationKey = activationKey.Encode(); - var actionCommand = new ActionCommand(new StandardConsole()); - var filePath = Path.Combine(Path.GetTempPath(), Path.GetTempFileName()); - actionCommand.ActivateAccount(encodedActivationKey, ByteUtil.Hex(nonce), filePath); - var console = new StringIOConsole(); - var txCommand = new TxCommand(console); - var timeStamp = DateTimeOffset.UtcNow; - txCommand.Sign(ByteUtil.Hex(privateKey.ByteArray), BlockChain.GetNextTxNonce(privateKey.Address), ByteUtil.Hex(BlockChain.Genesis.Hash.ByteArray), timeStamp.ToString(), new[] { filePath }); - var output = console.Out.ToString(); - output = output.Trim(); - var queryResult = await ExecuteQueryAsync( - $"mutation {{ stageTx(payload: \"{output}\") }}"); - var data = (Dictionary)((ExecutionNode)queryResult.Data!).ToValue()!; - block = BlockChain.ProposeBlock( - ProposerPrivateKey, - lastCommit: GenerateBlockCommit(BlockChain.Tip.Index, BlockChain.Tip.Hash, GenesisValidators)); - BlockChain.Append(block, GenerateBlockCommit(block.Index, block.Hash, GenesisValidators)); - - var result = (bool)data["stageTx"]; - Assert.True(result); - - IValue? state = BlockChain.GetNextWorldState().GetLegacyState(privateKey.Address.Derive(ActivationKey.DeriveKey)); - Assert.True((Bencodex.Types.Boolean)state); - } - [Fact] public async Task StageTransaction() { diff --git a/NineChronicles.Headless.Tests/GraphTypes/StandaloneQueryTest.cs b/NineChronicles.Headless.Tests/GraphTypes/StandaloneQueryTest.cs index 43385b869..5f4bd8ef4 100644 --- a/NineChronicles.Headless.Tests/GraphTypes/StandaloneQueryTest.cs +++ b/NineChronicles.Headless.Tests/GraphTypes/StandaloneQueryTest.cs @@ -453,130 +453,6 @@ public async Task ConvertPrivateKey(bool compress) Assert.Equal(privateKey.Address.ToString(), publicKeyResult["address"]); } - [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task ActivationStatus(bool existsActivatedAccounts) - { - var adminPrivateKey = new PrivateKey(); - var adminAddress = adminPrivateKey.Address; - var activatedAccounts = ImmutableHashSet
.Empty; - - if (existsActivatedAccounts) - { - activatedAccounts = new[] { adminAddress }.ToImmutableHashSet(); - } - - ValidatorSet validatorSetCandidate = new ValidatorSet(new[] - { - new Libplanet.Types.Consensus.Validator(ProposerPrivateKey.PublicKey, BigInteger.One), - }.ToList()); - Block genesis = - BlockChain.ProposeGenesisBlock( - transactions: ImmutableList.Empty - .Add(Transaction.Create(0, ProposerPrivateKey, null, - new ActionBase[] - { - new InitializeStates( - rankingState: new RankingState0(), - shopState: new ShopState(), - gameConfigState: new GameConfigState(), - redeemCodeState: new RedeemCodeState(Bencodex.Types.Dictionary.Empty - .Add("address", RedeemCodeState.Address.Serialize()) - .Add("map", Bencodex.Types.Dictionary.Empty) - ), - adminAddressState: new AdminState(adminAddress, 1500000), - activatedAccountsState: new ActivatedAccountsState(activatedAccounts), -#pragma warning disable CS0618 - // Use of obsolete method Currency.Legacy(): - // https://github.com/planetarium/lib9c/discussions/1319 - goldCurrencyState: new GoldCurrencyState(Currency.Legacy("NCG", 2, null)), -#pragma warning restore CS0618 - goldDistributions: new GoldDistribution[0], - tableSheets: _sheets, - pendingActivationStates: new PendingActivationState[] { } - ), - }.ToPlainValues())) - .AddRange(new IAction[] - { - new Initialize( - validatorSet: validatorSetCandidate, - states: ImmutableDictionary.Empty), - }.Select((sa, nonce) => - Transaction.Create(nonce + 1, ProposerPrivateKey, null, - new[] { sa.PlainValue })) - ), - privateKey: ProposerPrivateKey - ); - - var apvPrivateKey = new PrivateKey(); - var apv = AppProtocolVersion.Sign(apvPrivateKey, 0); - var userPrivateKey = new PrivateKey(); - var consensusPrivateKey = new PrivateKey(); - var properties = new LibplanetNodeServiceProperties - { - Host = System.Net.IPAddress.Loopback.ToString(), - AppProtocolVersion = apv, - GenesisBlock = genesis, - StorePath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()), - StoreStatesCacheSize = 2, - SwarmPrivateKey = new PrivateKey(), - ConsensusPrivateKey = consensusPrivateKey, - ConsensusPort = null, - Port = null, - NoMiner = true, - Render = false, - Peers = ImmutableHashSet.Empty, - TrustedAppProtocolVersionSigners = null, - IceServers = ImmutableList.Empty, - ConsensusSeeds = ImmutableList.Empty, - ConsensusPeers = ImmutableList.Empty - }; - var blockPolicy = new BlockPolicySource().GetPolicy(); - - var service = new NineChroniclesNodeService( - userPrivateKey, properties, blockPolicy, Planet.Odin, StaticActionLoaderSingleton.Instance); - StandaloneContextFx.NineChroniclesNodeService = service; - StandaloneContextFx.BlockChain = service.Swarm?.BlockChain; - - var blockChain = StandaloneContextFx.BlockChain!; - AppendEmptyBlock(GenesisValidators); - - var queryResult = await ExecuteQueryAsync("query { activationStatus { activated } }"); - var data = (Dictionary)((ExecutionNode)queryResult.Data!).ToValue()!; - var result = (bool) - ((Dictionary)data["activationStatus"])["activated"]; - - // If we don't use activated accounts, bypass check (always true). - Assert.Equal(!existsActivatedAccounts, result); - - var nonce = new byte[] { 0x00, 0x01, 0x02, 0x03 }; - var privateKey = new PrivateKey(); - (ActivationKey activationKey, PendingActivationState pendingActivation) = - ActivationKey.Create(privateKey, nonce); - ActionBase action = new CreatePendingActivation(pendingActivation); - blockChain.MakeTransaction(adminPrivateKey, new[] { action }); - Block block = blockChain.ProposeBlock( - ProposerPrivateKey, - lastCommit: GenerateBlockCommit(BlockChain.Tip.Index, BlockChain.Tip.Hash, GenesisValidators)); - blockChain.Append(block, GenerateBlockCommit(block.Index, block.Hash, GenesisValidators)); - - action = activationKey.CreateActivateAccount(nonce); - blockChain.MakeTransaction(userPrivateKey, new[] { action }); - block = blockChain.ProposeBlock( - ProposerPrivateKey, - lastCommit: GenerateBlockCommit(BlockChain.Tip.Index, BlockChain.Tip.Hash, GenesisValidators)); - blockChain.Append(block, GenerateBlockCommit(block.Index, block.Hash, GenesisValidators)); - AppendEmptyBlock(GenesisValidators); - - queryResult = await ExecuteQueryAsync("query { activationStatus { activated } }"); - data = (Dictionary)((ExecutionNode)queryResult.Data!).ToValue()!; - result = (bool) - ((Dictionary)data["activationStatus"])["activated"]; - - Assert.True(result); - } - [Fact] public async Task GoldBalance() { @@ -628,8 +504,7 @@ Transaction MakeTx(long nonce, ActionBase action) var currency = Currency.Uncapped("NCG", 2, null); var txs = new[] { - MakeTx(0, new TransferAsset0(sender, recipient, new FungibleAssetValue(currency, 1, 0), memo)), - MakeTx(1, new TransferAsset(sender, recipient, new FungibleAssetValue(currency, 1, 0), memo)), + MakeTx(0, new TransferAsset(sender, recipient, new FungibleAssetValue(currency, 1, 0), memo)), }; var block = new Domain.Model.BlockChain.Block( blockHash, diff --git a/NineChronicles.Headless/GraphTypes/ActivationStatusQuery.cs b/NineChronicles.Headless/GraphTypes/ActivationStatusQuery.cs index 542fcdc69..fc810c6da 100644 --- a/NineChronicles.Headless/GraphTypes/ActivationStatusQuery.cs +++ b/NineChronicles.Headless/GraphTypes/ActivationStatusQuery.cs @@ -18,62 +18,6 @@ public ActivationStatusQuery(StandaloneContext standaloneContext) { DeprecationReason = "Since NCIP-15, it doesn't care account activation."; - Field>( - name: "activated", - deprecationReason: "Since NCIP-15, it doesn't care account activation.", - resolve: context => - { - var service = standaloneContext.NineChroniclesNodeService; - - if (service is null) - { - return false; - } - - try - { - if (!(service.MinerPrivateKey is { } privateKey)) - { - throw new InvalidOperationException($"{nameof(service.MinerPrivateKey)} is null."); - } - - if (!(service.Swarm?.BlockChain is { } blockChain)) - { - throw new InvalidOperationException($"{nameof(service.Swarm.BlockChain)} is null."); - } - - Address userAddress = privateKey.Address; - Address activatedAddress = userAddress.Derive(ActivationKey.DeriveKey); - - if (blockChain.GetWorldState().GetLegacyState(activatedAddress) is Bencodex.Types.Boolean) - { - return true; - } - - // Preserve previous check code due to migration period. - // TODO: Remove this code after v100061+ - IValue state = blockChain.GetWorldState().GetLegacyState(ActivatedAccountsState.Address); - - if (state is Bencodex.Types.Dictionary asDict) - { - var activatedAccountsState = new ActivatedAccountsState(asDict); - var activatedAccounts = activatedAccountsState.Accounts; - return activatedAccounts.Count == 0 - || activatedAccounts.Contains(userAddress); - } - - return true; - } - catch (Exception e) - { - var msg = "Unexpected exception occurred during ActivationStatusQuery: {e}"; - context.Errors.Add(new ExecutionError(msg, e)); - Log.Error(msg, e); - return false; - } - } - ); - Field>( name: "addressActivated", deprecationReason: "Since NCIP-15, it doesn't care account activation.", diff --git a/NineChronicles.Headless/GraphTypes/StandaloneQuery.cs b/NineChronicles.Headless/GraphTypes/StandaloneQuery.cs index cc9e97804..3cfeb63ff 100644 --- a/NineChronicles.Headless/GraphTypes/StandaloneQuery.cs +++ b/NineChronicles.Headless/GraphTypes/StandaloneQuery.cs @@ -485,8 +485,8 @@ public StandaloneQuery(StandaloneContext standaloneContext, IKeyStore keyStore, if (worldState.GetLegacyState(activationKey.PendingAddress) is Dictionary dictionary) { var pending = new PendingActivationState(dictionary); - ActivateAccount action = activationKey.CreateActivateAccount(pending.Nonce); - if (pending.Verify(action)) + var signature = activationKey.PrivateKey.Sign(pending.Nonce); + if (pending.Verify(signature)) { return false; } From 204fbcf84bf99c371c4dfaf1599e664d56449748 Mon Sep 17 00:00:00 2001 From: Moreal Date: Mon, 23 Sep 2024 16:56:52 +0900 Subject: [PATCH 65/72] Make tests as comment --- .../TransactionHeadlessQueryTest.cs | 118 +++++++++--------- 1 file changed, 59 insertions(+), 59 deletions(-) diff --git a/NineChronicles.Headless.Tests/GraphTypes/TransactionHeadlessQueryTest.cs b/NineChronicles.Headless.Tests/GraphTypes/TransactionHeadlessQueryTest.cs index 8dcb7bd86..a1a9a1002 100644 --- a/NineChronicles.Headless.Tests/GraphTypes/TransactionHeadlessQueryTest.cs +++ b/NineChronicles.Headless.Tests/GraphTypes/TransactionHeadlessQueryTest.cs @@ -316,65 +316,65 @@ public async Task TransactionResultIsInvalid() Assert.Equal("INVALID", txStatus); } - [Fact] - public async Task TransactionResultIsSuccess() - { - var privateKey = new PrivateKey(); - // Because `AddActivatedAccount` doesn't need any prerequisites. - var action = new AddActivatedAccount(default); - Transaction tx = _blockChain.MakeTransaction(privateKey, new ActionBase[] { action }); - Block block = _blockChain.ProposeBlock(_proposer); - _blockChain.Append(block, GenerateBlockCommit(block.Index, block.Hash, _proposer)); - var queryFormat = @"query {{ - transactionResult(txId: ""{0}"") {{ - blockHash - txStatus - }} - }}"; - var result = await ExecuteAsync(string.Format( - queryFormat, - tx.Id.ToString())); - Assert.NotNull(result.Data); - var transactionResult = - ((Dictionary)((ExecutionNode)result.Data!).ToValue()!)["transactionResult"]; - var txStatus = (string)((Dictionary)transactionResult)["txStatus"]; - Assert.Equal("SUCCESS", txStatus); - } - - [Fact] - public async Task TransactionResults() - { - var privateKey = new PrivateKey(); - // Because `AddActivatedAccount` doesn't need any prerequisites. - var action = new AddActivatedAccount(default); - Transaction tx = _blockChain.MakeTransaction(privateKey, new ActionBase[] { action }); - var action2 = new DailyReward - { - avatarAddress = default - }; - Transaction tx2 = _blockChain.MakeTransaction(new PrivateKey(), new ActionBase[] { action2 }); - Block block = _blockChain.ProposeBlock(_proposer); - _blockChain.Append(block, GenerateBlockCommit(block.Index, block.Hash, _proposer)); - var queryFormat = @"query {{ - transactionResults(txIds: [""{0}"", ""{1}""]) {{ - blockHash - txStatus - }} - }}"; - var result = await ExecuteAsync(string.Format( - queryFormat, - tx.Id.ToString(), - tx2.Id.ToString() - )); - Assert.NotNull(result.Data); - var transactionResults = - (object[])((Dictionary)((ExecutionNode)result.Data!).ToValue()!)["transactionResults"]; - Assert.Equal(2, transactionResults.Length); - var txStatus = (string)((Dictionary)transactionResults[0])["txStatus"]; - Assert.Equal("SUCCESS", txStatus); - txStatus = (string)((Dictionary)transactionResults[1])["txStatus"]; - Assert.Equal("FAILURE", txStatus); - } + // [Fact] + // public async Task TransactionResultIsSuccess() + // { + // var privateKey = new PrivateKey(); + // // Because `AddActivatedAccount` doesn't need any prerequisites. + // var action = new AddActivatedAccount(default); + // Transaction tx = _blockChain.MakeTransaction(privateKey, new ActionBase[] { action }); + // Block block = _blockChain.ProposeBlock(_proposer); + // _blockChain.Append(block, GenerateBlockCommit(block.Index, block.Hash, _proposer)); + // var queryFormat = @"query {{ + // transactionResult(txId: ""{0}"") {{ + // blockHash + // txStatus + // }} + // }}"; + // var result = await ExecuteAsync(string.Format( + // queryFormat, + // tx.Id.ToString())); + // Assert.NotNull(result.Data); + // var transactionResult = + // ((Dictionary)((ExecutionNode)result.Data!).ToValue()!)["transactionResult"]; + // var txStatus = (string)((Dictionary)transactionResult)["txStatus"]; + // Assert.Equal("SUCCESS", txStatus); + // } + // + // [Fact] + // public async Task TransactionResults() + // { + // var privateKey = new PrivateKey(); + // // Because `AddActivatedAccount` doesn't need any prerequisites. + // var action = new AddActivatedAccount(default); + // Transaction tx = _blockChain.MakeTransaction(privateKey, new ActionBase[] { action }); + // var action2 = new DailyReward + // { + // avatarAddress = default + // }; + // Transaction tx2 = _blockChain.MakeTransaction(new PrivateKey(), new ActionBase[] { action2 }); + // Block block = _blockChain.ProposeBlock(_proposer); + // _blockChain.Append(block, GenerateBlockCommit(block.Index, block.Hash, _proposer)); + // var queryFormat = @"query {{ + // transactionResults(txIds: [""{0}"", ""{1}""]) {{ + // blockHash + // txStatus + // }} + // }}"; + // var result = await ExecuteAsync(string.Format( + // queryFormat, + // tx.Id.ToString(), + // tx2.Id.ToString() + // )); + // Assert.NotNull(result.Data); + // var transactionResults = + // (object[])((Dictionary)((ExecutionNode)result.Data!).ToValue()!)["transactionResults"]; + // Assert.Equal(2, transactionResults.Length); + // var txStatus = (string)((Dictionary)transactionResults[0])["txStatus"]; + // Assert.Equal("SUCCESS", txStatus); + // txStatus = (string)((Dictionary)transactionResults[1])["txStatus"]; + // Assert.Equal("FAILURE", txStatus); + // } [Fact] public async Task NcTransactionsOnTip() From bafa20bfa344210343ac70040fc0916b4d1fff44 Mon Sep 17 00:00:00 2001 From: Moreal Date: Mon, 23 Sep 2024 17:00:46 +0900 Subject: [PATCH 66/72] Remove staled tests --- .../GraphTypes/StandaloneMutationTest.cs | 34 ------------------- 1 file changed, 34 deletions(-) diff --git a/NineChronicles.Headless.Tests/GraphTypes/StandaloneMutationTest.cs b/NineChronicles.Headless.Tests/GraphTypes/StandaloneMutationTest.cs index 2d8854eda..075b60c14 100644 --- a/NineChronicles.Headless.Tests/GraphTypes/StandaloneMutationTest.cs +++ b/NineChronicles.Headless.Tests/GraphTypes/StandaloneMutationTest.cs @@ -114,40 +114,6 @@ public async Task RevokePrivateKey() Assert.Equal(address.ToString(), revokedPrivateKeyAddress); } - [Fact] - public async Task ActivateAccount() - { - var nonce = new byte[] { 0x00, 0x01, 0x02, 0x03 }; - var privateKey = new PrivateKey(); - (ActivationKey activationKey, PendingActivationState pendingActivation) = - ActivationKey.Create(privateKey, nonce); - ActionBase action = new CreatePendingActivation(pendingActivation); - BlockChain.MakeTransaction(AdminPrivateKey, new[] { action }); - Block block = BlockChain.ProposeBlock( - ProposerPrivateKey, - lastCommit: GenerateBlockCommit(BlockChain.Tip.Index, BlockChain.Tip.Hash, GenesisValidators)); - BlockChain.Append(block, GenerateBlockCommit(block.Index, block.Hash, GenesisValidators)); - AppendEmptyBlock(GenesisValidators); - - var encodedActivationKey = activationKey.Encode(); - var queryResult = await ExecuteQueryAsync( - $"mutation {{ activationStatus {{ activateAccount(encodedActivationKey: \"{encodedActivationKey}\") }} }}"); - var data = (Dictionary)((ExecutionNode)queryResult.Data!).ToValue()!; - block = BlockChain.ProposeBlock( - ProposerPrivateKey, - lastCommit: GenerateBlockCommit(BlockChain.Tip.Index, BlockChain.Tip.Hash, GenesisValidators)); - BlockChain.Append(block, GenerateBlockCommit(block.Index, block.Hash, GenesisValidators)); - - var result = - (bool)((Dictionary) - data["activationStatus"])["activateAccount"]; - Assert.True(result); - - Address userAddress = StandaloneContextFx.NineChroniclesNodeService!.MinerPrivateKey!.Address; - IValue? state = BlockChain.GetNextWorldState().GetLegacyState(userAddress.Derive(ActivationKey.DeriveKey)); - Assert.True((Bencodex.Types.Boolean)state); - } - [Theory] [InlineData(null, false)] [InlineData("", false)] From bc75b9eda0e7c4f4cd960f3f19d52d372d04141c Mon Sep 17 00:00:00 2001 From: Moreal Date: Mon, 23 Sep 2024 17:06:46 +0900 Subject: [PATCH 67/72] Fix tests --- .../GraphTypes/StandaloneQueryTest.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/NineChronicles.Headless.Tests/GraphTypes/StandaloneQueryTest.cs b/NineChronicles.Headless.Tests/GraphTypes/StandaloneQueryTest.cs index 5f4bd8ef4..0e8a91c3f 100644 --- a/NineChronicles.Headless.Tests/GraphTypes/StandaloneQueryTest.cs +++ b/NineChronicles.Headless.Tests/GraphTypes/StandaloneQueryTest.cs @@ -521,9 +521,6 @@ Transaction MakeTx(long nonce, ActionBase action) TransactionRepository.Setup(repo => repo.GetTxExecution(blockHash, txs[0].Id)) .Returns(new TxExecution( blockHash, txs[0].Id, false, MerkleTrie.EmptyRootHash, MerkleTrie.EmptyRootHash, new List())); - TransactionRepository.Setup(repo => repo.GetTxExecution(blockHash, txs[1].Id)) - .Returns(new TxExecution( - blockHash, txs[1].Id, false, MerkleTrie.EmptyRootHash, MerkleTrie.EmptyRootHash, new List())); var blockHashHex = ByteUtil.Hex(block.Hash.ToByteArray()); var result = From 263a2b7dbdb41176376554bc431206b681643f42 Mon Sep 17 00:00:00 2001 From: hyeon Date: Mon, 23 Sep 2024 16:20:13 +0900 Subject: [PATCH 68/72] Fix function args --- .../ArenaParticipantsWorkerTest.cs | 24 ++----------------- .../Common/Fixtures.cs | 11 ++------- 2 files changed, 4 insertions(+), 31 deletions(-) diff --git a/NineChronicles.Headless.Tests/ArenaParticipantsWorkerTest.cs b/NineChronicles.Headless.Tests/ArenaParticipantsWorkerTest.cs index f2218842b..f0835bbc7 100644 --- a/NineChronicles.Headless.Tests/ArenaParticipantsWorkerTest.cs +++ b/NineChronicles.Headless.Tests/ArenaParticipantsWorkerTest.cs @@ -7,11 +7,9 @@ using Libplanet.Mocks; using Nekoyume; using Nekoyume.Action; -using Nekoyume.Model; using Nekoyume.Model.Arena; using Nekoyume.Model.EnumType; using Nekoyume.Model.Item; -using Nekoyume.Model.Quest; using Nekoyume.Model.State; using Nekoyume.Module; using Nekoyume.TableData; @@ -117,16 +115,7 @@ public void GetArenaParticipants() avatarAddress, agentAddress, 0, - new QuestList( - tableSheets.QuestSheet, - tableSheets.QuestRewardSheet, - tableSheets.QuestItemRewardSheet, - tableSheets.EquipmentItemRecipeSheet, - tableSheets.EquipmentItemSubRecipeSheet - ), - new WorldInformation( - 0, tableSheets.WorldSheet, GameConfig.IsEditor, "test" - ), + tableSheets.GetAvatarSheets(), new Address(), "avatar_state" ); @@ -135,16 +124,7 @@ public void GetArenaParticipants() avatar2Address, agentAddress, 0, - new QuestList( - tableSheets.QuestSheet, - tableSheets.QuestRewardSheet, - tableSheets.QuestItemRewardSheet, - tableSheets.EquipmentItemRecipeSheet, - tableSheets.EquipmentItemSubRecipeSheet - ), - new WorldInformation( - 0, tableSheets.WorldSheet, GameConfig.IsEditor, "test" - ), + tableSheets.GetAvatarSheets(), new Address(), "avatar_state2" ); diff --git a/NineChronicles.Headless.Tests/Common/Fixtures.cs b/NineChronicles.Headless.Tests/Common/Fixtures.cs index 81bf16c2e..851646c29 100644 --- a/NineChronicles.Headless.Tests/Common/Fixtures.cs +++ b/NineChronicles.Headless.Tests/Common/Fixtures.cs @@ -11,6 +11,7 @@ using Nekoyume.Model.Item; using Nekoyume.Model.Quest; using Nekoyume.Model.State; +using Nekoyume.TableData; namespace NineChronicles.Headless.Tests { @@ -33,15 +34,7 @@ public static class Fixtures AvatarAddress, UserAddress, 0, - new QuestList( - TableSheetsFX.GetAvatarSheets().QuestSheet, - TableSheetsFX.GetAvatarSheets().QuestRewardSheet, - TableSheetsFX.GetAvatarSheets().QuestItemRewardSheet, - TableSheetsFX.GetAvatarSheets().EquipmentItemRecipeSheet, - TableSheetsFX.GetAvatarSheets().EquipmentItemSubRecipeSheet - ), - new WorldInformation(0, TableSheetsFX.GetAvatarSheets().WorldSheet, - GameConfig.IsEditor, "test"), + TableSheetsFX.GetAvatarSheets(), new Address(), "avatar_state_fx" ); From 3cba470ad189741a57d0118187b779eeafc3113a Mon Sep 17 00:00:00 2001 From: hyeon Date: Tue, 24 Sep 2024 17:46:09 +0900 Subject: [PATCH 69/72] Bump lib9c: update custom craft CP selection --- Lib9c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib9c b/Lib9c index 0d91af77c..20013a2bf 160000 --- a/Lib9c +++ b/Lib9c @@ -1 +1 @@ -Subproject commit 0d91af77c324907272c1a5e7385b36cc2ad6dc54 +Subproject commit 20013a2bf993e0d52fb1ad1c4ec52034c2f2c9f1 From 4343d4163714f52b6e8c89304489a3568d8a8ec5 Mon Sep 17 00:00:00 2001 From: hyeon Date: Wed, 25 Sep 2024 15:14:24 +0900 Subject: [PATCH 70/72] Bump lib9c: Update mail --- Lib9c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib9c b/Lib9c index 20013a2bf..00ac3e8ea 160000 --- a/Lib9c +++ b/Lib9c @@ -1 +1 @@ -Subproject commit 20013a2bf993e0d52fb1ad1c4ec52034c2f2c9f1 +Subproject commit 00ac3e8ea53f76a809e7b6bcfc22c3d6d8cc0f09 From 35ab420254afaecb562f20383a0120ec97725e97 Mon Sep 17 00:00:00 2001 From: hyeon Date: Wed, 25 Sep 2024 17:30:41 +0900 Subject: [PATCH 71/72] Bump lib9c --- Lib9c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib9c b/Lib9c index 00ac3e8ea..2a67d1456 160000 --- a/Lib9c +++ b/Lib9c @@ -1 +1 @@ -Subproject commit 00ac3e8ea53f76a809e7b6bcfc22c3d6d8cc0f09 +Subproject commit 2a67d1456c6d3102f3356a3574951686c885cc61 From f6d44addbff7bd842432c7d6a45b74b57dd9d314 Mon Sep 17 00:00:00 2001 From: hyeon Date: Fri, 27 Sep 2024 18:53:20 +0900 Subject: [PATCH 72/72] Bump lib9c: Update custom craft cost calculator --- Lib9c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib9c b/Lib9c index 2a67d1456..5e6cea511 160000 --- a/Lib9c +++ b/Lib9c @@ -1 +1 @@ -Subproject commit 2a67d1456c6d3102f3356a3574951686c885cc61 +Subproject commit 5e6cea5115277ddc79e39366c26d21eb73d1ddaf