diff --git a/.circleci/config.yml b/.circleci/config.yml index 34828ef5e6..b911cafed1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -198,7 +198,7 @@ commands: shell: bash.exe command: | choco install -y msys2 pacman make wget --force - choco install -y golang --version=1.16.15 --force + choco install -y golang --version=1.17.9 --force choco install -y python3 --version=3.7.3 --force export msys2='cmd //C RefreshEnv.cmd ' export msys2+='& set MSYS=winsymlinks:nativestrict ' diff --git a/.codecov.yml b/.codecov.yml new file mode 100644 index 0000000000..def78dc007 --- /dev/null +++ b/.codecov.yml @@ -0,0 +1,18 @@ +codecov: + require_ci_to_pass: yes + +ignore: + - "**/*_gen.go" + - "**/*_gen_test.go" + - "**/generated" + +coverage: + status: + project: + default: + target: auto + informational: true + patch: + default: + target: auto + informational: true diff --git a/.github/workflows/README.md b/.github/workflows/README.md new file mode 100644 index 0000000000..e1c3fa8477 --- /dev/null +++ b/.github/workflows/README.md @@ -0,0 +1,26 @@ +# Github Actions Workflows + +## Benchmarking Performance Tests +`benchmarks.yml` contains a workflow to check for any performance regressions or +improvements in benchmark tests. + +It uses +[github-action-benchmark](https://github.com/benchmark-action/github-action-benchmark) +to check performance diffs between a PR and the `master` branch, comments if it +there is a regression past a certain threshold (default: `200%`), and generates +a performance diff JSON between consecutive commits in the `master` branch in +the `gh-pages` branch (the JSON is visualized into a graph that can be seen at: +https://algorand.github.io/go-algorand/dev/bench/). + +### Adding benchmark tests +Add run steps or extend existing benchmark invocations in the `Run benchmark` +step. Additional benchmarks can be run using the `-bench` flag. Since there's +few benchmarks run by the workflow, there are _no_ formal groupings and/or +naming conventions. + +### CI Variance +There may be some variance between runs because github actions might spin up a +different machine each time (e.g. Intel Xeon 8370C vs 8171M; the latter might +run benchmarks slightly slower). Empirically, the variance seems to be 10~30% +for the most part. Due to this environment variance, the workflow is most +suitable for finding _large_ performance degradations. diff --git a/.github/workflows/benchmarks.yml b/.github/workflows/benchmarks.yml new file mode 100644 index 0000000000..65c0e90bf2 --- /dev/null +++ b/.github/workflows/benchmarks.yml @@ -0,0 +1,51 @@ +name: "Benchmark workflow" +on: + # Push and update benchmarks when a commit is merged into master. + push: + branches: + - master + # Trigger benchmark test on this PR's commit against master. + pull_request: + branches: + - master +permissions: + # Push benchmark performance graph to gh-pages branch. + contents: write + deployments: write +jobs: + benchmark: + name: Performance regression check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-go@v3 + with: + go-version-file: 'go.mod' + - run: go version + - name: Build go-algorand + run: scripts/travis/build.sh + # BenchmarkUintMath - Serves as a proxy for AVM `eval` performance. + # Performance degradations suggest either or both: (1) op code + # degradation, (2) `eval` degradation. (2) suggests a broader performance + # issue. + - name: Run benchmark + run: go test ./data/transactions/logic -bench 'BenchmarkUintMath' | tee benchmark_output.txt + - name: Push benchmark result to gh-pages branch + if: github.event_name == 'push' + uses: benchmark-action/github-action-benchmark@v1 + with: + name: Go Benchmark + tool: 'go' + output-file-path: benchmark_output.txt + github-token: ${{ secrets.GITHUB_TOKEN }} + auto-push: true + - name: Evaluate benchmark on PR branch + if: github.event.pull_request + uses: benchmark-action/github-action-benchmark@v1 + with: + name: Go Benchmark + tool: 'go' + output-file-path: benchmark_output.txt + github-token: ${{ secrets.GITHUB_TOKEN }} + alert-threshold: '200%' + comment-on-alert: true diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4cc8eaba40..825056b1e1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -20,7 +20,7 @@ jobs: - name: Install golang uses: actions/setup-go@v2 with: - go-version: '1.16.15' + go-version: '1.17.9' - name: Build Test run: | export ALGORAND_DEADLOCK=enable diff --git a/.github/workflows/reviewdog.yml b/.github/workflows/reviewdog.yml index 134685fc6e..6cc82a6e55 100644 --- a/.github/workflows/reviewdog.yml +++ b/.github/workflows/reviewdog.yml @@ -44,7 +44,7 @@ jobs: - name: Install specific golang uses: actions/setup-go@v2 with: - go-version: '1.16.15' + go-version: '1.17.9' - name: Create folders for golangci-lint run: mkdir -p cicdtmp/golangci-lint - name: Check if custom golangci-lint is already built diff --git a/Makefile b/Makefile index 90bcc70215..f55089890c 100644 --- a/Makefile +++ b/Makefile @@ -36,6 +36,13 @@ else export GOTESTCOMMAND=gotestsum --format pkgname --jsonfile testresults.json -- endif +# M1 Mac--homebrew install location in /opt/homebrew +ifeq ($(OS_TYPE), darwin) +ifeq ($(ARCH), arm64) +export CPATH=/opt/homebrew/include +export LIBRARY_PATH=/opt/homebrew/lib +endif +endif ifeq ($(UNAME), Linux) EXTLDFLAGS := -static-libstdc++ -static-libgcc ifeq ($(ARCH), amd64) diff --git a/agreement/fuzzer/bandwidthFilter_test.go b/agreement/fuzzer/bandwidthFilter_test.go index e06ff72602..e5a31bf2e0 100644 --- a/agreement/fuzzer/bandwidthFilter_test.go +++ b/agreement/fuzzer/bandwidthFilter_test.go @@ -167,7 +167,7 @@ func (n *BandwidthFilter) Tick(newClockTime int) bool { n.downstreamMutex.Lock() if n.downstreamDataSize < 0 && n.downstreamQueue.Len() == 0 { if n.debugMessageLevel >= 1 { - fmt.Printf("node: %d, tick: %d, reseting queued downstream capacity %d -> 0\n", n.nodeID, n.currentTick, n.upstreamDataSize) + fmt.Printf("node: %d, tick: %d, resetting queued downstream capacity %d -> 0\n", n.nodeID, n.currentTick, n.upstreamDataSize) } n.downstreamDataSize = 0 } @@ -179,7 +179,7 @@ func (n *BandwidthFilter) Tick(newClockTime int) bool { // adjust the upstream size. if n.upstreamDataSize < 0 && n.upstreamQueue.Len() == 0 { if n.debugMessageLevel >= 1 { - fmt.Printf("node: %d, tick: %d, reseting queued upstream capacity %d -> 0\n", n.nodeID, n.currentTick, n.upstreamDataSize) + fmt.Printf("node: %d, tick: %d, resetting queued upstream capacity %d -> 0\n", n.nodeID, n.currentTick, n.upstreamDataSize) } n.upstreamDataSize = 0 } diff --git a/agreement/gossip/network.go b/agreement/gossip/network.go index e6b7d77aad..43eefd2db5 100644 --- a/agreement/gossip/network.go +++ b/agreement/gossip/network.go @@ -32,9 +32,11 @@ import ( ) var messagesHandledTotal = metrics.MakeCounter(metrics.AgreementMessagesHandled) -var messagesHandledByType = metrics.NewTagCounter("algod_agreement_handled_{TAG}", "Number of agreement messages handled per type") +var messagesHandledByType = metrics.NewTagCounter("algod_agreement_handled_{TAG}", "Number of agreement {TAG} messages handled", + agreementVoteMessageType, agreementProposalMessageType, agreementBundleMessageType) var messagesDroppedTotal = metrics.MakeCounter(metrics.AgreementMessagesDropped) -var messagesDroppedByType = metrics.NewTagCounter("algod_agreement_dropped_{TAG}", "Number of agreement messages handled per type") +var messagesDroppedByType = metrics.NewTagCounter("algod_agreement_dropped_{TAG}", "Number of agreement {TAG} messages dropped", + agreementVoteMessageType, agreementProposalMessageType, agreementBundleMessageType) const ( agreementVoteMessageType = "vote" diff --git a/agreement/msgp_gen.go b/agreement/msgp_gen.go index 8df6c47a99..4f2252b875 100644 --- a/agreement/msgp_gen.go +++ b/agreement/msgp_gen.go @@ -5,11 +5,12 @@ package agreement import ( "sort" + "github.com/algorand/msgp/msgp" + "github.com/algorand/go-algorand/config" "github.com/algorand/go-algorand/data/basics" "github.com/algorand/go-algorand/data/bookkeeping" "github.com/algorand/go-algorand/protocol" - "github.com/algorand/msgp/msgp" ) // The following msgp objects are implemented in this file: @@ -1355,124 +1356,128 @@ func (z period) MsgIsZero() bool { func (z *proposal) MarshalMsg(b []byte) (o []byte) { o = msgp.Require(b, z.Msgsize()) // omitempty: check for empty values - zb0004Len := uint32(28) - var zb0004Mask uint64 /* 35 bits */ + zb0004Len := uint32(29) + var zb0004Mask uint64 /* 37 bits */ if len((*z).unauthenticatedProposal.Block.BlockHeader.CompactCert) == 0 { zb0004Len-- - zb0004Mask |= 0x20 + zb0004Mask |= 0x40 } if (*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsLevel == 0 { zb0004Len-- - zb0004Mask |= 0x40 + zb0004Mask |= 0x80 } if (*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.FeeSink.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x80 + zb0004Mask |= 0x100 } if (*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsResidue == 0 { zb0004Len-- - zb0004Mask |= 0x100 + zb0004Mask |= 0x200 } if (*z).unauthenticatedProposal.Block.BlockHeader.GenesisID == "" { zb0004Len-- - zb0004Mask |= 0x200 + zb0004Mask |= 0x400 } if (*z).unauthenticatedProposal.Block.BlockHeader.GenesisHash.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x400 + zb0004Mask |= 0x800 } if (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocolVoteBefore.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x800 + zb0004Mask |= 0x1000 } if (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocol.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x1000 + zb0004Mask |= 0x2000 } if (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocolSwitchOn.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x2000 + zb0004Mask |= 0x4000 } if (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocolApprovals == 0 { zb0004Len-- - zb0004Mask |= 0x4000 + zb0004Mask |= 0x8000 } if (*z).unauthenticatedProposal.OriginalPeriod == 0 { zb0004Len-- - zb0004Mask |= 0x8000 + zb0004Mask |= 0x10000 } if (*z).unauthenticatedProposal.OriginalProposer.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x10000 + zb0004Mask |= 0x20000 } if len((*z).unauthenticatedProposal.Block.BlockHeader.ParticipationUpdates.ExpiredParticipationAccounts) == 0 { zb0004Len-- - zb0004Mask |= 0x20000 + zb0004Mask |= 0x40000 } if (*z).unauthenticatedProposal.Block.BlockHeader.Branch.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x40000 + zb0004Mask |= 0x80000 } if (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.CurrentProtocol.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x80000 + zb0004Mask |= 0x100000 } if (*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsRate == 0 { zb0004Len-- - zb0004Mask |= 0x100000 + zb0004Mask |= 0x200000 } if (*z).unauthenticatedProposal.Block.BlockHeader.Round.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x200000 + zb0004Mask |= 0x400000 } if (*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsRecalculationRound.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x400000 + zb0004Mask |= 0x800000 } if (*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsPool.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x800000 + zb0004Mask |= 0x1000000 } if (*z).unauthenticatedProposal.SeedProof.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x1000000 + zb0004Mask |= 0x2000000 } if (*z).unauthenticatedProposal.Block.BlockHeader.Seed.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x2000000 + zb0004Mask |= 0x4000000 } if (*z).unauthenticatedProposal.Block.BlockHeader.TxnCounter == 0 { zb0004Len-- - zb0004Mask |= 0x4000000 + zb0004Mask |= 0x8000000 } if (*z).unauthenticatedProposal.Block.BlockHeader.TimeStamp == 0 { zb0004Len-- - zb0004Mask |= 0x8000000 + zb0004Mask |= 0x10000000 } - if (*z).unauthenticatedProposal.Block.BlockHeader.TxnRoot.MsgIsZero() { + if (*z).unauthenticatedProposal.Block.BlockHeader.TxnCommitments.NativeSha512_256Commitment.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x10000000 + zb0004Mask |= 0x20000000 + } + if (*z).unauthenticatedProposal.Block.BlockHeader.TxnCommitments.Sha256Commitment.MsgIsZero() { + zb0004Len-- + zb0004Mask |= 0x40000000 } if (*z).unauthenticatedProposal.Block.Payset.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x20000000 + zb0004Mask |= 0x80000000 } if (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeVote.UpgradeDelay.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x40000000 + zb0004Mask |= 0x100000000 } if (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeVote.UpgradePropose.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x80000000 + zb0004Mask |= 0x200000000 } if (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeVote.UpgradeApprove == false { zb0004Len-- - zb0004Mask |= 0x100000000 + zb0004Mask |= 0x400000000 } // variable map header, size zb0004Len o = msgp.AppendMapHeader(o, zb0004Len) if zb0004Len != 0 { - if (zb0004Mask & 0x20) == 0 { // if not empty + if (zb0004Mask & 0x40) == 0 { // if not empty // string "cc" o = append(o, 0xa2, 0x63, 0x63) if (*z).unauthenticatedProposal.Block.BlockHeader.CompactCert == nil { @@ -1492,62 +1497,62 @@ func (z *proposal) MarshalMsg(b []byte) (o []byte) { o = zb0002.MarshalMsg(o) } } - if (zb0004Mask & 0x40) == 0 { // if not empty + if (zb0004Mask & 0x80) == 0 { // if not empty // string "earn" o = append(o, 0xa4, 0x65, 0x61, 0x72, 0x6e) o = msgp.AppendUint64(o, (*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsLevel) } - if (zb0004Mask & 0x80) == 0 { // if not empty + if (zb0004Mask & 0x100) == 0 { // if not empty // string "fees" o = append(o, 0xa4, 0x66, 0x65, 0x65, 0x73) o = (*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.FeeSink.MarshalMsg(o) } - if (zb0004Mask & 0x100) == 0 { // if not empty + if (zb0004Mask & 0x200) == 0 { // if not empty // string "frac" o = append(o, 0xa4, 0x66, 0x72, 0x61, 0x63) o = msgp.AppendUint64(o, (*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsResidue) } - if (zb0004Mask & 0x200) == 0 { // if not empty + if (zb0004Mask & 0x400) == 0 { // if not empty // string "gen" o = append(o, 0xa3, 0x67, 0x65, 0x6e) o = msgp.AppendString(o, (*z).unauthenticatedProposal.Block.BlockHeader.GenesisID) } - if (zb0004Mask & 0x400) == 0 { // if not empty + if (zb0004Mask & 0x800) == 0 { // if not empty // string "gh" o = append(o, 0xa2, 0x67, 0x68) o = (*z).unauthenticatedProposal.Block.BlockHeader.GenesisHash.MarshalMsg(o) } - if (zb0004Mask & 0x800) == 0 { // if not empty + if (zb0004Mask & 0x1000) == 0 { // if not empty // string "nextbefore" o = append(o, 0xaa, 0x6e, 0x65, 0x78, 0x74, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65) o = (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocolVoteBefore.MarshalMsg(o) } - if (zb0004Mask & 0x1000) == 0 { // if not empty + if (zb0004Mask & 0x2000) == 0 { // if not empty // string "nextproto" o = append(o, 0xa9, 0x6e, 0x65, 0x78, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f) o = (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocol.MarshalMsg(o) } - if (zb0004Mask & 0x2000) == 0 { // if not empty + if (zb0004Mask & 0x4000) == 0 { // if not empty // string "nextswitch" o = append(o, 0xaa, 0x6e, 0x65, 0x78, 0x74, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68) o = (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocolSwitchOn.MarshalMsg(o) } - if (zb0004Mask & 0x4000) == 0 { // if not empty + if (zb0004Mask & 0x8000) == 0 { // if not empty // string "nextyes" o = append(o, 0xa7, 0x6e, 0x65, 0x78, 0x74, 0x79, 0x65, 0x73) o = msgp.AppendUint64(o, (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocolApprovals) } - if (zb0004Mask & 0x8000) == 0 { // if not empty + if (zb0004Mask & 0x10000) == 0 { // if not empty // string "oper" o = append(o, 0xa4, 0x6f, 0x70, 0x65, 0x72) o = msgp.AppendUint64(o, uint64((*z).unauthenticatedProposal.OriginalPeriod)) } - if (zb0004Mask & 0x10000) == 0 { // if not empty + if (zb0004Mask & 0x20000) == 0 { // if not empty // string "oprop" o = append(o, 0xa5, 0x6f, 0x70, 0x72, 0x6f, 0x70) o = (*z).unauthenticatedProposal.OriginalProposer.MarshalMsg(o) } - if (zb0004Mask & 0x20000) == 0 { // if not empty + if (zb0004Mask & 0x40000) == 0 { // if not empty // string "partupdrmv" o = append(o, 0xaa, 0x70, 0x61, 0x72, 0x74, 0x75, 0x70, 0x64, 0x72, 0x6d, 0x76) if (*z).unauthenticatedProposal.Block.BlockHeader.ParticipationUpdates.ExpiredParticipationAccounts == nil { @@ -1559,77 +1564,82 @@ func (z *proposal) MarshalMsg(b []byte) (o []byte) { o = (*z).unauthenticatedProposal.Block.BlockHeader.ParticipationUpdates.ExpiredParticipationAccounts[zb0003].MarshalMsg(o) } } - if (zb0004Mask & 0x40000) == 0 { // if not empty + if (zb0004Mask & 0x80000) == 0 { // if not empty // string "prev" o = append(o, 0xa4, 0x70, 0x72, 0x65, 0x76) o = (*z).unauthenticatedProposal.Block.BlockHeader.Branch.MarshalMsg(o) } - if (zb0004Mask & 0x80000) == 0 { // if not empty + if (zb0004Mask & 0x100000) == 0 { // if not empty // string "proto" o = append(o, 0xa5, 0x70, 0x72, 0x6f, 0x74, 0x6f) o = (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.CurrentProtocol.MarshalMsg(o) } - if (zb0004Mask & 0x100000) == 0 { // if not empty + if (zb0004Mask & 0x200000) == 0 { // if not empty // string "rate" o = append(o, 0xa4, 0x72, 0x61, 0x74, 0x65) o = msgp.AppendUint64(o, (*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsRate) } - if (zb0004Mask & 0x200000) == 0 { // if not empty + if (zb0004Mask & 0x400000) == 0 { // if not empty // string "rnd" o = append(o, 0xa3, 0x72, 0x6e, 0x64) o = (*z).unauthenticatedProposal.Block.BlockHeader.Round.MarshalMsg(o) } - if (zb0004Mask & 0x400000) == 0 { // if not empty + if (zb0004Mask & 0x800000) == 0 { // if not empty // string "rwcalr" o = append(o, 0xa6, 0x72, 0x77, 0x63, 0x61, 0x6c, 0x72) o = (*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsRecalculationRound.MarshalMsg(o) } - if (zb0004Mask & 0x800000) == 0 { // if not empty + if (zb0004Mask & 0x1000000) == 0 { // if not empty // string "rwd" o = append(o, 0xa3, 0x72, 0x77, 0x64) o = (*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsPool.MarshalMsg(o) } - if (zb0004Mask & 0x1000000) == 0 { // if not empty + if (zb0004Mask & 0x2000000) == 0 { // if not empty // string "sdpf" o = append(o, 0xa4, 0x73, 0x64, 0x70, 0x66) o = (*z).unauthenticatedProposal.SeedProof.MarshalMsg(o) } - if (zb0004Mask & 0x2000000) == 0 { // if not empty + if (zb0004Mask & 0x4000000) == 0 { // if not empty // string "seed" o = append(o, 0xa4, 0x73, 0x65, 0x65, 0x64) o = (*z).unauthenticatedProposal.Block.BlockHeader.Seed.MarshalMsg(o) } - if (zb0004Mask & 0x4000000) == 0 { // if not empty + if (zb0004Mask & 0x8000000) == 0 { // if not empty // string "tc" o = append(o, 0xa2, 0x74, 0x63) o = msgp.AppendUint64(o, (*z).unauthenticatedProposal.Block.BlockHeader.TxnCounter) } - if (zb0004Mask & 0x8000000) == 0 { // if not empty + if (zb0004Mask & 0x10000000) == 0 { // if not empty // string "ts" o = append(o, 0xa2, 0x74, 0x73) o = msgp.AppendInt64(o, (*z).unauthenticatedProposal.Block.BlockHeader.TimeStamp) } - if (zb0004Mask & 0x10000000) == 0 { // if not empty + if (zb0004Mask & 0x20000000) == 0 { // if not empty // string "txn" o = append(o, 0xa3, 0x74, 0x78, 0x6e) - o = (*z).unauthenticatedProposal.Block.BlockHeader.TxnRoot.MarshalMsg(o) + o = (*z).unauthenticatedProposal.Block.BlockHeader.TxnCommitments.NativeSha512_256Commitment.MarshalMsg(o) } - if (zb0004Mask & 0x20000000) == 0 { // if not empty + if (zb0004Mask & 0x40000000) == 0 { // if not empty + // string "txn256" + o = append(o, 0xa6, 0x74, 0x78, 0x6e, 0x32, 0x35, 0x36) + o = (*z).unauthenticatedProposal.Block.BlockHeader.TxnCommitments.Sha256Commitment.MarshalMsg(o) + } + if (zb0004Mask & 0x80000000) == 0 { // if not empty // string "txns" o = append(o, 0xa4, 0x74, 0x78, 0x6e, 0x73) o = (*z).unauthenticatedProposal.Block.Payset.MarshalMsg(o) } - if (zb0004Mask & 0x40000000) == 0 { // if not empty + if (zb0004Mask & 0x100000000) == 0 { // if not empty // string "upgradedelay" o = append(o, 0xac, 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x64, 0x65, 0x6c, 0x61, 0x79) o = (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeVote.UpgradeDelay.MarshalMsg(o) } - if (zb0004Mask & 0x80000000) == 0 { // if not empty + if (zb0004Mask & 0x200000000) == 0 { // if not empty // string "upgradeprop" o = append(o, 0xab, 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x70, 0x72, 0x6f, 0x70) o = (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeVote.UpgradePropose.MarshalMsg(o) } - if (zb0004Mask & 0x100000000) == 0 { // if not empty + if (zb0004Mask & 0x400000000) == 0 { // if not empty // string "upgradeyes" o = append(o, 0xaa, 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x79, 0x65, 0x73) o = msgp.AppendBool(o, (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeVote.UpgradeApprove) @@ -1682,9 +1692,17 @@ func (z *proposal) UnmarshalMsg(bts []byte) (o []byte, err error) { } if zb0004 > 0 { zb0004-- - bts, err = (*z).unauthenticatedProposal.Block.BlockHeader.TxnRoot.UnmarshalMsg(bts) + bts, err = (*z).unauthenticatedProposal.Block.BlockHeader.TxnCommitments.NativeSha512_256Commitment.UnmarshalMsg(bts) if err != nil { - err = msgp.WrapError(err, "struct-from-array", "TxnRoot") + err = msgp.WrapError(err, "struct-from-array", "NativeSha512_256Commitment") + return + } + } + if zb0004 > 0 { + zb0004-- + bts, err = (*z).unauthenticatedProposal.Block.BlockHeader.TxnCommitments.Sha256Commitment.UnmarshalMsg(bts) + if err != nil { + err = msgp.WrapError(err, "struct-from-array", "Sha256Commitment") return } } @@ -1975,9 +1993,15 @@ func (z *proposal) UnmarshalMsg(bts []byte) (o []byte, err error) { return } case "txn": - bts, err = (*z).unauthenticatedProposal.Block.BlockHeader.TxnRoot.UnmarshalMsg(bts) + bts, err = (*z).unauthenticatedProposal.Block.BlockHeader.TxnCommitments.NativeSha512_256Commitment.UnmarshalMsg(bts) if err != nil { - err = msgp.WrapError(err, "TxnRoot") + err = msgp.WrapError(err, "NativeSha512_256Commitment") + return + } + case "txn256": + bts, err = (*z).unauthenticatedProposal.Block.BlockHeader.TxnCommitments.Sha256Commitment.UnmarshalMsg(bts) + if err != nil { + err = msgp.WrapError(err, "Sha256Commitment") return } case "ts": @@ -2197,7 +2221,7 @@ func (_ *proposal) CanUnmarshalMsg(z interface{}) bool { // Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message func (z *proposal) Msgsize() (s int) { - s = 3 + 4 + (*z).unauthenticatedProposal.Block.BlockHeader.Round.Msgsize() + 5 + (*z).unauthenticatedProposal.Block.BlockHeader.Branch.Msgsize() + 5 + (*z).unauthenticatedProposal.Block.BlockHeader.Seed.Msgsize() + 4 + (*z).unauthenticatedProposal.Block.BlockHeader.TxnRoot.Msgsize() + 3 + msgp.Int64Size + 4 + msgp.StringPrefixSize + len((*z).unauthenticatedProposal.Block.BlockHeader.GenesisID) + 3 + (*z).unauthenticatedProposal.Block.BlockHeader.GenesisHash.Msgsize() + 5 + (*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.FeeSink.Msgsize() + 4 + (*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsPool.Msgsize() + 5 + msgp.Uint64Size + 5 + msgp.Uint64Size + 5 + msgp.Uint64Size + 7 + (*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsRecalculationRound.Msgsize() + 6 + (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.CurrentProtocol.Msgsize() + 10 + (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocol.Msgsize() + 8 + msgp.Uint64Size + 11 + (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocolVoteBefore.Msgsize() + 11 + (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocolSwitchOn.Msgsize() + 12 + (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeVote.UpgradePropose.Msgsize() + 13 + (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeVote.UpgradeDelay.Msgsize() + 11 + msgp.BoolSize + 3 + msgp.Uint64Size + 3 + msgp.MapHeaderSize + s = 3 + 4 + (*z).unauthenticatedProposal.Block.BlockHeader.Round.Msgsize() + 5 + (*z).unauthenticatedProposal.Block.BlockHeader.Branch.Msgsize() + 5 + (*z).unauthenticatedProposal.Block.BlockHeader.Seed.Msgsize() + 4 + (*z).unauthenticatedProposal.Block.BlockHeader.TxnCommitments.NativeSha512_256Commitment.Msgsize() + 7 + (*z).unauthenticatedProposal.Block.BlockHeader.TxnCommitments.Sha256Commitment.Msgsize() + 3 + msgp.Int64Size + 4 + msgp.StringPrefixSize + len((*z).unauthenticatedProposal.Block.BlockHeader.GenesisID) + 3 + (*z).unauthenticatedProposal.Block.BlockHeader.GenesisHash.Msgsize() + 5 + (*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.FeeSink.Msgsize() + 4 + (*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsPool.Msgsize() + 5 + msgp.Uint64Size + 5 + msgp.Uint64Size + 5 + msgp.Uint64Size + 7 + (*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsRecalculationRound.Msgsize() + 6 + (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.CurrentProtocol.Msgsize() + 10 + (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocol.Msgsize() + 8 + msgp.Uint64Size + 11 + (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocolVoteBefore.Msgsize() + 11 + (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocolSwitchOn.Msgsize() + 12 + (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeVote.UpgradePropose.Msgsize() + 13 + (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeVote.UpgradeDelay.Msgsize() + 11 + msgp.BoolSize + 3 + msgp.Uint64Size + 3 + msgp.MapHeaderSize if (*z).unauthenticatedProposal.Block.BlockHeader.CompactCert != nil { for zb0001, zb0002 := range (*z).unauthenticatedProposal.Block.BlockHeader.CompactCert { _ = zb0001 @@ -2215,7 +2239,7 @@ func (z *proposal) Msgsize() (s int) { // MsgIsZero returns whether this is a zero value func (z *proposal) MsgIsZero() bool { - return ((*z).unauthenticatedProposal.Block.BlockHeader.Round.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.Branch.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.Seed.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.TxnRoot.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.TimeStamp == 0) && ((*z).unauthenticatedProposal.Block.BlockHeader.GenesisID == "") && ((*z).unauthenticatedProposal.Block.BlockHeader.GenesisHash.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.FeeSink.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsPool.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsLevel == 0) && ((*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsRate == 0) && ((*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsResidue == 0) && ((*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsRecalculationRound.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.CurrentProtocol.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocol.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocolApprovals == 0) && ((*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocolVoteBefore.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocolSwitchOn.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.UpgradeVote.UpgradePropose.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.UpgradeVote.UpgradeDelay.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.UpgradeVote.UpgradeApprove == false) && ((*z).unauthenticatedProposal.Block.BlockHeader.TxnCounter == 0) && (len((*z).unauthenticatedProposal.Block.BlockHeader.CompactCert) == 0) && (len((*z).unauthenticatedProposal.Block.BlockHeader.ParticipationUpdates.ExpiredParticipationAccounts) == 0) && ((*z).unauthenticatedProposal.Block.Payset.MsgIsZero()) && ((*z).unauthenticatedProposal.SeedProof.MsgIsZero()) && ((*z).unauthenticatedProposal.OriginalPeriod == 0) && ((*z).unauthenticatedProposal.OriginalProposer.MsgIsZero()) + return ((*z).unauthenticatedProposal.Block.BlockHeader.Round.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.Branch.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.Seed.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.TxnCommitments.NativeSha512_256Commitment.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.TxnCommitments.Sha256Commitment.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.TimeStamp == 0) && ((*z).unauthenticatedProposal.Block.BlockHeader.GenesisID == "") && ((*z).unauthenticatedProposal.Block.BlockHeader.GenesisHash.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.FeeSink.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsPool.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsLevel == 0) && ((*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsRate == 0) && ((*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsResidue == 0) && ((*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsRecalculationRound.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.CurrentProtocol.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocol.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocolApprovals == 0) && ((*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocolVoteBefore.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocolSwitchOn.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.UpgradeVote.UpgradePropose.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.UpgradeVote.UpgradeDelay.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.UpgradeVote.UpgradeApprove == false) && ((*z).unauthenticatedProposal.Block.BlockHeader.TxnCounter == 0) && (len((*z).unauthenticatedProposal.Block.BlockHeader.CompactCert) == 0) && (len((*z).unauthenticatedProposal.Block.BlockHeader.ParticipationUpdates.ExpiredParticipationAccounts) == 0) && ((*z).unauthenticatedProposal.Block.Payset.MsgIsZero()) && ((*z).unauthenticatedProposal.SeedProof.MsgIsZero()) && ((*z).unauthenticatedProposal.OriginalPeriod == 0) && ((*z).unauthenticatedProposal.OriginalProposer.MsgIsZero()) } // MarshalMsg implements msgp.Marshaler @@ -3094,128 +3118,132 @@ func (z step) MsgIsZero() bool { func (z *transmittedPayload) MarshalMsg(b []byte) (o []byte) { o = msgp.Require(b, z.Msgsize()) // omitempty: check for empty values - zb0004Len := uint32(29) - var zb0004Mask uint64 /* 35 bits */ + zb0004Len := uint32(30) + var zb0004Mask uint64 /* 37 bits */ if len((*z).unauthenticatedProposal.Block.BlockHeader.CompactCert) == 0 { zb0004Len-- - zb0004Mask |= 0x40 + zb0004Mask |= 0x80 } if (*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsLevel == 0 { zb0004Len-- - zb0004Mask |= 0x80 + zb0004Mask |= 0x100 } if (*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.FeeSink.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x100 + zb0004Mask |= 0x200 } if (*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsResidue == 0 { zb0004Len-- - zb0004Mask |= 0x200 + zb0004Mask |= 0x400 } if (*z).unauthenticatedProposal.Block.BlockHeader.GenesisID == "" { zb0004Len-- - zb0004Mask |= 0x400 + zb0004Mask |= 0x800 } if (*z).unauthenticatedProposal.Block.BlockHeader.GenesisHash.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x800 + zb0004Mask |= 0x1000 } if (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocolVoteBefore.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x1000 + zb0004Mask |= 0x2000 } if (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocol.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x2000 + zb0004Mask |= 0x4000 } if (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocolSwitchOn.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x4000 + zb0004Mask |= 0x8000 } if (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocolApprovals == 0 { zb0004Len-- - zb0004Mask |= 0x8000 + zb0004Mask |= 0x10000 } if (*z).unauthenticatedProposal.OriginalPeriod == 0 { zb0004Len-- - zb0004Mask |= 0x10000 + zb0004Mask |= 0x20000 } if (*z).unauthenticatedProposal.OriginalProposer.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x20000 + zb0004Mask |= 0x40000 } if len((*z).unauthenticatedProposal.Block.BlockHeader.ParticipationUpdates.ExpiredParticipationAccounts) == 0 { zb0004Len-- - zb0004Mask |= 0x40000 + zb0004Mask |= 0x80000 } if (*z).unauthenticatedProposal.Block.BlockHeader.Branch.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x80000 + zb0004Mask |= 0x100000 } if (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.CurrentProtocol.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x100000 + zb0004Mask |= 0x200000 } if (*z).PriorVote.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x200000 + zb0004Mask |= 0x400000 } if (*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsRate == 0 { zb0004Len-- - zb0004Mask |= 0x400000 + zb0004Mask |= 0x800000 } if (*z).unauthenticatedProposal.Block.BlockHeader.Round.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x800000 + zb0004Mask |= 0x1000000 } if (*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsRecalculationRound.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x1000000 + zb0004Mask |= 0x2000000 } if (*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsPool.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x2000000 + zb0004Mask |= 0x4000000 } if (*z).unauthenticatedProposal.SeedProof.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x4000000 + zb0004Mask |= 0x8000000 } if (*z).unauthenticatedProposal.Block.BlockHeader.Seed.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x8000000 + zb0004Mask |= 0x10000000 } if (*z).unauthenticatedProposal.Block.BlockHeader.TxnCounter == 0 { zb0004Len-- - zb0004Mask |= 0x10000000 + zb0004Mask |= 0x20000000 } if (*z).unauthenticatedProposal.Block.BlockHeader.TimeStamp == 0 { zb0004Len-- - zb0004Mask |= 0x20000000 + zb0004Mask |= 0x40000000 } - if (*z).unauthenticatedProposal.Block.BlockHeader.TxnRoot.MsgIsZero() { + if (*z).unauthenticatedProposal.Block.BlockHeader.TxnCommitments.NativeSha512_256Commitment.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x40000000 + zb0004Mask |= 0x80000000 + } + if (*z).unauthenticatedProposal.Block.BlockHeader.TxnCommitments.Sha256Commitment.MsgIsZero() { + zb0004Len-- + zb0004Mask |= 0x100000000 } if (*z).unauthenticatedProposal.Block.Payset.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x80000000 + zb0004Mask |= 0x200000000 } if (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeVote.UpgradeDelay.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x100000000 + zb0004Mask |= 0x400000000 } if (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeVote.UpgradePropose.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x200000000 + zb0004Mask |= 0x800000000 } if (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeVote.UpgradeApprove == false { zb0004Len-- - zb0004Mask |= 0x400000000 + zb0004Mask |= 0x1000000000 } // variable map header, size zb0004Len o = msgp.AppendMapHeader(o, zb0004Len) if zb0004Len != 0 { - if (zb0004Mask & 0x40) == 0 { // if not empty + if (zb0004Mask & 0x80) == 0 { // if not empty // string "cc" o = append(o, 0xa2, 0x63, 0x63) if (*z).unauthenticatedProposal.Block.BlockHeader.CompactCert == nil { @@ -3235,62 +3263,62 @@ func (z *transmittedPayload) MarshalMsg(b []byte) (o []byte) { o = zb0002.MarshalMsg(o) } } - if (zb0004Mask & 0x80) == 0 { // if not empty + if (zb0004Mask & 0x100) == 0 { // if not empty // string "earn" o = append(o, 0xa4, 0x65, 0x61, 0x72, 0x6e) o = msgp.AppendUint64(o, (*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsLevel) } - if (zb0004Mask & 0x100) == 0 { // if not empty + if (zb0004Mask & 0x200) == 0 { // if not empty // string "fees" o = append(o, 0xa4, 0x66, 0x65, 0x65, 0x73) o = (*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.FeeSink.MarshalMsg(o) } - if (zb0004Mask & 0x200) == 0 { // if not empty + if (zb0004Mask & 0x400) == 0 { // if not empty // string "frac" o = append(o, 0xa4, 0x66, 0x72, 0x61, 0x63) o = msgp.AppendUint64(o, (*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsResidue) } - if (zb0004Mask & 0x400) == 0 { // if not empty + if (zb0004Mask & 0x800) == 0 { // if not empty // string "gen" o = append(o, 0xa3, 0x67, 0x65, 0x6e) o = msgp.AppendString(o, (*z).unauthenticatedProposal.Block.BlockHeader.GenesisID) } - if (zb0004Mask & 0x800) == 0 { // if not empty + if (zb0004Mask & 0x1000) == 0 { // if not empty // string "gh" o = append(o, 0xa2, 0x67, 0x68) o = (*z).unauthenticatedProposal.Block.BlockHeader.GenesisHash.MarshalMsg(o) } - if (zb0004Mask & 0x1000) == 0 { // if not empty + if (zb0004Mask & 0x2000) == 0 { // if not empty // string "nextbefore" o = append(o, 0xaa, 0x6e, 0x65, 0x78, 0x74, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65) o = (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocolVoteBefore.MarshalMsg(o) } - if (zb0004Mask & 0x2000) == 0 { // if not empty + if (zb0004Mask & 0x4000) == 0 { // if not empty // string "nextproto" o = append(o, 0xa9, 0x6e, 0x65, 0x78, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f) o = (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocol.MarshalMsg(o) } - if (zb0004Mask & 0x4000) == 0 { // if not empty + if (zb0004Mask & 0x8000) == 0 { // if not empty // string "nextswitch" o = append(o, 0xaa, 0x6e, 0x65, 0x78, 0x74, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68) o = (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocolSwitchOn.MarshalMsg(o) } - if (zb0004Mask & 0x8000) == 0 { // if not empty + if (zb0004Mask & 0x10000) == 0 { // if not empty // string "nextyes" o = append(o, 0xa7, 0x6e, 0x65, 0x78, 0x74, 0x79, 0x65, 0x73) o = msgp.AppendUint64(o, (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocolApprovals) } - if (zb0004Mask & 0x10000) == 0 { // if not empty + if (zb0004Mask & 0x20000) == 0 { // if not empty // string "oper" o = append(o, 0xa4, 0x6f, 0x70, 0x65, 0x72) o = msgp.AppendUint64(o, uint64((*z).unauthenticatedProposal.OriginalPeriod)) } - if (zb0004Mask & 0x20000) == 0 { // if not empty + if (zb0004Mask & 0x40000) == 0 { // if not empty // string "oprop" o = append(o, 0xa5, 0x6f, 0x70, 0x72, 0x6f, 0x70) o = (*z).unauthenticatedProposal.OriginalProposer.MarshalMsg(o) } - if (zb0004Mask & 0x40000) == 0 { // if not empty + if (zb0004Mask & 0x80000) == 0 { // if not empty // string "partupdrmv" o = append(o, 0xaa, 0x70, 0x61, 0x72, 0x74, 0x75, 0x70, 0x64, 0x72, 0x6d, 0x76) if (*z).unauthenticatedProposal.Block.BlockHeader.ParticipationUpdates.ExpiredParticipationAccounts == nil { @@ -3302,82 +3330,87 @@ func (z *transmittedPayload) MarshalMsg(b []byte) (o []byte) { o = (*z).unauthenticatedProposal.Block.BlockHeader.ParticipationUpdates.ExpiredParticipationAccounts[zb0003].MarshalMsg(o) } } - if (zb0004Mask & 0x80000) == 0 { // if not empty + if (zb0004Mask & 0x100000) == 0 { // if not empty // string "prev" o = append(o, 0xa4, 0x70, 0x72, 0x65, 0x76) o = (*z).unauthenticatedProposal.Block.BlockHeader.Branch.MarshalMsg(o) } - if (zb0004Mask & 0x100000) == 0 { // if not empty + if (zb0004Mask & 0x200000) == 0 { // if not empty // string "proto" o = append(o, 0xa5, 0x70, 0x72, 0x6f, 0x74, 0x6f) o = (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.CurrentProtocol.MarshalMsg(o) } - if (zb0004Mask & 0x200000) == 0 { // if not empty + if (zb0004Mask & 0x400000) == 0 { // if not empty // string "pv" o = append(o, 0xa2, 0x70, 0x76) o = (*z).PriorVote.MarshalMsg(o) } - if (zb0004Mask & 0x400000) == 0 { // if not empty + if (zb0004Mask & 0x800000) == 0 { // if not empty // string "rate" o = append(o, 0xa4, 0x72, 0x61, 0x74, 0x65) o = msgp.AppendUint64(o, (*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsRate) } - if (zb0004Mask & 0x800000) == 0 { // if not empty + if (zb0004Mask & 0x1000000) == 0 { // if not empty // string "rnd" o = append(o, 0xa3, 0x72, 0x6e, 0x64) o = (*z).unauthenticatedProposal.Block.BlockHeader.Round.MarshalMsg(o) } - if (zb0004Mask & 0x1000000) == 0 { // if not empty + if (zb0004Mask & 0x2000000) == 0 { // if not empty // string "rwcalr" o = append(o, 0xa6, 0x72, 0x77, 0x63, 0x61, 0x6c, 0x72) o = (*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsRecalculationRound.MarshalMsg(o) } - if (zb0004Mask & 0x2000000) == 0 { // if not empty + if (zb0004Mask & 0x4000000) == 0 { // if not empty // string "rwd" o = append(o, 0xa3, 0x72, 0x77, 0x64) o = (*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsPool.MarshalMsg(o) } - if (zb0004Mask & 0x4000000) == 0 { // if not empty + if (zb0004Mask & 0x8000000) == 0 { // if not empty // string "sdpf" o = append(o, 0xa4, 0x73, 0x64, 0x70, 0x66) o = (*z).unauthenticatedProposal.SeedProof.MarshalMsg(o) } - if (zb0004Mask & 0x8000000) == 0 { // if not empty + if (zb0004Mask & 0x10000000) == 0 { // if not empty // string "seed" o = append(o, 0xa4, 0x73, 0x65, 0x65, 0x64) o = (*z).unauthenticatedProposal.Block.BlockHeader.Seed.MarshalMsg(o) } - if (zb0004Mask & 0x10000000) == 0 { // if not empty + if (zb0004Mask & 0x20000000) == 0 { // if not empty // string "tc" o = append(o, 0xa2, 0x74, 0x63) o = msgp.AppendUint64(o, (*z).unauthenticatedProposal.Block.BlockHeader.TxnCounter) } - if (zb0004Mask & 0x20000000) == 0 { // if not empty + if (zb0004Mask & 0x40000000) == 0 { // if not empty // string "ts" o = append(o, 0xa2, 0x74, 0x73) o = msgp.AppendInt64(o, (*z).unauthenticatedProposal.Block.BlockHeader.TimeStamp) } - if (zb0004Mask & 0x40000000) == 0 { // if not empty + if (zb0004Mask & 0x80000000) == 0 { // if not empty // string "txn" o = append(o, 0xa3, 0x74, 0x78, 0x6e) - o = (*z).unauthenticatedProposal.Block.BlockHeader.TxnRoot.MarshalMsg(o) + o = (*z).unauthenticatedProposal.Block.BlockHeader.TxnCommitments.NativeSha512_256Commitment.MarshalMsg(o) } - if (zb0004Mask & 0x80000000) == 0 { // if not empty + if (zb0004Mask & 0x100000000) == 0 { // if not empty + // string "txn256" + o = append(o, 0xa6, 0x74, 0x78, 0x6e, 0x32, 0x35, 0x36) + o = (*z).unauthenticatedProposal.Block.BlockHeader.TxnCommitments.Sha256Commitment.MarshalMsg(o) + } + if (zb0004Mask & 0x200000000) == 0 { // if not empty // string "txns" o = append(o, 0xa4, 0x74, 0x78, 0x6e, 0x73) o = (*z).unauthenticatedProposal.Block.Payset.MarshalMsg(o) } - if (zb0004Mask & 0x100000000) == 0 { // if not empty + if (zb0004Mask & 0x400000000) == 0 { // if not empty // string "upgradedelay" o = append(o, 0xac, 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x64, 0x65, 0x6c, 0x61, 0x79) o = (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeVote.UpgradeDelay.MarshalMsg(o) } - if (zb0004Mask & 0x200000000) == 0 { // if not empty + if (zb0004Mask & 0x800000000) == 0 { // if not empty // string "upgradeprop" o = append(o, 0xab, 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x70, 0x72, 0x6f, 0x70) o = (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeVote.UpgradePropose.MarshalMsg(o) } - if (zb0004Mask & 0x400000000) == 0 { // if not empty + if (zb0004Mask & 0x1000000000) == 0 { // if not empty // string "upgradeyes" o = append(o, 0xaa, 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x79, 0x65, 0x73) o = msgp.AppendBool(o, (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeVote.UpgradeApprove) @@ -3430,9 +3463,17 @@ func (z *transmittedPayload) UnmarshalMsg(bts []byte) (o []byte, err error) { } if zb0004 > 0 { zb0004-- - bts, err = (*z).unauthenticatedProposal.Block.BlockHeader.TxnRoot.UnmarshalMsg(bts) + bts, err = (*z).unauthenticatedProposal.Block.BlockHeader.TxnCommitments.NativeSha512_256Commitment.UnmarshalMsg(bts) + if err != nil { + err = msgp.WrapError(err, "struct-from-array", "NativeSha512_256Commitment") + return + } + } + if zb0004 > 0 { + zb0004-- + bts, err = (*z).unauthenticatedProposal.Block.BlockHeader.TxnCommitments.Sha256Commitment.UnmarshalMsg(bts) if err != nil { - err = msgp.WrapError(err, "struct-from-array", "TxnRoot") + err = msgp.WrapError(err, "struct-from-array", "Sha256Commitment") return } } @@ -3731,9 +3772,15 @@ func (z *transmittedPayload) UnmarshalMsg(bts []byte) (o []byte, err error) { return } case "txn": - bts, err = (*z).unauthenticatedProposal.Block.BlockHeader.TxnRoot.UnmarshalMsg(bts) + bts, err = (*z).unauthenticatedProposal.Block.BlockHeader.TxnCommitments.NativeSha512_256Commitment.UnmarshalMsg(bts) + if err != nil { + err = msgp.WrapError(err, "NativeSha512_256Commitment") + return + } + case "txn256": + bts, err = (*z).unauthenticatedProposal.Block.BlockHeader.TxnCommitments.Sha256Commitment.UnmarshalMsg(bts) if err != nil { - err = msgp.WrapError(err, "TxnRoot") + err = msgp.WrapError(err, "Sha256Commitment") return } case "ts": @@ -3959,7 +4006,7 @@ func (_ *transmittedPayload) CanUnmarshalMsg(z interface{}) bool { // Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message func (z *transmittedPayload) Msgsize() (s int) { - s = 3 + 4 + (*z).unauthenticatedProposal.Block.BlockHeader.Round.Msgsize() + 5 + (*z).unauthenticatedProposal.Block.BlockHeader.Branch.Msgsize() + 5 + (*z).unauthenticatedProposal.Block.BlockHeader.Seed.Msgsize() + 4 + (*z).unauthenticatedProposal.Block.BlockHeader.TxnRoot.Msgsize() + 3 + msgp.Int64Size + 4 + msgp.StringPrefixSize + len((*z).unauthenticatedProposal.Block.BlockHeader.GenesisID) + 3 + (*z).unauthenticatedProposal.Block.BlockHeader.GenesisHash.Msgsize() + 5 + (*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.FeeSink.Msgsize() + 4 + (*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsPool.Msgsize() + 5 + msgp.Uint64Size + 5 + msgp.Uint64Size + 5 + msgp.Uint64Size + 7 + (*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsRecalculationRound.Msgsize() + 6 + (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.CurrentProtocol.Msgsize() + 10 + (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocol.Msgsize() + 8 + msgp.Uint64Size + 11 + (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocolVoteBefore.Msgsize() + 11 + (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocolSwitchOn.Msgsize() + 12 + (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeVote.UpgradePropose.Msgsize() + 13 + (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeVote.UpgradeDelay.Msgsize() + 11 + msgp.BoolSize + 3 + msgp.Uint64Size + 3 + msgp.MapHeaderSize + s = 3 + 4 + (*z).unauthenticatedProposal.Block.BlockHeader.Round.Msgsize() + 5 + (*z).unauthenticatedProposal.Block.BlockHeader.Branch.Msgsize() + 5 + (*z).unauthenticatedProposal.Block.BlockHeader.Seed.Msgsize() + 4 + (*z).unauthenticatedProposal.Block.BlockHeader.TxnCommitments.NativeSha512_256Commitment.Msgsize() + 7 + (*z).unauthenticatedProposal.Block.BlockHeader.TxnCommitments.Sha256Commitment.Msgsize() + 3 + msgp.Int64Size + 4 + msgp.StringPrefixSize + len((*z).unauthenticatedProposal.Block.BlockHeader.GenesisID) + 3 + (*z).unauthenticatedProposal.Block.BlockHeader.GenesisHash.Msgsize() + 5 + (*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.FeeSink.Msgsize() + 4 + (*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsPool.Msgsize() + 5 + msgp.Uint64Size + 5 + msgp.Uint64Size + 5 + msgp.Uint64Size + 7 + (*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsRecalculationRound.Msgsize() + 6 + (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.CurrentProtocol.Msgsize() + 10 + (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocol.Msgsize() + 8 + msgp.Uint64Size + 11 + (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocolVoteBefore.Msgsize() + 11 + (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocolSwitchOn.Msgsize() + 12 + (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeVote.UpgradePropose.Msgsize() + 13 + (*z).unauthenticatedProposal.Block.BlockHeader.UpgradeVote.UpgradeDelay.Msgsize() + 11 + msgp.BoolSize + 3 + msgp.Uint64Size + 3 + msgp.MapHeaderSize if (*z).unauthenticatedProposal.Block.BlockHeader.CompactCert != nil { for zb0001, zb0002 := range (*z).unauthenticatedProposal.Block.BlockHeader.CompactCert { _ = zb0001 @@ -3977,7 +4024,7 @@ func (z *transmittedPayload) Msgsize() (s int) { // MsgIsZero returns whether this is a zero value func (z *transmittedPayload) MsgIsZero() bool { - return ((*z).unauthenticatedProposal.Block.BlockHeader.Round.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.Branch.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.Seed.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.TxnRoot.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.TimeStamp == 0) && ((*z).unauthenticatedProposal.Block.BlockHeader.GenesisID == "") && ((*z).unauthenticatedProposal.Block.BlockHeader.GenesisHash.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.FeeSink.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsPool.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsLevel == 0) && ((*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsRate == 0) && ((*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsResidue == 0) && ((*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsRecalculationRound.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.CurrentProtocol.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocol.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocolApprovals == 0) && ((*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocolVoteBefore.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocolSwitchOn.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.UpgradeVote.UpgradePropose.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.UpgradeVote.UpgradeDelay.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.UpgradeVote.UpgradeApprove == false) && ((*z).unauthenticatedProposal.Block.BlockHeader.TxnCounter == 0) && (len((*z).unauthenticatedProposal.Block.BlockHeader.CompactCert) == 0) && (len((*z).unauthenticatedProposal.Block.BlockHeader.ParticipationUpdates.ExpiredParticipationAccounts) == 0) && ((*z).unauthenticatedProposal.Block.Payset.MsgIsZero()) && ((*z).unauthenticatedProposal.SeedProof.MsgIsZero()) && ((*z).unauthenticatedProposal.OriginalPeriod == 0) && ((*z).unauthenticatedProposal.OriginalProposer.MsgIsZero()) && ((*z).PriorVote.MsgIsZero()) + return ((*z).unauthenticatedProposal.Block.BlockHeader.Round.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.Branch.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.Seed.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.TxnCommitments.NativeSha512_256Commitment.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.TxnCommitments.Sha256Commitment.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.TimeStamp == 0) && ((*z).unauthenticatedProposal.Block.BlockHeader.GenesisID == "") && ((*z).unauthenticatedProposal.Block.BlockHeader.GenesisHash.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.FeeSink.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsPool.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsLevel == 0) && ((*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsRate == 0) && ((*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsResidue == 0) && ((*z).unauthenticatedProposal.Block.BlockHeader.RewardsState.RewardsRecalculationRound.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.CurrentProtocol.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocol.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocolApprovals == 0) && ((*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocolVoteBefore.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.UpgradeState.NextProtocolSwitchOn.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.UpgradeVote.UpgradePropose.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.UpgradeVote.UpgradeDelay.MsgIsZero()) && ((*z).unauthenticatedProposal.Block.BlockHeader.UpgradeVote.UpgradeApprove == false) && ((*z).unauthenticatedProposal.Block.BlockHeader.TxnCounter == 0) && (len((*z).unauthenticatedProposal.Block.BlockHeader.CompactCert) == 0) && (len((*z).unauthenticatedProposal.Block.BlockHeader.ParticipationUpdates.ExpiredParticipationAccounts) == 0) && ((*z).unauthenticatedProposal.Block.Payset.MsgIsZero()) && ((*z).unauthenticatedProposal.SeedProof.MsgIsZero()) && ((*z).unauthenticatedProposal.OriginalPeriod == 0) && ((*z).unauthenticatedProposal.OriginalProposer.MsgIsZero()) && ((*z).PriorVote.MsgIsZero()) } // MarshalMsg implements msgp.Marshaler @@ -4647,124 +4694,128 @@ func (z *unauthenticatedEquivocationVote) MsgIsZero() bool { func (z *unauthenticatedProposal) MarshalMsg(b []byte) (o []byte) { o = msgp.Require(b, z.Msgsize()) // omitempty: check for empty values - zb0004Len := uint32(28) - var zb0004Mask uint64 /* 33 bits */ + zb0004Len := uint32(29) + var zb0004Mask uint64 /* 35 bits */ if len((*z).Block.BlockHeader.CompactCert) == 0 { zb0004Len-- - zb0004Mask |= 0x20 + zb0004Mask |= 0x40 } if (*z).Block.BlockHeader.RewardsState.RewardsLevel == 0 { zb0004Len-- - zb0004Mask |= 0x40 + zb0004Mask |= 0x80 } if (*z).Block.BlockHeader.RewardsState.FeeSink.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x80 + zb0004Mask |= 0x100 } if (*z).Block.BlockHeader.RewardsState.RewardsResidue == 0 { zb0004Len-- - zb0004Mask |= 0x100 + zb0004Mask |= 0x200 } if (*z).Block.BlockHeader.GenesisID == "" { zb0004Len-- - zb0004Mask |= 0x200 + zb0004Mask |= 0x400 } if (*z).Block.BlockHeader.GenesisHash.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x400 + zb0004Mask |= 0x800 } if (*z).Block.BlockHeader.UpgradeState.NextProtocolVoteBefore.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x800 + zb0004Mask |= 0x1000 } if (*z).Block.BlockHeader.UpgradeState.NextProtocol.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x1000 + zb0004Mask |= 0x2000 } if (*z).Block.BlockHeader.UpgradeState.NextProtocolSwitchOn.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x2000 + zb0004Mask |= 0x4000 } if (*z).Block.BlockHeader.UpgradeState.NextProtocolApprovals == 0 { zb0004Len-- - zb0004Mask |= 0x4000 + zb0004Mask |= 0x8000 } if (*z).OriginalPeriod == 0 { zb0004Len-- - zb0004Mask |= 0x8000 + zb0004Mask |= 0x10000 } if (*z).OriginalProposer.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x10000 + zb0004Mask |= 0x20000 } if len((*z).Block.BlockHeader.ParticipationUpdates.ExpiredParticipationAccounts) == 0 { zb0004Len-- - zb0004Mask |= 0x20000 + zb0004Mask |= 0x40000 } if (*z).Block.BlockHeader.Branch.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x40000 + zb0004Mask |= 0x80000 } if (*z).Block.BlockHeader.UpgradeState.CurrentProtocol.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x80000 + zb0004Mask |= 0x100000 } if (*z).Block.BlockHeader.RewardsState.RewardsRate == 0 { zb0004Len-- - zb0004Mask |= 0x100000 + zb0004Mask |= 0x200000 } if (*z).Block.BlockHeader.Round.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x200000 + zb0004Mask |= 0x400000 } if (*z).Block.BlockHeader.RewardsState.RewardsRecalculationRound.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x400000 + zb0004Mask |= 0x800000 } if (*z).Block.BlockHeader.RewardsState.RewardsPool.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x800000 + zb0004Mask |= 0x1000000 } if (*z).SeedProof.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x1000000 + zb0004Mask |= 0x2000000 } if (*z).Block.BlockHeader.Seed.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x2000000 + zb0004Mask |= 0x4000000 } if (*z).Block.BlockHeader.TxnCounter == 0 { zb0004Len-- - zb0004Mask |= 0x4000000 + zb0004Mask |= 0x8000000 } if (*z).Block.BlockHeader.TimeStamp == 0 { zb0004Len-- - zb0004Mask |= 0x8000000 + zb0004Mask |= 0x10000000 } - if (*z).Block.BlockHeader.TxnRoot.MsgIsZero() { + if (*z).Block.BlockHeader.TxnCommitments.NativeSha512_256Commitment.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x10000000 + zb0004Mask |= 0x20000000 + } + if (*z).Block.BlockHeader.TxnCommitments.Sha256Commitment.MsgIsZero() { + zb0004Len-- + zb0004Mask |= 0x40000000 } if (*z).Block.Payset.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x20000000 + zb0004Mask |= 0x80000000 } if (*z).Block.BlockHeader.UpgradeVote.UpgradeDelay.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x40000000 + zb0004Mask |= 0x100000000 } if (*z).Block.BlockHeader.UpgradeVote.UpgradePropose.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x80000000 + zb0004Mask |= 0x200000000 } if (*z).Block.BlockHeader.UpgradeVote.UpgradeApprove == false { zb0004Len-- - zb0004Mask |= 0x100000000 + zb0004Mask |= 0x400000000 } // variable map header, size zb0004Len o = msgp.AppendMapHeader(o, zb0004Len) if zb0004Len != 0 { - if (zb0004Mask & 0x20) == 0 { // if not empty + if (zb0004Mask & 0x40) == 0 { // if not empty // string "cc" o = append(o, 0xa2, 0x63, 0x63) if (*z).Block.BlockHeader.CompactCert == nil { @@ -4784,62 +4835,62 @@ func (z *unauthenticatedProposal) MarshalMsg(b []byte) (o []byte) { o = zb0002.MarshalMsg(o) } } - if (zb0004Mask & 0x40) == 0 { // if not empty + if (zb0004Mask & 0x80) == 0 { // if not empty // string "earn" o = append(o, 0xa4, 0x65, 0x61, 0x72, 0x6e) o = msgp.AppendUint64(o, (*z).Block.BlockHeader.RewardsState.RewardsLevel) } - if (zb0004Mask & 0x80) == 0 { // if not empty + if (zb0004Mask & 0x100) == 0 { // if not empty // string "fees" o = append(o, 0xa4, 0x66, 0x65, 0x65, 0x73) o = (*z).Block.BlockHeader.RewardsState.FeeSink.MarshalMsg(o) } - if (zb0004Mask & 0x100) == 0 { // if not empty + if (zb0004Mask & 0x200) == 0 { // if not empty // string "frac" o = append(o, 0xa4, 0x66, 0x72, 0x61, 0x63) o = msgp.AppendUint64(o, (*z).Block.BlockHeader.RewardsState.RewardsResidue) } - if (zb0004Mask & 0x200) == 0 { // if not empty + if (zb0004Mask & 0x400) == 0 { // if not empty // string "gen" o = append(o, 0xa3, 0x67, 0x65, 0x6e) o = msgp.AppendString(o, (*z).Block.BlockHeader.GenesisID) } - if (zb0004Mask & 0x400) == 0 { // if not empty + if (zb0004Mask & 0x800) == 0 { // if not empty // string "gh" o = append(o, 0xa2, 0x67, 0x68) o = (*z).Block.BlockHeader.GenesisHash.MarshalMsg(o) } - if (zb0004Mask & 0x800) == 0 { // if not empty + if (zb0004Mask & 0x1000) == 0 { // if not empty // string "nextbefore" o = append(o, 0xaa, 0x6e, 0x65, 0x78, 0x74, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65) o = (*z).Block.BlockHeader.UpgradeState.NextProtocolVoteBefore.MarshalMsg(o) } - if (zb0004Mask & 0x1000) == 0 { // if not empty + if (zb0004Mask & 0x2000) == 0 { // if not empty // string "nextproto" o = append(o, 0xa9, 0x6e, 0x65, 0x78, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f) o = (*z).Block.BlockHeader.UpgradeState.NextProtocol.MarshalMsg(o) } - if (zb0004Mask & 0x2000) == 0 { // if not empty + if (zb0004Mask & 0x4000) == 0 { // if not empty // string "nextswitch" o = append(o, 0xaa, 0x6e, 0x65, 0x78, 0x74, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68) o = (*z).Block.BlockHeader.UpgradeState.NextProtocolSwitchOn.MarshalMsg(o) } - if (zb0004Mask & 0x4000) == 0 { // if not empty + if (zb0004Mask & 0x8000) == 0 { // if not empty // string "nextyes" o = append(o, 0xa7, 0x6e, 0x65, 0x78, 0x74, 0x79, 0x65, 0x73) o = msgp.AppendUint64(o, (*z).Block.BlockHeader.UpgradeState.NextProtocolApprovals) } - if (zb0004Mask & 0x8000) == 0 { // if not empty + if (zb0004Mask & 0x10000) == 0 { // if not empty // string "oper" o = append(o, 0xa4, 0x6f, 0x70, 0x65, 0x72) o = msgp.AppendUint64(o, uint64((*z).OriginalPeriod)) } - if (zb0004Mask & 0x10000) == 0 { // if not empty + if (zb0004Mask & 0x20000) == 0 { // if not empty // string "oprop" o = append(o, 0xa5, 0x6f, 0x70, 0x72, 0x6f, 0x70) o = (*z).OriginalProposer.MarshalMsg(o) } - if (zb0004Mask & 0x20000) == 0 { // if not empty + if (zb0004Mask & 0x40000) == 0 { // if not empty // string "partupdrmv" o = append(o, 0xaa, 0x70, 0x61, 0x72, 0x74, 0x75, 0x70, 0x64, 0x72, 0x6d, 0x76) if (*z).Block.BlockHeader.ParticipationUpdates.ExpiredParticipationAccounts == nil { @@ -4851,77 +4902,82 @@ func (z *unauthenticatedProposal) MarshalMsg(b []byte) (o []byte) { o = (*z).Block.BlockHeader.ParticipationUpdates.ExpiredParticipationAccounts[zb0003].MarshalMsg(o) } } - if (zb0004Mask & 0x40000) == 0 { // if not empty + if (zb0004Mask & 0x80000) == 0 { // if not empty // string "prev" o = append(o, 0xa4, 0x70, 0x72, 0x65, 0x76) o = (*z).Block.BlockHeader.Branch.MarshalMsg(o) } - if (zb0004Mask & 0x80000) == 0 { // if not empty + if (zb0004Mask & 0x100000) == 0 { // if not empty // string "proto" o = append(o, 0xa5, 0x70, 0x72, 0x6f, 0x74, 0x6f) o = (*z).Block.BlockHeader.UpgradeState.CurrentProtocol.MarshalMsg(o) } - if (zb0004Mask & 0x100000) == 0 { // if not empty + if (zb0004Mask & 0x200000) == 0 { // if not empty // string "rate" o = append(o, 0xa4, 0x72, 0x61, 0x74, 0x65) o = msgp.AppendUint64(o, (*z).Block.BlockHeader.RewardsState.RewardsRate) } - if (zb0004Mask & 0x200000) == 0 { // if not empty + if (zb0004Mask & 0x400000) == 0 { // if not empty // string "rnd" o = append(o, 0xa3, 0x72, 0x6e, 0x64) o = (*z).Block.BlockHeader.Round.MarshalMsg(o) } - if (zb0004Mask & 0x400000) == 0 { // if not empty + if (zb0004Mask & 0x800000) == 0 { // if not empty // string "rwcalr" o = append(o, 0xa6, 0x72, 0x77, 0x63, 0x61, 0x6c, 0x72) o = (*z).Block.BlockHeader.RewardsState.RewardsRecalculationRound.MarshalMsg(o) } - if (zb0004Mask & 0x800000) == 0 { // if not empty + if (zb0004Mask & 0x1000000) == 0 { // if not empty // string "rwd" o = append(o, 0xa3, 0x72, 0x77, 0x64) o = (*z).Block.BlockHeader.RewardsState.RewardsPool.MarshalMsg(o) } - if (zb0004Mask & 0x1000000) == 0 { // if not empty + if (zb0004Mask & 0x2000000) == 0 { // if not empty // string "sdpf" o = append(o, 0xa4, 0x73, 0x64, 0x70, 0x66) o = (*z).SeedProof.MarshalMsg(o) } - if (zb0004Mask & 0x2000000) == 0 { // if not empty + if (zb0004Mask & 0x4000000) == 0 { // if not empty // string "seed" o = append(o, 0xa4, 0x73, 0x65, 0x65, 0x64) o = (*z).Block.BlockHeader.Seed.MarshalMsg(o) } - if (zb0004Mask & 0x4000000) == 0 { // if not empty + if (zb0004Mask & 0x8000000) == 0 { // if not empty // string "tc" o = append(o, 0xa2, 0x74, 0x63) o = msgp.AppendUint64(o, (*z).Block.BlockHeader.TxnCounter) } - if (zb0004Mask & 0x8000000) == 0 { // if not empty + if (zb0004Mask & 0x10000000) == 0 { // if not empty // string "ts" o = append(o, 0xa2, 0x74, 0x73) o = msgp.AppendInt64(o, (*z).Block.BlockHeader.TimeStamp) } - if (zb0004Mask & 0x10000000) == 0 { // if not empty + if (zb0004Mask & 0x20000000) == 0 { // if not empty // string "txn" o = append(o, 0xa3, 0x74, 0x78, 0x6e) - o = (*z).Block.BlockHeader.TxnRoot.MarshalMsg(o) + o = (*z).Block.BlockHeader.TxnCommitments.NativeSha512_256Commitment.MarshalMsg(o) } - if (zb0004Mask & 0x20000000) == 0 { // if not empty + if (zb0004Mask & 0x40000000) == 0 { // if not empty + // string "txn256" + o = append(o, 0xa6, 0x74, 0x78, 0x6e, 0x32, 0x35, 0x36) + o = (*z).Block.BlockHeader.TxnCommitments.Sha256Commitment.MarshalMsg(o) + } + if (zb0004Mask & 0x80000000) == 0 { // if not empty // string "txns" o = append(o, 0xa4, 0x74, 0x78, 0x6e, 0x73) o = (*z).Block.Payset.MarshalMsg(o) } - if (zb0004Mask & 0x40000000) == 0 { // if not empty + if (zb0004Mask & 0x100000000) == 0 { // if not empty // string "upgradedelay" o = append(o, 0xac, 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x64, 0x65, 0x6c, 0x61, 0x79) o = (*z).Block.BlockHeader.UpgradeVote.UpgradeDelay.MarshalMsg(o) } - if (zb0004Mask & 0x80000000) == 0 { // if not empty + if (zb0004Mask & 0x200000000) == 0 { // if not empty // string "upgradeprop" o = append(o, 0xab, 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x70, 0x72, 0x6f, 0x70) o = (*z).Block.BlockHeader.UpgradeVote.UpgradePropose.MarshalMsg(o) } - if (zb0004Mask & 0x100000000) == 0 { // if not empty + if (zb0004Mask & 0x400000000) == 0 { // if not empty // string "upgradeyes" o = append(o, 0xaa, 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x79, 0x65, 0x73) o = msgp.AppendBool(o, (*z).Block.BlockHeader.UpgradeVote.UpgradeApprove) @@ -4974,9 +5030,17 @@ func (z *unauthenticatedProposal) UnmarshalMsg(bts []byte) (o []byte, err error) } if zb0004 > 0 { zb0004-- - bts, err = (*z).Block.BlockHeader.TxnRoot.UnmarshalMsg(bts) + bts, err = (*z).Block.BlockHeader.TxnCommitments.NativeSha512_256Commitment.UnmarshalMsg(bts) if err != nil { - err = msgp.WrapError(err, "struct-from-array", "TxnRoot") + err = msgp.WrapError(err, "struct-from-array", "NativeSha512_256Commitment") + return + } + } + if zb0004 > 0 { + zb0004-- + bts, err = (*z).Block.BlockHeader.TxnCommitments.Sha256Commitment.UnmarshalMsg(bts) + if err != nil { + err = msgp.WrapError(err, "struct-from-array", "Sha256Commitment") return } } @@ -5267,9 +5331,15 @@ func (z *unauthenticatedProposal) UnmarshalMsg(bts []byte) (o []byte, err error) return } case "txn": - bts, err = (*z).Block.BlockHeader.TxnRoot.UnmarshalMsg(bts) + bts, err = (*z).Block.BlockHeader.TxnCommitments.NativeSha512_256Commitment.UnmarshalMsg(bts) + if err != nil { + err = msgp.WrapError(err, "NativeSha512_256Commitment") + return + } + case "txn256": + bts, err = (*z).Block.BlockHeader.TxnCommitments.Sha256Commitment.UnmarshalMsg(bts) if err != nil { - err = msgp.WrapError(err, "TxnRoot") + err = msgp.WrapError(err, "Sha256Commitment") return } case "ts": @@ -5489,7 +5559,7 @@ func (_ *unauthenticatedProposal) CanUnmarshalMsg(z interface{}) bool { // Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message func (z *unauthenticatedProposal) Msgsize() (s int) { - s = 3 + 4 + (*z).Block.BlockHeader.Round.Msgsize() + 5 + (*z).Block.BlockHeader.Branch.Msgsize() + 5 + (*z).Block.BlockHeader.Seed.Msgsize() + 4 + (*z).Block.BlockHeader.TxnRoot.Msgsize() + 3 + msgp.Int64Size + 4 + msgp.StringPrefixSize + len((*z).Block.BlockHeader.GenesisID) + 3 + (*z).Block.BlockHeader.GenesisHash.Msgsize() + 5 + (*z).Block.BlockHeader.RewardsState.FeeSink.Msgsize() + 4 + (*z).Block.BlockHeader.RewardsState.RewardsPool.Msgsize() + 5 + msgp.Uint64Size + 5 + msgp.Uint64Size + 5 + msgp.Uint64Size + 7 + (*z).Block.BlockHeader.RewardsState.RewardsRecalculationRound.Msgsize() + 6 + (*z).Block.BlockHeader.UpgradeState.CurrentProtocol.Msgsize() + 10 + (*z).Block.BlockHeader.UpgradeState.NextProtocol.Msgsize() + 8 + msgp.Uint64Size + 11 + (*z).Block.BlockHeader.UpgradeState.NextProtocolVoteBefore.Msgsize() + 11 + (*z).Block.BlockHeader.UpgradeState.NextProtocolSwitchOn.Msgsize() + 12 + (*z).Block.BlockHeader.UpgradeVote.UpgradePropose.Msgsize() + 13 + (*z).Block.BlockHeader.UpgradeVote.UpgradeDelay.Msgsize() + 11 + msgp.BoolSize + 3 + msgp.Uint64Size + 3 + msgp.MapHeaderSize + s = 3 + 4 + (*z).Block.BlockHeader.Round.Msgsize() + 5 + (*z).Block.BlockHeader.Branch.Msgsize() + 5 + (*z).Block.BlockHeader.Seed.Msgsize() + 4 + (*z).Block.BlockHeader.TxnCommitments.NativeSha512_256Commitment.Msgsize() + 7 + (*z).Block.BlockHeader.TxnCommitments.Sha256Commitment.Msgsize() + 3 + msgp.Int64Size + 4 + msgp.StringPrefixSize + len((*z).Block.BlockHeader.GenesisID) + 3 + (*z).Block.BlockHeader.GenesisHash.Msgsize() + 5 + (*z).Block.BlockHeader.RewardsState.FeeSink.Msgsize() + 4 + (*z).Block.BlockHeader.RewardsState.RewardsPool.Msgsize() + 5 + msgp.Uint64Size + 5 + msgp.Uint64Size + 5 + msgp.Uint64Size + 7 + (*z).Block.BlockHeader.RewardsState.RewardsRecalculationRound.Msgsize() + 6 + (*z).Block.BlockHeader.UpgradeState.CurrentProtocol.Msgsize() + 10 + (*z).Block.BlockHeader.UpgradeState.NextProtocol.Msgsize() + 8 + msgp.Uint64Size + 11 + (*z).Block.BlockHeader.UpgradeState.NextProtocolVoteBefore.Msgsize() + 11 + (*z).Block.BlockHeader.UpgradeState.NextProtocolSwitchOn.Msgsize() + 12 + (*z).Block.BlockHeader.UpgradeVote.UpgradePropose.Msgsize() + 13 + (*z).Block.BlockHeader.UpgradeVote.UpgradeDelay.Msgsize() + 11 + msgp.BoolSize + 3 + msgp.Uint64Size + 3 + msgp.MapHeaderSize if (*z).Block.BlockHeader.CompactCert != nil { for zb0001, zb0002 := range (*z).Block.BlockHeader.CompactCert { _ = zb0001 @@ -5507,7 +5577,7 @@ func (z *unauthenticatedProposal) Msgsize() (s int) { // MsgIsZero returns whether this is a zero value func (z *unauthenticatedProposal) MsgIsZero() bool { - return ((*z).Block.BlockHeader.Round.MsgIsZero()) && ((*z).Block.BlockHeader.Branch.MsgIsZero()) && ((*z).Block.BlockHeader.Seed.MsgIsZero()) && ((*z).Block.BlockHeader.TxnRoot.MsgIsZero()) && ((*z).Block.BlockHeader.TimeStamp == 0) && ((*z).Block.BlockHeader.GenesisID == "") && ((*z).Block.BlockHeader.GenesisHash.MsgIsZero()) && ((*z).Block.BlockHeader.RewardsState.FeeSink.MsgIsZero()) && ((*z).Block.BlockHeader.RewardsState.RewardsPool.MsgIsZero()) && ((*z).Block.BlockHeader.RewardsState.RewardsLevel == 0) && ((*z).Block.BlockHeader.RewardsState.RewardsRate == 0) && ((*z).Block.BlockHeader.RewardsState.RewardsResidue == 0) && ((*z).Block.BlockHeader.RewardsState.RewardsRecalculationRound.MsgIsZero()) && ((*z).Block.BlockHeader.UpgradeState.CurrentProtocol.MsgIsZero()) && ((*z).Block.BlockHeader.UpgradeState.NextProtocol.MsgIsZero()) && ((*z).Block.BlockHeader.UpgradeState.NextProtocolApprovals == 0) && ((*z).Block.BlockHeader.UpgradeState.NextProtocolVoteBefore.MsgIsZero()) && ((*z).Block.BlockHeader.UpgradeState.NextProtocolSwitchOn.MsgIsZero()) && ((*z).Block.BlockHeader.UpgradeVote.UpgradePropose.MsgIsZero()) && ((*z).Block.BlockHeader.UpgradeVote.UpgradeDelay.MsgIsZero()) && ((*z).Block.BlockHeader.UpgradeVote.UpgradeApprove == false) && ((*z).Block.BlockHeader.TxnCounter == 0) && (len((*z).Block.BlockHeader.CompactCert) == 0) && (len((*z).Block.BlockHeader.ParticipationUpdates.ExpiredParticipationAccounts) == 0) && ((*z).Block.Payset.MsgIsZero()) && ((*z).SeedProof.MsgIsZero()) && ((*z).OriginalPeriod == 0) && ((*z).OriginalProposer.MsgIsZero()) + return ((*z).Block.BlockHeader.Round.MsgIsZero()) && ((*z).Block.BlockHeader.Branch.MsgIsZero()) && ((*z).Block.BlockHeader.Seed.MsgIsZero()) && ((*z).Block.BlockHeader.TxnCommitments.NativeSha512_256Commitment.MsgIsZero()) && ((*z).Block.BlockHeader.TxnCommitments.Sha256Commitment.MsgIsZero()) && ((*z).Block.BlockHeader.TimeStamp == 0) && ((*z).Block.BlockHeader.GenesisID == "") && ((*z).Block.BlockHeader.GenesisHash.MsgIsZero()) && ((*z).Block.BlockHeader.RewardsState.FeeSink.MsgIsZero()) && ((*z).Block.BlockHeader.RewardsState.RewardsPool.MsgIsZero()) && ((*z).Block.BlockHeader.RewardsState.RewardsLevel == 0) && ((*z).Block.BlockHeader.RewardsState.RewardsRate == 0) && ((*z).Block.BlockHeader.RewardsState.RewardsResidue == 0) && ((*z).Block.BlockHeader.RewardsState.RewardsRecalculationRound.MsgIsZero()) && ((*z).Block.BlockHeader.UpgradeState.CurrentProtocol.MsgIsZero()) && ((*z).Block.BlockHeader.UpgradeState.NextProtocol.MsgIsZero()) && ((*z).Block.BlockHeader.UpgradeState.NextProtocolApprovals == 0) && ((*z).Block.BlockHeader.UpgradeState.NextProtocolVoteBefore.MsgIsZero()) && ((*z).Block.BlockHeader.UpgradeState.NextProtocolSwitchOn.MsgIsZero()) && ((*z).Block.BlockHeader.UpgradeVote.UpgradePropose.MsgIsZero()) && ((*z).Block.BlockHeader.UpgradeVote.UpgradeDelay.MsgIsZero()) && ((*z).Block.BlockHeader.UpgradeVote.UpgradeApprove == false) && ((*z).Block.BlockHeader.TxnCounter == 0) && (len((*z).Block.BlockHeader.CompactCert) == 0) && (len((*z).Block.BlockHeader.ParticipationUpdates.ExpiredParticipationAccounts) == 0) && ((*z).Block.Payset.MsgIsZero()) && ((*z).SeedProof.MsgIsZero()) && ((*z).OriginalPeriod == 0) && ((*z).OriginalProposer.MsgIsZero()) } // MarshalMsg implements msgp.Marshaler diff --git a/agreement/msgp_gen_test.go b/agreement/msgp_gen_test.go index 4bfe9d0280..0231cc28ad 100644 --- a/agreement/msgp_gen_test.go +++ b/agreement/msgp_gen_test.go @@ -1,3 +1,4 @@ +//go:build !skip_msgp_testing // +build !skip_msgp_testing package agreement @@ -7,9 +8,10 @@ package agreement import ( "testing" + "github.com/algorand/msgp/msgp" + "github.com/algorand/go-algorand/protocol" "github.com/algorand/go-algorand/test/partitiontest" - "github.com/algorand/msgp/msgp" ) func TestMarshalUnmarshalCertificate(t *testing.T) { diff --git a/agreement/pseudonode.go b/agreement/pseudonode.go index bdaa2f359d..06a91b210e 100644 --- a/agreement/pseudonode.go +++ b/agreement/pseudonode.go @@ -44,8 +44,8 @@ var errPseudonodeVerifierClosedChannel = errors.New("crypto verifier closed the var errPseudonodeNoVotes = errors.New("no valid participation keys to generate votes for given round") var errPseudonodeNoProposals = errors.New("no valid participation keys to generate proposals for given round") -var pseudonodeBacklogFullByType = metrics.NewTagCounter("algod_agreement_pseudonode_tasks_dropped_{TAG}", "Number of pseudonode tasks dropped per type") -var pseudonodeResultTimeoutsByType = metrics.NewTagCounter("algod_agreement_pseudonode_tasks_timeouts_{TAG}", "Number of pseudonode task result timeouts per type") +var pseudonodeBacklogFullByType = metrics.NewTagCounter("algod_agreement_pseudonode_tasks_dropped_{TAG}", "Number of pseudonode {TAG} tasks dropped", "proposal", "vote") +var pseudonodeResultTimeoutsByType = metrics.NewTagCounter("algod_agreement_pseudonode_tasks_timeouts_{TAG}", "Number of pseudonode {TAG} task result timeouts", "vote", "pvote", "ppayload") // A pseudonode creates proposals and votes with a KeyManager which holds participation keys. // diff --git a/buildnumber.dat b/buildnumber.dat index 0cfbf08886..573541ac97 100644 --- a/buildnumber.dat +++ b/buildnumber.dat @@ -1 +1 @@ -2 +0 diff --git a/catchup/fetcher_test.go b/catchup/fetcher_test.go index 55ed33bbc6..44e9ab19fa 100644 --- a/catchup/fetcher_test.go +++ b/catchup/fetcher_test.go @@ -105,7 +105,7 @@ func buildTestLedger(t *testing.T, blk bookkeeping.Block) (ledger *data.Ledger, b.Payset = []transactions.SignedTxnInBlock{ txib, } - b.TxnRoot, err = b.PaysetCommit() + b.TxnCommitments, err = b.PaysetCommit() require.NoError(t, err) require.NoError(t, ledger.AddBlock(b, agreement.Certificate{Round: next})) return @@ -116,7 +116,7 @@ func addBlocks(t *testing.T, ledger *data.Ledger, blk bookkeeping.Block, numBloc for i := 0; i < numBlocks; i++ { blk.BlockHeader.Round++ blk.BlockHeader.TimeStamp += int64(crypto.RandUint64() % 100 * 1000) - blk.TxnRoot, err = blk.PaysetCommit() + blk.TxnCommitments, err = blk.PaysetCommit() require.NoError(t, err) err := ledger.AddBlock(blk, agreement.Certificate{Round: blk.BlockHeader.Round}) diff --git a/cmd/algokey/main.go b/cmd/algokey/main.go index 8182c35f8b..450253e566 100644 --- a/cmd/algokey/main.go +++ b/cmd/algokey/main.go @@ -22,13 +22,21 @@ import ( "github.com/spf13/cobra" "github.com/spf13/cobra/doc" + + "github.com/algorand/go-algorand/config" ) +var versionCheck bool + var rootCmd = &cobra.Command{ Use: "algokey", Short: "CLI for managing Algorand keys", Args: cobra.NoArgs, Run: func(cmd *cobra.Command, args []string) { + if versionCheck { + fmt.Println(config.FormatVersionAndLicense()) + return + } // If no arguments passed, we should fallback to help cmd.HelpFunc()(cmd, args) }, @@ -41,6 +49,7 @@ func init() { rootCmd.AddCommand(signCmd) rootCmd.AddCommand(multisigCmd) rootCmd.AddCommand(partCmd) + rootCmd.Flags().BoolVarP(&versionCheck, "version", "v", false, "Display and write current build version and exit") } func main() { diff --git a/cmd/goal/clerk.go b/cmd/goal/clerk.go index 11275c875d..000304fa3e 100644 --- a/cmd/goal/clerk.go +++ b/cmd/goal/clerk.go @@ -874,7 +874,7 @@ var groupCmd = &cobra.Command{ } stxns = append(stxns, stxn) - group.TxGroupHashes = append(group.TxGroupHashes, crypto.HashObj(stxn.Txn)) + group.TxGroupHashes = append(group.TxGroupHashes, crypto.Digest(stxn.ID())) transactionIdx++ } @@ -1214,6 +1214,12 @@ var dryrunRemoteCmd = &cobra.Command{ if txnResult.Cost != nil { fmt.Fprintf(os.Stdout, "tx[%d] cost: %d\n", i, *txnResult.Cost) } + if txnResult.BudgetConsumed != nil { + fmt.Fprintf(os.Stdout, "tx[%d] budget consumed: %d\n", i, *txnResult.BudgetConsumed) + } + if txnResult.BudgetAdded != nil { + fmt.Fprintf(os.Stdout, "tx[%d] budget added: %d\n", i, *txnResult.BudgetAdded) + } fmt.Fprintf(os.Stdout, "tx[%d] messages:\n", i) for _, msg := range msgs { diff --git a/cmd/partitiontest_linter/go.mod b/cmd/partitiontest_linter/go.mod index 17a694f6de..3e9db30e99 100644 --- a/cmd/partitiontest_linter/go.mod +++ b/cmd/partitiontest_linter/go.mod @@ -1,6 +1,6 @@ module github.com/algorand/go-algorand/cmd/partitiontest_linter -go 1.16 +go 1.17 require golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 require golang.org/x/sys v0.0.0-20210510120138-977fb7262007 diff --git a/cmd/tealdbg/main.go b/cmd/tealdbg/main.go index 97701b9791..9ab3d3dec0 100644 --- a/cmd/tealdbg/main.go +++ b/cmd/tealdbg/main.go @@ -23,11 +23,23 @@ import ( "github.com/gorilla/mux" "github.com/spf13/cobra" + "github.com/spf13/cobra/doc" cmdutil "github.com/algorand/go-algorand/cmd/util" ) func main() { + // Hidden command to generate docs in a given directory + // tealdbg generate-docs [path] + if len(os.Args) == 3 && os.Args[1] == "generate-docs" { + err := doc.GenMarkdownTree(rootCmd, os.Args[2]) + if err != nil { + log.Println(err) + os.Exit(1) + } + os.Exit(0) + } + if err := rootCmd.Execute(); err != nil { log.Println(err) os.Exit(1) diff --git a/cmd/updater/update.sh b/cmd/updater/update.sh index 60fbe05617..3ed4622bad 100755 --- a/cmd/updater/update.sh +++ b/cmd/updater/update.sh @@ -22,6 +22,7 @@ GENESIS_NETWORK_DIR_SPEC="" SKIP_UPDATE=0 TOOLS_OUTPUT_DIR="" DRYRUN=false +VERIFY_UPDATER_ARCHIVE="0" IS_ROOT=false if [ $EUID -eq 0 ]; then IS_ROOT=true @@ -100,6 +101,10 @@ while [ "$1" != "" ]; do shift TOOLS_OUTPUT_DIR=$1 ;; + -verify) + shift + VERIFY_UPDATER_ARCHIVE="1" + ;; -z) DRYRUN=true ;; @@ -190,50 +195,134 @@ function get_updater_url() { echo "This operation system ${UNAME} is not supported by updater." exit 1 fi - UPDATER_FILENAME="install_master_${OS}-${ARCH}.tar.gz" - UPDATER_URL="https://github.com/algorand/go-algorand-doc/raw/master/downloads/installers/${OS}_${ARCH}/${UPDATER_FILENAME}" + + # the updater will auto-update itself to the latest version, this means that the version of updater that is downloaded + # can be arbitrary as long as the self-updating functionality is working, hence the hard-coded version + UPDATER_URL="http://algorand-dev-deb-repo.s3-website-us-east-1.amazonaws.com/releases/stable/f9d842778_3.6.2/install_stable_${OS}-${ARCH}_3.6.2.tar.gz" + UPDATER_FILENAME="install_stable_${OS}-${ARCH}_3.6.2.tar.gz" + + # if on linux, also set variables for signature and checksum validation + if [ "$OS" = "linux" ] && [ "$VERIFY_UPDATER_ARCHIVE" = "1" ]; then + UPDATER_PUBKEYURL="https://releases.algorand.com/key.pub" + UPDATER_SIGURL="http://algorand-dev-deb-repo.s3-website-us-east-1.amazonaws.com/releases/stable/f9d842778_3.6.2/install_stable_${OS}-${ARCH}_3.6.2.tar.gz.sig" + UPDATER_CHECKSUMURL="https://algorand-releases.s3.amazonaws.com/channel/stable/hashes_stable_${OS}_${ARCH}_3.6.2" + fi } # check to see if the binary updater exists. if not, it will automatically the correct updater binary for the current platform function check_for_updater() { + local UNAME + UNAME="$(uname)" + # check if the updater binary exist and is not empty. if [[ -s "${SCRIPTPATH}/updater" && -f "${SCRIPTPATH}/updater" ]]; then return 0 fi + + # set UPDATER_URL and UPDATER_ARCHIVE as a global that can be referenced here + # if linux, UPDATER_PUBKEYURL, UPDATER_SIGURL, UPDATER_CHECKSUMURL will be set to try verification get_updater_url - # check the curl is available. - CURL_VER=$(curl -V 2>/dev/null || true) - if [ "${CURL_VER}" = "" ]; then + # check if curl is available + if ! type curl &>/dev/null; then # no curl is installed. echo "updater binary is missing and cannot be downloaded since curl is missing." - if [[ "$(uname)" = "Linux" ]]; then + if [ "$UNAME" = "Linux" ]; then echo "To install curl, run the following command:" echo "apt-get update; apt-get install -y curl" fi exit 1 fi - CURL_OUT=$(curl -LJO --silent ${UPDATER_URL}) - if [ "$?" != "0" ]; then - echo "failed to download updater binary from ${UPDATER_URL} using curl." - echo "${CURL_OUT}" + # create temporary directory for updater archive + local UPDATER_TEMPDIR="" UPDATER_ARCHIVE="" + UPDATER_TEMPDIR="$(mktemp -d 2>/dev/null || mktemp -d -t "tmp")" + UPDATER_ARCHIVE="${UPDATER_TEMPDIR}/${UPDATER_FILENAME}" + + # download updater archive + if ! curl -sSL "$UPDATER_URL" -o "$UPDATER_ARCHIVE"; then + echo "failed to download updater archive from ${UPDATER_URL} using curl." exit 1 fi - if [ ! -f "${SCRIPTPATH}/${UPDATER_FILENAME}" ]; then - echo "downloaded file ${SCRIPTPATH}/${UPDATER_FILENAME} is missing." + if [ ! -f "$UPDATER_ARCHIVE" ]; then + echo "downloaded file ${UPDATER_ARCHIVE} is missing." exit fi - tar -zxvf "${SCRIPTPATH}/${UPDATER_FILENAME}" updater - if [ "$?" != "0" ]; then - echo "failed to extract updater binary from ${SCRIPTPATH}/${UPDATER_FILENAME}" + # if -verify command line flag is set, try verifying updater archive + if [ "$VERIFY_UPDATER_ARCHIVE" = "1" ]; then + # if linux, check for checksum and signature validation dependencies + local GPG_VERIFY="0" CHECKSUM_VERIFY="0" + if [ "$UNAME" = "Linux" ]; then + if type gpg >&/dev/null; then + GPG_VERIFY="1" + else + echo "gpg is not available to perform signature validation." + fi + + if type sha256sum &>/dev/null; then + CHECKSUM_VERIFY="1" + else + echo "sha256sum is not available to perform checksum validation." + fi + fi + + # try signature validation + if [ "$GPG_VERIFY" = "1" ]; then + local UPDATER_SIGFILE="$UPDATER_TEMPDIR/updater.sig" UPDATER_PUBKEYFILE="key.pub" + # try downloading public key + if curl -sSL "$UPDATER_PUBKEYURL" -o "$UPDATER_PUBKEYFILE"; then + GNUPGHOME="$(mktemp -d)"; export GNUPGHOME + if gpg --import "$UPDATER_PUBKEYFILE"; then + if curl -sSL "$UPDATER_SIGURL" -o "$UPDATER_SIGFILE"; then + if ! gpg --verify "$UPDATER_SIGFILE" "$UPDATER_ARCHIVE"; then + echo "failed to verify signature of updater archive." + exit 1 + fi + else + echo "failed download signature file, cannot perform signature validation." + fi + else + echo "failed importing GPG public key, cannot perform signature validation." + fi + # clean up temporary directory used for signature validation + rm -rf "$GNUPGHOME"; unset GNUPGHOME + else + echo "failed downloading GPG public key, cannot perform signature validation." + fi + fi + + # try checksum validation + if [ "$CHECKSUM_VERIFY" = "1" ]; then + local UPDATER_CHECKSUMFILE="$UPDATER_TEMPDIR/updater.checksum" + # try downloading checksum file + if curl -sSL "$UPDATER_CHECKSUMURL" -o "$UPDATER_CHECKSUMFILE"; then + # have to be in same directory as archive + pushd "$UPDATER_TEMPDIR" + if ! sha256sum --quiet --ignore-missing -c "$UPDATER_CHECKSUMFILE"; then + echo "failed to verify checksum of updater archive." + popd + exit 1 + fi + popd + else + echo "failed downloading checksum file, cannot perform checksum validation." + fi + fi + fi + + # extract and install updater + if ! tar -zxf "$UPDATER_ARCHIVE" -C "$UPDATER_TEMPDIR" updater; then + echo "failed to extract updater binary from ${UPDATER_ARCHIVE}" exit 1 + else + mv "${UPDATER_TEMPDIR}/updater" "$SCRIPTPATH" fi - rm -f "${SCRIPTPATH}/${UPDATER_FILENAME}" - echo "updater binary was downloaded" + # clean up temp directory + rm -rf "$UPDATER_TEMPDIR" + echo "updater binary was installed at ${SCRIPTPATH}/updater" } function check_for_update() { diff --git a/compactcert/msgp_gen_test.go b/compactcert/msgp_gen_test.go index 88c8395a37..0f206656e1 100644 --- a/compactcert/msgp_gen_test.go +++ b/compactcert/msgp_gen_test.go @@ -1,3 +1,4 @@ +//go:build !skip_msgp_testing // +build !skip_msgp_testing package compactcert @@ -7,9 +8,10 @@ package compactcert import ( "testing" + "github.com/algorand/msgp/msgp" + "github.com/algorand/go-algorand/protocol" "github.com/algorand/go-algorand/test/partitiontest" - "github.com/algorand/msgp/msgp" ) func TestMarshalUnmarshalsigFromAddr(t *testing.T) { diff --git a/components/mocks/mockParticipationRegistry.go b/components/mocks/mockParticipationRegistry.go index 2ccce5ff17..d2aa53f269 100644 --- a/components/mocks/mockParticipationRegistry.go +++ b/components/mocks/mockParticipationRegistry.go @@ -69,6 +69,11 @@ func (m *MockParticipationRegistry) GetStateProofForRound(id account.Participati return account.StateProofRecordForRound{}, nil } +// HasLiveKeys quickly tests to see if there is a valid participation key over some range of rounds +func (m *MockParticipationRegistry) HasLiveKeys(from, to basics.Round) bool { + return false +} + // Register updates the EffectiveFirst and EffectiveLast fields. If there are multiple records for the account // then it is possible for multiple records to be updated. func (m *MockParticipationRegistry) Register(id account.ParticipationID, on basics.Round) error { diff --git a/config/consensus.go b/config/consensus.go index 7dbe2b7ab7..07aa9ba84f 100644 --- a/config/consensus.go +++ b/config/consensus.go @@ -432,6 +432,14 @@ type ConsensusParams struct { // The hard-limit for number of StateProof keys is derived from the maximum depth allowed for the merkle signature scheme's tree - 2^16. // More keys => deeper merkle tree => longer proof required => infeasible for our SNARK. MaxKeyregValidPeriod uint64 + + // UnifyInnerTxIDs enables a consistent, unified way of computing inner transaction IDs + UnifyInnerTxIDs bool + + // EnableSHA256TxnCommitmentHeader enables the creation of a transaction vector commitment tree using SHA256 hash function. (vector commitment extends Merkle tree by having a position binding property). + // This new header is in addition to the existing SHA512_256 merkle root. + // It is useful for verifying transaction on different blockchains, as some may not support SHA512_256 OPCODE natively but SHA256 is common. + EnableSHA256TxnCommitmentHeader bool } // PaysetCommitType enumerates possible ways for the block header to commit to @@ -1139,6 +1147,10 @@ func initConsensusProtocols() { vFuture.LogicSigVersion = 7 vFuture.MinInnerApplVersion = 4 + vFuture.UnifyInnerTxIDs = true + + vFuture.EnableSHA256TxnCommitmentHeader = true + Consensus[protocol.ConsensusFuture] = vFuture } diff --git a/config/localTemplate.go b/config/localTemplate.go index 1e95d5f999..74c69c0cf4 100644 --- a/config/localTemplate.go +++ b/config/localTemplate.go @@ -41,7 +41,7 @@ type Local struct { // Version tracks the current version of the defaults so we can migrate old -> new // This is specifically important whenever we decide to change the default value // for an existing parameter. This field tag must be updated any time we add a new version. - Version uint32 `version[0]:"0" version[1]:"1" version[2]:"2" version[3]:"3" version[4]:"4" version[5]:"5" version[6]:"6" version[7]:"7" version[8]:"8" version[9]:"9" version[10]:"10" version[11]:"11" version[12]:"12" version[13]:"13" version[14]:"14" version[15]:"15" version[16]:"16" version[17]:"17" version[18]:"18" version[19]:"19" version[20]:"20" version[21]:"21"` + Version uint32 `version[0]:"0" version[1]:"1" version[2]:"2" version[3]:"3" version[4]:"4" version[5]:"5" version[6]:"6" version[7]:"7" version[8]:"8" version[9]:"9" version[10]:"10" version[11]:"11" version[12]:"12" version[13]:"13" version[14]:"14" version[15]:"15" version[16]:"16" version[17]:"17" version[18]:"18" version[19]:"19" version[20]:"20" version[21]:"21" version[22]:"22"` // environmental (may be overridden) // When enabled, stores blocks indefinitally, otherwise, only the most recents blocks @@ -251,6 +251,9 @@ type Local struct { // the algod api will be exposed to untrusted individuals EnableProfiler bool `version[0]:"false"` + // EnableRuntimeMetrics exposes Go runtime metrics in /metrics and via node_exporter. + EnableRuntimeMetrics bool `version[22]:"false"` + // TelemetryToLog records messages to node.log that are normally sent to remote event monitoring TelemetryToLog bool `version[5]:"true"` diff --git a/config/local_defaults.go b/config/local_defaults.go index 55eba24d14..b8354926b4 100644 --- a/config/local_defaults.go +++ b/config/local_defaults.go @@ -20,7 +20,7 @@ package config var defaultLocal = Local{ - Version: 21, + Version: 22, AccountUpdatesStatsInterval: 5000000000, AccountsRebuildSynchronousMode: 1, AgreementIncomingBundlesQueueLength: 7, @@ -68,6 +68,7 @@ var defaultLocal = Local{ EnableProcessBlockStats: false, EnableProfiler: false, EnableRequestLogger: false, + EnableRuntimeMetrics: false, EnableTopAccountsReporting: false, EnableVerbosedTransactionSyncLogging: false, EndpointAddress: "127.0.0.1:0", diff --git a/config/version.go b/config/version.go index c8dc1b4fe4..fb07796ecc 100644 --- a/config/version.go +++ b/config/version.go @@ -33,7 +33,7 @@ const VersionMajor = 3 // VersionMinor is the Minor semantic version number (x.#.z) - changed when backwards-compatible features are introduced. // Not enforced until after initial public release (x > 0). -const VersionMinor = 6 +const VersionMinor = 7 // Version is the type holding our full version information. type Version struct { diff --git a/crypto/compactcert/msgp_gen_test.go b/crypto/compactcert/msgp_gen_test.go index 23ebb5a3fd..1e682b46e5 100644 --- a/crypto/compactcert/msgp_gen_test.go +++ b/crypto/compactcert/msgp_gen_test.go @@ -1,3 +1,4 @@ +//go:build !skip_msgp_testing // +build !skip_msgp_testing package compactcert @@ -7,9 +8,10 @@ package compactcert import ( "testing" + "github.com/algorand/msgp/msgp" + "github.com/algorand/go-algorand/protocol" "github.com/algorand/go-algorand/test/partitiontest" - "github.com/algorand/msgp/msgp" ) func TestMarshalUnmarshalCert(t *testing.T) { diff --git a/crypto/compactcert/structs.go b/crypto/compactcert/structs.go index dd1a4f3156..9d3aaca168 100644 --- a/crypto/compactcert/structs.go +++ b/crypto/compactcert/structs.go @@ -25,7 +25,7 @@ import ( // Params defines common parameters for the verifier and builder. type Params struct { - Msg crypto.Hashable // Message to be cerified + Msg crypto.Hashable // Message to be certified ProvenWeight uint64 // Weight threshold proven by the certificate SigRound basics.Round // The round for which the ephemeral key is committed to SecKQ uint64 // Security parameter (k+q) from analysis document diff --git a/crypto/hashes.go b/crypto/hashes.go index 51db955242..67ccdafc0c 100644 --- a/crypto/hashes.go +++ b/crypto/hashes.go @@ -17,6 +17,7 @@ package crypto import ( + "crypto/sha256" "crypto/sha512" "errors" "fmt" @@ -41,7 +42,7 @@ func (h HashType) Validate() error { const ( Sha512_256 HashType = iota Sumhash - + Sha256 MaxHashType ) @@ -53,6 +54,7 @@ const MaxHashDigestSize = SumhashDigestSize const ( Sha512_256Size = sha512.Size256 SumhashDigestSize = sumhash.Sumhash512DigestSize + Sha256Size = sha256.Size ) // HashFactory is responsible for generating new hashes accordingly to the type it stores. @@ -71,6 +73,8 @@ func (h HashType) String() string { return "sha512_256" case Sumhash: return "sumhash" + case Sha256: + return "sha256" default: return "" } @@ -83,6 +87,8 @@ func UnmarshalHashType(s string) (HashType, error) { return Sha512_256, nil case "sumhash": return Sumhash, nil + case "sha256": + return Sha256, nil default: return 0, fmt.Errorf("HashType not supported: %s", s) } @@ -96,6 +102,8 @@ func (z HashFactory) NewHash() hash.Hash { return sha512.New512_256() case Sumhash: return sumhash.New512(nil) + case Sha256: + return sha256.New() // This shouldn't be reached, when creating a new hash, one would know the type of hash they wanted, // in addition to that, unmarshalling of the hashFactory verifies the HashType of the factory. default: diff --git a/crypto/hashes_test.go b/crypto/hashes_test.go index 2ebff4239d..a3054d298a 100644 --- a/crypto/hashes_test.go +++ b/crypto/hashes_test.go @@ -37,6 +37,9 @@ func TestHashFactoryCreatingNewHashes(t *testing.T) { a.NotNil(h) a.Equal(SumhashDigestSize, h.Size()) + h = HashFactory{HashType: Sha256}.NewHash() + a.NotNil(h) + a.Equal(Sha256Size, h.Size()) } func TestHashSum(t *testing.T) { diff --git a/crypto/merklearray/merkle_test.go b/crypto/merklearray/merkle_test.go index 2fa9c4a409..0f87474e52 100644 --- a/crypto/merklearray/merkle_test.go +++ b/crypto/merklearray/merkle_test.go @@ -17,6 +17,7 @@ package merklearray import ( + "encoding/hex" "fmt" "hash" "runtime" @@ -29,9 +30,10 @@ import ( "github.com/algorand/go-algorand/test/partitiontest" ) +// Hex encoded strings representing the byte arrays type KATElement struct { - expectedRoot []byte - elements [][]byte + expectedRoot string + elements []string } type TestMessage string @@ -589,84 +591,174 @@ func testMerkelSizeLimits(t *testing.T, hashtype crypto.HashType, size uint64, p return tree, proof } -var KATs = []KATElement{ +var KATsSHA256 = []KATElement{ { - []byte{223, 165, 76, 43, 118, 131, 205, 83, 151, 176, 50, 187, 236, 17, 236, 27, 119, 185, 251, 236, 90, 86, 201, 233, 66, 15, 107, 153, 128, 120, 64, 52}, - [][]byte{{212, 60, 103, 72, 82, 10, 118, 248, 31, 184, 37, 10, 169, 225, 166, 86, 240, 115, 255, 241, 229, 81, 86, 47, 173, 67, 233, 255, 251, 26, 184, 139}}, + "5a7fb9d3fb8976d942feac36d762b8d0530476c022c297582123eca18ad8c7b8", + []string{ + "d43c6748520a76f81fb8250aa9e1a656f073fff1e551562fad43e9fffb1ab88b", + }, + }, + { + "c9bc24bd5fc8961a8721458fd93044871c9009fe4c66b9614744dd6e9216d93f", + []string{ + "27a9011335fc96dc095f348a6c9347d3c7cdd56c57c650297d87df95d13f770b", + "5878453e4d5bce024b4ee07f6c57186868f3410348f5a7d601c0d9ce1efed239", + }, + }, + { + "ad1828b8460ec541fdbeee2eb4f9d37cfad9da54c0c3a98b1eb20d24de9af6ce", + []string{ + "44b5606ae49d81bc7f3451c4ff803998a8fe0057e22d6367080e5a155b661008", + "70ce7df8bda42920f5e75ae788ee7b9809826a92701a4e0e490138380ea60f44", + "77b439e99f764a1f6749e669b1361fe3bb5ce41beac4b5cd55fe51aa9efe3c67", + }, + }, + { + "d78b0c411d1360bd6d49c755a60f9ada519942911411269637287bd0b5c19bab", + []string{ + "faae213dd72151728a24c36f9aa3e07efbe326c058f85f6822c1dc2175e09d99", + "29e90fcc4b1c9513bc155c018db796d07e97c7a5009bd7a5eed4281e93de9413", + "f93c340847344999651c1bd71949cb974c7cad7bd421ccc677670f686ae520cc", + "76a8ebfe26a3353c2702937191dd766215689e5a07bda60fffd48ecfc22084d4", + }, + }, + { + "f8744f4648d1974c38fca858873006126d93f1a150f0eb7da1072fef83e66341", + []string{ + "fc2d600b2e43457221e35fcf4275221f66d6ce250b8696879d7ce7a4974f975d", + "a3fa0c2e13151fd3c3d002a5450819ae7150a1172decad45e2aa93056ab245b6", + "eb0e437994a16b1c3b8dfee99b6e8630c7bbb12f88759eb774b4e3935c551106", + "3a44dce2fba3f26f0e0ae2c47483e8cb1d815f9d9981f030edc380d4efac4f57", + "52c4079055e96c3ef3114ca93188410e8a8a08aa7e53dfb2bb18c301756faf9e", + }, + }, +} + +var KATsSUMHASH = []KATElement{ + { + "a1951e9ec9d630a975fbbdf5fa290f66bf2c55fbf5ec5ad5de08d281a971d97a64a0475d6d93ddda4480b1dbaaf33f7d72f79f9076da029e148fca0ba354b58c", + []string{ + "d43c6748520a76f81fb8250aa9e1a656f073fff1e551562fad43e9fffb1ab88b", + }, + }, + { + "8b60182211195e366021236b8bd26b004f0773f41de837dff8c483357d26aff1c06c8692b96df11fe30b2c87e6400a005d7f6e71e9b3b1f39207fe4525719cd2", + []string{ + "27a9011335fc96dc095f348a6c9347d3c7cdd56c57c650297d87df95d13f770b", + "5878453e4d5bce024b4ee07f6c57186868f3410348f5a7d601c0d9ce1efed239", + }, + }, + { + "8c427bfa1723d733b20ac58e2ce6c9791a25e9bdd57e1dc252e98b6b909a089e1c9077cea3852df6495cacbe750f41a777c593e5ce5d132d49b354b2790ae9a8", + []string{ + "44b5606ae49d81bc7f3451c4ff803998a8fe0057e22d6367080e5a155b661008", + "70ce7df8bda42920f5e75ae788ee7b9809826a92701a4e0e490138380ea60f44", + "77b439e99f764a1f6749e669b1361fe3bb5ce41beac4b5cd55fe51aa9efe3c67", + }, }, { - []byte{117, 207, 58, 54, 89, 80, 47, 147, 38, 223, 250, 114, 218, 81, 102, 235, 222, 29, 19, 246, 82, 156, 146, 35, 36, 135, 70, 68, 244, 183, 97, 110}, - [][]byte{ - {39, 169, 1, 19, 53, 252, 150, 220, 9, 95, 52, 138, 108, 147, 71, 211, 199, 205, 213, 108, 87, 198, 80, 41, 125, 135, 223, 149, 209, 63, 119, 11}, - {88, 120, 69, 62, 77, 91, 206, 2, 75, 78, 224, 127, 108, 87, 24, 104, 104, 243, 65, 3, 72, 245, 167, 214, 1, 192, 217, 206, 30, 254, 210, 57}, + "09b34fb15d43b16a22e7830ede8df4f84f4b63f46af2f6843aaf36a08c5652bcdf033162e2002c658265f4395058af1b4cef13dee70ebef4ca2cd8e870bd50c6", + []string{ + "faae213dd72151728a24c36f9aa3e07efbe326c058f85f6822c1dc2175e09d99", + "29e90fcc4b1c9513bc155c018db796d07e97c7a5009bd7a5eed4281e93de9413", + "f93c340847344999651c1bd71949cb974c7cad7bd421ccc677670f686ae520cc", + "76a8ebfe26a3353c2702937191dd766215689e5a07bda60fffd48ecfc22084d4", }, }, { - []byte{7, 177, 51, 83, 39, 122, 156, 203, 107, 66, 79, 87, 58, 180, 252, 158, 38, 138, 1, 39, 206, 188, 73, 150, 82, 146, 64, 181, 226, 155, 109, 233}, - [][]byte{ - {68, 181, 96, 106, 228, 157, 129, 188, 127, 52, 81, 196, 255, 128, 57, 152, 168, 254, 0, 87, 226, 45, 99, 103, 8, 14, 90, 21, 91, 102, 16, 8}, - {112, 206, 125, 248, 189, 164, 41, 32, 245, 231, 90, 231, 136, 238, 123, 152, 9, 130, 106, 146, 112, 26, 78, 14, 73, 1, 56, 56, 14, 166, 15, 68}, - {119, 180, 57, 233, 159, 118, 74, 31, 103, 73, 230, 105, 177, 54, 31, 227, 187, 92, 228, 27, 234, 196, 181, 205, 85, 254, 81, 170, 158, 254, 60, 103}, + "6a55c0f451c211e1c961871cc0bb640c103768f0d25ddfa0b1c1d054e92adcd1480cdca21af805da887540d343fe78a3a515c761becc7e66371b740f6ff13b6b", + []string{ + "fc2d600b2e43457221e35fcf4275221f66d6ce250b8696879d7ce7a4974f975d", + "a3fa0c2e13151fd3c3d002a5450819ae7150a1172decad45e2aa93056ab245b6", + "eb0e437994a16b1c3b8dfee99b6e8630c7bbb12f88759eb774b4e3935c551106", + "3a44dce2fba3f26f0e0ae2c47483e8cb1d815f9d9981f030edc380d4efac4f57", + "52c4079055e96c3ef3114ca93188410e8a8a08aa7e53dfb2bb18c301756faf9e", + }, + }, +} + +var KATsSHA512_256 = []KATElement{ + { + "dfa54c2b7683cd5397b032bbec11ec1b77b9fbec5a56c9e9420f6b9980784034", + []string{ + "d43c6748520a76f81fb8250aa9e1a656f073fff1e551562fad43e9fffb1ab88b", }, }, { - []byte{50, 251, 85, 206, 75, 56, 190, 244, 154, 96, 138, 178, 226, 117, 12, 255, 22, 50, 26, 246, 34, 43, 225, 20, 151, 233, 26, 249, 252, 146, 165, 63}, - [][]byte{ - {250, 174, 33, 61, 215, 33, 81, 114, 138, 36, 195, 111, 154, 163, 224, 126, 251, 227, 38, 192, 88, 248, 95, 104, 34, 193, 220, 33, 117, 224, 157, 153}, - {41, 233, 15, 204, 75, 28, 149, 19, 188, 21, 92, 1, 141, 183, 150, 208, 126, 151, 199, 165, 0, 155, 215, 165, 238, 212, 40, 30, 147, 222, 148, 19}, - {249, 60, 52, 8, 71, 52, 73, 153, 101, 28, 27, 215, 25, 73, 203, 151, 76, 124, 173, 123, 212, 33, 204, 198, 119, 103, 15, 104, 106, 229, 32, 204}, - {118, 168, 235, 254, 38, 163, 53, 60, 39, 2, 147, 113, 145, 221, 118, 98, 21, 104, 158, 90, 7, 189, 166, 15, 255, 212, 142, 207, 194, 32, 132, 212}, + "75cf3a3659502f9326dffa72da5166ebde1d13f6529c922324874644f4b7616e", + []string{ + "27a9011335fc96dc095f348a6c9347d3c7cdd56c57c650297d87df95d13f770b", + "5878453e4d5bce024b4ee07f6c57186868f3410348f5a7d601c0d9ce1efed239", }, }, { - []byte{23, 88, 226, 198, 37, 223, 43, 60, 98, 133, 183, 139, 102, 123, 221, 123, 0, 86, 205, 53, 28, 245, 228, 182, 120, 52, 206, 148, 27, 1, 84, 194}, - [][]byte{ - {252, 45, 96, 11, 46, 67, 69, 114, 33, 227, 95, 207, 66, 117, 34, 31, 102, 214, 206, 37, 11, 134, 150, 135, 157, 124, 231, 164, 151, 79, 151, 93}, - {163, 250, 12, 46, 19, 21, 31, 211, 195, 208, 2, 165, 69, 8, 25, 174, 113, 80, 161, 23, 45, 236, 173, 69, 226, 170, 147, 5, 106, 178, 69, 182}, - {235, 14, 67, 121, 148, 161, 107, 28, 59, 141, 254, 233, 155, 110, 134, 48, 199, 187, 177, 47, 136, 117, 158, 183, 116, 180, 227, 147, 92, 85, 17, 6}, - {58, 68, 220, 226, 251, 163, 242, 111, 14, 10, 226, 196, 116, 131, 232, 203, 29, 129, 95, 157, 153, 129, 240, 48, 237, 195, 128, 212, 239, 172, 79, 87}, - {82, 196, 7, 144, 85, 233, 108, 62, 243, 17, 76, 169, 49, 136, 65, 14, 138, 138, 8, 170, 126, 83, 223, 178, 187, 24, 195, 1, 117, 111, 175, 158}, + "07b13353277a9ccb6b424f573ab4fc9e268a0127cebc4996529240b5e29b6de9", + []string{ + "44b5606ae49d81bc7f3451c4ff803998a8fe0057e22d6367080e5a155b661008", + "70ce7df8bda42920f5e75ae788ee7b9809826a92701a4e0e490138380ea60f44", + "77b439e99f764a1f6749e669b1361fe3bb5ce41beac4b5cd55fe51aa9efe3c67", + }, + }, + { + "32fb55ce4b38bef49a608ab2e2750cff16321af6222be11497e91af9fc92a53f", + []string{ + "faae213dd72151728a24c36f9aa3e07efbe326c058f85f6822c1dc2175e09d99", + "29e90fcc4b1c9513bc155c018db796d07e97c7a5009bd7a5eed4281e93de9413", + "f93c340847344999651c1bd71949cb974c7cad7bd421ccc677670f686ae520cc", + "76a8ebfe26a3353c2702937191dd766215689e5a07bda60fffd48ecfc22084d4", + }, + }, + { + "1758e2c625df2b3c6285b78b667bdd7b0056cd351cf5e4b67834ce941b0154c2", + []string{ + "fc2d600b2e43457221e35fcf4275221f66d6ce250b8696879d7ce7a4974f975d", + "a3fa0c2e13151fd3c3d002a5450819ae7150a1172decad45e2aa93056ab245b6", + "eb0e437994a16b1c3b8dfee99b6e8630c7bbb12f88759eb774b4e3935c551106", + "3a44dce2fba3f26f0e0ae2c47483e8cb1d815f9d9981f030edc380d4efac4f57", + "52c4079055e96c3ef3114ca93188410e8a8a08aa7e53dfb2bb18c301756faf9e", }, }, } var VCKATs = []KATElement{ { - []byte{223, 165, 76, 43, 118, 131, 205, 83, 151, 176, 50, 187, 236, 17, 236, 27, 119, 185, 251, 236, 90, 86, 201, 233, 66, 15, 107, 153, 128, 120, 64, 52}, - [][]byte{{212, 60, 103, 72, 82, 10, 118, 248, 31, 184, 37, 10, 169, 225, 166, 86, 240, 115, 255, 241, 229, 81, 86, 47, 173, 67, 233, 255, 251, 26, 184, 139}}, + "dfa54c2b7683cd5397b032bbec11ec1b77b9fbec5a56c9e9420f6b9980784034", + []string{ + "d43c6748520a76f81fb8250aa9e1a656f073fff1e551562fad43e9fffb1ab88b", + }, }, { - []byte{117, 207, 58, 54, 89, 80, 47, 147, 38, 223, 250, 114, 218, 81, 102, 235, 222, 29, 19, 246, 82, 156, 146, 35, 36, 135, 70, 68, 244, 183, 97, 110}, - [][]byte{ - {39, 169, 1, 19, 53, 252, 150, 220, 9, 95, 52, 138, 108, 147, 71, 211, 199, 205, 213, 108, 87, 198, 80, 41, 125, 135, 223, 149, 209, 63, 119, 11}, - {88, 120, 69, 62, 77, 91, 206, 2, 75, 78, 224, 127, 108, 87, 24, 104, 104, 243, 65, 3, 72, 245, 167, 214, 1, 192, 217, 206, 30, 254, 210, 57}, + "75cf3a3659502f9326dffa72da5166ebde1d13f6529c922324874644f4b7616e", + []string{ + "27a9011335fc96dc095f348a6c9347d3c7cdd56c57c650297d87df95d13f770b", + "5878453e4d5bce024b4ee07f6c57186868f3410348f5a7d601c0d9ce1efed239", }, }, { - []byte{56, 245, 10, 65, 222, 10, 236, 127, 224, 228, 244, 247, 143, 31, 84, 13, 93, 198, 17, 209, 144, 160, 206, 206, 111, 1, 40, 234, 42, 2, 127, 94}, - [][]byte{ - {68, 181, 96, 106, 228, 157, 129, 188, 127, 52, 81, 196, 255, 128, 57, 152, 168, 254, 0, 87, 226, 45, 99, 103, 8, 14, 90, 21, 91, 102, 16, 8}, - {112, 206, 125, 248, 189, 164, 41, 32, 245, 231, 90, 231, 136, 238, 123, 152, 9, 130, 106, 146, 112, 26, 78, 14, 73, 1, 56, 56, 14, 166, 15, 68}, - {119, 180, 57, 233, 159, 118, 74, 31, 103, 73, 230, 105, 177, 54, 31, 227, 187, 92, 228, 27, 234, 196, 181, 205, 85, 254, 81, 170, 158, 254, 60, 103}, + "38f50a41de0aec7fe0e4f4f78f1f540d5dc611d190a0cece6f0128ea2a027f5e", + []string{ + "44b5606ae49d81bc7f3451c4ff803998a8fe0057e22d6367080e5a155b661008", + "70ce7df8bda42920f5e75ae788ee7b9809826a92701a4e0e490138380ea60f44", + "77b439e99f764a1f6749e669b1361fe3bb5ce41beac4b5cd55fe51aa9efe3c67", }, }, { - []byte{149, 179, 79, 29, 252, 65, 254, 212, 129, 21, 202, 49, 189, 67, 34, 93, 255, 147, 245, 64, 56, 124, 35, 10, 207, 166, 67, 226, 103, 248, 141, 120}, - [][]byte{ - {250, 174, 33, 61, 215, 33, 81, 114, 138, 36, 195, 111, 154, 163, 224, 126, 251, 227, 38, 192, 88, 248, 95, 104, 34, 193, 220, 33, 117, 224, 157, 153}, - {41, 233, 15, 204, 75, 28, 149, 19, 188, 21, 92, 1, 141, 183, 150, 208, 126, 151, 199, 165, 0, 155, 215, 165, 238, 212, 40, 30, 147, 222, 148, 19}, - {249, 60, 52, 8, 71, 52, 73, 153, 101, 28, 27, 215, 25, 73, 203, 151, 76, 124, 173, 123, 212, 33, 204, 198, 119, 103, 15, 104, 106, 229, 32, 204}, - {118, 168, 235, 254, 38, 163, 53, 60, 39, 2, 147, 113, 145, 221, 118, 98, 21, 104, 158, 90, 7, 189, 166, 15, 255, 212, 142, 207, 194, 32, 132, 212}, + "95b34f1dfc41fed48115ca31bd43225dff93f540387c230acfa643e267f88d78", + []string{ + "faae213dd72151728a24c36f9aa3e07efbe326c058f85f6822c1dc2175e09d99", + "29e90fcc4b1c9513bc155c018db796d07e97c7a5009bd7a5eed4281e93de9413", + "f93c340847344999651c1bd71949cb974c7cad7bd421ccc677670f686ae520cc", + "76a8ebfe26a3353c2702937191dd766215689e5a07bda60fffd48ecfc22084d4", }, }, { - []byte{151, 119, 38, 117, 253, 236, 112, 179, 1, 14, 240, 139, 87, 243, 203, 241, 230, 247, 178, 63, 65, 17, 80, 118, 188, 195, 74, 221, 141, 140, 10, 27}, - [][]byte{ - {252, 45, 96, 11, 46, 67, 69, 114, 33, 227, 95, 207, 66, 117, 34, 31, 102, 214, 206, 37, 11, 134, 150, 135, 157, 124, 231, 164, 151, 79, 151, 93}, - {163, 250, 12, 46, 19, 21, 31, 211, 195, 208, 2, 165, 69, 8, 25, 174, 113, 80, 161, 23, 45, 236, 173, 69, 226, 170, 147, 5, 106, 178, 69, 182}, - {235, 14, 67, 121, 148, 161, 107, 28, 59, 141, 254, 233, 155, 110, 134, 48, 199, 187, 177, 47, 136, 117, 158, 183, 116, 180, 227, 147, 92, 85, 17, 6}, - {58, 68, 220, 226, 251, 163, 242, 111, 14, 10, 226, 196, 116, 131, 232, 203, 29, 129, 95, 157, 153, 129, 240, 48, 237, 195, 128, 212, 239, 172, 79, 87}, - {82, 196, 7, 144, 85, 233, 108, 62, 243, 17, 76, 169, 49, 136, 65, 14, 138, 138, 8, 170, 126, 83, 223, 178, 187, 24, 195, 1, 117, 111, 175, 158}, + "97772675fdec70b3010ef08b57f3cbf1e6f7b23f41115076bcc34add8d8c0a1b", + []string{ + "fc2d600b2e43457221e35fcf4275221f66d6ce250b8696879d7ce7a4974f975d", + "a3fa0c2e13151fd3c3d002a5450819ae7150a1172decad45e2aa93056ab245b6", + "eb0e437994a16b1c3b8dfee99b6e8630c7bbb12f88759eb774b4e3935c551106", + "3a44dce2fba3f26f0e0ae2c47483e8cb1d815f9d9981f030edc380d4efac4f57", + "52c4079055e96c3ef3114ca93188410e8a8a08aa7e53dfb2bb18c301756faf9e", }, }, } @@ -674,16 +766,24 @@ var VCKATs = []KATElement{ func TestMerkleTreeKATs(t *testing.T) { partitiontest.PartitionTest(t) + testMerkleTreeKATsAux(t, KATsSHA512_256, crypto.Sha512_256) + testMerkleTreeKATsAux(t, KATsSUMHASH, crypto.Sumhash) + testMerkleTreeKATsAux(t, KATsSHA256, crypto.Sha256) +} + +func testMerkleTreeKATsAux(t *testing.T, KATs []KATElement, hashType crypto.HashType) { for j := 0; j < len(KATs); j++ { a := make(TestArray, len(KATs[j].elements)) for i := 0; i < len(KATs[j].elements); i++ { - copy(a[i][:], KATs[j].elements[i]) + decodedBytes, err := hex.DecodeString(KATs[j].elements[i]) + require.NoError(t, err) + copy(a[i][:], decodedBytes) } root := KATs[j].expectedRoot - tree, err := Build(a, crypto.HashFactory{HashType: crypto.Sha512_256}) + tree, err := Build(a, crypto.HashFactory{HashType: hashType}) require.NoError(t, err) - root2 := tree.Root() - require.Equal(t, root, []byte(root2), "mismatched roots on KATs index %d", j) + root2 := hex.EncodeToString(tree.Root()) + require.Equal(t, root, root2, "mismatched roots on KATs %s index %d", hashType.String(), j) } } @@ -693,13 +793,15 @@ func TestVCKATs(t *testing.T) { for j := 0; j < len(VCKATs); j++ { a := make(TestArray, len(VCKATs[j].elements)) for i := 0; i < len(VCKATs[j].elements); i++ { - copy(a[i][:], VCKATs[j].elements[i]) + decodedBytes, err := hex.DecodeString(VCKATs[j].elements[i]) + require.NoError(t, err) + copy(a[i][:], decodedBytes) } root := VCKATs[j].expectedRoot tree, err := BuildVectorCommitmentTree(a, crypto.HashFactory{HashType: crypto.Sha512_256}) require.NoError(t, err) - root2 := tree.Root() - require.Equal(t, root, []byte(root2), "mismatched roots on KATs index %d", j) + root2 := hex.EncodeToString(tree.Root()) + require.Equal(t, root, root2, "mismatched roots on VCKATs index %d", j) } } @@ -1062,6 +1164,7 @@ func TestVCProveSingleLeaf(t *testing.T) { func BenchmarkMerkleCommit(b *testing.B) { b.Run("sha512_256", func(b *testing.B) { merkleCommitBench(b, crypto.Sha512_256) }) b.Run("sumhash", func(b *testing.B) { merkleCommitBench(b, crypto.Sumhash) }) + b.Run("sha256", func(b *testing.B) { merkleCommitBench(b, crypto.Sha256) }) } func merkleCommitBench(b *testing.B, hashType crypto.HashType) { @@ -1088,6 +1191,7 @@ func merkleCommitBench(b *testing.B, hashType crypto.HashType) { func BenchmarkMerkleProve1M(b *testing.B) { b.Run("sha512_256", func(b *testing.B) { benchmarkMerkleProve1M(b, crypto.Sha512_256) }) b.Run("sumhash", func(b *testing.B) { benchmarkMerkleProve1M(b, crypto.Sumhash) }) + b.Run("sha256", func(b *testing.B) { benchmarkMerkleProve1M(b, crypto.Sha256) }) } func benchmarkMerkleProve1M(b *testing.B, hashType crypto.HashType) { @@ -1113,6 +1217,7 @@ func benchmarkMerkleProve1M(b *testing.B, hashType crypto.HashType) { func BenchmarkMerkleVerify1M(b *testing.B) { b.Run("sha512_256", func(b *testing.B) { benchmarkMerkleVerify1M(b, crypto.Sha512_256) }) b.Run("sumhash", func(b *testing.B) { benchmarkMerkleVerify1M(b, crypto.Sumhash) }) + b.Run("sha256", func(b *testing.B) { benchmarkMerkleVerify1M(b, crypto.Sha256) }) } func benchmarkMerkleVerify1M(b *testing.B, hashType crypto.HashType) { diff --git a/crypto/merklearray/msgp_gen.go b/crypto/merklearray/msgp_gen.go index 344e7b86d2..ba7e4a61c7 100644 --- a/crypto/merklearray/msgp_gen.go +++ b/crypto/merklearray/msgp_gen.go @@ -3,8 +3,9 @@ package merklearray // Code generated by github.com/algorand/msgp DO NOT EDIT. import ( - "github.com/algorand/go-algorand/crypto" "github.com/algorand/msgp/msgp" + + "github.com/algorand/go-algorand/crypto" ) // The following msgp objects are implemented in this file: diff --git a/crypto/merklearray/msgp_gen_test.go b/crypto/merklearray/msgp_gen_test.go index fbcc81970a..2b50c643b4 100644 --- a/crypto/merklearray/msgp_gen_test.go +++ b/crypto/merklearray/msgp_gen_test.go @@ -1,3 +1,4 @@ +//go:build !skip_msgp_testing // +build !skip_msgp_testing package merklearray @@ -7,9 +8,10 @@ package merklearray import ( "testing" + "github.com/algorand/msgp/msgp" + "github.com/algorand/go-algorand/protocol" "github.com/algorand/go-algorand/test/partitiontest" - "github.com/algorand/msgp/msgp" ) func TestMarshalUnmarshalLayer(t *testing.T) { diff --git a/crypto/merklesignature/msgp_gen.go b/crypto/merklesignature/msgp_gen.go index c97e0df408..a40196d4a6 100644 --- a/crypto/merklesignature/msgp_gen.go +++ b/crypto/merklesignature/msgp_gen.go @@ -3,8 +3,9 @@ package merklesignature // Code generated by github.com/algorand/msgp DO NOT EDIT. import ( - "github.com/algorand/go-algorand/crypto" "github.com/algorand/msgp/msgp" + + "github.com/algorand/go-algorand/crypto" ) // The following msgp objects are implemented in this file: diff --git a/crypto/merklesignature/msgp_gen_test.go b/crypto/merklesignature/msgp_gen_test.go index 9c73788c54..56c8e2bdf3 100644 --- a/crypto/merklesignature/msgp_gen_test.go +++ b/crypto/merklesignature/msgp_gen_test.go @@ -1,3 +1,4 @@ +//go:build !skip_msgp_testing // +build !skip_msgp_testing package merklesignature @@ -7,9 +8,10 @@ package merklesignature import ( "testing" + "github.com/algorand/msgp/msgp" + "github.com/algorand/go-algorand/protocol" "github.com/algorand/go-algorand/test/partitiontest" - "github.com/algorand/msgp/msgp" ) func TestMarshalUnmarshalKeyRoundPair(t *testing.T) { diff --git a/crypto/msgp_gen_test.go b/crypto/msgp_gen_test.go index 21be375fad..b3fb95150b 100644 --- a/crypto/msgp_gen_test.go +++ b/crypto/msgp_gen_test.go @@ -1,3 +1,4 @@ +//go:build !skip_msgp_testing // +build !skip_msgp_testing package crypto @@ -7,9 +8,10 @@ package crypto import ( "testing" + "github.com/algorand/msgp/msgp" + "github.com/algorand/go-algorand/protocol" "github.com/algorand/go-algorand/test/partitiontest" - "github.com/algorand/msgp/msgp" ) func TestMarshalUnmarshalDigest(t *testing.T) { diff --git a/crypto/secp256k1/dummy.go b/crypto/secp256k1/dummy.go index 7c86a7f42a..479e07dc8e 100644 --- a/crypto/secp256k1/dummy.go +++ b/crypto/secp256k1/dummy.go @@ -1,3 +1,4 @@ +//go:build dummy // +build dummy // This file is part of a workaround for `go mod vendor` which won't vendor diff --git a/crypto/secp256k1/libsecp256k1/contrib/dummy.go b/crypto/secp256k1/libsecp256k1/contrib/dummy.go index fda594be99..2c946210c5 100644 --- a/crypto/secp256k1/libsecp256k1/contrib/dummy.go +++ b/crypto/secp256k1/libsecp256k1/contrib/dummy.go @@ -1,3 +1,4 @@ +//go:build dummy // +build dummy // Package c contains only a C file. diff --git a/crypto/secp256k1/libsecp256k1/dummy.go b/crypto/secp256k1/libsecp256k1/dummy.go index 379b16992f..04bbe3d76e 100644 --- a/crypto/secp256k1/libsecp256k1/dummy.go +++ b/crypto/secp256k1/libsecp256k1/dummy.go @@ -1,3 +1,4 @@ +//go:build dummy // +build dummy // Package c contains only a C file. diff --git a/crypto/secp256k1/libsecp256k1/include/dummy.go b/crypto/secp256k1/libsecp256k1/include/dummy.go index 5af540c73c..64c71b8451 100644 --- a/crypto/secp256k1/libsecp256k1/include/dummy.go +++ b/crypto/secp256k1/libsecp256k1/include/dummy.go @@ -1,3 +1,4 @@ +//go:build dummy // +build dummy // Package c contains only a C file. diff --git a/crypto/secp256k1/libsecp256k1/src/dummy.go b/crypto/secp256k1/libsecp256k1/src/dummy.go index 65868f38a8..2df270adc3 100644 --- a/crypto/secp256k1/libsecp256k1/src/dummy.go +++ b/crypto/secp256k1/libsecp256k1/src/dummy.go @@ -1,3 +1,4 @@ +//go:build dummy // +build dummy // Package c contains only a C file. diff --git a/crypto/secp256k1/libsecp256k1/src/modules/dummy.go b/crypto/secp256k1/libsecp256k1/src/modules/dummy.go index 3c7a696439..99c538db51 100644 --- a/crypto/secp256k1/libsecp256k1/src/modules/dummy.go +++ b/crypto/secp256k1/libsecp256k1/src/modules/dummy.go @@ -1,3 +1,4 @@ +//go:build dummy // +build dummy // Package c contains only a C file. diff --git a/crypto/secp256k1/libsecp256k1/src/modules/ecdh/dummy.go b/crypto/secp256k1/libsecp256k1/src/modules/ecdh/dummy.go index b6fc38327e..48c2e0aa54 100644 --- a/crypto/secp256k1/libsecp256k1/src/modules/ecdh/dummy.go +++ b/crypto/secp256k1/libsecp256k1/src/modules/ecdh/dummy.go @@ -1,3 +1,4 @@ +//go:build dummy // +build dummy // Package c contains only a C file. diff --git a/crypto/secp256k1/libsecp256k1/src/modules/recovery/dummy.go b/crypto/secp256k1/libsecp256k1/src/modules/recovery/dummy.go index b9491f0cb9..8efbd7abe7 100644 --- a/crypto/secp256k1/libsecp256k1/src/modules/recovery/dummy.go +++ b/crypto/secp256k1/libsecp256k1/src/modules/recovery/dummy.go @@ -1,3 +1,4 @@ +//go:build dummy // +build dummy // Package c contains only a C file. diff --git a/crypto/secp256k1/panic_cb.go b/crypto/secp256k1/panic_cb.go index 5da2bea376..a30b04f51b 100644 --- a/crypto/secp256k1/panic_cb.go +++ b/crypto/secp256k1/panic_cb.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be found in // the LICENSE file. -// +build !gofuzz -// +build cgo +//go:build !gofuzz && cgo +// +build !gofuzz,cgo package secp256k1 diff --git a/crypto/secp256k1/scalar_mult_cgo.go b/crypto/secp256k1/scalar_mult_cgo.go index 8e29d65b04..d1b4c8b20e 100644 --- a/crypto/secp256k1/scalar_mult_cgo.go +++ b/crypto/secp256k1/scalar_mult_cgo.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be found in // the LICENSE file. -// +build !gofuzz -// +build cgo +//go:build !gofuzz && cgo +// +build !gofuzz,cgo package secp256k1 diff --git a/crypto/secp256k1/scalar_mult_nocgo.go b/crypto/secp256k1/scalar_mult_nocgo.go index 55756b5be8..22f53ac6ae 100644 --- a/crypto/secp256k1/scalar_mult_nocgo.go +++ b/crypto/secp256k1/scalar_mult_nocgo.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be found in // the LICENSE file. +//go:build gofuzz || !cgo // +build gofuzz !cgo package secp256k1 diff --git a/crypto/secp256k1/secp256.go b/crypto/secp256k1/secp256.go index 067b5e6c50..7fbce862e1 100644 --- a/crypto/secp256k1/secp256.go +++ b/crypto/secp256k1/secp256.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be found in // the LICENSE file. -// +build !gofuzz -// +build cgo +//go:build !gofuzz && cgo +// +build !gofuzz,cgo // Package secp256k1 wraps the bitcoin secp256k1 C library. package secp256k1 diff --git a/daemon/algod/api/algod.oas2.json b/daemon/algod/api/algod.oas2.json index 8202ce1caa..8e2c69e54c 100644 --- a/daemon/algod/api/algod.oas2.json +++ b/daemon/algod/api/algod.oas2.json @@ -549,6 +549,17 @@ "in": "path", "required": true }, + { + "type": "string", + "enum": [ + "sha512_256", + "sha256" + ], + "description": "The type of hash function used to create the proof, must be one of: \n* sha512_256 \n* sha256", + "name": "hashtype", + "in": "query", + "required": false + }, { "$ref": "#/parameters/format" } @@ -1385,6 +1396,12 @@ "type": "string", "format": "binary" } + }, + { + "name": "sourcemap", + "description": "When set to `true`, returns the source map of the program as a JSON. Defaults to `false`.", + "in": "query", + "type": "boolean" } ], "responses": { @@ -1421,7 +1438,7 @@ }, "/v2/teal/disassemble": { "post": { - "description": "Given the base64 encoded program bytes, return the TEAL source code in plain text. This endpoint is only enabled when a node's configuration file sets EnableDeveloperAPI to true.", + "description": "Given the program bytes, return the TEAL source code in plain text. This endpoint is only enabled when a node's configuration file sets EnableDeveloperAPI to true.", "consumes": [ "application/x-binary" ], @@ -2278,8 +2295,16 @@ "format": "byte" } }, + "budget-added": { + "description": "Budget added during execution of app call transaction.", + "type": "integer" + }, + "budget-consumed": { + "description": "Budget consumed during execution of app call transaction.", + "type": "integer" + }, "cost": { - "description": "Execution cost of app call transaction", + "description": "Net cost of app execution. Field is DEPRECATED and is subject for removal. Instead, use `budget-added` and `budget-consumed.", "type": "integer" } } @@ -2801,12 +2826,12 @@ "type": "integer" }, "hashtype": { + "type": "string", "enum": [ - "sumhash", - "sha512_256" + "sha512_256", + "sha256" ], - "type": "string", - "description": "The type of hash function used to create the proof, must be one of:\n* sumhash \n* sha512_256" + "description": "The type of hash function used to create the proof, must be one of: \n* sha512_256 \n* sha256" } } } @@ -3094,6 +3119,10 @@ "result": { "description": "base64 encoded program bytes", "type": "string" + }, + "sourcemap": { + "description": "JSON of the source map", + "type": "object" } } } diff --git a/daemon/algod/api/algod.oas3.yml b/daemon/algod/api/algod.oas3.yml index bb8b76408c..0fa09dd559 100644 --- a/daemon/algod/api/algod.oas3.yml +++ b/daemon/algod/api/algod.oas3.yml @@ -380,6 +380,11 @@ "result": { "description": "base64 encoded program bytes", "type": "string" + }, + "sourcemap": { + "description": "JSON of the source map", + "properties": {}, + "type": "object" } }, "required": [ @@ -620,10 +625,10 @@ "schema": { "properties": { "hashtype": { - "description": "The type of hash function used to create the proof, must be one of:\n* sumhash \n* sha512_256", + "description": "The type of hash function used to create the proof, must be one of: \n* sha512_256 \n* sha256", "enum": [ - "sumhash", - "sha512_256" + "sha512_256", + "sha256" ], "type": "string" }, @@ -1323,8 +1328,16 @@ }, "type": "array" }, + "budget-added": { + "description": "Budget added during execution of app call transaction.", + "type": "integer" + }, + "budget-consumed": { + "description": "Budget consumed during execution of app call transaction.", + "type": "integer" + }, "cost": { - "description": "Execution cost of app call transaction", + "description": "Net cost of app execution. Field is DEPRECATED and is subject for removal. Instead, use `budget-added` and `budget-consumed.", "type": "integer" }, "disassembly": { @@ -2606,6 +2619,18 @@ "type": "string" } }, + { + "description": "The type of hash function used to create the proof, must be one of: \n* sha512_256 \n* sha256", + "in": "query", + "name": "hashtype", + "schema": { + "enum": [ + "sha512_256", + "sha256" + ], + "type": "string" + } + }, { "description": "Configures whether the response object is JSON or MessagePack encoded.", "in": "query", @@ -2626,10 +2651,10 @@ "schema": { "properties": { "hashtype": { - "description": "The type of hash function used to create the proof, must be one of:\n* sumhash \n* sha512_256", + "description": "The type of hash function used to create the proof, must be one of: \n* sha512_256 \n* sha256", "enum": [ - "sumhash", - "sha512_256" + "sha512_256", + "sha256" ], "type": "string" }, @@ -3634,6 +3659,16 @@ "post": { "description": "Given TEAL source code in plain text, return base64 encoded program bytes and base32 SHA512_256 hash of program bytes (Address style). This endpoint is only enabled when a node's configuration file sets EnableDeveloperAPI to true.", "operationId": "TealCompile", + "parameters": [ + { + "description": "When set to `true`, returns the source map of the program as a JSON. Defaults to `false`.", + "in": "query", + "name": "sourcemap", + "schema": { + "type": "boolean" + } + } + ], "requestBody": { "content": { "text/plain": { @@ -3659,6 +3694,11 @@ "result": { "description": "base64 encoded program bytes", "type": "string" + }, + "sourcemap": { + "description": "JSON of the source map", + "properties": {}, + "type": "object" } }, "required": [ @@ -3716,7 +3756,7 @@ }, "/v2/teal/disassemble": { "post": { - "description": "Given the base64 encoded program bytes, return the TEAL source code in plain text. This endpoint is only enabled when a node's configuration file sets EnableDeveloperAPI to true.", + "description": "Given the program bytes, return the TEAL source code in plain text. This endpoint is only enabled when a node's configuration file sets EnableDeveloperAPI to true.", "operationId": "TealDisassemble", "requestBody": { "content": { diff --git a/daemon/algod/api/client/restClient.go b/daemon/algod/api/client/restClient.go index 596a8d4581..ecaafc6360 100644 --- a/daemon/algod/api/client/restClient.go +++ b/daemon/algod/api/client/restClient.go @@ -369,6 +369,10 @@ type rawFormat struct { Format string `url:"format"` } +type proofParams struct { + HashType string `url:"hashtype"` +} + type accountInformationParams struct { Format string `url:"format"` Exclude string `url:"exclude"` @@ -651,9 +655,9 @@ func (client RestClient) RawDryrun(data []byte) (response []byte, err error) { } // Proof gets a Merkle proof for a transaction in a block. -func (client RestClient) Proof(txid string, round uint64) (response generatedV2.ProofResponse, err error) { +func (client RestClient) Proof(txid string, round uint64, hashType crypto.HashType) (response generatedV2.ProofResponse, err error) { txid = stripTransaction(txid) - err = client.get(&response, fmt.Sprintf("/v2/blocks/%d/transactions/%s/proof", round, txid), nil) + err = client.get(&response, fmt.Sprintf("/v2/blocks/%d/transactions/%s/proof", round, txid), proofParams{HashType: hashType.String()}) return } diff --git a/daemon/algod/api/server/lib/bundledSpecInject.go b/daemon/algod/api/server/lib/bundledSpecInject.go index cd8f380d0f..fefff94163 100644 --- a/daemon/algod/api/server/lib/bundledSpecInject.go +++ b/daemon/algod/api/server/lib/bundledSpecInject.go @@ -2668,230 +2668,189 @@ func init() { 0x2E, 0x5C, 0x6E, 0x46, 0x6F, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x6D, 0x70, 0x74, 0x79, 0x20, 0x62, 0x6C, 0x6F, 0x63, 0x6B, 0x2C, 0x20, 0x69, 0x74, 0x27, 0x73, 0x20, 0x30, 0x2E, 0x5C, 0x6E, 0x4E, 0x6F, 0x74, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x54, - 0x78, 0x6E, 0x52, 0x6F, 0x6F, 0x74, 0x20, 0x64, 0x6F, 0x65, 0x73, 0x20, 0x6E, 0x6F, 0x74, 0x20, - 0x61, 0x75, 0x74, 0x68, 0x65, 0x6E, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x73, 0x69, 0x67, 0x6E, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x20, 0x6F, 0x6E, 0x20, 0x74, - 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2C, - 0x20, 0x6F, 0x6E, 0x6C, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x20, 0x74, 0x68, 0x65, 0x6D, 0x73, 0x65, 0x6C, 0x76, 0x65, - 0x73, 0x2E, 0x5C, 0x6E, 0x54, 0x77, 0x6F, 0x20, 0x62, 0x6C, 0x6F, 0x63, 0x6B, 0x73, 0x20, 0x77, - 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x6D, 0x65, 0x20, 0x74, 0x72, 0x61, - 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x20, 0x62, 0x75, 0x74, 0x20, 0x69, 0x6E, - 0x20, 0x61, 0x20, 0x64, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6E, 0x74, 0x20, 0x6F, 0x72, 0x64, - 0x65, 0x72, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x64, 0x69, 0x66, 0x66, - 0x65, 0x72, 0x65, 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, - 0x20, 0x77, 0x69, 0x6C, 0x6C, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, - 0x61, 0x6D, 0x65, 0x20, 0x54, 0x78, 0x6E, 0x52, 0x6F, 0x6F, 0x74, 0x2E, 0x22, 0x2C, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, - 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, - 0x3A, 0x20, 0x22, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x52, - 0x6F, 0x6F, 0x74, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x78, 0x6E, 0x73, 0x22, 0x3A, 0x20, - 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x24, 0x72, 0x65, - 0x66, 0x22, 0x3A, 0x20, 0x22, 0x23, 0x2F, 0x64, 0x65, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x6F, - 0x6E, 0x73, 0x2F, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x4C, 0x69, - 0x73, 0x74, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x41, - 0x70, 0x70, 0x72, 0x6F, 0x76, 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, - 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x41, 0x70, 0x70, 0x72, - 0x6F, 0x76, 0x65, 0x20, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x20, 0x61, 0x20, - 0x79, 0x65, 0x73, 0x20, 0x76, 0x6F, 0x74, 0x65, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x74, 0x20, 0x70, 0x72, 0x6F, 0x70, 0x6F, 0x73, 0x61, - 0x6C, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, - 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x62, 0x6F, 0x6F, 0x6C, 0x65, 0x61, 0x6E, 0x22, 0x2C, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, - 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, - 0x41, 0x70, 0x70, 0x72, 0x6F, 0x76, 0x65, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x75, 0x70, 0x67, - 0x72, 0x61, 0x64, 0x65, 0x50, 0x72, 0x6F, 0x70, 0x6F, 0x73, 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, - 0x65, 0x50, 0x72, 0x6F, 0x70, 0x6F, 0x73, 0x65, 0x20, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x61, 0x74, - 0x65, 0x73, 0x20, 0x61, 0x20, 0x70, 0x72, 0x6F, 0x70, 0x6F, 0x73, 0x65, 0x64, 0x20, 0x75, 0x70, - 0x67, 0x72, 0x61, 0x64, 0x65, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, - 0x67, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, - 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x55, 0x70, 0x67, 0x72, - 0x61, 0x64, 0x65, 0x50, 0x72, 0x6F, 0x70, 0x6F, 0x73, 0x65, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x70, 0x61, 0x63, 0x6B, 0x61, - 0x67, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2E, 0x63, 0x6F, 0x6D, - 0x2F, 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x67, 0x6F, 0x2D, 0x61, 0x6C, 0x67, - 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x64, 0x61, 0x65, 0x6D, 0x6F, 0x6E, 0x2F, 0x61, 0x6C, 0x67, - 0x6F, 0x64, 0x2F, 0x61, 0x70, 0x69, 0x2F, 0x73, 0x70, 0x65, 0x63, 0x2F, 0x76, 0x31, 0x22, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, 0x42, 0x75, 0x69, 0x6C, - 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x6F, 0x62, 0x6A, 0x65, - 0x63, 0x74, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x69, 0x74, 0x6C, - 0x65, 0x22, 0x3A, 0x20, 0x22, 0x42, 0x75, 0x69, 0x6C, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, - 0x6E, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, - 0x75, 0x72, 0x72, 0x65, 0x6E, 0x74, 0x20, 0x61, 0x6C, 0x67, 0x6F, 0x64, 0x20, 0x62, 0x75, 0x69, - 0x6C, 0x64, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x69, 0x6E, 0x66, 0x6F, 0x72, - 0x6D, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x2E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x22, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x22, 0x3A, 0x20, 0x5B, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6D, 0x61, 0x6A, 0x6F, 0x72, 0x22, 0x2C, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6D, 0x69, 0x6E, 0x6F, 0x72, 0x22, 0x2C, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x62, 0x75, 0x69, 0x6C, 0x64, 0x5F, 0x6E, - 0x75, 0x6D, 0x62, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x22, 0x63, 0x6F, 0x6D, 0x6D, 0x69, 0x74, 0x5F, 0x68, 0x61, 0x73, 0x68, 0x22, 0x2C, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x62, 0x72, 0x61, 0x6E, 0x63, 0x68, 0x22, 0x2C, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x68, 0x61, 0x6E, 0x6E, 0x65, - 0x6C, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x22, 0x70, 0x72, 0x6F, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3A, 0x20, - 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x62, 0x72, 0x61, 0x6E, 0x63, - 0x68, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, - 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, - 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x42, 0x72, 0x61, 0x6E, 0x63, 0x68, + 0x78, 0x6E, 0x43, 0x6F, 0x6D, 0x6D, 0x69, 0x74, 0x6D, 0x65, 0x6E, 0x74, 0x73, 0x20, 0x64, 0x6F, + 0x65, 0x73, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6E, 0x74, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x61, 0x74, 0x75, 0x72, + 0x65, 0x73, 0x20, 0x6F, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2C, 0x20, 0x6F, 0x6E, 0x6C, 0x79, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x20, 0x74, 0x68, + 0x65, 0x6D, 0x73, 0x65, 0x6C, 0x76, 0x65, 0x73, 0x2E, 0x5C, 0x6E, 0x54, 0x77, 0x6F, 0x20, 0x62, + 0x6C, 0x6F, 0x63, 0x6B, 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, + 0x61, 0x6D, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, + 0x20, 0x62, 0x75, 0x74, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, 0x64, 0x69, 0x66, 0x66, 0x65, 0x72, + 0x65, 0x6E, 0x74, 0x20, 0x6F, 0x72, 0x64, 0x65, 0x72, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x20, 0x64, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, + 0x6E, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x20, 0x77, 0x69, 0x6C, 0x6C, 0x20, 0x68, 0x61, 0x76, + 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x6D, 0x65, 0x20, 0x54, 0x78, 0x6E, 0x43, 0x6F, + 0x6D, 0x6D, 0x69, 0x74, 0x6D, 0x65, 0x6E, 0x74, 0x73, 0x2E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, + 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, + 0x22, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x52, 0x6F, 0x6F, + 0x74, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x78, 0x6E, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, + 0x3A, 0x20, 0x22, 0x23, 0x2F, 0x64, 0x65, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, + 0x2F, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x62, 0x75, 0x69, 0x6C, 0x64, 0x5F, 0x6E, 0x75, 0x6D, 0x62, - 0x65, 0x72, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, - 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, - 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, - 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x42, 0x75, 0x69, 0x6C, 0x64, 0x4E, 0x75, - 0x6D, 0x62, 0x65, 0x72, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x68, 0x61, 0x6E, 0x6E, 0x65, - 0x6C, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x41, 0x70, 0x70, + 0x72, 0x6F, 0x76, 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, + 0x3A, 0x20, 0x22, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x41, 0x70, 0x70, 0x72, 0x6F, 0x76, + 0x65, 0x20, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x20, 0x61, 0x20, 0x79, 0x65, + 0x73, 0x20, 0x76, 0x6F, 0x74, 0x65, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, + 0x75, 0x72, 0x72, 0x65, 0x6E, 0x74, 0x20, 0x70, 0x72, 0x6F, 0x70, 0x6F, 0x73, 0x61, 0x6C, 0x22, + 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, + 0x65, 0x22, 0x3A, 0x20, 0x22, 0x62, 0x6F, 0x6F, 0x6C, 0x65, 0x61, 0x6E, 0x22, 0x2C, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, + 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x41, 0x70, + 0x70, 0x72, 0x6F, 0x76, 0x65, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, + 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x75, 0x70, 0x67, 0x72, 0x61, + 0x64, 0x65, 0x50, 0x72, 0x6F, 0x70, 0x6F, 0x73, 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x50, + 0x72, 0x6F, 0x70, 0x6F, 0x73, 0x65, 0x20, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, + 0x20, 0x61, 0x20, 0x70, 0x72, 0x6F, 0x70, 0x6F, 0x73, 0x65, 0x64, 0x20, 0x75, 0x70, 0x67, 0x72, + 0x61, 0x64, 0x65, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, - 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x43, 0x68, 0x61, 0x6E, 0x6E, 0x65, - 0x6C, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x6F, 0x6D, 0x6D, 0x69, 0x74, 0x5F, 0x68, 0x61, - 0x73, 0x68, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, - 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, - 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x43, 0x6F, 0x6D, 0x6D, 0x69, - 0x74, 0x48, 0x61, 0x73, 0x68, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, - 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6D, 0x61, 0x6A, 0x6F, 0x72, + 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, + 0x65, 0x50, 0x72, 0x6F, 0x70, 0x6F, 0x73, 0x65, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x70, 0x61, 0x63, 0x6B, 0x61, 0x67, 0x65, + 0x22, 0x3A, 0x20, 0x22, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x61, + 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x67, 0x6F, 0x2D, 0x61, 0x6C, 0x67, 0x6F, 0x72, + 0x61, 0x6E, 0x64, 0x2F, 0x64, 0x61, 0x65, 0x6D, 0x6F, 0x6E, 0x2F, 0x61, 0x6C, 0x67, 0x6F, 0x64, + 0x2F, 0x61, 0x70, 0x69, 0x2F, 0x73, 0x70, 0x65, 0x63, 0x2F, 0x76, 0x31, 0x22, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, 0x42, 0x75, 0x69, 0x6C, 0x64, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, + 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x69, 0x74, 0x6C, 0x65, 0x22, + 0x3A, 0x20, 0x22, 0x42, 0x75, 0x69, 0x6C, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x20, + 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x75, 0x72, + 0x72, 0x65, 0x6E, 0x74, 0x20, 0x61, 0x6C, 0x67, 0x6F, 0x64, 0x20, 0x62, 0x75, 0x69, 0x6C, 0x64, + 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x69, 0x6E, 0x66, 0x6F, 0x72, 0x6D, 0x61, + 0x74, 0x69, 0x6F, 0x6E, 0x2E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x72, + 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x22, 0x3A, 0x20, 0x5B, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x6D, 0x61, 0x6A, 0x6F, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6D, 0x69, 0x6E, 0x6F, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x62, 0x75, 0x69, 0x6C, 0x64, 0x5F, 0x6E, 0x75, 0x6D, + 0x62, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, + 0x6F, 0x6D, 0x6D, 0x69, 0x74, 0x5F, 0x68, 0x61, 0x73, 0x68, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x62, 0x72, 0x61, 0x6E, 0x63, 0x68, 0x22, 0x2C, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x68, 0x61, 0x6E, 0x6E, 0x65, 0x6C, 0x22, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x22, 0x70, 0x72, 0x6F, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x62, 0x72, 0x61, 0x6E, 0x63, 0x68, 0x22, + 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, + 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, + 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x42, 0x72, 0x61, 0x6E, 0x63, 0x68, 0x22, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x62, 0x75, 0x69, 0x6C, 0x64, 0x5F, 0x6E, 0x75, 0x6D, 0x62, 0x65, 0x72, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, - 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x4D, 0x61, 0x6A, 0x6F, 0x72, 0x22, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x6D, 0x69, 0x6E, 0x6F, 0x72, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, - 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, - 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x4D, 0x69, - 0x6E, 0x6F, 0x72, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, - 0x2D, 0x67, 0x6F, 0x2D, 0x70, 0x61, 0x63, 0x6B, 0x61, 0x67, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, - 0x6E, 0x64, 0x2F, 0x67, 0x6F, 0x2D, 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x64, - 0x61, 0x65, 0x6D, 0x6F, 0x6E, 0x2F, 0x61, 0x6C, 0x67, 0x6F, 0x64, 0x2F, 0x61, 0x70, 0x69, 0x2F, - 0x73, 0x70, 0x65, 0x63, 0x2F, 0x63, 0x6F, 0x6D, 0x6D, 0x6F, 0x6E, 0x22, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, 0x43, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, - 0x43, 0x65, 0x72, 0x74, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x54, - 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, - 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x43, 0x6F, - 0x6D, 0x70, 0x61, 0x63, 0x74, 0x43, 0x65, 0x72, 0x74, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6F, 0x6E, 0x54, 0x79, 0x70, 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, 0x6E, - 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x61, 0x6C, - 0x20, 0x66, 0x69, 0x65, 0x6C, 0x64, 0x73, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x61, 0x20, 0x63, 0x6F, - 0x6D, 0x70, 0x61, 0x63, 0x74, 0x20, 0x63, 0x65, 0x72, 0x74, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, - 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x22, 0x2C, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, - 0x22, 0x3A, 0x20, 0x5B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x72, 0x6E, - 0x64, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x65, 0x72, - 0x74, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x22, 0x70, 0x72, 0x6F, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3A, 0x20, - 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x65, 0x72, 0x74, 0x22, - 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, - 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x43, 0x65, - 0x72, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6D, 0x73, 0x67, 0x70, 0x61, 0x63, - 0x6B, 0x20, 0x65, 0x6E, 0x63, 0x6F, 0x64, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, - 0x65, 0x20, 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0x20, 0x63, 0x65, 0x72, 0x74, 0x2E, 0x22, - 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, - 0x65, 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, - 0x3A, 0x20, 0x22, 0x62, 0x79, 0x74, 0x65, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, - 0x20, 0x22, 0x43, 0x65, 0x72, 0x74, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x72, 0x6E, 0x64, 0x22, - 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, - 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x43, 0x65, - 0x72, 0x74, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, - 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x77, 0x68, 0x6F, 0x73, 0x65, 0x20, 0x62, 0x6C, 0x6F, 0x63, 0x6B, - 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0x20, 0x63, 0x65, - 0x72, 0x74, 0x20, 0x72, 0x65, 0x66, 0x65, 0x72, 0x73, 0x20, 0x74, 0x6F, 0x2E, 0x22, 0x2C, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, - 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, - 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, - 0x3A, 0x20, 0x22, 0x43, 0x65, 0x72, 0x74, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x70, 0x61, 0x63, - 0x6B, 0x61, 0x67, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2E, 0x63, - 0x6F, 0x6D, 0x2F, 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x67, 0x6F, 0x2D, 0x61, - 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x64, 0x61, 0x65, 0x6D, 0x6F, 0x6E, 0x2F, 0x61, - 0x6C, 0x67, 0x6F, 0x64, 0x2F, 0x61, 0x70, 0x69, 0x2F, 0x73, 0x70, 0x65, 0x63, 0x2F, 0x76, 0x31, - 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, 0x4B, 0x65, - 0x79, 0x72, 0x65, 0x67, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x54, - 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, - 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x4B, 0x65, - 0x79, 0x72, 0x65, 0x67, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x54, - 0x79, 0x70, 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x73, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x66, 0x69, 0x65, 0x6C, - 0x64, 0x73, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x61, 0x20, 0x6B, 0x65, 0x79, 0x72, 0x65, 0x67, 0x20, - 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x6F, 0x62, 0x6A, - 0x65, 0x63, 0x74, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x72, 0x6F, - 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x65, 0x6C, 0x6B, 0x65, 0x79, 0x22, 0x3A, 0x20, 0x7B, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x53, 0x65, 0x6C, 0x65, 0x63, 0x74, - 0x69, 0x6F, 0x6E, 0x50, 0x4B, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x56, 0x52, 0x46, - 0x20, 0x70, 0x75, 0x62, 0x6C, 0x69, 0x63, 0x20, 0x6B, 0x65, 0x79, 0x20, 0x75, 0x73, 0x65, 0x64, - 0x20, 0x69, 0x6E, 0x20, 0x6B, 0x65, 0x79, 0x20, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, - 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, - 0x73, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, + 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x42, 0x75, 0x69, 0x6C, 0x64, 0x4E, 0x75, 0x6D, 0x62, + 0x65, 0x72, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x68, 0x61, 0x6E, 0x6E, 0x65, 0x6C, 0x22, + 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, - 0x74, 0x22, 0x3A, 0x20, 0x22, 0x62, 0x79, 0x74, 0x65, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, - 0x22, 0x3A, 0x20, 0x22, 0x53, 0x65, 0x6C, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x50, 0x4B, 0x22, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, + 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x43, 0x68, 0x61, 0x6E, 0x6E, 0x65, 0x6C, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x6F, 0x74, 0x65, 0x66, 0x73, 0x74, 0x22, 0x3A, 0x20, 0x7B, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x56, 0x6F, 0x74, 0x65, 0x46, - 0x69, 0x72, 0x73, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x72, 0x73, - 0x74, 0x20, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x70, 0x61, 0x72, - 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x6B, 0x65, 0x79, 0x20, 0x69, - 0x73, 0x20, 0x76, 0x61, 0x6C, 0x69, 0x64, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x6F, 0x6D, 0x6D, 0x69, 0x74, 0x5F, 0x68, 0x61, 0x73, 0x68, + 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, + 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x43, 0x6F, 0x6D, 0x6D, 0x69, 0x74, 0x48, + 0x61, 0x73, 0x68, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6D, 0x61, 0x6A, 0x6F, 0x72, 0x22, 0x3A, + 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, + 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, + 0x74, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, + 0x65, 0x22, 0x3A, 0x20, 0x22, 0x4D, 0x61, 0x6A, 0x6F, 0x72, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x6D, 0x69, 0x6E, 0x6F, 0x72, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, - 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, - 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x56, 0x6F, 0x74, - 0x65, 0x46, 0x69, 0x72, 0x73, 0x74, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x6F, 0x74, 0x65, - 0x6B, 0x64, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, - 0x22, 0x56, 0x6F, 0x74, 0x65, 0x4B, 0x65, 0x79, 0x44, 0x69, 0x6C, 0x75, 0x74, 0x69, 0x6F, 0x6E, - 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x69, 0x6C, 0x75, 0x74, 0x69, 0x6F, 0x6E, - 0x20, 0x66, 0x6F, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x32, 0x2D, 0x6C, 0x65, 0x76, 0x65, 0x6C, - 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x6B, - 0x65, 0x79, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, - 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, - 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, - 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, - 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x56, 0x6F, 0x74, 0x65, 0x4B, 0x65, 0x79, 0x44, - 0x69, 0x6C, 0x75, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x6F, 0x74, - 0x65, 0x6B, 0x65, 0x79, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, - 0x3A, 0x20, 0x22, 0x56, 0x6F, 0x74, 0x65, 0x50, 0x4B, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x70, + 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x36, + 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, + 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x4D, 0x69, 0x6E, 0x6F, + 0x72, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, + 0x6F, 0x2D, 0x70, 0x61, 0x63, 0x6B, 0x61, 0x67, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, + 0x2F, 0x67, 0x6F, 0x2D, 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x64, 0x61, 0x65, + 0x6D, 0x6F, 0x6E, 0x2F, 0x61, 0x6C, 0x67, 0x6F, 0x64, 0x2F, 0x61, 0x70, 0x69, 0x2F, 0x73, 0x70, + 0x65, 0x63, 0x2F, 0x63, 0x6F, 0x6D, 0x6D, 0x6F, 0x6E, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, + 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, 0x43, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0x43, 0x65, + 0x72, 0x74, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x54, 0x79, 0x70, + 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x43, 0x6F, 0x6D, 0x70, + 0x61, 0x63, 0x74, 0x43, 0x65, 0x72, 0x74, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6F, 0x6E, 0x54, 0x79, 0x70, 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x73, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x66, + 0x69, 0x65, 0x6C, 0x64, 0x73, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x61, 0x20, 0x63, 0x6F, 0x6D, 0x70, + 0x61, 0x63, 0x74, 0x20, 0x63, 0x65, 0x72, 0x74, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, + 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x22, 0x2C, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x22, 0x3A, + 0x20, 0x5B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x72, 0x6E, 0x64, 0x22, + 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x65, 0x72, 0x74, 0x22, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x22, 0x70, 0x72, 0x6F, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x65, 0x72, 0x74, 0x22, 0x3A, 0x20, + 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x43, 0x65, 0x72, 0x74, + 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6D, 0x73, 0x67, 0x70, 0x61, 0x63, 0x6B, 0x20, + 0x65, 0x6E, 0x63, 0x6F, 0x64, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0x20, 0x63, 0x65, 0x72, 0x74, 0x2E, 0x22, 0x2C, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, + 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, + 0x22, 0x62, 0x79, 0x74, 0x65, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, + 0x43, 0x65, 0x72, 0x74, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x72, 0x6E, 0x64, 0x22, 0x3A, 0x20, + 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x43, 0x65, 0x72, 0x74, + 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x6F, 0x75, + 0x6E, 0x64, 0x20, 0x77, 0x68, 0x6F, 0x73, 0x65, 0x20, 0x62, 0x6C, 0x6F, 0x63, 0x6B, 0x20, 0x74, + 0x68, 0x69, 0x73, 0x20, 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0x20, 0x63, 0x65, 0x72, 0x74, + 0x20, 0x72, 0x65, 0x66, 0x65, 0x72, 0x73, 0x20, 0x74, 0x6F, 0x2E, 0x22, 0x2C, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, + 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, + 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, + 0x22, 0x43, 0x65, 0x72, 0x74, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x70, 0x61, 0x63, 0x6B, 0x61, + 0x67, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2E, 0x63, 0x6F, 0x6D, + 0x2F, 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x67, 0x6F, 0x2D, 0x61, 0x6C, 0x67, + 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x64, 0x61, 0x65, 0x6D, 0x6F, 0x6E, 0x2F, 0x61, 0x6C, 0x67, + 0x6F, 0x64, 0x2F, 0x61, 0x70, 0x69, 0x2F, 0x73, 0x70, 0x65, 0x63, 0x2F, 0x76, 0x31, 0x22, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, 0x4B, 0x65, 0x79, 0x72, + 0x65, 0x67, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x54, 0x79, 0x70, + 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x4B, 0x65, 0x79, 0x72, + 0x65, 0x67, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x54, 0x79, 0x70, + 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, + 0x64, 0x64, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x66, 0x69, 0x65, 0x6C, 0x64, 0x73, + 0x20, 0x66, 0x6F, 0x72, 0x20, 0x61, 0x20, 0x6B, 0x65, 0x79, 0x72, 0x65, 0x67, 0x20, 0x54, 0x72, + 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, + 0x74, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x72, 0x6F, 0x70, 0x65, + 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x73, 0x65, 0x6C, 0x6B, 0x65, 0x79, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x53, 0x65, 0x6C, 0x65, 0x63, 0x74, 0x69, 0x6F, + 0x6E, 0x50, 0x4B, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x56, 0x52, 0x46, 0x20, 0x70, 0x75, 0x62, 0x6C, 0x69, 0x63, 0x20, 0x6B, 0x65, 0x79, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x69, 0x6E, 0x20, 0x6B, 0x65, 0x79, 0x20, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x22, @@ -2900,1311 +2859,1353 @@ func init() { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x62, 0x79, 0x74, 0x65, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, - 0x20, 0x22, 0x56, 0x6F, 0x74, 0x65, 0x50, 0x4B, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x6F, - 0x74, 0x65, 0x6C, 0x73, 0x74, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, - 0x22, 0x3A, 0x20, 0x22, 0x56, 0x6F, 0x74, 0x65, 0x4C, 0x61, 0x73, 0x74, 0x20, 0x69, 0x73, 0x20, - 0x74, 0x68, 0x65, 0x20, 0x6C, 0x61, 0x73, 0x74, 0x20, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x74, - 0x68, 0x69, 0x73, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x74, 0x69, 0x6F, - 0x6E, 0x20, 0x6B, 0x65, 0x79, 0x20, 0x69, 0x73, 0x20, 0x76, 0x61, 0x6C, 0x69, 0x64, 0x22, 0x2C, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, - 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, - 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, - 0x22, 0x3A, 0x20, 0x22, 0x56, 0x6F, 0x74, 0x65, 0x4C, 0x61, 0x73, 0x74, 0x22, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x70, 0x61, 0x63, - 0x6B, 0x61, 0x67, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2E, 0x63, - 0x6F, 0x6D, 0x2F, 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x67, 0x6F, 0x2D, 0x61, - 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x64, 0x61, 0x65, 0x6D, 0x6F, 0x6E, 0x2F, 0x61, - 0x6C, 0x67, 0x6F, 0x64, 0x2F, 0x61, 0x70, 0x69, 0x2F, 0x73, 0x70, 0x65, 0x63, 0x2F, 0x76, 0x31, - 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, 0x4E, 0x6F, - 0x64, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, - 0x3A, 0x20, 0x22, 0x4E, 0x6F, 0x64, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x20, 0x63, 0x6F, - 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x69, 0x6E, 0x66, 0x6F, 0x72, - 0x6D, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x61, 0x20, 0x6E, - 0x6F, 0x64, 0x65, 0x20, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x6F, 0x62, 0x6A, 0x65, - 0x63, 0x74, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x72, 0x65, 0x71, 0x75, - 0x69, 0x72, 0x65, 0x64, 0x22, 0x3A, 0x20, 0x5B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x6C, 0x61, 0x73, 0x74, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x2C, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6C, 0x61, 0x73, 0x74, 0x43, 0x6F, 0x6E, 0x73, 0x65, - 0x6E, 0x73, 0x75, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6E, 0x65, 0x78, 0x74, 0x43, 0x6F, 0x6E, 0x73, 0x65, - 0x6E, 0x73, 0x75, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6E, 0x65, 0x78, 0x74, 0x43, 0x6F, 0x6E, 0x73, 0x65, - 0x6E, 0x73, 0x75, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x52, 0x6F, 0x75, 0x6E, 0x64, - 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6E, 0x65, 0x78, 0x74, - 0x43, 0x6F, 0x6E, 0x73, 0x65, 0x6E, 0x73, 0x75, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, - 0x53, 0x75, 0x70, 0x70, 0x6F, 0x72, 0x74, 0x65, 0x64, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x69, 0x6D, 0x65, 0x53, 0x69, 0x6E, 0x63, 0x65, 0x4C, 0x61, - 0x73, 0x74, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x22, 0x63, 0x61, 0x74, 0x63, 0x68, 0x75, 0x70, 0x54, 0x69, 0x6D, 0x65, 0x22, 0x2C, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x68, 0x61, 0x73, 0x53, 0x79, 0x6E, - 0x63, 0x65, 0x64, 0x53, 0x69, 0x6E, 0x63, 0x65, 0x53, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x22, - 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x74, 0x6F, 0x70, 0x70, - 0x65, 0x64, 0x41, 0x74, 0x55, 0x6E, 0x73, 0x75, 0x70, 0x70, 0x6F, 0x72, 0x74, 0x65, 0x64, 0x52, - 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5D, 0x2C, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x72, 0x6F, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, - 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x61, - 0x74, 0x63, 0x68, 0x75, 0x70, 0x54, 0x69, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x43, 0x61, 0x74, 0x63, 0x68, 0x75, 0x70, 0x54, - 0x69, 0x6D, 0x65, 0x20, 0x69, 0x6E, 0x20, 0x6E, 0x61, 0x6E, 0x6F, 0x73, 0x65, 0x63, 0x6F, 0x6E, - 0x64, 0x73, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, - 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, - 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, - 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, - 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x43, 0x61, 0x74, 0x63, 0x68, 0x75, 0x70, 0x54, 0x69, - 0x6D, 0x65, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x68, 0x61, 0x73, 0x53, 0x79, 0x6E, 0x63, 0x65, - 0x64, 0x53, 0x69, 0x6E, 0x63, 0x65, 0x53, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x22, 0x3A, 0x20, - 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x48, 0x61, 0x73, 0x53, - 0x79, 0x6E, 0x63, 0x65, 0x64, 0x53, 0x69, 0x6E, 0x63, 0x65, 0x53, 0x74, 0x61, 0x72, 0x74, 0x75, - 0x70, 0x20, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x20, 0x77, 0x68, 0x65, 0x74, - 0x68, 0x65, 0x72, 0x20, 0x61, 0x20, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x68, 0x61, 0x73, 0x20, - 0x63, 0x6F, 0x6D, 0x70, 0x6C, 0x65, 0x74, 0x65, 0x64, 0x20, 0x73, 0x69, 0x6E, 0x63, 0x65, 0x20, - 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x62, 0x6F, 0x6F, - 0x6C, 0x65, 0x61, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x48, - 0x61, 0x73, 0x53, 0x79, 0x6E, 0x63, 0x65, 0x64, 0x53, 0x69, 0x6E, 0x63, 0x65, 0x53, 0x74, 0x61, - 0x72, 0x74, 0x75, 0x70, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6C, 0x61, 0x73, 0x74, 0x43, 0x6F, - 0x6E, 0x73, 0x65, 0x6E, 0x73, 0x75, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x22, 0x3A, - 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x4C, 0x61, 0x73, - 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x61, 0x74, - 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6C, 0x61, 0x73, 0x74, 0x20, 0x63, 0x6F, 0x6E, 0x73, - 0x65, 0x6E, 0x73, 0x75, 0x73, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x73, 0x75, - 0x70, 0x70, 0x6F, 0x72, 0x74, 0x65, 0x64, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, - 0x69, 0x6E, 0x67, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x4C, 0x61, - 0x73, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6C, - 0x61, 0x73, 0x74, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x4C, 0x61, 0x73, 0x74, 0x52, 0x6F, 0x75, 0x6E, 0x64, - 0x20, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6C, - 0x61, 0x73, 0x74, 0x20, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x73, 0x65, 0x65, 0x6E, 0x22, 0x2C, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, - 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, - 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, - 0x22, 0x3A, 0x20, 0x22, 0x4C, 0x61, 0x73, 0x74, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x22, 0x6E, 0x65, 0x78, 0x74, 0x43, 0x6F, 0x6E, 0x73, 0x65, 0x6E, 0x73, 0x75, 0x73, - 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, - 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x4E, 0x65, 0x78, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, - 0x6E, 0x20, 0x6F, 0x66, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x65, 0x6E, 0x73, 0x75, 0x73, 0x20, 0x70, - 0x72, 0x6F, 0x74, 0x6F, 0x63, 0x6F, 0x6C, 0x20, 0x74, 0x6F, 0x20, 0x75, 0x73, 0x65, 0x22, 0x2C, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, - 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, - 0x65, 0x22, 0x3A, 0x20, 0x22, 0x4E, 0x65, 0x78, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, - 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6E, 0x65, 0x78, 0x74, 0x43, 0x6F, 0x6E, 0x73, 0x65, 0x6E, - 0x73, 0x75, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x22, - 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, - 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x4E, 0x65, - 0x78, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x69, - 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x61, 0x74, 0x20, 0x77, - 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6E, 0x65, 0x78, 0x74, 0x20, 0x63, 0x6F, - 0x6E, 0x73, 0x65, 0x6E, 0x73, 0x75, 0x73, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x20, - 0x77, 0x69, 0x6C, 0x6C, 0x20, 0x61, 0x70, 0x70, 0x6C, 0x79, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, - 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x75, - 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, - 0x4E, 0x65, 0x78, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x52, 0x6F, 0x75, 0x6E, 0x64, - 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6E, 0x65, 0x78, 0x74, 0x43, 0x6F, 0x6E, 0x73, 0x65, 0x6E, - 0x73, 0x75, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x53, 0x75, 0x70, 0x70, 0x6F, 0x72, - 0x74, 0x65, 0x64, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, - 0x20, 0x22, 0x4E, 0x65, 0x78, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x53, 0x75, 0x70, - 0x70, 0x6F, 0x72, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, - 0x20, 0x77, 0x68, 0x65, 0x74, 0x68, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6E, 0x65, 0x78, - 0x74, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x65, 0x6E, 0x73, 0x75, 0x73, 0x20, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6F, 0x6E, 0x20, 0x69, 0x73, 0x20, 0x73, 0x75, 0x70, 0x70, 0x6F, 0x72, 0x74, 0x65, 0x64, - 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x6E, 0x6F, 0x64, 0x65, 0x22, 0x2C, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, - 0x3A, 0x20, 0x22, 0x62, 0x6F, 0x6F, 0x6C, 0x65, 0x61, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, - 0x65, 0x22, 0x3A, 0x20, 0x22, 0x4E, 0x65, 0x78, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, - 0x53, 0x75, 0x70, 0x70, 0x6F, 0x72, 0x74, 0x65, 0x64, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, - 0x74, 0x6F, 0x70, 0x70, 0x65, 0x64, 0x41, 0x74, 0x55, 0x6E, 0x73, 0x75, 0x70, 0x70, 0x6F, 0x72, - 0x74, 0x65, 0x64, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x53, 0x74, 0x6F, 0x70, 0x70, 0x65, 0x64, 0x41, 0x74, - 0x55, 0x6E, 0x73, 0x75, 0x70, 0x70, 0x6F, 0x72, 0x74, 0x65, 0x64, 0x52, 0x6F, 0x75, 0x6E, 0x64, - 0x20, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, - 0x74, 0x68, 0x65, 0x20, 0x6E, 0x6F, 0x64, 0x65, 0x20, 0x64, 0x6F, 0x65, 0x73, 0x20, 0x6E, 0x6F, - 0x74, 0x20, 0x73, 0x75, 0x70, 0x70, 0x6F, 0x72, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6E, 0x65, - 0x77, 0x20, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x73, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x68, 0x61, 0x73, - 0x20, 0x73, 0x74, 0x6F, 0x70, 0x70, 0x65, 0x64, 0x20, 0x6D, 0x61, 0x6B, 0x69, 0x6E, 0x67, 0x20, - 0x70, 0x72, 0x6F, 0x67, 0x72, 0x65, 0x73, 0x73, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x62, 0x6F, - 0x6F, 0x6C, 0x65, 0x61, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, - 0x53, 0x74, 0x6F, 0x70, 0x70, 0x65, 0x64, 0x41, 0x74, 0x55, 0x6E, 0x73, 0x75, 0x70, 0x70, 0x6F, - 0x72, 0x74, 0x65, 0x64, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, - 0x69, 0x6D, 0x65, 0x53, 0x69, 0x6E, 0x63, 0x65, 0x4C, 0x61, 0x73, 0x74, 0x52, 0x6F, 0x75, 0x6E, - 0x64, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, - 0x54, 0x69, 0x6D, 0x65, 0x53, 0x69, 0x6E, 0x63, 0x65, 0x4C, 0x61, 0x73, 0x74, 0x52, 0x6F, 0x75, - 0x6E, 0x64, 0x20, 0x69, 0x6E, 0x20, 0x6E, 0x61, 0x6E, 0x6F, 0x73, 0x65, 0x63, 0x6F, 0x6E, 0x64, - 0x73, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, - 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, - 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, - 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x54, 0x69, 0x6D, 0x65, 0x53, 0x69, 0x6E, 0x63, 0x65, 0x4C, - 0x61, 0x73, 0x74, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x70, 0x61, 0x63, 0x6B, 0x61, 0x67, 0x65, - 0x22, 0x3A, 0x20, 0x22, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x61, - 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x67, 0x6F, 0x2D, 0x61, 0x6C, 0x67, 0x6F, 0x72, - 0x61, 0x6E, 0x64, 0x2F, 0x64, 0x61, 0x65, 0x6D, 0x6F, 0x6E, 0x2F, 0x61, 0x6C, 0x67, 0x6F, 0x64, - 0x2F, 0x61, 0x70, 0x69, 0x2F, 0x73, 0x70, 0x65, 0x63, 0x2F, 0x76, 0x31, 0x22, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, - 0x69, 0x70, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, - 0x20, 0x22, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, - 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x6F, 0x62, 0x6A, - 0x65, 0x63, 0x74, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x72, 0x65, 0x71, - 0x75, 0x69, 0x72, 0x65, 0x64, 0x22, 0x3A, 0x20, 0x5B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x22, 0x70, 0x61, 0x72, 0x74, 0x70, 0x6B, 0x62, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x72, 0x66, 0x70, 0x6B, 0x62, 0x36, 0x34, - 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x6F, 0x74, 0x65, - 0x66, 0x73, 0x74, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, - 0x6F, 0x74, 0x65, 0x6C, 0x73, 0x74, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x76, 0x6F, 0x74, 0x65, 0x6B, 0x64, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x5D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x72, 0x6F, 0x70, 0x65, 0x72, - 0x74, 0x69, 0x65, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x70, 0x61, 0x72, 0x74, 0x70, 0x6B, 0x62, 0x36, 0x34, 0x22, 0x3A, 0x20, 0x7B, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, - 0x69, 0x70, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x50, 0x4B, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x72, 0x6F, 0x6F, 0x74, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x74, - 0x69, 0x6F, 0x6E, 0x20, 0x70, 0x75, 0x62, 0x6C, 0x69, 0x63, 0x20, 0x6B, 0x65, 0x79, 0x20, 0x28, - 0x69, 0x66, 0x20, 0x61, 0x6E, 0x79, 0x29, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x74, 0x6C, - 0x79, 0x20, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x20, 0x66, 0x6F, 0x72, - 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x2C, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, - 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x62, - 0x79, 0x74, 0x65, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x50, 0x61, - 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x50, 0x4B, 0x22, 0x0A, 0x20, + 0x20, 0x22, 0x53, 0x65, 0x6C, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x50, 0x4B, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x6F, 0x74, 0x65, 0x66, 0x73, 0x74, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x56, 0x6F, 0x74, 0x65, 0x46, 0x69, 0x72, 0x73, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, - 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, - 0x74, 0x68, 0x69, 0x73, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x74, 0x69, - 0x6F, 0x6E, 0x20, 0x69, 0x73, 0x20, 0x76, 0x61, 0x6C, 0x69, 0x64, 0x2E, 0x22, 0x2C, 0x0A, 0x20, + 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, + 0x63, 0x69, 0x70, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x6B, 0x65, 0x79, 0x20, 0x69, 0x73, 0x20, + 0x76, 0x61, 0x6C, 0x69, 0x64, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, + 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, + 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, + 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x56, 0x6F, 0x74, 0x65, 0x46, + 0x69, 0x72, 0x73, 0x74, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x6F, 0x74, 0x65, 0x6B, 0x64, + 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x56, + 0x6F, 0x74, 0x65, 0x4B, 0x65, 0x79, 0x44, 0x69, 0x6C, 0x75, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x69, + 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x69, 0x6C, 0x75, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x66, + 0x6F, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x32, 0x2D, 0x6C, 0x65, 0x76, 0x65, 0x6C, 0x20, 0x70, + 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x6B, 0x65, 0x79, + 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, + 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, + 0x74, 0x22, 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, + 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x56, 0x6F, 0x74, 0x65, 0x4B, 0x65, 0x79, 0x44, 0x69, 0x6C, + 0x75, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, + 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x6F, 0x74, 0x65, 0x6B, + 0x65, 0x79, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, + 0x22, 0x56, 0x6F, 0x74, 0x65, 0x50, 0x4B, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, + 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x70, 0x75, 0x62, + 0x6C, 0x69, 0x63, 0x20, 0x6B, 0x65, 0x79, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x69, 0x6E, 0x20, + 0x6B, 0x65, 0x79, 0x20, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6F, 0x6E, + 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x22, 0x2C, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, + 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, + 0x22, 0x62, 0x79, 0x74, 0x65, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, + 0x56, 0x6F, 0x74, 0x65, 0x50, 0x4B, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x6F, 0x74, 0x65, + 0x6C, 0x73, 0x74, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, + 0x20, 0x22, 0x56, 0x6F, 0x74, 0x65, 0x4C, 0x61, 0x73, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x6C, 0x61, 0x73, 0x74, 0x20, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x74, 0x68, 0x69, + 0x73, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, + 0x6B, 0x65, 0x79, 0x20, 0x69, 0x73, 0x20, 0x76, 0x61, 0x6C, 0x69, 0x64, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, - 0x20, 0x22, 0x56, 0x6F, 0x74, 0x65, 0x46, 0x69, 0x72, 0x73, 0x74, 0x22, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x22, 0x76, 0x6F, 0x74, 0x65, 0x6B, 0x64, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, - 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x56, 0x6F, 0x74, 0x65, 0x4B, 0x65, 0x79, 0x44, 0x69, 0x6C, - 0x75, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6E, 0x75, 0x6D, - 0x62, 0x65, 0x72, 0x20, 0x6F, 0x66, 0x20, 0x73, 0x75, 0x62, 0x6B, 0x65, 0x79, 0x73, 0x20, 0x69, - 0x6E, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x65, 0x61, 0x63, 0x68, 0x20, 0x62, 0x61, 0x74, 0x63, 0x68, - 0x20, 0x6F, 0x66, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x74, 0x69, 0x6F, - 0x6E, 0x20, 0x6B, 0x65, 0x79, 0x73, 0x2E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, - 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, - 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, - 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x56, 0x6F, 0x74, - 0x65, 0x4B, 0x65, 0x79, 0x44, 0x69, 0x6C, 0x75, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x76, 0x6F, 0x74, 0x65, 0x6C, 0x73, 0x74, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x56, 0x6F, 0x74, 0x65, 0x4C, 0x61, 0x73, 0x74, - 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6C, 0x61, 0x73, 0x74, 0x20, 0x72, 0x6F, 0x75, - 0x6E, 0x64, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, 0x68, 0x69, - 0x73, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, - 0x69, 0x73, 0x20, 0x76, 0x61, 0x6C, 0x69, 0x64, 0x2E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, - 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x75, 0x69, - 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x56, - 0x6F, 0x74, 0x65, 0x4C, 0x61, 0x73, 0x74, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x72, 0x66, - 0x70, 0x6B, 0x62, 0x36, 0x34, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, - 0x22, 0x3A, 0x20, 0x22, 0x56, 0x52, 0x46, 0x50, 0x4B, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x73, 0x65, 0x6C, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x70, 0x75, 0x62, 0x6C, 0x69, - 0x63, 0x20, 0x6B, 0x65, 0x79, 0x20, 0x28, 0x69, 0x66, 0x20, 0x61, 0x6E, 0x79, 0x29, 0x20, 0x63, - 0x75, 0x72, 0x72, 0x65, 0x6E, 0x74, 0x6C, 0x79, 0x20, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, - 0x72, 0x65, 0x64, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x72, 0x6F, 0x75, - 0x6E, 0x64, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, - 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, - 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x62, 0x79, 0x74, 0x65, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, - 0x65, 0x22, 0x3A, 0x20, 0x22, 0x56, 0x52, 0x46, 0x50, 0x4B, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x56, 0x6F, 0x74, 0x65, 0x4C, 0x61, 0x73, 0x74, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x70, 0x61, 0x63, 0x6B, 0x61, 0x67, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x67, 0x6F, 0x2D, 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x64, 0x61, 0x65, 0x6D, 0x6F, 0x6E, 0x2F, 0x61, 0x6C, 0x67, 0x6F, 0x64, 0x2F, 0x61, 0x70, 0x69, 0x2F, 0x73, 0x70, 0x65, 0x63, 0x2F, 0x76, 0x31, 0x22, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, 0x50, 0x61, 0x79, 0x6D, - 0x65, 0x6E, 0x74, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x54, 0x79, - 0x70, 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x50, 0x61, 0x79, - 0x6D, 0x65, 0x6E, 0x74, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x54, - 0x79, 0x70, 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x73, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x66, 0x69, 0x65, 0x6C, - 0x64, 0x73, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x61, 0x20, 0x70, 0x61, 0x79, 0x6D, 0x65, 0x6E, 0x74, - 0x20, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x2C, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x6F, 0x62, - 0x6A, 0x65, 0x63, 0x74, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x72, 0x65, - 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x22, 0x3A, 0x20, 0x5B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x74, 0x6F, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x61, 0x6D, 0x6F, 0x75, 0x6E, 0x74, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x5D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x72, 0x6F, 0x70, 0x65, 0x72, - 0x74, 0x69, 0x65, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x61, 0x6D, 0x6F, 0x75, 0x6E, 0x74, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x41, 0x6D, 0x6F, 0x75, 0x6E, 0x74, 0x20, 0x69, 0x73, - 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x6D, 0x6F, 0x75, 0x6E, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x4D, - 0x69, 0x63, 0x72, 0x6F, 0x41, 0x6C, 0x67, 0x6F, 0x73, 0x20, 0x69, 0x6E, 0x74, 0x65, 0x6E, 0x64, - 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x62, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x66, 0x65, - 0x72, 0x72, 0x65, 0x64, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, - 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, - 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, - 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, - 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x41, 0x6D, 0x6F, 0x75, 0x6E, 0x74, - 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x6C, 0x6F, 0x73, 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x43, 0x6C, 0x6F, 0x73, 0x65, 0x52, - 0x65, 0x6D, 0x61, 0x69, 0x6E, 0x64, 0x65, 0x72, 0x54, 0x6F, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, - 0x65, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, - 0x6E, 0x64, 0x65, 0x72, 0x20, 0x63, 0x6C, 0x6F, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x22, 0x2C, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, - 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, 0x4E, 0x6F, 0x64, 0x65, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, + 0x22, 0x4E, 0x6F, 0x64, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x20, 0x63, 0x6F, 0x6E, 0x74, + 0x61, 0x69, 0x6E, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x69, 0x6E, 0x66, 0x6F, 0x72, 0x6D, 0x61, + 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x61, 0x20, 0x6E, 0x6F, 0x64, + 0x65, 0x20, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, + 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, + 0x65, 0x64, 0x22, 0x3A, 0x20, 0x5B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x6C, 0x61, 0x73, 0x74, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x6C, 0x61, 0x73, 0x74, 0x43, 0x6F, 0x6E, 0x73, 0x65, 0x6E, 0x73, + 0x75, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x6E, 0x65, 0x78, 0x74, 0x43, 0x6F, 0x6E, 0x73, 0x65, 0x6E, 0x73, + 0x75, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x6E, 0x65, 0x78, 0x74, 0x43, 0x6F, 0x6E, 0x73, 0x65, 0x6E, 0x73, + 0x75, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x2C, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6E, 0x65, 0x78, 0x74, 0x43, 0x6F, + 0x6E, 0x73, 0x65, 0x6E, 0x73, 0x75, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x53, 0x75, + 0x70, 0x70, 0x6F, 0x72, 0x74, 0x65, 0x64, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x74, 0x69, 0x6D, 0x65, 0x53, 0x69, 0x6E, 0x63, 0x65, 0x4C, 0x61, 0x73, 0x74, + 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x22, 0x63, 0x61, 0x74, 0x63, 0x68, 0x75, 0x70, 0x54, 0x69, 0x6D, 0x65, 0x22, 0x2C, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x68, 0x61, 0x73, 0x53, 0x79, 0x6E, 0x63, 0x65, + 0x64, 0x53, 0x69, 0x6E, 0x63, 0x65, 0x53, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x22, 0x2C, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x74, 0x6F, 0x70, 0x70, 0x65, 0x64, + 0x41, 0x74, 0x55, 0x6E, 0x73, 0x75, 0x70, 0x70, 0x6F, 0x72, 0x74, 0x65, 0x64, 0x52, 0x6F, 0x75, + 0x6E, 0x64, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5D, 0x2C, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x70, 0x72, 0x6F, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3A, + 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x61, 0x74, 0x63, + 0x68, 0x75, 0x70, 0x54, 0x69, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x43, 0x61, 0x74, 0x63, 0x68, 0x75, 0x70, 0x54, 0x69, 0x6D, + 0x65, 0x20, 0x69, 0x6E, 0x20, 0x6E, 0x61, 0x6E, 0x6F, 0x73, 0x65, 0x63, 0x6F, 0x6E, 0x64, 0x73, + 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, + 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, + 0x74, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, - 0x65, 0x22, 0x3A, 0x20, 0x22, 0x43, 0x6C, 0x6F, 0x73, 0x65, 0x52, 0x65, 0x6D, 0x61, 0x69, 0x6E, - 0x64, 0x65, 0x72, 0x54, 0x6F, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, - 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x6C, 0x6F, 0x73, 0x65, - 0x61, 0x6D, 0x6F, 0x75, 0x6E, 0x74, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x65, 0x22, 0x3A, 0x20, 0x22, 0x43, 0x61, 0x74, 0x63, 0x68, 0x75, 0x70, 0x54, 0x69, 0x6D, 0x65, + 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x68, 0x61, 0x73, 0x53, 0x79, 0x6E, 0x63, 0x65, 0x64, 0x53, + 0x69, 0x6E, 0x63, 0x65, 0x53, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x22, 0x3A, 0x20, 0x7B, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x48, 0x61, 0x73, 0x53, 0x79, 0x6E, + 0x63, 0x65, 0x64, 0x53, 0x69, 0x6E, 0x63, 0x65, 0x53, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x20, + 0x69, 0x6E, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x20, 0x77, 0x68, 0x65, 0x74, 0x68, 0x65, + 0x72, 0x20, 0x61, 0x20, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x68, 0x61, 0x73, 0x20, 0x63, 0x6F, + 0x6D, 0x70, 0x6C, 0x65, 0x74, 0x65, 0x64, 0x20, 0x73, 0x69, 0x6E, 0x63, 0x65, 0x20, 0x73, 0x74, + 0x61, 0x72, 0x74, 0x75, 0x70, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x62, 0x6F, 0x6F, 0x6C, 0x65, + 0x61, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x48, 0x61, 0x73, + 0x53, 0x79, 0x6E, 0x63, 0x65, 0x64, 0x53, 0x69, 0x6E, 0x63, 0x65, 0x53, 0x74, 0x61, 0x72, 0x74, + 0x75, 0x70, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6C, 0x61, 0x73, 0x74, 0x43, 0x6F, 0x6E, 0x73, + 0x65, 0x6E, 0x73, 0x75, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x7B, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x4C, 0x61, 0x73, 0x74, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x6C, 0x61, 0x73, 0x74, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x65, 0x6E, + 0x73, 0x75, 0x73, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x73, 0x75, 0x70, 0x70, + 0x6F, 0x72, 0x74, 0x65, 0x64, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, + 0x67, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, + 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x4C, 0x61, 0x73, 0x74, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6C, 0x61, 0x73, + 0x74, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, - 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x43, 0x6C, 0x6F, 0x73, 0x65, 0x41, 0x6D, 0x6F, 0x75, 0x6E, 0x74, - 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x6D, 0x6F, 0x75, 0x6E, 0x74, 0x20, 0x73, - 0x65, 0x6E, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x43, 0x6C, 0x6F, 0x73, 0x65, 0x52, 0x65, 0x6D, 0x61, - 0x69, 0x6E, 0x64, 0x65, 0x72, 0x54, 0x6F, 0x2C, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x63, 0x6F, 0x6D, - 0x6D, 0x69, 0x74, 0x74, 0x65, 0x64, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6F, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, - 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, - 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, - 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, - 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x43, 0x6C, 0x6F, 0x73, 0x65, 0x41, 0x6D, 0x6F, - 0x75, 0x6E, 0x74, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x6C, 0x6F, 0x73, 0x65, 0x72, 0x65, - 0x77, 0x61, 0x72, 0x64, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x4C, 0x61, 0x73, 0x74, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x69, + 0x6E, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6C, 0x61, 0x73, + 0x74, 0x20, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x73, 0x65, 0x65, 0x6E, 0x22, 0x2C, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, + 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, + 0x22, 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, + 0x20, 0x22, 0x4C, 0x61, 0x73, 0x74, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x22, 0x6E, 0x65, 0x78, 0x74, 0x43, 0x6F, 0x6E, 0x73, 0x65, 0x6E, 0x73, 0x75, 0x73, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, - 0x22, 0x3A, 0x20, 0x22, 0x43, 0x6C, 0x6F, 0x73, 0x65, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, - 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x6D, 0x6F, 0x75, 0x6E, 0x74, 0x20, 0x6F, - 0x66, 0x20, 0x70, 0x65, 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x20, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, - 0x73, 0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x43, 0x6C, 0x6F, 0x73, 0x65, 0x52, 0x65, 0x6D, 0x61, 0x69, 0x6E, 0x64, 0x65, 0x72, 0x54, - 0x6F, 0x5C, 0x6E, 0x61, 0x63, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x20, 0x61, 0x73, 0x20, 0x70, 0x61, - 0x72, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x2E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x22, 0x3A, 0x20, 0x22, 0x4E, 0x65, 0x78, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x20, + 0x6F, 0x66, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x65, 0x6E, 0x73, 0x75, 0x73, 0x20, 0x70, 0x72, 0x6F, + 0x74, 0x6F, 0x63, 0x6F, 0x6C, 0x20, 0x74, 0x6F, 0x20, 0x75, 0x73, 0x65, 0x22, 0x2C, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, + 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, + 0x3A, 0x20, 0x22, 0x4E, 0x65, 0x78, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x22, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x6E, 0x65, 0x78, 0x74, 0x43, 0x6F, 0x6E, 0x73, 0x65, 0x6E, 0x73, 0x75, + 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x3A, 0x20, + 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x4E, 0x65, 0x78, 0x74, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x69, 0x73, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x61, 0x74, 0x20, 0x77, 0x68, 0x69, + 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6E, 0x65, 0x78, 0x74, 0x20, 0x63, 0x6F, 0x6E, 0x73, + 0x65, 0x6E, 0x73, 0x75, 0x73, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x77, 0x69, + 0x6C, 0x6C, 0x20, 0x61, 0x70, 0x70, 0x6C, 0x79, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, + 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, + 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x4E, 0x65, + 0x78, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x6E, 0x65, 0x78, 0x74, 0x43, 0x6F, 0x6E, 0x73, 0x65, 0x6E, 0x73, 0x75, + 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x53, 0x75, 0x70, 0x70, 0x6F, 0x72, 0x74, 0x65, + 0x64, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, + 0x4E, 0x65, 0x78, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x53, 0x75, 0x70, 0x70, 0x6F, + 0x72, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x20, 0x77, + 0x68, 0x65, 0x74, 0x68, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6E, 0x65, 0x78, 0x74, 0x20, + 0x63, 0x6F, 0x6E, 0x73, 0x65, 0x6E, 0x73, 0x75, 0x73, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, + 0x6E, 0x20, 0x69, 0x73, 0x20, 0x73, 0x75, 0x70, 0x70, 0x6F, 0x72, 0x74, 0x65, 0x64, 0x20, 0x62, + 0x79, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x6E, 0x6F, 0x64, 0x65, 0x22, 0x2C, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, + 0x22, 0x62, 0x6F, 0x6F, 0x6C, 0x65, 0x61, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, + 0x3A, 0x20, 0x22, 0x4E, 0x65, 0x78, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x53, 0x75, + 0x70, 0x70, 0x6F, 0x72, 0x74, 0x65, 0x64, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x74, 0x6F, + 0x70, 0x70, 0x65, 0x64, 0x41, 0x74, 0x55, 0x6E, 0x73, 0x75, 0x70, 0x70, 0x6F, 0x72, 0x74, 0x65, + 0x64, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, + 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x53, 0x74, 0x6F, 0x70, 0x70, 0x65, 0x64, 0x41, 0x74, 0x55, 0x6E, + 0x73, 0x75, 0x70, 0x70, 0x6F, 0x72, 0x74, 0x65, 0x64, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x69, + 0x6E, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x6E, 0x6F, 0x64, 0x65, 0x20, 0x64, 0x6F, 0x65, 0x73, 0x20, 0x6E, 0x6F, 0x74, 0x20, + 0x73, 0x75, 0x70, 0x70, 0x6F, 0x72, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6E, 0x65, 0x77, 0x20, + 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x73, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x68, 0x61, 0x73, 0x20, 0x73, + 0x74, 0x6F, 0x70, 0x70, 0x65, 0x64, 0x20, 0x6D, 0x61, 0x6B, 0x69, 0x6E, 0x67, 0x20, 0x70, 0x72, + 0x6F, 0x67, 0x72, 0x65, 0x73, 0x73, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x62, 0x6F, 0x6F, 0x6C, + 0x65, 0x61, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x53, 0x74, + 0x6F, 0x70, 0x70, 0x65, 0x64, 0x41, 0x74, 0x55, 0x6E, 0x73, 0x75, 0x70, 0x70, 0x6F, 0x72, 0x74, + 0x65, 0x64, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x69, 0x6D, + 0x65, 0x53, 0x69, 0x6E, 0x63, 0x65, 0x4C, 0x61, 0x73, 0x74, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x22, + 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x54, 0x69, + 0x6D, 0x65, 0x53, 0x69, 0x6E, 0x63, 0x65, 0x4C, 0x61, 0x73, 0x74, 0x52, 0x6F, 0x75, 0x6E, 0x64, + 0x20, 0x69, 0x6E, 0x20, 0x6E, 0x61, 0x6E, 0x6F, 0x73, 0x65, 0x63, 0x6F, 0x6E, 0x64, 0x73, 0x22, + 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, + 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, + 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, + 0x22, 0x3A, 0x20, 0x22, 0x54, 0x69, 0x6D, 0x65, 0x53, 0x69, 0x6E, 0x63, 0x65, 0x4C, 0x61, 0x73, + 0x74, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x70, 0x61, 0x63, 0x6B, 0x61, 0x67, 0x65, 0x22, 0x3A, + 0x20, 0x22, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x61, 0x6C, 0x67, + 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x67, 0x6F, 0x2D, 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, + 0x64, 0x2F, 0x64, 0x61, 0x65, 0x6D, 0x6F, 0x6E, 0x2F, 0x61, 0x6C, 0x67, 0x6F, 0x64, 0x2F, 0x61, + 0x70, 0x69, 0x2F, 0x73, 0x70, 0x65, 0x63, 0x2F, 0x76, 0x31, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, + 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, + 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x44, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, + 0x74, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x72, 0x65, 0x71, 0x75, 0x69, + 0x72, 0x65, 0x64, 0x22, 0x3A, 0x20, 0x5B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x22, 0x70, 0x61, 0x72, 0x74, 0x70, 0x6B, 0x62, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x72, 0x66, 0x70, 0x6B, 0x62, 0x36, 0x34, 0x22, 0x2C, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x6F, 0x74, 0x65, 0x66, 0x73, + 0x74, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x6F, 0x74, + 0x65, 0x6C, 0x73, 0x74, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x76, 0x6F, 0x74, 0x65, 0x6B, 0x64, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5D, 0x2C, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x72, 0x6F, 0x70, 0x65, 0x72, 0x74, 0x69, + 0x65, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x70, 0x61, 0x72, 0x74, 0x70, 0x6B, 0x62, 0x36, 0x34, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, + 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x50, 0x4B, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, + 0x6F, 0x6F, 0x74, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x74, 0x69, 0x6F, + 0x6E, 0x20, 0x70, 0x75, 0x62, 0x6C, 0x69, 0x63, 0x20, 0x6B, 0x65, 0x79, 0x20, 0x28, 0x69, 0x66, + 0x20, 0x61, 0x6E, 0x79, 0x29, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x74, 0x6C, 0x79, 0x20, + 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x74, + 0x68, 0x69, 0x73, 0x20, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x73, + 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x62, 0x79, 0x74, + 0x65, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, + 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x50, 0x61, 0x72, 0x74, + 0x69, 0x63, 0x69, 0x70, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x50, 0x4B, 0x22, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x22, 0x76, 0x6F, 0x74, 0x65, 0x66, 0x73, 0x74, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x56, 0x6F, 0x74, 0x65, 0x46, 0x69, 0x72, 0x73, 0x74, + 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x72, 0x6F, + 0x75, 0x6E, 0x64, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, 0x68, + 0x69, 0x73, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x74, 0x69, 0x6F, 0x6E, + 0x20, 0x69, 0x73, 0x20, 0x76, 0x61, 0x6C, 0x69, 0x64, 0x2E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, + 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x75, + 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, + 0x56, 0x6F, 0x74, 0x65, 0x46, 0x69, 0x72, 0x73, 0x74, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, + 0x6F, 0x74, 0x65, 0x6B, 0x64, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, + 0x22, 0x3A, 0x20, 0x22, 0x56, 0x6F, 0x74, 0x65, 0x4B, 0x65, 0x79, 0x44, 0x69, 0x6C, 0x75, 0x74, + 0x69, 0x6F, 0x6E, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6E, 0x75, 0x6D, 0x62, 0x65, + 0x72, 0x20, 0x6F, 0x66, 0x20, 0x73, 0x75, 0x62, 0x6B, 0x65, 0x79, 0x73, 0x20, 0x69, 0x6E, 0x20, + 0x66, 0x6F, 0x72, 0x20, 0x65, 0x61, 0x63, 0x68, 0x20, 0x62, 0x61, 0x74, 0x63, 0x68, 0x20, 0x6F, + 0x66, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, + 0x6B, 0x65, 0x79, 0x73, 0x2E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, + 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, + 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, + 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x56, 0x6F, 0x74, 0x65, 0x4B, + 0x65, 0x79, 0x44, 0x69, 0x6C, 0x75, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x76, 0x6F, 0x74, 0x65, 0x6C, 0x73, 0x74, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x56, 0x6F, 0x74, 0x65, 0x4C, 0x61, 0x73, 0x74, 0x20, 0x69, + 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6C, 0x61, 0x73, 0x74, 0x20, 0x72, 0x6F, 0x75, 0x6E, 0x64, + 0x20, 0x66, 0x6F, 0x72, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, + 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x69, 0x73, + 0x20, 0x76, 0x61, 0x6C, 0x69, 0x64, 0x2E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, - 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x43, 0x6C, 0x6F, - 0x73, 0x65, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, - 0x6F, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, - 0x54, 0x6F, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, - 0x65, 0x72, 0x27, 0x73, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x2C, 0x0A, 0x20, + 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x56, 0x6F, 0x74, + 0x65, 0x4C, 0x61, 0x73, 0x74, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, + 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x72, 0x66, 0x70, 0x6B, + 0x62, 0x36, 0x34, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, + 0x20, 0x22, 0x56, 0x52, 0x46, 0x50, 0x4B, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, + 0x65, 0x6C, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x70, 0x75, 0x62, 0x6C, 0x69, 0x63, 0x20, + 0x6B, 0x65, 0x79, 0x20, 0x28, 0x69, 0x66, 0x20, 0x61, 0x6E, 0x79, 0x29, 0x20, 0x63, 0x75, 0x72, + 0x72, 0x65, 0x6E, 0x74, 0x6C, 0x79, 0x20, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, + 0x64, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x72, 0x6F, 0x75, 0x6E, 0x64, + 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, + 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, + 0x22, 0x3A, 0x20, 0x22, 0x62, 0x79, 0x74, 0x65, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, + 0x3A, 0x20, 0x22, 0x56, 0x52, 0x46, 0x50, 0x4B, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x70, 0x61, 0x63, 0x6B, 0x61, 0x67, 0x65, + 0x22, 0x3A, 0x20, 0x22, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x61, + 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x67, 0x6F, 0x2D, 0x61, 0x6C, 0x67, 0x6F, 0x72, + 0x61, 0x6E, 0x64, 0x2F, 0x64, 0x61, 0x65, 0x6D, 0x6F, 0x6E, 0x2F, 0x61, 0x6C, 0x67, 0x6F, 0x64, + 0x2F, 0x61, 0x70, 0x69, 0x2F, 0x73, 0x70, 0x65, 0x63, 0x2F, 0x76, 0x31, 0x22, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, 0x50, 0x61, 0x79, 0x6D, 0x65, 0x6E, + 0x74, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x54, 0x79, 0x70, 0x65, + 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x50, 0x61, 0x79, 0x6D, 0x65, + 0x6E, 0x74, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x54, 0x79, 0x70, + 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, + 0x64, 0x64, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x66, 0x69, 0x65, 0x6C, 0x64, 0x73, + 0x20, 0x66, 0x6F, 0x72, 0x20, 0x61, 0x20, 0x70, 0x61, 0x79, 0x6D, 0x65, 0x6E, 0x74, 0x20, 0x54, + 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x6F, 0x62, 0x6A, 0x65, + 0x63, 0x74, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x72, 0x65, 0x71, 0x75, + 0x69, 0x72, 0x65, 0x64, 0x22, 0x3A, 0x20, 0x5B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x74, 0x6F, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x61, 0x6D, 0x6F, 0x75, 0x6E, 0x74, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5D, 0x2C, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x72, 0x6F, 0x70, 0x65, 0x72, 0x74, 0x69, + 0x65, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x61, 0x6D, 0x6F, 0x75, 0x6E, 0x74, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, + 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x41, 0x6D, 0x6F, 0x75, 0x6E, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x61, 0x6D, 0x6F, 0x75, 0x6E, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x4D, 0x69, 0x63, + 0x72, 0x6F, 0x41, 0x6C, 0x67, 0x6F, 0x73, 0x20, 0x69, 0x6E, 0x74, 0x65, 0x6E, 0x64, 0x65, 0x64, + 0x20, 0x74, 0x6F, 0x20, 0x62, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x66, 0x65, 0x72, 0x72, + 0x65, 0x64, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, + 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, + 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, + 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x41, 0x6D, 0x6F, 0x75, 0x6E, 0x74, 0x22, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x63, 0x6C, 0x6F, 0x73, 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x43, 0x6C, 0x6F, 0x73, 0x65, 0x52, 0x65, 0x6D, + 0x61, 0x69, 0x6E, 0x64, 0x65, 0x72, 0x54, 0x6F, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6E, 0x64, + 0x65, 0x72, 0x20, 0x63, 0x6C, 0x6F, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, - 0x3A, 0x20, 0x22, 0x54, 0x6F, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, - 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x6F, 0x72, 0x65, 0x77, - 0x61, 0x72, 0x64, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x3A, 0x20, 0x22, 0x43, 0x6C, 0x6F, 0x73, 0x65, 0x52, 0x65, 0x6D, 0x61, 0x69, 0x6E, 0x64, 0x65, + 0x72, 0x54, 0x6F, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x6C, 0x6F, 0x73, 0x65, 0x61, 0x6D, + 0x6F, 0x75, 0x6E, 0x74, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, - 0x3A, 0x20, 0x22, 0x54, 0x6F, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x20, 0x69, 0x73, 0x20, - 0x74, 0x68, 0x65, 0x20, 0x61, 0x6D, 0x6F, 0x75, 0x6E, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x70, 0x65, - 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x20, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x20, 0x61, 0x70, - 0x70, 0x6C, 0x69, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x54, 0x6F, 0x20, - 0x61, 0x63, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x5C, 0x6E, 0x61, 0x73, 0x20, 0x70, 0x61, 0x72, 0x74, + 0x3A, 0x20, 0x22, 0x43, 0x6C, 0x6F, 0x73, 0x65, 0x41, 0x6D, 0x6F, 0x75, 0x6E, 0x74, 0x20, 0x69, + 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x6D, 0x6F, 0x75, 0x6E, 0x74, 0x20, 0x73, 0x65, 0x6E, + 0x74, 0x20, 0x74, 0x6F, 0x20, 0x43, 0x6C, 0x6F, 0x73, 0x65, 0x52, 0x65, 0x6D, 0x61, 0x69, 0x6E, + 0x64, 0x65, 0x72, 0x54, 0x6F, 0x2C, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x63, 0x6F, 0x6D, 0x6D, 0x69, + 0x74, 0x74, 0x65, 0x64, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, + 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, + 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, + 0x74, 0x22, 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, + 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x43, 0x6C, 0x6F, 0x73, 0x65, 0x41, 0x6D, 0x6F, 0x75, 0x6E, + 0x74, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x6C, 0x6F, 0x73, 0x65, 0x72, 0x65, 0x77, 0x61, + 0x72, 0x64, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, + 0x20, 0x22, 0x43, 0x6C, 0x6F, 0x73, 0x65, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x20, 0x69, + 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x6D, 0x6F, 0x75, 0x6E, 0x74, 0x20, 0x6F, 0x66, 0x20, + 0x70, 0x65, 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x20, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x20, + 0x61, 0x70, 0x70, 0x6C, 0x69, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x43, + 0x6C, 0x6F, 0x73, 0x65, 0x52, 0x65, 0x6D, 0x61, 0x69, 0x6E, 0x64, 0x65, 0x72, 0x54, 0x6F, 0x5C, + 0x6E, 0x61, 0x63, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x20, 0x61, 0x73, 0x20, 0x70, 0x61, 0x72, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x2E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, - 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x54, 0x6F, 0x52, 0x65, 0x77, - 0x61, 0x72, 0x64, 0x73, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, + 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x43, 0x6C, 0x6F, 0x73, 0x65, + 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x6F, 0x22, + 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x54, 0x6F, + 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, + 0x27, 0x73, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, + 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, + 0x22, 0x54, 0x6F, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x6F, 0x72, 0x65, 0x77, 0x61, 0x72, + 0x64, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, + 0x22, 0x54, 0x6F, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x61, 0x6D, 0x6F, 0x75, 0x6E, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x70, 0x65, 0x6E, 0x64, + 0x69, 0x6E, 0x67, 0x20, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x20, 0x61, 0x70, 0x70, 0x6C, + 0x69, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x54, 0x6F, 0x20, 0x61, 0x63, + 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x5C, 0x6E, 0x61, 0x73, 0x20, 0x70, 0x61, 0x72, 0x74, 0x20, 0x6F, + 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6F, 0x6E, 0x2E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, + 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, + 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, + 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x54, 0x6F, 0x52, 0x65, 0x77, 0x61, 0x72, + 0x64, 0x73, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, + 0x67, 0x6F, 0x2D, 0x70, 0x61, 0x63, 0x6B, 0x61, 0x67, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x67, 0x69, + 0x74, 0x68, 0x75, 0x62, 0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, + 0x64, 0x2F, 0x67, 0x6F, 0x2D, 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x64, 0x61, + 0x65, 0x6D, 0x6F, 0x6E, 0x2F, 0x61, 0x6C, 0x67, 0x6F, 0x64, 0x2F, 0x61, 0x70, 0x69, 0x2F, 0x73, + 0x70, 0x65, 0x63, 0x2F, 0x76, 0x31, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x50, 0x65, 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x54, 0x72, 0x61, 0x6E, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, + 0x20, 0x22, 0x50, 0x65, 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x20, 0x72, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6E, 0x74, 0x73, + 0x20, 0x61, 0x20, 0x70, 0x6F, 0x74, 0x65, 0x6E, 0x74, 0x69, 0x61, 0x6C, 0x6C, 0x79, 0x20, 0x74, + 0x72, 0x75, 0x6E, 0x63, 0x61, 0x74, 0x65, 0x64, 0x20, 0x6C, 0x69, 0x73, 0x74, 0x20, 0x6F, 0x66, + 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x20, 0x63, 0x75, + 0x72, 0x72, 0x65, 0x6E, 0x74, 0x6C, 0x79, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x5C, 0x6E, + 0x6E, 0x6F, 0x64, 0x65, 0x27, 0x73, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6F, 0x6E, 0x20, 0x70, 0x6F, 0x6F, 0x6C, 0x2E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, + 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, + 0x65, 0x64, 0x22, 0x3A, 0x20, 0x5B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x74, 0x72, 0x75, 0x6E, 0x63, 0x61, 0x74, 0x65, 0x64, 0x54, 0x78, 0x6E, 0x73, 0x22, 0x2C, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x6F, 0x74, 0x61, 0x6C, 0x54, 0x78, + 0x6E, 0x73, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5D, 0x2C, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x70, 0x72, 0x6F, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3A, + 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x6F, 0x74, 0x61, + 0x6C, 0x54, 0x78, 0x6E, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, + 0x22, 0x3A, 0x20, 0x22, 0x54, 0x6F, 0x74, 0x61, 0x6C, 0x54, 0x78, 0x6E, 0x73, 0x22, 0x2C, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, + 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, + 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, + 0x3A, 0x20, 0x22, 0x54, 0x6F, 0x74, 0x61, 0x6C, 0x54, 0x78, 0x6E, 0x73, 0x22, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x74, 0x72, 0x75, 0x6E, 0x63, 0x61, 0x74, 0x65, 0x64, 0x54, 0x78, 0x6E, 0x73, 0x22, + 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x24, + 0x72, 0x65, 0x66, 0x22, 0x3A, 0x20, 0x22, 0x23, 0x2F, 0x64, 0x65, 0x66, 0x69, 0x6E, 0x69, 0x74, + 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, + 0x4C, 0x69, 0x73, 0x74, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x70, 0x61, 0x63, 0x6B, 0x61, 0x67, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x67, 0x6F, 0x2D, 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x64, 0x61, 0x65, 0x6D, 0x6F, 0x6E, 0x2F, 0x61, 0x6C, 0x67, 0x6F, 0x64, 0x2F, 0x61, 0x70, 0x69, 0x2F, 0x73, 0x70, 0x65, 0x63, 0x2F, 0x76, 0x31, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, 0x50, 0x65, 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x54, 0x72, 0x61, - 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, - 0x22, 0x3A, 0x20, 0x22, 0x50, 0x65, 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x54, 0x72, 0x61, 0x6E, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x20, 0x72, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6E, - 0x74, 0x73, 0x20, 0x61, 0x20, 0x70, 0x6F, 0x74, 0x65, 0x6E, 0x74, 0x69, 0x61, 0x6C, 0x6C, 0x79, - 0x20, 0x74, 0x72, 0x75, 0x6E, 0x63, 0x61, 0x74, 0x65, 0x64, 0x20, 0x6C, 0x69, 0x73, 0x74, 0x20, - 0x6F, 0x66, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x20, - 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x74, 0x6C, 0x79, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, - 0x5C, 0x6E, 0x6E, 0x6F, 0x64, 0x65, 0x27, 0x73, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x70, 0x6F, 0x6F, 0x6C, 0x2E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x6F, 0x62, 0x6A, 0x65, - 0x63, 0x74, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x72, 0x65, 0x71, 0x75, - 0x69, 0x72, 0x65, 0x64, 0x22, 0x3A, 0x20, 0x5B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x74, 0x72, 0x75, 0x6E, 0x63, 0x61, 0x74, 0x65, 0x64, 0x54, 0x78, 0x6E, 0x73, 0x22, - 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x6F, 0x74, 0x61, 0x6C, - 0x54, 0x78, 0x6E, 0x73, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5D, 0x2C, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x72, 0x6F, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, - 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x6F, - 0x74, 0x61, 0x6C, 0x54, 0x78, 0x6E, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, - 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x54, 0x6F, 0x74, 0x61, 0x6C, 0x54, 0x78, 0x6E, 0x73, 0x22, - 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, - 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, - 0x22, 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, - 0x65, 0x22, 0x3A, 0x20, 0x22, 0x54, 0x6F, 0x74, 0x61, 0x6C, 0x54, 0x78, 0x6E, 0x73, 0x22, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x74, 0x72, 0x75, 0x6E, 0x63, 0x61, 0x74, 0x65, 0x64, 0x54, 0x78, 0x6E, - 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3A, 0x20, 0x22, 0x23, 0x2F, 0x64, 0x65, 0x66, 0x69, 0x6E, - 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6F, 0x6E, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x70, 0x61, 0x63, 0x6B, 0x61, 0x67, 0x65, 0x22, 0x3A, - 0x20, 0x22, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x61, 0x6C, 0x67, - 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x67, 0x6F, 0x2D, 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, - 0x64, 0x2F, 0x64, 0x61, 0x65, 0x6D, 0x6F, 0x6E, 0x2F, 0x61, 0x6C, 0x67, 0x6F, 0x64, 0x2F, 0x61, - 0x70, 0x69, 0x2F, 0x73, 0x70, 0x65, 0x63, 0x2F, 0x76, 0x31, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, - 0x65, 0x6D, 0x61, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, - 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x73, 0x77, - 0x61, 0x67, 0x67, 0x65, 0x72, 0x3A, 0x20, 0x6D, 0x6F, 0x64, 0x65, 0x6C, 0x20, 0x53, 0x74, 0x61, - 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, - 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x69, 0x74, 0x6C, 0x65, 0x22, - 0x3A, 0x20, 0x22, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x20, 0x72, - 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6E, 0x74, 0x73, 0x20, 0x61, 0x20, 0x4C, 0x6F, 0x63, 0x61, - 0x6C, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x20, 0x6F, 0x72, 0x20, - 0x47, 0x6C, 0x6F, 0x62, 0x61, 0x6C, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6D, - 0x61, 0x2E, 0x20, 0x54, 0x68, 0x65, 0x73, 0x65, 0x5C, 0x6E, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, - 0x73, 0x20, 0x64, 0x65, 0x74, 0x65, 0x72, 0x6D, 0x69, 0x6E, 0x65, 0x20, 0x68, 0x6F, 0x77, 0x20, - 0x6D, 0x75, 0x63, 0x68, 0x20, 0x73, 0x74, 0x6F, 0x72, 0x61, 0x67, 0x65, 0x20, 0x6D, 0x61, 0x79, - 0x20, 0x62, 0x65, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, 0x4C, 0x6F, - 0x63, 0x61, 0x6C, 0x53, 0x74, 0x61, 0x74, 0x65, 0x20, 0x6F, 0x72, 0x5C, 0x6E, 0x47, 0x6C, 0x6F, - 0x62, 0x61, 0x6C, 0x53, 0x74, 0x61, 0x74, 0x65, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x61, 0x6E, 0x20, - 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x2E, 0x20, 0x54, 0x68, 0x65, - 0x20, 0x6D, 0x6F, 0x72, 0x65, 0x20, 0x73, 0x70, 0x61, 0x63, 0x65, 0x20, 0x75, 0x73, 0x65, 0x64, - 0x2C, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x6D, 0x69, 0x6E, - 0x69, 0x6D, 0x75, 0x6D, 0x5C, 0x6E, 0x62, 0x61, 0x6C, 0x61, 0x6E, 0x63, 0x65, 0x20, 0x6D, 0x75, - 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x6D, 0x61, 0x69, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x65, 0x64, - 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x63, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x20, - 0x68, 0x6F, 0x6C, 0x64, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x61, 0x74, 0x61, - 0x2E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x72, 0x65, 0x71, 0x75, 0x69, - 0x72, 0x65, 0x64, 0x22, 0x3A, 0x20, 0x5B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x22, 0x75, 0x69, 0x6E, 0x74, 0x73, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x62, 0x79, 0x74, 0x65, 0x73, 0x6C, 0x69, 0x63, 0x65, 0x73, 0x22, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x5D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x72, - 0x6F, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x62, 0x79, 0x74, 0x65, 0x73, 0x6C, 0x69, 0x63, 0x65, 0x73, - 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, - 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x4E, - 0x75, 0x6D, 0x42, 0x79, 0x74, 0x65, 0x53, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x69, 0x73, 0x20, 0x74, - 0x68, 0x65, 0x20, 0x6D, 0x61, 0x78, 0x69, 0x6D, 0x75, 0x6D, 0x20, 0x6E, 0x75, 0x6D, 0x62, 0x65, - 0x72, 0x20, 0x6F, 0x66, 0x20, 0x54, 0x45, 0x41, 0x4C, 0x20, 0x62, 0x79, 0x74, 0x65, 0x20, 0x73, - 0x6C, 0x69, 0x63, 0x65, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x6D, 0x61, 0x79, 0x20, 0x62, - 0x65, 0x5C, 0x6E, 0x73, 0x74, 0x6F, 0x72, 0x65, 0x64, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6D, + 0x61, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x73, 0x77, 0x61, 0x67, + 0x67, 0x65, 0x72, 0x3A, 0x20, 0x6D, 0x6F, 0x64, 0x65, 0x6C, 0x20, 0x53, 0x74, 0x61, 0x74, 0x65, + 0x53, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x22, 0x2C, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x69, 0x74, 0x6C, 0x65, 0x22, 0x3A, 0x20, + 0x22, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x20, 0x72, 0x65, 0x70, + 0x72, 0x65, 0x73, 0x65, 0x6E, 0x74, 0x73, 0x20, 0x61, 0x20, 0x4C, 0x6F, 0x63, 0x61, 0x6C, 0x53, + 0x74, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x20, 0x6F, 0x72, 0x20, 0x47, 0x6C, + 0x6F, 0x62, 0x61, 0x6C, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x2E, + 0x20, 0x54, 0x68, 0x65, 0x73, 0x65, 0x5C, 0x6E, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x73, 0x20, + 0x64, 0x65, 0x74, 0x65, 0x72, 0x6D, 0x69, 0x6E, 0x65, 0x20, 0x68, 0x6F, 0x77, 0x20, 0x6D, 0x75, + 0x63, 0x68, 0x20, 0x73, 0x74, 0x6F, 0x72, 0x61, 0x67, 0x65, 0x20, 0x6D, 0x61, 0x79, 0x20, 0x62, + 0x65, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x69, 0x6E, 0x20, 0x61, 0x20, 0x4C, 0x6F, 0x63, 0x61, + 0x6C, 0x53, 0x74, 0x61, 0x74, 0x65, 0x20, 0x6F, 0x72, 0x5C, 0x6E, 0x47, 0x6C, 0x6F, 0x62, 0x61, + 0x6C, 0x53, 0x74, 0x61, 0x74, 0x65, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x61, 0x6E, 0x20, 0x61, 0x70, + 0x70, 0x6C, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x2E, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6D, + 0x6F, 0x72, 0x65, 0x20, 0x73, 0x70, 0x61, 0x63, 0x65, 0x20, 0x75, 0x73, 0x65, 0x64, 0x2C, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x6D, 0x69, 0x6E, 0x69, 0x6D, + 0x75, 0x6D, 0x5C, 0x6E, 0x62, 0x61, 0x6C, 0x61, 0x6E, 0x63, 0x65, 0x20, 0x6D, 0x75, 0x73, 0x74, + 0x20, 0x62, 0x65, 0x20, 0x6D, 0x61, 0x69, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x65, 0x64, 0x20, 0x69, + 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x63, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x20, 0x68, 0x6F, + 0x6C, 0x64, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x61, 0x74, 0x61, 0x2E, 0x22, + 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, + 0x64, 0x22, 0x3A, 0x20, 0x5B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x75, + 0x69, 0x6E, 0x74, 0x73, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x62, 0x79, 0x74, 0x65, 0x73, 0x6C, 0x69, 0x63, 0x65, 0x73, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x5D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x72, 0x6F, 0x70, + 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x62, 0x79, 0x74, 0x65, 0x73, 0x6C, 0x69, 0x63, 0x65, 0x73, 0x22, 0x3A, + 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x4E, 0x75, 0x6D, + 0x42, 0x79, 0x74, 0x65, 0x53, 0x6C, 0x69, 0x63, 0x65, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x6D, 0x61, 0x78, 0x69, 0x6D, 0x75, 0x6D, 0x20, 0x6E, 0x75, 0x6D, 0x62, 0x65, 0x72, 0x20, + 0x6F, 0x66, 0x20, 0x54, 0x45, 0x41, 0x4C, 0x20, 0x62, 0x79, 0x74, 0x65, 0x20, 0x73, 0x6C, 0x69, + 0x63, 0x65, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x6D, 0x61, 0x79, 0x20, 0x62, 0x65, 0x5C, + 0x6E, 0x73, 0x74, 0x6F, 0x72, 0x65, 0x64, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6B, + 0x65, 0x79, 0x2F, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x20, 0x73, 0x74, 0x6F, 0x72, 0x65, 0x22, 0x2C, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, + 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, + 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, + 0x22, 0x3A, 0x20, 0x22, 0x4E, 0x75, 0x6D, 0x42, 0x79, 0x74, 0x65, 0x53, 0x6C, 0x69, 0x63, 0x65, + 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x4E, 0x75, 0x6D, 0x55, 0x69, 0x6E, + 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6D, 0x61, 0x78, 0x69, 0x6D, 0x75, 0x6D, + 0x20, 0x6E, 0x75, 0x6D, 0x62, 0x65, 0x72, 0x20, 0x6F, 0x66, 0x20, 0x54, 0x45, 0x41, 0x4C, 0x20, + 0x75, 0x69, 0x6E, 0x74, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x6D, 0x61, 0x79, 0x20, 0x62, + 0x65, 0x20, 0x73, 0x74, 0x6F, 0x72, 0x65, 0x64, 0x20, 0x69, 0x6E, 0x5C, 0x6E, 0x74, 0x68, 0x65, 0x20, 0x6B, 0x65, 0x79, 0x2F, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x20, 0x73, 0x74, 0x6F, 0x72, 0x65, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, - 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x4E, 0x75, 0x6D, 0x42, 0x79, 0x74, 0x65, 0x53, 0x6C, 0x69, - 0x63, 0x65, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x73, 0x22, 0x3A, 0x20, - 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x4E, 0x75, 0x6D, 0x55, - 0x69, 0x6E, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6D, 0x61, 0x78, 0x69, 0x6D, - 0x75, 0x6D, 0x20, 0x6E, 0x75, 0x6D, 0x62, 0x65, 0x72, 0x20, 0x6F, 0x66, 0x20, 0x54, 0x45, 0x41, - 0x4C, 0x20, 0x75, 0x69, 0x6E, 0x74, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x6D, 0x61, 0x79, - 0x20, 0x62, 0x65, 0x20, 0x73, 0x74, 0x6F, 0x72, 0x65, 0x64, 0x20, 0x69, 0x6E, 0x5C, 0x6E, 0x74, - 0x68, 0x65, 0x20, 0x6B, 0x65, 0x79, 0x2F, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x20, 0x73, 0x74, 0x6F, - 0x72, 0x65, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, - 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, - 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, - 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, - 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x4E, 0x75, 0x6D, 0x55, 0x69, 0x6E, 0x74, 0x22, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, - 0x70, 0x61, 0x63, 0x6B, 0x61, 0x67, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x67, 0x69, 0x74, 0x68, 0x75, - 0x62, 0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x67, - 0x6F, 0x2D, 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x64, 0x61, 0x65, 0x6D, 0x6F, - 0x6E, 0x2F, 0x61, 0x6C, 0x67, 0x6F, 0x64, 0x2F, 0x61, 0x70, 0x69, 0x2F, 0x73, 0x70, 0x65, 0x63, - 0x2F, 0x76, 0x31, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x22, 0x53, 0x75, 0x70, 0x70, 0x6C, 0x79, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, - 0x20, 0x22, 0x53, 0x75, 0x70, 0x70, 0x6C, 0x79, 0x20, 0x72, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, - 0x6E, 0x74, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x74, 0x20, - 0x73, 0x75, 0x70, 0x70, 0x6C, 0x79, 0x20, 0x6F, 0x66, 0x20, 0x4D, 0x69, 0x63, 0x72, 0x6F, 0x41, - 0x6C, 0x67, 0x6F, 0x73, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x79, 0x73, 0x74, - 0x65, 0x6D, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, - 0x22, 0x3A, 0x20, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x22, 0x3A, 0x20, 0x5B, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x22, - 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x6F, 0x74, 0x61, 0x6C, - 0x4D, 0x6F, 0x6E, 0x65, 0x79, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x22, 0x6F, 0x6E, 0x6C, 0x69, 0x6E, 0x65, 0x4D, 0x6F, 0x6E, 0x65, 0x79, 0x22, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x5D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x72, - 0x6F, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6F, 0x6E, 0x6C, 0x69, 0x6E, 0x65, 0x4D, 0x6F, 0x6E, 0x65, - 0x79, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x4E, 0x75, 0x6D, 0x55, 0x69, 0x6E, 0x74, 0x22, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, + 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x70, 0x61, + 0x63, 0x6B, 0x61, 0x67, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2E, + 0x63, 0x6F, 0x6D, 0x2F, 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x67, 0x6F, 0x2D, + 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x64, 0x61, 0x65, 0x6D, 0x6F, 0x6E, 0x2F, + 0x61, 0x6C, 0x67, 0x6F, 0x64, 0x2F, 0x61, 0x70, 0x69, 0x2F, 0x73, 0x70, 0x65, 0x63, 0x2F, 0x76, + 0x31, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, 0x53, + 0x75, 0x70, 0x70, 0x6C, 0x79, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, - 0x4F, 0x6E, 0x6C, 0x69, 0x6E, 0x65, 0x4D, 0x6F, 0x6E, 0x65, 0x79, 0x22, 0x2C, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, - 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, - 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, - 0x22, 0x4F, 0x6E, 0x6C, 0x69, 0x6E, 0x65, 0x4D, 0x6F, 0x6E, 0x65, 0x79, 0x22, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, - 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x2C, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, - 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, - 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, - 0x22, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x6F, 0x74, 0x61, - 0x6C, 0x4D, 0x6F, 0x6E, 0x65, 0x79, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, - 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x54, 0x6F, 0x74, 0x61, 0x6C, 0x4D, 0x6F, 0x6E, 0x65, 0x79, 0x22, - 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, - 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, - 0x22, 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, - 0x65, 0x22, 0x3A, 0x20, 0x22, 0x54, 0x6F, 0x74, 0x61, 0x6C, 0x4D, 0x6F, 0x6E, 0x65, 0x79, 0x22, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, - 0x70, 0x61, 0x63, 0x6B, 0x61, 0x67, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x67, 0x69, 0x74, 0x68, 0x75, - 0x62, 0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x67, - 0x6F, 0x2D, 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x64, 0x61, 0x65, 0x6D, 0x6F, - 0x6E, 0x2F, 0x61, 0x6C, 0x67, 0x6F, 0x64, 0x2F, 0x61, 0x70, 0x69, 0x2F, 0x73, 0x70, 0x65, 0x63, - 0x2F, 0x76, 0x31, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x22, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x7B, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6F, 0x6E, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x73, 0x20, 0x61, 0x6C, 0x6C, 0x20, - 0x66, 0x69, 0x65, 0x6C, 0x64, 0x73, 0x20, 0x63, 0x6F, 0x6D, 0x6D, 0x6F, 0x6E, 0x20, 0x74, 0x6F, - 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, - 0x73, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x73, 0x20, 0x61, 0x73, 0x20, - 0x61, 0x6E, 0x20, 0x65, 0x6E, 0x76, 0x65, 0x6C, 0x6F, 0x70, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x61, - 0x6C, 0x6C, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x5C, - 0x6E, 0x74, 0x79, 0x70, 0x65, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, - 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x22, 0x2C, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x22, - 0x3A, 0x20, 0x5B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, - 0x65, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x78, 0x22, - 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x72, 0x6F, 0x6D, 0x22, - 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x65, 0x65, 0x22, 0x2C, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x69, 0x72, 0x73, 0x74, 0x2D, - 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x22, 0x6C, 0x61, 0x73, 0x74, 0x2D, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x2C, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x70, 0x70, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0x63, 0x65, 0x72, - 0x74, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x67, 0x65, 0x6E, - 0x65, 0x73, 0x69, 0x73, 0x49, 0x44, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x67, 0x65, 0x6E, 0x65, 0x73, 0x69, 0x73, 0x68, 0x61, 0x73, 0x68, 0x62, 0x36, 0x34, - 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x70, 0x72, 0x6F, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3A, 0x20, 0x7B, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x70, 0x70, 0x22, 0x3A, 0x20, - 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x24, 0x72, 0x65, - 0x66, 0x22, 0x3A, 0x20, 0x22, 0x23, 0x2F, 0x64, 0x65, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x6F, - 0x6E, 0x73, 0x2F, 0x41, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x43, 0x61, - 0x6C, 0x6C, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x54, 0x79, 0x70, - 0x65, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0x63, 0x65, - 0x72, 0x74, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3A, 0x20, 0x22, 0x23, 0x2F, 0x64, 0x65, 0x66, 0x69, - 0x6E, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x43, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0x43, - 0x65, 0x72, 0x74, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x54, 0x79, - 0x70, 0x65, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x75, 0x72, 0x63, 0x66, 0x67, 0x22, 0x3A, - 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x24, 0x72, - 0x65, 0x66, 0x22, 0x3A, 0x20, 0x22, 0x23, 0x2F, 0x64, 0x65, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, - 0x6F, 0x6E, 0x73, 0x2F, 0x41, 0x73, 0x73, 0x65, 0x74, 0x43, 0x6F, 0x6E, 0x66, 0x69, 0x67, 0x54, - 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x54, 0x79, 0x70, 0x65, 0x22, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x63, 0x75, 0x72, 0x66, 0x72, 0x7A, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3A, - 0x20, 0x22, 0x23, 0x2F, 0x64, 0x65, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2F, - 0x41, 0x73, 0x73, 0x65, 0x74, 0x46, 0x72, 0x65, 0x65, 0x7A, 0x65, 0x54, 0x72, 0x61, 0x6E, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x54, 0x79, 0x70, 0x65, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, - 0x63, 0x75, 0x72, 0x78, 0x66, 0x65, 0x72, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3A, 0x20, 0x22, 0x23, - 0x2F, 0x64, 0x65, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x41, 0x73, 0x73, - 0x65, 0x74, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x66, 0x65, 0x72, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x54, 0x79, 0x70, 0x65, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, - 0x65, 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, - 0x22, 0x46, 0x65, 0x65, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6E, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x66, 0x65, 0x65, 0x22, 0x2C, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, - 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, - 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, - 0x22, 0x46, 0x65, 0x65, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x69, 0x72, 0x73, 0x74, 0x2D, - 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, - 0x22, 0x3A, 0x20, 0x22, 0x46, 0x69, 0x72, 0x73, 0x74, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x69, - 0x6E, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x72, - 0x73, 0x74, 0x20, 0x76, 0x61, 0x6C, 0x69, 0x64, 0x20, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x66, - 0x6F, 0x72, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6F, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, - 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, - 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, - 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x46, 0x69, 0x72, 0x73, 0x74, 0x52, 0x6F, - 0x75, 0x6E, 0x64, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x72, 0x6F, 0x6D, 0x22, 0x3A, 0x20, - 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x46, 0x72, 0x6F, 0x6D, - 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6E, 0x64, 0x65, 0x72, 0x27, 0x73, - 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, - 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x46, - 0x72, 0x6F, 0x6D, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x72, 0x6F, 0x6D, 0x72, 0x65, 0x77, - 0x61, 0x72, 0x64, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, - 0x3A, 0x20, 0x22, 0x46, 0x72, 0x6F, 0x6D, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x20, 0x69, - 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x6D, 0x6F, 0x75, 0x6E, 0x74, 0x20, 0x6F, 0x66, 0x20, - 0x70, 0x65, 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x20, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x20, - 0x61, 0x70, 0x70, 0x6C, 0x69, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x46, - 0x72, 0x6F, 0x6D, 0x5C, 0x6E, 0x61, 0x63, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x20, 0x61, 0x73, 0x20, - 0x70, 0x61, 0x72, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x74, 0x72, 0x61, - 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x2E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x53, 0x75, 0x70, 0x70, 0x6C, 0x79, 0x20, 0x72, 0x65, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6E, 0x74, + 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x74, 0x20, 0x73, 0x75, + 0x70, 0x70, 0x6C, 0x79, 0x20, 0x6F, 0x66, 0x20, 0x4D, 0x69, 0x63, 0x72, 0x6F, 0x41, 0x6C, 0x67, + 0x6F, 0x73, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6D, + 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, + 0x20, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x22, 0x3A, 0x20, 0x5B, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x2C, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x6F, 0x74, 0x61, 0x6C, 0x4D, 0x6F, + 0x6E, 0x65, 0x79, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6F, + 0x6E, 0x6C, 0x69, 0x6E, 0x65, 0x4D, 0x6F, 0x6E, 0x65, 0x79, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x5D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x72, 0x6F, 0x70, + 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x6F, 0x6E, 0x6C, 0x69, 0x6E, 0x65, 0x4D, 0x6F, 0x6E, 0x65, 0x79, 0x22, + 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x4F, 0x6E, + 0x6C, 0x69, 0x6E, 0x65, 0x4D, 0x6F, 0x6E, 0x65, 0x79, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x46, - 0x72, 0x6F, 0x6D, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x4F, + 0x6E, 0x6C, 0x69, 0x6E, 0x65, 0x4D, 0x6F, 0x6E, 0x65, 0x79, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, - 0x67, 0x65, 0x6E, 0x65, 0x73, 0x69, 0x73, 0x49, 0x44, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x47, 0x65, 0x6E, 0x65, 0x73, 0x69, 0x73, 0x20, - 0x49, 0x44, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, - 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, - 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x47, 0x65, 0x6E, 0x65, 0x73, 0x69, 0x73, - 0x49, 0x44, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x67, 0x65, 0x6E, 0x65, 0x73, 0x69, 0x73, 0x68, - 0x61, 0x73, 0x68, 0x62, 0x36, 0x34, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, - 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x47, 0x65, 0x6E, 0x65, 0x73, 0x69, 0x73, 0x20, 0x68, 0x61, 0x73, - 0x68, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, - 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, - 0x74, 0x22, 0x3A, 0x20, 0x22, 0x62, 0x79, 0x74, 0x65, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, - 0x22, 0x3A, 0x20, 0x22, 0x47, 0x65, 0x6E, 0x65, 0x73, 0x69, 0x73, 0x48, 0x61, 0x73, 0x68, 0x22, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x22, 0x67, 0x72, 0x6F, 0x75, 0x70, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x47, 0x72, 0x6F, 0x75, 0x70, 0x22, 0x2C, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, - 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, - 0x20, 0x22, 0x62, 0x79, 0x74, 0x65, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, - 0x22, 0x47, 0x72, 0x6F, 0x75, 0x70, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6B, 0x65, 0x79, 0x72, - 0x65, 0x67, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3A, 0x20, 0x22, 0x23, 0x2F, 0x64, 0x65, 0x66, 0x69, - 0x6E, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x4B, 0x65, 0x79, 0x72, 0x65, 0x67, 0x54, 0x72, - 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x54, 0x79, 0x70, 0x65, 0x22, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x22, 0x6C, 0x61, 0x73, 0x74, 0x2D, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x3A, 0x20, - 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x4C, 0x61, 0x73, 0x74, - 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x20, - 0x74, 0x68, 0x65, 0x20, 0x6C, 0x61, 0x73, 0x74, 0x20, 0x76, 0x61, 0x6C, 0x69, 0x64, 0x20, 0x72, - 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x74, 0x72, - 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, + 0x22, 0x3A, 0x20, 0x22, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x4C, - 0x61, 0x73, 0x74, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6C, 0x65, - 0x61, 0x73, 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, - 0x20, 0x22, 0x4C, 0x65, 0x61, 0x73, 0x65, 0x20, 0x65, 0x6E, 0x66, 0x6F, 0x72, 0x63, 0x65, 0x73, - 0x20, 0x6D, 0x75, 0x74, 0x75, 0x61, 0x6C, 0x20, 0x65, 0x78, 0x63, 0x6C, 0x75, 0x73, 0x69, 0x6F, - 0x6E, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, - 0x73, 0x2E, 0x20, 0x20, 0x49, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x66, 0x69, 0x65, 0x6C, - 0x64, 0x20, 0x69, 0x73, 0x5C, 0x6E, 0x6E, 0x6F, 0x6E, 0x7A, 0x65, 0x72, 0x6F, 0x2C, 0x20, 0x74, - 0x68, 0x65, 0x6E, 0x20, 0x6F, 0x6E, 0x63, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, - 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x69, 0x73, 0x20, 0x63, 0x6F, 0x6E, 0x66, - 0x69, 0x72, 0x6D, 0x65, 0x64, 0x2C, 0x20, 0x69, 0x74, 0x20, 0x61, 0x63, 0x71, 0x75, 0x69, 0x72, - 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x5C, 0x6E, 0x6C, 0x65, 0x61, 0x73, 0x65, 0x20, 0x69, 0x64, - 0x65, 0x6E, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x28, 0x53, 0x65, 0x6E, 0x64, 0x65, 0x72, 0x2C, 0x20, 0x4C, 0x65, 0x61, 0x73, 0x65, 0x29, 0x20, - 0x70, 0x61, 0x69, 0x72, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6E, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x75, 0x6E, 0x74, 0x69, 0x6C, 0x5C, 0x6E, 0x74, - 0x68, 0x65, 0x20, 0x4C, 0x61, 0x73, 0x74, 0x56, 0x61, 0x6C, 0x69, 0x64, 0x20, 0x72, 0x6F, 0x75, - 0x6E, 0x64, 0x20, 0x70, 0x61, 0x73, 0x73, 0x65, 0x73, 0x2E, 0x20, 0x20, 0x57, 0x68, 0x69, 0x6C, - 0x65, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6F, 0x6E, 0x20, 0x70, 0x6F, 0x73, 0x73, 0x65, 0x73, 0x73, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, - 0x5C, 0x6E, 0x6C, 0x65, 0x61, 0x73, 0x65, 0x2C, 0x20, 0x6E, 0x6F, 0x20, 0x6F, 0x74, 0x68, 0x65, - 0x72, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x73, 0x70, - 0x65, 0x63, 0x69, 0x66, 0x79, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x6C, 0x65, - 0x61, 0x73, 0x65, 0x20, 0x63, 0x61, 0x6E, 0x20, 0x62, 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x66, 0x69, - 0x72, 0x6D, 0x65, 0x64, 0x2E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, - 0x67, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, - 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x62, 0x79, 0x74, 0x65, 0x22, 0x2C, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, - 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x4C, 0x65, 0x61, 0x73, 0x65, 0x22, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x22, 0x6E, 0x6F, 0x74, 0x65, 0x62, 0x36, 0x34, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x4E, 0x6F, 0x74, 0x65, 0x20, 0x69, 0x73, - 0x20, 0x61, 0x20, 0x66, 0x72, 0x65, 0x65, 0x20, 0x66, 0x6F, 0x72, 0x6D, 0x20, 0x64, 0x61, 0x74, - 0x61, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, - 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, - 0x74, 0x22, 0x3A, 0x20, 0x22, 0x62, 0x79, 0x74, 0x65, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, - 0x22, 0x3A, 0x20, 0x22, 0x4E, 0x6F, 0x74, 0x65, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x61, - 0x79, 0x6D, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3A, 0x20, 0x22, 0x23, 0x2F, 0x64, - 0x65, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x50, 0x61, 0x79, 0x6D, 0x65, - 0x6E, 0x74, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x54, 0x79, 0x70, - 0x65, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x6F, 0x6F, 0x6C, 0x65, 0x72, 0x72, 0x6F, 0x72, - 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, - 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x50, - 0x6F, 0x6F, 0x6C, 0x45, 0x72, 0x72, 0x6F, 0x72, 0x20, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x61, 0x74, - 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, - 0x6F, 0x6E, 0x20, 0x77, 0x61, 0x73, 0x20, 0x65, 0x76, 0x69, 0x63, 0x74, 0x65, 0x64, 0x20, 0x66, - 0x72, 0x6F, 0x6D, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x6E, 0x6F, 0x64, 0x65, 0x27, 0x73, 0x20, - 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x5C, 0x6E, 0x70, 0x6F, 0x6F, - 0x6C, 0x20, 0x28, 0x69, 0x66, 0x20, 0x6E, 0x6F, 0x6E, 0x2D, 0x65, 0x6D, 0x70, 0x74, 0x79, 0x29, - 0x2E, 0x20, 0x20, 0x41, 0x20, 0x6E, 0x6F, 0x6E, 0x2D, 0x65, 0x6D, 0x70, 0x74, 0x79, 0x20, 0x50, - 0x6F, 0x6F, 0x6C, 0x45, 0x72, 0x72, 0x6F, 0x72, 0x20, 0x64, 0x6F, 0x65, 0x73, 0x20, 0x6E, 0x6F, - 0x74, 0x20, 0x67, 0x75, 0x61, 0x72, 0x61, 0x6E, 0x74, 0x65, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, - 0x20, 0x74, 0x68, 0x65, 0x5C, 0x6E, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, - 0x6E, 0x20, 0x77, 0x69, 0x6C, 0x6C, 0x20, 0x6E, 0x65, 0x76, 0x65, 0x72, 0x20, 0x62, 0x65, 0x20, - 0x63, 0x6F, 0x6D, 0x6D, 0x69, 0x74, 0x74, 0x65, 0x64, 0x3B, 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, - 0x20, 0x6E, 0x6F, 0x64, 0x65, 0x73, 0x20, 0x6D, 0x61, 0x79, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x68, - 0x61, 0x76, 0x65, 0x20, 0x65, 0x76, 0x69, 0x63, 0x74, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x5C, - 0x6E, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x61, 0x6E, 0x64, - 0x20, 0x6D, 0x61, 0x79, 0x20, 0x61, 0x74, 0x74, 0x65, 0x6D, 0x70, 0x74, 0x20, 0x74, 0x6F, 0x20, - 0x63, 0x6F, 0x6D, 0x6D, 0x69, 0x74, 0x20, 0x69, 0x74, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x66, 0x75, 0x74, 0x75, 0x72, 0x65, 0x2E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, - 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x50, - 0x6F, 0x6F, 0x6C, 0x45, 0x72, 0x72, 0x6F, 0x72, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x72, 0x6F, - 0x75, 0x6E, 0x64, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, - 0x20, 0x22, 0x43, 0x6F, 0x6E, 0x66, 0x69, 0x72, 0x6D, 0x65, 0x64, 0x52, 0x6F, 0x75, 0x6E, 0x64, - 0x20, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, - 0x6C, 0x6F, 0x63, 0x6B, 0x20, 0x6E, 0x75, 0x6D, 0x62, 0x65, 0x72, 0x20, 0x74, 0x68, 0x69, 0x73, - 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x61, 0x70, 0x70, - 0x65, 0x61, 0x72, 0x65, 0x64, 0x20, 0x69, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, - 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, - 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x43, 0x6F, - 0x6E, 0x66, 0x69, 0x72, 0x6D, 0x65, 0x64, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x74, 0x78, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x52, + 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x6F, 0x74, 0x61, 0x6C, 0x4D, + 0x6F, 0x6E, 0x65, 0x79, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, - 0x3A, 0x20, 0x22, 0x54, 0x78, 0x49, 0x44, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, - 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x49, 0x44, 0x22, 0x2C, 0x0A, + 0x3A, 0x20, 0x22, 0x54, 0x6F, 0x74, 0x61, 0x6C, 0x4D, 0x6F, 0x6E, 0x65, 0x79, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, - 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, - 0x22, 0x3A, 0x20, 0x22, 0x54, 0x78, 0x49, 0x44, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x78, - 0x72, 0x65, 0x73, 0x75, 0x6C, 0x74, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3A, 0x20, 0x22, 0x23, - 0x2F, 0x64, 0x65, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x54, 0x72, 0x61, - 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x52, 0x65, 0x73, 0x75, 0x6C, 0x74, 0x73, 0x22, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x54, 0x79, 0x70, 0x65, 0x20, 0x69, 0x73, 0x20, - 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, - 0x74, 0x79, 0x70, 0x65, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, - 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, - 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x54, 0x79, 0x70, 0x65, 0x22, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, - 0x70, 0x61, 0x63, 0x6B, 0x61, 0x67, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x67, 0x69, 0x74, 0x68, 0x75, - 0x62, 0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x67, - 0x6F, 0x2D, 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x64, 0x61, 0x65, 0x6D, 0x6F, - 0x6E, 0x2F, 0x61, 0x6C, 0x67, 0x6F, 0x64, 0x2F, 0x61, 0x70, 0x69, 0x2F, 0x73, 0x70, 0x65, 0x63, - 0x2F, 0x76, 0x31, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x22, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x46, 0x65, 0x65, 0x22, - 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x46, 0x65, 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, 0x6E, - 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x65, 0x64, 0x20, - 0x66, 0x65, 0x65, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, + 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, + 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, + 0x3A, 0x20, 0x22, 0x54, 0x6F, 0x74, 0x61, 0x6C, 0x4D, 0x6F, 0x6E, 0x65, 0x79, 0x22, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, + 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x70, 0x61, + 0x63, 0x6B, 0x61, 0x67, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2E, + 0x63, 0x6F, 0x6D, 0x2F, 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x67, 0x6F, 0x2D, + 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x64, 0x61, 0x65, 0x6D, 0x6F, 0x6E, 0x2F, + 0x61, 0x6C, 0x67, 0x6F, 0x64, 0x2F, 0x61, 0x70, 0x69, 0x2F, 0x73, 0x70, 0x65, 0x63, 0x2F, 0x76, + 0x31, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, 0x54, + 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, + 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, + 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x73, 0x20, 0x61, 0x6C, 0x6C, 0x20, 0x66, 0x69, + 0x65, 0x6C, 0x64, 0x73, 0x20, 0x63, 0x6F, 0x6D, 0x6D, 0x6F, 0x6E, 0x20, 0x74, 0x6F, 0x20, 0x61, + 0x6C, 0x6C, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x20, + 0x61, 0x6E, 0x64, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x73, 0x20, 0x61, 0x73, 0x20, 0x61, 0x6E, + 0x20, 0x65, 0x6E, 0x76, 0x65, 0x6C, 0x6F, 0x70, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x61, 0x6C, 0x6C, + 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x5C, 0x6E, 0x74, + 0x79, 0x70, 0x65, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x22, 0x3A, 0x20, - 0x5B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x65, 0x65, 0x22, 0x0A, + 0x5B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, + 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x78, 0x22, 0x2C, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x72, 0x6F, 0x6D, 0x22, 0x2C, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x65, 0x65, 0x22, 0x2C, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x69, 0x72, 0x73, 0x74, 0x2D, 0x72, 0x6F, + 0x75, 0x6E, 0x64, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6C, + 0x61, 0x73, 0x74, 0x2D, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x70, 0x70, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0x63, 0x65, 0x72, 0x74, 0x22, + 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x67, 0x65, 0x6E, 0x65, 0x73, + 0x69, 0x73, 0x49, 0x44, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x67, 0x65, 0x6E, 0x65, 0x73, 0x69, 0x73, 0x68, 0x61, 0x73, 0x68, 0x62, 0x36, 0x34, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x72, 0x6F, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x65, 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x61, 0x70, 0x70, 0x22, 0x3A, 0x20, 0x7B, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, + 0x3A, 0x20, 0x22, 0x23, 0x2F, 0x64, 0x65, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, + 0x2F, 0x41, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x43, 0x61, 0x6C, 0x6C, + 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x54, 0x79, 0x70, 0x65, 0x22, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0x63, 0x65, 0x72, 0x74, + 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x24, 0x72, 0x65, 0x66, 0x22, 0x3A, 0x20, 0x22, 0x23, 0x2F, 0x64, 0x65, 0x66, 0x69, 0x6E, 0x69, + 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x43, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0x43, 0x65, 0x72, + 0x74, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x54, 0x79, 0x70, 0x65, + 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x75, 0x72, 0x63, 0x66, 0x67, 0x22, 0x3A, 0x20, 0x7B, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, + 0x22, 0x3A, 0x20, 0x22, 0x23, 0x2F, 0x64, 0x65, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x6F, 0x6E, + 0x73, 0x2F, 0x41, 0x73, 0x73, 0x65, 0x74, 0x43, 0x6F, 0x6E, 0x66, 0x69, 0x67, 0x54, 0x72, 0x61, + 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x54, 0x79, 0x70, 0x65, 0x22, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x63, 0x75, 0x72, 0x66, 0x72, 0x7A, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3A, 0x20, 0x22, + 0x23, 0x2F, 0x64, 0x65, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x41, 0x73, + 0x73, 0x65, 0x74, 0x46, 0x72, 0x65, 0x65, 0x7A, 0x65, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6F, 0x6E, 0x54, 0x79, 0x70, 0x65, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x75, + 0x72, 0x78, 0x66, 0x65, 0x72, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3A, 0x20, 0x22, 0x23, 0x2F, 0x64, + 0x65, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x41, 0x73, 0x73, 0x65, 0x74, + 0x54, 0x72, 0x61, 0x6E, 0x73, 0x66, 0x65, 0x72, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6F, 0x6E, 0x54, 0x79, 0x70, 0x65, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x65, 0x65, + 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x46, + 0x65, 0x65, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x66, 0x65, 0x65, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, + 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x75, 0x69, + 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x46, + 0x65, 0x65, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x69, 0x72, 0x73, 0x74, 0x2D, 0x72, 0x6F, + 0x75, 0x6E, 0x64, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, + 0x20, 0x22, 0x46, 0x69, 0x72, 0x73, 0x74, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x69, 0x6E, 0x64, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, + 0x20, 0x76, 0x61, 0x6C, 0x69, 0x64, 0x20, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x66, 0x6F, 0x72, + 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, + 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, + 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, + 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, + 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x46, 0x69, 0x72, 0x73, 0x74, 0x52, 0x6F, 0x75, 0x6E, + 0x64, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x72, 0x6F, 0x6D, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x46, 0x65, 0x65, 0x20, 0x69, 0x73, - 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x66, 0x65, 0x65, - 0x5C, 0x6E, 0x46, 0x65, 0x65, 0x20, 0x69, 0x73, 0x20, 0x69, 0x6E, 0x20, 0x75, 0x6E, 0x69, 0x74, - 0x73, 0x20, 0x6F, 0x66, 0x20, 0x6D, 0x69, 0x63, 0x72, 0x6F, 0x2D, 0x41, 0x6C, 0x67, 0x6F, 0x73, - 0x20, 0x70, 0x65, 0x72, 0x20, 0x62, 0x79, 0x74, 0x65, 0x2E, 0x5C, 0x6E, 0x46, 0x65, 0x65, 0x20, - 0x6D, 0x61, 0x79, 0x20, 0x66, 0x61, 0x6C, 0x6C, 0x20, 0x74, 0x6F, 0x20, 0x7A, 0x65, 0x72, 0x6F, - 0x20, 0x62, 0x75, 0x74, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, - 0x73, 0x20, 0x6D, 0x75, 0x73, 0x74, 0x20, 0x73, 0x74, 0x69, 0x6C, 0x6C, 0x20, 0x68, 0x61, 0x76, - 0x65, 0x20, 0x61, 0x20, 0x66, 0x65, 0x65, 0x20, 0x6F, 0x66, 0x5C, 0x6E, 0x61, 0x74, 0x20, 0x6C, - 0x65, 0x61, 0x73, 0x74, 0x20, 0x4D, 0x69, 0x6E, 0x54, 0x78, 0x6E, 0x46, 0x65, 0x65, 0x20, 0x66, - 0x6F, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x74, 0x20, 0x6E, - 0x65, 0x74, 0x77, 0x6F, 0x72, 0x6B, 0x20, 0x70, 0x72, 0x6F, 0x74, 0x6F, 0x63, 0x6F, 0x6C, 0x2E, + 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x46, 0x72, 0x6F, 0x6D, 0x20, 0x69, + 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6E, 0x64, 0x65, 0x72, 0x27, 0x73, 0x20, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, + 0x6E, 0x67, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x46, 0x72, 0x6F, + 0x6D, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x72, 0x6F, 0x6D, 0x72, 0x65, 0x77, 0x61, 0x72, + 0x64, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, + 0x22, 0x46, 0x72, 0x6F, 0x6D, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x20, 0x69, 0x73, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x61, 0x6D, 0x6F, 0x75, 0x6E, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x70, 0x65, + 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x20, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x20, 0x61, 0x70, + 0x70, 0x6C, 0x69, 0x65, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65, 0x20, 0x46, 0x72, 0x6F, + 0x6D, 0x5C, 0x6E, 0x61, 0x63, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x20, 0x61, 0x73, 0x20, 0x70, 0x61, + 0x72, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x2E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, + 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, + 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x46, 0x72, 0x6F, + 0x6D, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x67, 0x65, + 0x6E, 0x65, 0x73, 0x69, 0x73, 0x49, 0x44, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x47, 0x65, 0x6E, 0x65, 0x73, 0x69, 0x73, 0x20, 0x49, 0x44, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, - 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, - 0x74, 0x22, 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, + 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, + 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x47, 0x65, 0x6E, 0x65, 0x73, 0x69, 0x73, 0x49, 0x44, + 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x67, 0x65, 0x6E, 0x65, 0x73, 0x69, 0x73, 0x68, 0x61, 0x73, + 0x68, 0x62, 0x36, 0x34, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, + 0x3A, 0x20, 0x22, 0x47, 0x65, 0x6E, 0x65, 0x73, 0x69, 0x73, 0x20, 0x68, 0x61, 0x73, 0x68, 0x22, + 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, + 0x65, 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, + 0x3A, 0x20, 0x22, 0x62, 0x79, 0x74, 0x65, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, + 0x20, 0x22, 0x47, 0x65, 0x6E, 0x65, 0x73, 0x69, 0x73, 0x48, 0x61, 0x73, 0x68, 0x22, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x67, 0x72, 0x6F, 0x75, 0x70, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x47, 0x72, 0x6F, 0x75, 0x70, 0x22, 0x2C, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, + 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, + 0x62, 0x79, 0x74, 0x65, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x47, + 0x72, 0x6F, 0x75, 0x70, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6B, 0x65, 0x79, 0x72, 0x65, 0x67, + 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x24, 0x72, 0x65, 0x66, 0x22, 0x3A, 0x20, 0x22, 0x23, 0x2F, 0x64, 0x65, 0x66, 0x69, 0x6E, 0x69, + 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x4B, 0x65, 0x79, 0x72, 0x65, 0x67, 0x54, 0x72, 0x61, 0x6E, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x54, 0x79, 0x70, 0x65, 0x22, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x22, 0x6C, 0x61, 0x73, 0x74, 0x2D, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x3A, 0x20, 0x7B, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x4C, 0x61, 0x73, 0x74, 0x52, 0x6F, + 0x75, 0x6E, 0x64, 0x20, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x6C, 0x61, 0x73, 0x74, 0x20, 0x76, 0x61, 0x6C, 0x69, 0x64, 0x20, 0x72, 0x6F, 0x75, + 0x6E, 0x64, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x74, 0x72, 0x61, 0x6E, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, + 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, + 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x4C, 0x61, 0x73, + 0x74, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6C, 0x65, 0x61, 0x73, + 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, + 0x4C, 0x65, 0x61, 0x73, 0x65, 0x20, 0x65, 0x6E, 0x66, 0x6F, 0x72, 0x63, 0x65, 0x73, 0x20, 0x6D, + 0x75, 0x74, 0x75, 0x61, 0x6C, 0x20, 0x65, 0x78, 0x63, 0x6C, 0x75, 0x73, 0x69, 0x6F, 0x6E, 0x20, + 0x6F, 0x66, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2E, + 0x20, 0x20, 0x49, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x66, 0x69, 0x65, 0x6C, 0x64, 0x20, + 0x69, 0x73, 0x5C, 0x6E, 0x6E, 0x6F, 0x6E, 0x7A, 0x65, 0x72, 0x6F, 0x2C, 0x20, 0x74, 0x68, 0x65, + 0x6E, 0x20, 0x6F, 0x6E, 0x63, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x69, 0x73, 0x20, 0x63, 0x6F, 0x6E, 0x66, 0x69, 0x72, + 0x6D, 0x65, 0x64, 0x2C, 0x20, 0x69, 0x74, 0x20, 0x61, 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, + 0x20, 0x74, 0x68, 0x65, 0x5C, 0x6E, 0x6C, 0x65, 0x61, 0x73, 0x65, 0x20, 0x69, 0x64, 0x65, 0x6E, + 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x28, 0x53, + 0x65, 0x6E, 0x64, 0x65, 0x72, 0x2C, 0x20, 0x4C, 0x65, 0x61, 0x73, 0x65, 0x29, 0x20, 0x70, 0x61, + 0x69, 0x72, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x75, 0x6E, 0x74, 0x69, 0x6C, 0x5C, 0x6E, 0x74, 0x68, 0x65, + 0x20, 0x4C, 0x61, 0x73, 0x74, 0x56, 0x61, 0x6C, 0x69, 0x64, 0x20, 0x72, 0x6F, 0x75, 0x6E, 0x64, + 0x20, 0x70, 0x61, 0x73, 0x73, 0x65, 0x73, 0x2E, 0x20, 0x20, 0x57, 0x68, 0x69, 0x6C, 0x65, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, + 0x20, 0x70, 0x6F, 0x73, 0x73, 0x65, 0x73, 0x73, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x5C, 0x6E, + 0x6C, 0x65, 0x61, 0x73, 0x65, 0x2C, 0x20, 0x6E, 0x6F, 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x20, + 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x73, 0x70, 0x65, 0x63, + 0x69, 0x66, 0x79, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x6C, 0x65, 0x61, 0x73, + 0x65, 0x20, 0x63, 0x61, 0x6E, 0x20, 0x62, 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x66, 0x69, 0x72, 0x6D, + 0x65, 0x64, 0x2E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, + 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, + 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x62, 0x79, 0x74, 0x65, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, - 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x46, 0x65, 0x65, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x70, 0x61, 0x63, 0x6B, 0x61, 0x67, - 0x65, 0x22, 0x3A, 0x20, 0x22, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2E, 0x63, 0x6F, 0x6D, 0x2F, - 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x67, 0x6F, 0x2D, 0x61, 0x6C, 0x67, 0x6F, - 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x64, 0x61, 0x65, 0x6D, 0x6F, 0x6E, 0x2F, 0x61, 0x6C, 0x67, 0x6F, - 0x64, 0x2F, 0x61, 0x70, 0x69, 0x2F, 0x73, 0x70, 0x65, 0x63, 0x2F, 0x76, 0x31, 0x22, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, 0x54, 0x72, 0x61, 0x6E, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, - 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, - 0x4C, 0x69, 0x73, 0x74, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x73, 0x20, 0x61, 0x20, - 0x6C, 0x69, 0x73, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6F, 0x6E, 0x73, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, - 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x22, 0x2C, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x22, 0x3A, - 0x20, 0x5B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x72, 0x61, 0x6E, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x5D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x72, 0x6F, 0x70, 0x65, 0x72, - 0x74, 0x69, 0x65, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x22, 0x3A, + 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x4C, 0x65, 0x61, 0x73, 0x65, 0x22, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x22, 0x6E, 0x6F, 0x74, 0x65, 0x62, 0x36, 0x34, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x4E, 0x6F, 0x74, 0x65, 0x20, 0x69, 0x73, 0x20, 0x61, + 0x20, 0x66, 0x72, 0x65, 0x65, 0x20, 0x66, 0x6F, 0x72, 0x6D, 0x20, 0x64, 0x61, 0x74, 0x61, 0x22, + 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, + 0x65, 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, + 0x3A, 0x20, 0x22, 0x62, 0x79, 0x74, 0x65, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, + 0x20, 0x22, 0x4E, 0x6F, 0x74, 0x65, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x61, 0x79, 0x6D, + 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3A, 0x20, 0x22, 0x23, 0x2F, 0x64, 0x65, 0x66, + 0x69, 0x6E, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x50, 0x61, 0x79, 0x6D, 0x65, 0x6E, 0x74, + 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x54, 0x79, 0x70, 0x65, 0x22, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x6F, 0x6F, 0x6C, 0x65, 0x72, 0x72, 0x6F, 0x72, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x54, 0x72, 0x61, - 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x4C, 0x69, 0x73, 0x74, 0x20, 0x69, 0x73, 0x20, - 0x61, 0x20, 0x6C, 0x69, 0x73, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x61, 0x72, 0x72, 0x61, - 0x79, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x69, - 0x74, 0x65, 0x6D, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3A, 0x20, 0x22, 0x23, 0x2F, - 0x64, 0x65, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x54, 0x72, 0x61, 0x6E, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x54, 0x72, - 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x70, 0x61, 0x63, 0x6B, 0x61, - 0x67, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2E, 0x63, 0x6F, 0x6D, - 0x2F, 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x67, 0x6F, 0x2D, 0x61, 0x6C, 0x67, - 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x64, 0x61, 0x65, 0x6D, 0x6F, 0x6E, 0x2F, 0x61, 0x6C, 0x67, - 0x6F, 0x64, 0x2F, 0x61, 0x70, 0x69, 0x2F, 0x73, 0x70, 0x65, 0x63, 0x2F, 0x76, 0x31, 0x22, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, 0x54, 0x72, 0x61, 0x6E, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x50, 0x61, 0x72, 0x61, 0x6D, 0x73, 0x22, 0x3A, 0x20, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x50, 0x6F, 0x6F, + 0x6C, 0x45, 0x72, 0x72, 0x6F, 0x72, 0x20, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, + 0x20, 0x77, 0x61, 0x73, 0x20, 0x65, 0x76, 0x69, 0x63, 0x74, 0x65, 0x64, 0x20, 0x66, 0x72, 0x6F, + 0x6D, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x6E, 0x6F, 0x64, 0x65, 0x27, 0x73, 0x20, 0x74, 0x72, + 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x5C, 0x6E, 0x70, 0x6F, 0x6F, 0x6C, 0x20, + 0x28, 0x69, 0x66, 0x20, 0x6E, 0x6F, 0x6E, 0x2D, 0x65, 0x6D, 0x70, 0x74, 0x79, 0x29, 0x2E, 0x20, + 0x20, 0x41, 0x20, 0x6E, 0x6F, 0x6E, 0x2D, 0x65, 0x6D, 0x70, 0x74, 0x79, 0x20, 0x50, 0x6F, 0x6F, + 0x6C, 0x45, 0x72, 0x72, 0x6F, 0x72, 0x20, 0x64, 0x6F, 0x65, 0x73, 0x20, 0x6E, 0x6F, 0x74, 0x20, + 0x67, 0x75, 0x61, 0x72, 0x61, 0x6E, 0x74, 0x65, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, + 0x68, 0x65, 0x5C, 0x6E, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, + 0x77, 0x69, 0x6C, 0x6C, 0x20, 0x6E, 0x65, 0x76, 0x65, 0x72, 0x20, 0x62, 0x65, 0x20, 0x63, 0x6F, + 0x6D, 0x6D, 0x69, 0x74, 0x74, 0x65, 0x64, 0x3B, 0x20, 0x6F, 0x74, 0x68, 0x65, 0x72, 0x20, 0x6E, + 0x6F, 0x64, 0x65, 0x73, 0x20, 0x6D, 0x61, 0x79, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x68, 0x61, 0x76, + 0x65, 0x20, 0x65, 0x76, 0x69, 0x63, 0x74, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x5C, 0x6E, 0x74, + 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6D, + 0x61, 0x79, 0x20, 0x61, 0x74, 0x74, 0x65, 0x6D, 0x70, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6F, + 0x6D, 0x6D, 0x69, 0x74, 0x20, 0x69, 0x74, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, + 0x75, 0x74, 0x75, 0x72, 0x65, 0x2E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, + 0x6E, 0x67, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x50, 0x6F, 0x6F, + 0x6C, 0x45, 0x72, 0x72, 0x6F, 0x72, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x72, 0x6F, 0x75, 0x6E, + 0x64, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, + 0x43, 0x6F, 0x6E, 0x66, 0x69, 0x72, 0x6D, 0x65, 0x64, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x69, + 0x6E, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6C, 0x6F, + 0x63, 0x6B, 0x20, 0x6E, 0x75, 0x6D, 0x62, 0x65, 0x72, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x74, + 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x61, 0x70, 0x70, 0x65, 0x61, + 0x72, 0x65, 0x64, 0x20, 0x69, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, + 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x36, + 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, + 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x43, 0x6F, 0x6E, 0x66, + 0x69, 0x72, 0x6D, 0x65, 0x64, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x74, 0x78, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, + 0x22, 0x54, 0x78, 0x49, 0x44, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, + 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x49, 0x44, 0x22, 0x2C, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, + 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, + 0x20, 0x22, 0x54, 0x78, 0x49, 0x44, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x78, 0x72, 0x65, + 0x73, 0x75, 0x6C, 0x74, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3A, 0x20, 0x22, 0x23, 0x2F, 0x64, + 0x65, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x54, 0x72, 0x61, 0x6E, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x52, 0x65, 0x73, 0x75, 0x6C, 0x74, 0x73, 0x22, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x54, 0x79, 0x70, 0x65, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x74, 0x79, + 0x70, 0x65, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, + 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x54, 0x79, 0x70, 0x65, 0x22, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, + 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x70, 0x61, + 0x63, 0x6B, 0x61, 0x67, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2E, + 0x63, 0x6F, 0x6D, 0x2F, 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x67, 0x6F, 0x2D, + 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x64, 0x61, 0x65, 0x6D, 0x6F, 0x6E, 0x2F, + 0x61, 0x6C, 0x67, 0x6F, 0x64, 0x2F, 0x61, 0x70, 0x69, 0x2F, 0x73, 0x70, 0x65, 0x63, 0x2F, 0x76, + 0x31, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, 0x54, + 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x46, 0x65, 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6F, 0x6E, 0x50, 0x61, 0x72, 0x61, 0x6D, 0x73, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, - 0x6E, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6D, 0x65, 0x74, 0x65, 0x72, - 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x68, 0x65, 0x6C, 0x70, 0x20, 0x61, 0x20, 0x63, 0x6C, - 0x69, 0x65, 0x6E, 0x74, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x5C, 0x6E, - 0x61, 0x20, 0x6E, 0x65, 0x77, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, - 0x6E, 0x2E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, + 0x69, 0x6F, 0x6E, 0x46, 0x65, 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x73, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x73, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x65, 0x64, 0x20, 0x66, 0x65, + 0x65, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, + 0x3A, 0x20, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x22, 0x3A, 0x20, 0x5B, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x65, 0x65, 0x22, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x5D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x72, + 0x6F, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x65, 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x46, 0x65, 0x65, 0x20, 0x69, 0x73, 0x20, 0x74, + 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x66, 0x65, 0x65, 0x5C, 0x6E, + 0x46, 0x65, 0x65, 0x20, 0x69, 0x73, 0x20, 0x69, 0x6E, 0x20, 0x75, 0x6E, 0x69, 0x74, 0x73, 0x20, + 0x6F, 0x66, 0x20, 0x6D, 0x69, 0x63, 0x72, 0x6F, 0x2D, 0x41, 0x6C, 0x67, 0x6F, 0x73, 0x20, 0x70, + 0x65, 0x72, 0x20, 0x62, 0x79, 0x74, 0x65, 0x2E, 0x5C, 0x6E, 0x46, 0x65, 0x65, 0x20, 0x6D, 0x61, + 0x79, 0x20, 0x66, 0x61, 0x6C, 0x6C, 0x20, 0x74, 0x6F, 0x20, 0x7A, 0x65, 0x72, 0x6F, 0x20, 0x62, + 0x75, 0x74, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x20, + 0x6D, 0x75, 0x73, 0x74, 0x20, 0x73, 0x74, 0x69, 0x6C, 0x6C, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, + 0x61, 0x20, 0x66, 0x65, 0x65, 0x20, 0x6F, 0x66, 0x5C, 0x6E, 0x61, 0x74, 0x20, 0x6C, 0x65, 0x61, + 0x73, 0x74, 0x20, 0x4D, 0x69, 0x6E, 0x54, 0x78, 0x6E, 0x46, 0x65, 0x65, 0x20, 0x66, 0x6F, 0x72, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x74, 0x20, 0x6E, 0x65, 0x74, + 0x77, 0x6F, 0x72, 0x6B, 0x20, 0x70, 0x72, 0x6F, 0x74, 0x6F, 0x63, 0x6F, 0x6C, 0x2E, 0x22, 0x2C, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, + 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, + 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, + 0x22, 0x3A, 0x20, 0x22, 0x46, 0x65, 0x65, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x70, 0x61, 0x63, 0x6B, 0x61, 0x67, 0x65, 0x22, + 0x3A, 0x20, 0x22, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x61, 0x6C, + 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x67, 0x6F, 0x2D, 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, + 0x6E, 0x64, 0x2F, 0x64, 0x61, 0x65, 0x6D, 0x6F, 0x6E, 0x2F, 0x61, 0x6C, 0x67, 0x6F, 0x64, 0x2F, + 0x61, 0x70, 0x69, 0x2F, 0x73, 0x70, 0x65, 0x63, 0x2F, 0x76, 0x31, 0x22, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, + 0x74, 0x69, 0x6F, 0x6E, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, + 0x3A, 0x20, 0x22, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x4C, 0x69, + 0x73, 0x74, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x73, 0x20, 0x61, 0x20, 0x6C, 0x69, + 0x73, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, + 0x6E, 0x73, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x22, 0x3A, 0x20, 0x5B, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x65, 0x65, 0x22, 0x2C, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x67, 0x65, 0x6E, 0x65, 0x73, 0x69, 0x73, - 0x49, 0x44, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x67, 0x65, - 0x6E, 0x65, 0x73, 0x69, 0x73, 0x68, 0x61, 0x73, 0x68, 0x62, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6C, 0x61, 0x73, 0x74, 0x52, 0x6F, 0x75, 0x6E, - 0x64, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x6F, 0x6E, - 0x73, 0x65, 0x6E, 0x73, 0x75, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x22, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x5D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, - 0x72, 0x6F, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x6F, 0x6E, 0x73, 0x65, 0x6E, 0x73, 0x75, 0x73, - 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5D, 0x2C, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x72, 0x6F, 0x70, 0x65, 0x72, 0x74, 0x69, + 0x65, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x22, 0x3A, 0x20, 0x7B, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x54, 0x72, 0x61, 0x6E, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x4C, 0x69, 0x73, 0x74, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, + 0x6C, 0x69, 0x73, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6F, 0x6E, 0x73, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x61, 0x72, 0x72, 0x61, 0x79, 0x22, + 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x69, 0x74, 0x65, + 0x6D, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3A, 0x20, 0x22, 0x23, 0x2F, 0x64, 0x65, + 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, + 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x54, 0x72, 0x61, 0x6E, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x70, 0x61, 0x63, 0x6B, 0x61, 0x67, 0x65, + 0x22, 0x3A, 0x20, 0x22, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x61, + 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x67, 0x6F, 0x2D, 0x61, 0x6C, 0x67, 0x6F, 0x72, + 0x61, 0x6E, 0x64, 0x2F, 0x64, 0x61, 0x65, 0x6D, 0x6F, 0x6E, 0x2F, 0x61, 0x6C, 0x67, 0x6F, 0x64, + 0x2F, 0x61, 0x70, 0x69, 0x2F, 0x73, 0x70, 0x65, 0x63, 0x2F, 0x76, 0x31, 0x22, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x50, 0x61, 0x72, 0x61, 0x6D, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, - 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x43, 0x6F, 0x6E, 0x73, 0x65, 0x6E, 0x73, 0x75, 0x73, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, - 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x65, 0x6E, 0x73, 0x75, 0x73, 0x20, 0x70, - 0x72, 0x6F, 0x74, 0x6F, 0x63, 0x6F, 0x6C, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x5C, - 0x6E, 0x61, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x4C, 0x61, 0x73, 0x74, 0x52, 0x6F, 0x75, 0x6E, 0x64, - 0x2E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, - 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, 0x0A, + 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, + 0x6E, 0x50, 0x61, 0x72, 0x61, 0x6D, 0x73, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x73, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6D, 0x65, 0x74, 0x65, 0x72, 0x73, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x20, 0x68, 0x65, 0x6C, 0x70, 0x20, 0x61, 0x20, 0x63, 0x6C, 0x69, 0x65, + 0x6E, 0x74, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x5C, 0x6E, 0x61, 0x20, + 0x6E, 0x65, 0x77, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x2E, + 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, + 0x20, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x22, 0x3A, 0x20, 0x5B, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x65, 0x65, 0x22, 0x2C, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x67, 0x65, 0x6E, 0x65, 0x73, 0x69, 0x73, 0x49, 0x44, + 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x67, 0x65, 0x6E, 0x65, + 0x73, 0x69, 0x73, 0x68, 0x61, 0x73, 0x68, 0x62, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6C, 0x61, 0x73, 0x74, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x22, + 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x6F, 0x6E, 0x73, 0x65, + 0x6E, 0x73, 0x75, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x22, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x5D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x72, 0x6F, + 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x6F, 0x6E, 0x73, 0x65, 0x6E, 0x73, 0x75, 0x73, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, + 0x22, 0x3A, 0x20, 0x22, 0x43, 0x6F, 0x6E, 0x73, 0x65, 0x6E, 0x73, 0x75, 0x73, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x65, 0x6E, 0x73, 0x75, 0x73, 0x20, 0x70, 0x72, 0x6F, + 0x74, 0x6F, 0x63, 0x6F, 0x6C, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x5C, 0x6E, 0x61, + 0x73, 0x20, 0x6F, 0x66, 0x20, 0x4C, 0x61, 0x73, 0x74, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x2E, 0x22, + 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, + 0x65, 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, + 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x43, 0x6F, 0x6E, 0x73, 0x65, 0x6E, 0x73, 0x75, 0x73, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x65, 0x65, 0x22, + 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x46, 0x65, + 0x65, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, + 0x65, 0x64, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x66, + 0x65, 0x65, 0x5C, 0x6E, 0x46, 0x65, 0x65, 0x20, 0x69, 0x73, 0x20, 0x69, 0x6E, 0x20, 0x75, 0x6E, + 0x69, 0x74, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x6D, 0x69, 0x63, 0x72, 0x6F, 0x2D, 0x41, 0x6C, 0x67, + 0x6F, 0x73, 0x20, 0x70, 0x65, 0x72, 0x20, 0x62, 0x79, 0x74, 0x65, 0x2E, 0x5C, 0x6E, 0x46, 0x65, + 0x65, 0x20, 0x6D, 0x61, 0x79, 0x20, 0x66, 0x61, 0x6C, 0x6C, 0x20, 0x74, 0x6F, 0x20, 0x7A, 0x65, + 0x72, 0x6F, 0x20, 0x62, 0x75, 0x74, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6F, 0x6E, 0x73, 0x20, 0x6D, 0x75, 0x73, 0x74, 0x20, 0x73, 0x74, 0x69, 0x6C, 0x6C, 0x20, 0x68, + 0x61, 0x76, 0x65, 0x20, 0x61, 0x20, 0x66, 0x65, 0x65, 0x20, 0x6F, 0x66, 0x5C, 0x6E, 0x61, 0x74, + 0x20, 0x6C, 0x65, 0x61, 0x73, 0x74, 0x20, 0x4D, 0x69, 0x6E, 0x54, 0x78, 0x6E, 0x46, 0x65, 0x65, + 0x20, 0x66, 0x6F, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x74, + 0x20, 0x6E, 0x65, 0x74, 0x77, 0x6F, 0x72, 0x6B, 0x20, 0x70, 0x72, 0x6F, 0x74, 0x6F, 0x63, 0x6F, + 0x6C, 0x2E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, + 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, + 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, - 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x43, 0x6F, 0x6E, 0x73, 0x65, 0x6E, 0x73, 0x75, - 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x65, - 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, - 0x46, 0x65, 0x65, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x75, 0x67, 0x67, 0x65, - 0x73, 0x74, 0x65, 0x64, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, - 0x20, 0x66, 0x65, 0x65, 0x5C, 0x6E, 0x46, 0x65, 0x65, 0x20, 0x69, 0x73, 0x20, 0x69, 0x6E, 0x20, - 0x75, 0x6E, 0x69, 0x74, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x6D, 0x69, 0x63, 0x72, 0x6F, 0x2D, 0x41, - 0x6C, 0x67, 0x6F, 0x73, 0x20, 0x70, 0x65, 0x72, 0x20, 0x62, 0x79, 0x74, 0x65, 0x2E, 0x5C, 0x6E, - 0x46, 0x65, 0x65, 0x20, 0x6D, 0x61, 0x79, 0x20, 0x66, 0x61, 0x6C, 0x6C, 0x20, 0x74, 0x6F, 0x20, - 0x7A, 0x65, 0x72, 0x6F, 0x20, 0x62, 0x75, 0x74, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x20, 0x6D, 0x75, 0x73, 0x74, 0x20, 0x73, 0x74, 0x69, 0x6C, 0x6C, - 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x61, 0x20, 0x66, 0x65, 0x65, 0x20, 0x6F, 0x66, 0x5C, 0x6E, - 0x61, 0x74, 0x20, 0x6C, 0x65, 0x61, 0x73, 0x74, 0x20, 0x4D, 0x69, 0x6E, 0x54, 0x78, 0x6E, 0x46, - 0x65, 0x65, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, - 0x6E, 0x74, 0x20, 0x6E, 0x65, 0x74, 0x77, 0x6F, 0x72, 0x6B, 0x20, 0x70, 0x72, 0x6F, 0x74, 0x6F, - 0x63, 0x6F, 0x6C, 0x2E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, - 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, - 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, + 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x46, 0x65, 0x65, 0x22, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x22, 0x67, 0x65, 0x6E, 0x65, 0x73, 0x69, 0x73, 0x49, 0x44, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x47, 0x65, 0x6E, 0x65, 0x73, 0x69, 0x73, + 0x20, 0x49, 0x44, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, - 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x46, 0x65, 0x65, 0x22, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x22, 0x67, 0x65, 0x6E, 0x65, 0x73, 0x69, 0x73, 0x49, 0x44, 0x22, 0x3A, 0x20, 0x7B, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x47, 0x65, 0x6E, 0x65, 0x73, - 0x69, 0x73, 0x20, 0x49, 0x44, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, - 0x67, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, - 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x47, 0x65, 0x6E, 0x65, - 0x73, 0x69, 0x73, 0x49, 0x44, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, - 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x67, 0x65, 0x6E, 0x65, 0x73, - 0x69, 0x73, 0x68, 0x61, 0x73, 0x68, 0x62, 0x36, 0x34, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x47, 0x65, 0x6E, 0x65, 0x73, 0x69, 0x73, 0x20, - 0x68, 0x61, 0x73, 0x68, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, - 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, - 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x62, 0x79, 0x74, 0x65, 0x22, 0x2C, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, - 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x47, 0x65, 0x6E, 0x65, 0x73, 0x69, 0x73, 0x48, 0x61, - 0x73, 0x68, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6C, 0x61, 0x73, 0x74, 0x52, 0x6F, 0x75, 0x6E, - 0x64, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, - 0x4C, 0x61, 0x73, 0x74, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x61, - 0x74, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6C, 0x61, 0x73, 0x74, 0x20, 0x72, 0x6F, 0x75, - 0x6E, 0x64, 0x20, 0x73, 0x65, 0x65, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, - 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, - 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, - 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x4C, 0x61, 0x73, - 0x74, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6D, 0x69, 0x6E, 0x46, - 0x65, 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, - 0x22, 0x54, 0x68, 0x65, 0x20, 0x6D, 0x69, 0x6E, 0x69, 0x6D, 0x75, 0x6D, 0x20, 0x74, 0x72, 0x61, - 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x66, 0x65, 0x65, 0x20, 0x28, 0x6E, 0x6F, - 0x74, 0x20, 0x70, 0x65, 0x72, 0x20, 0x62, 0x79, 0x74, 0x65, 0x29, 0x20, 0x72, 0x65, 0x71, 0x75, - 0x69, 0x72, 0x65, 0x64, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x74, 0x68, 0x65, 0x5C, 0x6E, 0x74, 0x78, - 0x6E, 0x20, 0x74, 0x6F, 0x20, 0x76, 0x61, 0x6C, 0x69, 0x64, 0x61, 0x74, 0x65, 0x20, 0x66, 0x6F, - 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x74, 0x20, 0x6E, 0x65, - 0x74, 0x77, 0x6F, 0x72, 0x6B, 0x20, 0x70, 0x72, 0x6F, 0x74, 0x6F, 0x63, 0x6F, 0x6C, 0x2E, 0x22, - 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, - 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, - 0x22, 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, + 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x47, 0x65, 0x6E, 0x65, 0x73, 0x69, + 0x73, 0x49, 0x44, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x67, 0x65, 0x6E, 0x65, 0x73, 0x69, 0x73, + 0x68, 0x61, 0x73, 0x68, 0x62, 0x36, 0x34, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x47, 0x65, 0x6E, 0x65, 0x73, 0x69, 0x73, 0x20, 0x68, 0x61, + 0x73, 0x68, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, + 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x62, 0x79, 0x74, 0x65, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, - 0x65, 0x22, 0x3A, 0x20, 0x22, 0x4D, 0x69, 0x6E, 0x54, 0x78, 0x6E, 0x46, 0x65, 0x65, 0x22, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x70, - 0x61, 0x63, 0x6B, 0x61, 0x67, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, - 0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x67, 0x6F, - 0x2D, 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x64, 0x61, 0x65, 0x6D, 0x6F, 0x6E, - 0x2F, 0x61, 0x6C, 0x67, 0x6F, 0x64, 0x2F, 0x61, 0x70, 0x69, 0x2F, 0x73, 0x70, 0x65, 0x63, 0x2F, - 0x76, 0x31, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, - 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x52, 0x65, 0x73, 0x75, 0x6C, - 0x74, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x54, 0x72, 0x61, - 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x52, 0x65, 0x73, 0x75, 0x6C, 0x74, 0x73, 0x20, - 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x73, 0x20, 0x69, 0x6E, 0x66, 0x6F, 0x72, 0x6D, 0x61, - 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, - 0x69, 0x64, 0x65, 0x20, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x61, - 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x2C, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x6F, 0x62, - 0x6A, 0x65, 0x63, 0x74, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x72, - 0x6F, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x61, 0x70, 0x70, - 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, - 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x70, 0x70, 0x49, 0x6E, 0x64, 0x65, 0x78, 0x20, 0x69, - 0x6E, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x70, 0x70, - 0x20, 0x69, 0x6E, 0x64, 0x65, 0x78, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x6E, 0x20, 0x61, 0x70, 0x70, - 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x69, 0x73, - 0x20, 0x74, 0x78, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, - 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, - 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, - 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, - 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x64, 0x41, 0x70, 0x70, 0x49, 0x6E, 0x64, 0x65, 0x78, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x61, 0x73, 0x73, 0x65, 0x74, 0x22, 0x3A, 0x20, 0x7B, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x49, 0x6E, 0x64, 0x65, 0x78, 0x20, 0x69, 0x6E, 0x64, 0x69, - 0x63, 0x61, 0x74, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x73, 0x73, 0x65, 0x74, 0x20, - 0x69, 0x6E, 0x64, 0x65, 0x78, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x6E, 0x20, 0x61, 0x73, 0x73, 0x65, - 0x74, 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x69, - 0x73, 0x20, 0x74, 0x78, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x65, 0x22, 0x3A, 0x20, 0x22, 0x47, 0x65, 0x6E, 0x65, 0x73, 0x69, 0x73, 0x48, 0x61, 0x73, 0x68, + 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6C, 0x61, 0x73, 0x74, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x22, + 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x4C, 0x61, + 0x73, 0x74, 0x52, 0x6F, 0x75, 0x6E, 0x64, 0x20, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, + 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6C, 0x61, 0x73, 0x74, 0x20, 0x72, 0x6F, 0x75, 0x6E, 0x64, + 0x20, 0x73, 0x65, 0x65, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, - 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x49, 0x6E, 0x64, 0x65, 0x78, 0x22, 0x0A, 0x20, 0x20, + 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x4C, 0x61, 0x73, 0x74, 0x52, + 0x6F, 0x75, 0x6E, 0x64, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x6D, 0x69, 0x6E, 0x46, 0x65, 0x65, + 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x54, + 0x68, 0x65, 0x20, 0x6D, 0x69, 0x6E, 0x69, 0x6D, 0x75, 0x6D, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x66, 0x65, 0x65, 0x20, 0x28, 0x6E, 0x6F, 0x74, 0x20, + 0x70, 0x65, 0x72, 0x20, 0x62, 0x79, 0x74, 0x65, 0x29, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, + 0x65, 0x64, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x74, 0x68, 0x65, 0x5C, 0x6E, 0x74, 0x78, 0x6E, 0x20, + 0x74, 0x6F, 0x20, 0x76, 0x61, 0x6C, 0x69, 0x64, 0x61, 0x74, 0x65, 0x20, 0x66, 0x6F, 0x72, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x74, 0x20, 0x6E, 0x65, 0x74, 0x77, + 0x6F, 0x72, 0x6B, 0x20, 0x70, 0x72, 0x6F, 0x74, 0x6F, 0x63, 0x6F, 0x6C, 0x2E, 0x22, 0x2C, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, + 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, + 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, + 0x3A, 0x20, 0x22, 0x4D, 0x69, 0x6E, 0x54, 0x78, 0x6E, 0x46, 0x65, 0x65, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x70, 0x61, 0x63, 0x6B, 0x61, 0x67, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x67, 0x6F, 0x2D, 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x64, 0x61, 0x65, 0x6D, 0x6F, 0x6E, 0x2F, 0x61, 0x6C, 0x67, 0x6F, 0x64, 0x2F, 0x61, 0x70, 0x69, 0x2F, 0x73, 0x70, 0x65, 0x63, 0x2F, 0x76, 0x31, - 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, 0x56, 0x65, - 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, - 0x4E, 0x6F, 0x74, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x77, 0x65, 0x20, 0x61, 0x6E, 0x6E, - 0x6F, 0x74, 0x61, 0x74, 0x65, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x61, 0x73, 0x20, 0x61, 0x20, - 0x6D, 0x6F, 0x64, 0x65, 0x6C, 0x20, 0x73, 0x6F, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x6C, 0x65, - 0x67, 0x61, 0x63, 0x79, 0x20, 0x63, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x73, 0x5C, 0x6E, 0x63, 0x61, - 0x6E, 0x20, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6C, 0x79, 0x20, 0x69, 0x6D, 0x70, 0x6F, 0x72, - 0x74, 0x20, 0x61, 0x20, 0x73, 0x77, 0x61, 0x67, 0x67, 0x65, 0x72, 0x20, 0x67, 0x65, 0x6E, 0x65, - 0x72, 0x61, 0x74, 0x65, 0x64, 0x20, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x6D, 0x6F, - 0x64, 0x65, 0x6C, 0x2E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, - 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x22, 0x2C, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x69, 0x74, 0x6C, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x73, 0x20, - 0x74, 0x68, 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x74, 0x20, 0x61, 0x6C, 0x67, 0x6F, - 0x64, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x2E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x22, 0x3A, 0x20, 0x5B, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, - 0x6E, 0x73, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x67, 0x65, - 0x6E, 0x65, 0x73, 0x69, 0x73, 0x5F, 0x69, 0x64, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x67, 0x65, 0x6E, 0x65, 0x73, 0x69, 0x73, 0x5F, 0x68, 0x61, 0x73, 0x68, - 0x5F, 0x62, 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, - 0x62, 0x75, 0x69, 0x6C, 0x64, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5D, 0x2C, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x72, 0x6F, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, - 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x62, - 0x75, 0x69, 0x6C, 0x64, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3A, 0x20, 0x22, 0x23, 0x2F, 0x64, 0x65, - 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x42, 0x75, 0x69, 0x6C, 0x64, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x67, 0x65, 0x6E, 0x65, - 0x73, 0x69, 0x73, 0x5F, 0x68, 0x61, 0x73, 0x68, 0x5F, 0x62, 0x36, 0x34, 0x22, 0x3A, 0x20, 0x7B, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, - 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, - 0x20, 0x22, 0x62, 0x79, 0x74, 0x65, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, - 0x22, 0x47, 0x65, 0x6E, 0x65, 0x73, 0x69, 0x73, 0x48, 0x61, 0x73, 0x68, 0x22, 0x0A, 0x20, 0x20, + 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, 0x54, 0x72, + 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x52, 0x65, 0x73, 0x75, 0x6C, 0x74, 0x73, + 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x54, 0x72, 0x61, 0x6E, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x52, 0x65, 0x73, 0x75, 0x6C, 0x74, 0x73, 0x20, 0x63, 0x6F, + 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x73, 0x20, 0x69, 0x6E, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x69, + 0x6F, 0x6E, 0x20, 0x61, 0x62, 0x6F, 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x69, 0x64, + 0x65, 0x20, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x20, 0x74, + 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x6F, 0x62, 0x6A, 0x65, + 0x63, 0x74, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x72, 0x6F, 0x70, + 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x61, 0x70, 0x70, 0x22, 0x3A, + 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x64, 0x41, 0x70, 0x70, 0x49, 0x6E, 0x64, 0x65, 0x78, 0x20, 0x69, 0x6E, 0x64, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x70, 0x70, 0x20, 0x69, + 0x6E, 0x64, 0x65, 0x78, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x6E, 0x20, 0x61, 0x70, 0x70, 0x20, 0x63, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x74, + 0x78, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, + 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, + 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, + 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, + 0x70, 0x70, 0x49, 0x6E, 0x64, 0x65, 0x78, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x64, 0x61, 0x73, 0x73, 0x65, 0x74, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, + 0x73, 0x73, 0x65, 0x74, 0x49, 0x6E, 0x64, 0x65, 0x78, 0x20, 0x69, 0x6E, 0x64, 0x69, 0x63, 0x61, + 0x74, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x73, 0x73, 0x65, 0x74, 0x20, 0x69, 0x6E, + 0x64, 0x65, 0x78, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x6E, 0x20, 0x61, 0x73, 0x73, 0x65, 0x74, 0x20, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, + 0x74, 0x78, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, + 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, + 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, 0x75, 0x69, 0x6E, 0x74, 0x36, 0x34, 0x22, 0x2C, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, + 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, + 0x41, 0x73, 0x73, 0x65, 0x74, 0x49, 0x6E, 0x64, 0x65, 0x78, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x70, 0x61, 0x63, 0x6B, 0x61, + 0x67, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2E, 0x63, 0x6F, 0x6D, + 0x2F, 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x67, 0x6F, 0x2D, 0x61, 0x6C, 0x67, + 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x64, 0x61, 0x65, 0x6D, 0x6F, 0x6E, 0x2F, 0x61, 0x6C, 0x67, + 0x6F, 0x64, 0x2F, 0x61, 0x70, 0x69, 0x2F, 0x73, 0x70, 0x65, 0x63, 0x2F, 0x76, 0x31, 0x22, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x4E, 0x6F, + 0x74, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x77, 0x65, 0x20, 0x61, 0x6E, 0x6E, 0x6F, 0x74, + 0x61, 0x74, 0x65, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x61, 0x73, 0x20, 0x61, 0x20, 0x6D, 0x6F, + 0x64, 0x65, 0x6C, 0x20, 0x73, 0x6F, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x6C, 0x65, 0x67, 0x61, + 0x63, 0x79, 0x20, 0x63, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x73, 0x5C, 0x6E, 0x63, 0x61, 0x6E, 0x20, + 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6C, 0x79, 0x20, 0x69, 0x6D, 0x70, 0x6F, 0x72, 0x74, 0x20, + 0x61, 0x20, 0x73, 0x77, 0x61, 0x67, 0x67, 0x65, 0x72, 0x20, 0x67, 0x65, 0x6E, 0x65, 0x72, 0x61, + 0x74, 0x65, 0x64, 0x20, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x6D, 0x6F, 0x64, 0x65, + 0x6C, 0x2E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, + 0x22, 0x3A, 0x20, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x74, 0x69, 0x74, 0x6C, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x73, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x74, 0x20, 0x61, 0x6C, 0x67, 0x6F, 0x64, 0x20, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x2E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x22, 0x3A, 0x20, 0x5B, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x73, + 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x67, 0x65, 0x6E, 0x65, + 0x73, 0x69, 0x73, 0x5F, 0x69, 0x64, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x67, 0x65, 0x6E, 0x65, 0x73, 0x69, 0x73, 0x5F, 0x68, 0x61, 0x73, 0x68, 0x5F, 0x62, + 0x36, 0x34, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x62, 0x75, + 0x69, 0x6C, 0x64, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5D, 0x2C, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x72, 0x6F, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, + 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x62, 0x75, 0x69, + 0x6C, 0x64, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3A, 0x20, 0x22, 0x23, 0x2F, 0x64, 0x65, 0x66, 0x69, + 0x6E, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x42, 0x75, 0x69, 0x6C, 0x64, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6F, 0x6E, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x67, 0x65, 0x6E, 0x65, 0x73, 0x69, + 0x73, 0x5F, 0x68, 0x61, 0x73, 0x68, 0x5F, 0x62, 0x36, 0x34, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, + 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x22, 0x3A, 0x20, 0x22, + 0x62, 0x79, 0x74, 0x65, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x47, + 0x65, 0x6E, 0x65, 0x73, 0x69, 0x73, 0x48, 0x61, 0x73, 0x68, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x67, 0x65, 0x6E, 0x65, 0x73, 0x69, 0x73, 0x5F, 0x69, 0x64, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, + 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, + 0x3A, 0x20, 0x22, 0x47, 0x65, 0x6E, 0x65, 0x73, 0x69, 0x73, 0x49, 0x44, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x67, 0x65, 0x6E, 0x65, 0x73, 0x69, 0x73, 0x5F, 0x69, 0x64, 0x22, 0x3A, 0x20, 0x7B, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, - 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, - 0x65, 0x22, 0x3A, 0x20, 0x22, 0x47, 0x65, 0x6E, 0x65, 0x73, 0x69, 0x73, 0x49, 0x44, 0x22, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x73, 0x22, 0x3A, 0x20, 0x7B, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, - 0x22, 0x3A, 0x20, 0x22, 0x61, 0x72, 0x72, 0x61, 0x79, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x69, 0x74, 0x65, 0x6D, 0x73, 0x22, 0x3A, 0x20, 0x7B, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, - 0x70, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, + 0x20, 0x22, 0x61, 0x72, 0x72, 0x61, 0x79, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x69, 0x74, 0x65, 0x6D, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, + 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, + 0x22, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x73, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x70, 0x61, 0x63, 0x6B, 0x61, 0x67, + 0x65, 0x22, 0x3A, 0x20, 0x22, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2E, 0x63, 0x6F, 0x6D, 0x2F, + 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x67, 0x6F, 0x2D, 0x61, 0x6C, 0x67, 0x6F, + 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x64, 0x61, 0x65, 0x6D, 0x6F, 0x6E, 0x2F, 0x61, 0x6C, 0x67, 0x6F, + 0x64, 0x2F, 0x61, 0x70, 0x69, 0x2F, 0x73, 0x70, 0x65, 0x63, 0x2F, 0x63, 0x6F, 0x6D, 0x6D, 0x6F, + 0x6E, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, + 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x49, 0x44, 0x22, 0x3A, 0x20, 0x7B, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6F, 0x6E, 0x49, 0x44, 0x20, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, + 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, + 0x20, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x22, 0x3A, 0x20, 0x5B, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x78, 0x49, 0x64, 0x22, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x5D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x70, 0x72, + 0x6F, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x78, 0x49, 0x64, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x54, 0x78, 0x49, 0x64, 0x20, 0x69, 0x73, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x20, 0x65, 0x6E, 0x63, 0x6F, + 0x64, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6E, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x68, 0x61, 0x73, 0x68, 0x22, 0x2C, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, + 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, - 0x3A, 0x20, 0x22, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x73, 0x22, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, + 0x3A, 0x20, 0x22, 0x54, 0x78, 0x49, 0x44, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, + 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x49, 0x44, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x70, 0x61, 0x63, 0x6B, 0x61, 0x67, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x67, 0x6F, 0x2D, 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x64, 0x61, 0x65, 0x6D, 0x6F, 0x6E, 0x2F, 0x61, 0x6C, - 0x67, 0x6F, 0x64, 0x2F, 0x61, 0x70, 0x69, 0x2F, 0x73, 0x70, 0x65, 0x63, 0x2F, 0x63, 0x6F, 0x6D, - 0x6D, 0x6F, 0x6E, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x22, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x49, 0x44, 0x22, 0x3A, - 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6F, 0x6E, 0x49, 0x44, 0x20, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, - 0x6F, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, - 0x22, 0x3A, 0x20, 0x22, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x22, 0x3A, 0x20, 0x5B, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x78, 0x49, 0x64, 0x22, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, - 0x70, 0x72, 0x6F, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x78, 0x49, 0x64, 0x22, 0x3A, 0x20, 0x7B, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x54, 0x78, 0x49, 0x64, 0x20, - 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x20, 0x65, 0x6E, - 0x63, 0x6F, 0x64, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, - 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x68, 0x61, 0x73, 0x68, 0x22, 0x2C, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, - 0x22, 0x3A, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, - 0x65, 0x22, 0x3A, 0x20, 0x22, 0x54, 0x78, 0x49, 0x44, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, - 0x20, 0x22, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x49, 0x44, 0x22, - 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x67, 0x6F, 0x2D, 0x70, 0x61, - 0x63, 0x6B, 0x61, 0x67, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2E, - 0x63, 0x6F, 0x6D, 0x2F, 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x67, 0x6F, 0x2D, - 0x61, 0x6C, 0x67, 0x6F, 0x72, 0x61, 0x6E, 0x64, 0x2F, 0x64, 0x61, 0x65, 0x6D, 0x6F, 0x6E, 0x2F, - 0x61, 0x6C, 0x67, 0x6F, 0x64, 0x2F, 0x61, 0x70, 0x69, 0x2F, 0x73, 0x70, 0x65, 0x63, 0x2F, 0x76, - 0x31, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, - 0x22, 0x72, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x41, 0x63, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x49, 0x6E, 0x66, 0x6F, 0x72, - 0x6D, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x22, 0x3A, + 0x67, 0x6F, 0x64, 0x2F, 0x61, 0x70, 0x69, 0x2F, 0x73, 0x70, 0x65, 0x63, 0x2F, 0x76, 0x31, 0x22, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x22, 0x72, + 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x41, 0x63, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x49, 0x6E, 0x66, 0x6F, 0x72, 0x6D, 0x61, + 0x74, 0x69, 0x6F, 0x6E, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x22, 0x3A, 0x20, 0x7B, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x41, 0x63, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x49, 0x6E, + 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, + 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x73, 0x20, 0x61, 0x6E, 0x20, 0x61, 0x63, + 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x20, 0x69, 0x6E, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x69, 0x6F, + 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x63, 0x68, 0x65, 0x6D, + 0x61, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x24, + 0x72, 0x65, 0x66, 0x22, 0x3A, 0x20, 0x22, 0x23, 0x2F, 0x64, 0x65, 0x66, 0x69, 0x6E, 0x69, 0x74, + 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x41, 0x63, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x22, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x41, 0x73, 0x73, 0x65, 0x74, 0x49, 0x6E, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x69, + 0x6F, 0x6E, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, + 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x41, 0x73, 0x73, 0x65, 0x74, 0x49, 0x6E, 0x66, 0x6F, 0x72, 0x6D, + 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x20, 0x63, 0x6F, + 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x73, 0x20, 0x61, 0x73, 0x73, 0x65, 0x74, 0x20, 0x69, 0x6E, 0x66, + 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3A, 0x20, 0x22, 0x23, 0x2F, + 0x64, 0x65, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x41, 0x73, 0x73, 0x65, + 0x74, 0x50, 0x61, 0x72, 0x61, 0x6D, 0x73, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, 0x41, 0x73, 0x73, + 0x65, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x41, 0x73, 0x73, 0x65, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6F, 0x6E, 0x73, 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x73, 0x20, 0x61, 0x20, + 0x6C, 0x69, 0x73, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x73, 0x73, 0x65, 0x74, 0x73, 0x22, 0x2C, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x22, 0x3A, + 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, + 0x22, 0x3A, 0x20, 0x22, 0x23, 0x2F, 0x64, 0x65, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x6F, 0x6E, + 0x73, 0x2F, 0x41, 0x73, 0x73, 0x65, 0x74, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x22, 0x42, 0x6C, 0x6F, 0x63, 0x6B, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x41, 0x63, 0x63, 0x6F, 0x75, 0x6E, 0x74, - 0x49, 0x6E, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x52, 0x65, 0x73, 0x70, 0x6F, - 0x6E, 0x73, 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x73, 0x20, 0x61, 0x6E, 0x20, - 0x61, 0x63, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x20, 0x69, 0x6E, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, + 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x42, 0x6C, 0x6F, 0x63, 0x6B, 0x52, 0x65, + 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x73, 0x20, + 0x62, 0x6C, 0x6F, 0x63, 0x6B, 0x20, 0x69, 0x6E, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x69, 0x6F, + 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x63, 0x68, 0x65, 0x6D, + 0x61, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x24, + 0x72, 0x65, 0x66, 0x22, 0x3A, 0x20, 0x22, 0x23, 0x2F, 0x64, 0x65, 0x66, 0x69, 0x6E, 0x69, 0x74, + 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x42, 0x6C, 0x6F, 0x63, 0x6B, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x50, 0x65, 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6F, 0x6E, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x50, 0x65, 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x54, 0x72, 0x61, + 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, + 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x73, 0x20, 0x61, 0x20, 0x28, 0x70, 0x6F, + 0x74, 0x65, 0x6E, 0x74, 0x69, 0x61, 0x6C, 0x6C, 0x79, 0x20, 0x74, 0x72, 0x75, 0x6E, 0x63, 0x61, + 0x74, 0x65, 0x64, 0x29, 0x20, 0x6C, 0x69, 0x73, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x72, 0x61, + 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x20, 0x61, 0x6E, 0x64, 0x5C, 0x6E, 0x74, + 0x68, 0x65, 0x20, 0x74, 0x6F, 0x74, 0x61, 0x6C, 0x20, 0x6E, 0x75, 0x6D, 0x62, 0x65, 0x72, 0x20, + 0x6F, 0x66, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x20, + 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x74, 0x6C, 0x79, 0x20, 0x69, 0x6E, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x70, 0x6F, 0x6F, 0x6C, 0x2E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3A, 0x20, 0x22, 0x23, 0x2F, 0x64, 0x65, + 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x50, 0x65, 0x6E, 0x64, 0x69, 0x6E, + 0x67, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x22, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, + 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x61, + 0x69, 0x6E, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6E, 0x6F, 0x64, 0x65, 0x27, 0x73, 0x20, 0x73, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x20, 0x69, 0x6E, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x69, 0x6F, + 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x63, 0x68, 0x65, 0x6D, + 0x61, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x24, + 0x72, 0x65, 0x66, 0x22, 0x3A, 0x20, 0x22, 0x23, 0x2F, 0x64, 0x65, 0x66, 0x69, 0x6E, 0x69, 0x74, + 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x4E, 0x6F, 0x64, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x53, 0x75, 0x70, 0x70, 0x6C, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6F, + 0x6E, 0x73, 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x53, 0x75, + 0x70, 0x70, 0x6C, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x20, 0x63, 0x6F, 0x6E, + 0x74, 0x61, 0x69, 0x6E, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6C, 0x65, 0x64, 0x67, 0x65, 0x72, + 0x20, 0x73, 0x75, 0x70, 0x70, 0x6C, 0x79, 0x20, 0x69, 0x6E, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3A, 0x20, 0x22, 0x23, 0x2F, 0x64, 0x65, 0x66, 0x69, 0x6E, - 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x41, 0x63, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x22, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x41, 0x73, 0x73, 0x65, 0x74, 0x49, 0x6E, 0x66, 0x6F, 0x72, 0x6D, 0x61, - 0x74, 0x69, 0x6F, 0x6E, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x22, 0x3A, 0x20, 0x7B, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x41, 0x73, 0x73, 0x65, 0x74, 0x49, 0x6E, 0x66, 0x6F, - 0x72, 0x6D, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x20, - 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x73, 0x20, 0x61, 0x73, 0x73, 0x65, 0x74, 0x20, 0x69, - 0x6E, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3A, 0x20, 0x22, - 0x23, 0x2F, 0x64, 0x65, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x41, 0x73, - 0x73, 0x65, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6D, 0x73, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, 0x41, - 0x73, 0x73, 0x65, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x22, 0x3A, 0x20, - 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x41, 0x73, 0x73, 0x65, 0x74, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x73, 0x20, - 0x61, 0x20, 0x6C, 0x69, 0x73, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x61, 0x73, 0x73, 0x65, 0x74, 0x73, - 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, - 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x24, 0x72, - 0x65, 0x66, 0x22, 0x3A, 0x20, 0x22, 0x23, 0x2F, 0x64, 0x65, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, - 0x6F, 0x6E, 0x73, 0x2F, 0x41, 0x73, 0x73, 0x65, 0x74, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x0A, 0x20, + 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x53, 0x75, 0x70, 0x70, 0x6C, 0x79, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x22, 0x42, 0x6C, 0x6F, 0x63, 0x6B, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, + 0x20, 0x20, 0x22, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x46, 0x65, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, + 0x22, 0x3A, 0x20, 0x22, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x46, + 0x65, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x61, + 0x69, 0x6E, 0x73, 0x20, 0x61, 0x20, 0x73, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x65, 0x64, 0x20, + 0x66, 0x65, 0x65, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x63, 0x68, + 0x65, 0x6D, 0x61, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3A, 0x20, 0x22, 0x23, 0x2F, 0x64, 0x65, 0x66, 0x69, 0x6E, + 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6F, 0x6E, 0x46, 0x65, 0x65, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, 0x54, 0x72, 0x61, 0x6E, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x49, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x42, 0x6C, 0x6F, 0x63, 0x6B, - 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, 0x6E, - 0x73, 0x20, 0x62, 0x6C, 0x6F, 0x63, 0x6B, 0x20, 0x69, 0x6E, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x54, 0x72, 0x61, 0x6E, 0x73, + 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x49, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, + 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x73, 0x20, 0x61, 0x20, 0x74, 0x72, 0x61, 0x6E, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x69, 0x6E, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3A, 0x20, 0x22, 0x23, 0x2F, 0x64, 0x65, 0x66, 0x69, 0x6E, - 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x42, 0x6C, 0x6F, 0x63, 0x6B, 0x22, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x50, 0x65, 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x22, 0x3A, 0x20, - 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x50, 0x65, 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x54, - 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6F, - 0x6E, 0x73, 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x73, 0x20, 0x61, 0x20, 0x28, - 0x70, 0x6F, 0x74, 0x65, 0x6E, 0x74, 0x69, 0x61, 0x6C, 0x6C, 0x79, 0x20, 0x74, 0x72, 0x75, 0x6E, - 0x63, 0x61, 0x74, 0x65, 0x64, 0x29, 0x20, 0x6C, 0x69, 0x73, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x74, - 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x20, 0x61, 0x6E, 0x64, 0x5C, - 0x6E, 0x74, 0x68, 0x65, 0x20, 0x74, 0x6F, 0x74, 0x61, 0x6C, 0x20, 0x6E, 0x75, 0x6D, 0x62, 0x65, - 0x72, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, - 0x73, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x74, 0x6C, 0x79, 0x20, 0x69, 0x6E, 0x20, 0x74, - 0x68, 0x65, 0x20, 0x70, 0x6F, 0x6F, 0x6C, 0x2E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3A, 0x20, 0x22, 0x23, 0x2F, - 0x64, 0x65, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x50, 0x65, 0x6E, 0x64, - 0x69, 0x6E, 0x67, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x22, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x22, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6F, + 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6F, 0x6E, 0x49, 0x44, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x50, 0x61, 0x72, 0x61, 0x6D, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, - 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x20, 0x63, 0x6F, 0x6E, - 0x74, 0x61, 0x69, 0x6E, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6E, 0x6F, 0x64, 0x65, 0x27, 0x73, - 0x20, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x20, 0x69, 0x6E, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x54, 0x72, + 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x50, 0x61, 0x72, 0x61, 0x6D, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x73, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6D, 0x65, 0x74, 0x65, 0x72, 0x73, 0x20, + 0x66, 0x6F, 0x72, 0x5C, 0x6E, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x69, 0x6E, + 0x67, 0x20, 0x61, 0x20, 0x6E, 0x65, 0x77, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6F, 0x6E, 0x2E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x63, + 0x68, 0x65, 0x6D, 0x61, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3A, 0x20, 0x22, 0x23, 0x2F, 0x64, 0x65, 0x66, 0x69, + 0x6E, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6F, 0x6E, 0x50, 0x61, 0x72, 0x61, 0x6D, 0x73, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, 0x54, + 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, + 0x73, 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x54, 0x72, 0x61, + 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, + 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x73, 0x20, 0x61, 0x20, 0x74, 0x72, 0x61, 0x6E, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x69, 0x6E, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3A, 0x20, 0x22, 0x23, 0x2F, 0x64, 0x65, 0x66, 0x69, 0x6E, - 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x4E, 0x6F, 0x64, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, - 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, 0x53, 0x75, 0x70, 0x70, 0x6C, 0x79, 0x52, 0x65, 0x73, - 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, - 0x53, 0x75, 0x70, 0x70, 0x6C, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x20, 0x63, - 0x6F, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6C, 0x65, 0x64, 0x67, - 0x65, 0x72, 0x20, 0x73, 0x75, 0x70, 0x70, 0x6C, 0x79, 0x20, 0x69, 0x6E, 0x66, 0x6F, 0x72, 0x6D, - 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, - 0x63, 0x68, 0x65, 0x6D, 0x61, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3A, 0x20, 0x22, 0x23, 0x2F, 0x64, 0x65, 0x66, - 0x69, 0x6E, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x53, 0x75, 0x70, 0x70, 0x6C, 0x79, 0x22, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x22, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, - 0x46, 0x65, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, - 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, - 0x6E, 0x46, 0x65, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x20, 0x63, 0x6F, 0x6E, - 0x74, 0x61, 0x69, 0x6E, 0x73, 0x20, 0x61, 0x20, 0x73, 0x75, 0x67, 0x67, 0x65, 0x73, 0x74, 0x65, - 0x64, 0x20, 0x66, 0x65, 0x65, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, - 0x63, 0x68, 0x65, 0x6D, 0x61, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3A, 0x20, 0x22, 0x23, 0x2F, 0x64, 0x65, 0x66, - 0x69, 0x6E, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6F, 0x6E, 0x46, 0x65, 0x65, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, 0x54, 0x72, 0x61, - 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x49, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, - 0x73, 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x54, 0x72, 0x61, - 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x49, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, - 0x73, 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x73, 0x20, 0x61, 0x20, 0x74, 0x72, - 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x69, 0x6E, 0x66, 0x6F, 0x72, 0x6D, - 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, - 0x63, 0x68, 0x65, 0x6D, 0x61, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3A, 0x20, 0x22, 0x23, 0x2F, 0x64, 0x65, 0x66, - 0x69, 0x6E, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6F, 0x6E, 0x49, 0x44, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, 0x54, 0x72, 0x61, 0x6E, - 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x50, 0x61, 0x72, 0x61, 0x6D, 0x73, 0x52, 0x65, 0x73, - 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, - 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x50, 0x61, 0x72, 0x61, 0x6D, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, - 0x6E, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6D, 0x65, 0x74, 0x65, 0x72, - 0x73, 0x20, 0x66, 0x6F, 0x72, 0x5C, 0x6E, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, - 0x69, 0x6E, 0x67, 0x20, 0x61, 0x20, 0x6E, 0x65, 0x77, 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x2E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, - 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3A, 0x20, 0x22, 0x23, 0x2F, 0x64, 0x65, - 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x50, 0x61, 0x72, 0x61, 0x6D, 0x73, 0x22, 0x0A, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x22, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x52, 0x65, 0x73, 0x70, + 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6F, 0x6E, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6F, 0x6E, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x22, 0x3A, 0x20, 0x7B, + 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6F, 0x6E, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x74, + 0x61, 0x69, 0x6E, 0x73, 0x20, 0x61, 0x20, 0x6C, 0x69, 0x73, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x74, + 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x22, 0x2C, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x22, 0x3A, 0x20, 0x7B, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3A, 0x20, + 0x22, 0x23, 0x2F, 0x64, 0x65, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x54, + 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x4C, 0x69, 0x73, 0x74, 0x22, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x22, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, - 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x54, - 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, - 0x73, 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x73, 0x20, 0x61, 0x20, 0x74, 0x72, - 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x69, 0x6E, 0x66, 0x6F, 0x72, 0x6D, - 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, - 0x63, 0x68, 0x65, 0x6D, 0x61, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3A, 0x20, 0x22, 0x23, 0x2F, 0x64, 0x65, 0x66, - 0x69, 0x6E, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x22, 0x3A, - 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, - 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x20, 0x63, 0x6F, - 0x6E, 0x74, 0x61, 0x69, 0x6E, 0x73, 0x20, 0x61, 0x20, 0x6C, 0x69, 0x73, 0x74, 0x20, 0x6F, 0x66, - 0x20, 0x74, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x22, 0x2C, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x22, 0x3A, 0x20, - 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, - 0x3A, 0x20, 0x22, 0x23, 0x2F, 0x64, 0x65, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, - 0x2F, 0x54, 0x72, 0x61, 0x6E, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x4C, 0x69, 0x73, 0x74, - 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x2C, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x22, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, - 0x22, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, - 0x65, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, - 0x65, 0x20, 0x74, 0x6F, 0x20, 0x27, 0x47, 0x45, 0x54, 0x20, 0x2F, 0x76, 0x65, 0x72, 0x73, 0x69, - 0x6F, 0x6E, 0x73, 0x27, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x63, - 0x68, 0x65, 0x6D, 0x61, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x24, 0x72, 0x65, 0x66, 0x22, 0x3A, 0x20, 0x22, 0x23, 0x2F, 0x64, 0x65, 0x66, 0x69, - 0x6E, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x22, - 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, - 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x22, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, - 0x65, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x22, 0x61, 0x70, 0x69, 0x5F, 0x6B, 0x65, 0x79, 0x22, 0x3A, 0x20, 0x7B, 0x0A, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, - 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x47, 0x65, 0x6E, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x20, - 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6D, 0x65, 0x74, 0x65, 0x72, - 0x2E, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x74, 0x6F, 0x6B, 0x65, 0x6E, 0x20, 0x63, 0x61, 0x6E, - 0x20, 0x62, 0x65, 0x20, 0x67, 0x65, 0x6E, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x20, 0x75, 0x73, - 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x6F, 0x61, 0x6C, 0x20, 0x63, 0x6F, 0x6D, - 0x6D, 0x61, 0x6E, 0x64, 0x20, 0x6C, 0x69, 0x6E, 0x65, 0x20, 0x74, 0x6F, 0x6F, 0x6C, 0x2E, 0x20, - 0x45, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x20, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x20, 0x3D, 0x27, - 0x62, 0x37, 0x65, 0x33, 0x38, 0x34, 0x64, 0x30, 0x33, 0x31, 0x37, 0x62, 0x38, 0x30, 0x35, 0x30, - 0x63, 0x65, 0x34, 0x35, 0x39, 0x30, 0x30, 0x61, 0x39, 0x34, 0x61, 0x31, 0x39, 0x33, 0x31, 0x65, - 0x32, 0x38, 0x35, 0x34, 0x30, 0x65, 0x31, 0x66, 0x36, 0x39, 0x62, 0x32, 0x64, 0x32, 0x34, 0x32, - 0x62, 0x34, 0x32, 0x34, 0x36, 0x35, 0x39, 0x63, 0x33, 0x34, 0x31, 0x62, 0x34, 0x36, 0x39, 0x37, - 0x27, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, - 0x3A, 0x20, 0x22, 0x61, 0x70, 0x69, 0x4B, 0x65, 0x79, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x22, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x58, 0x2D, 0x41, 0x6C, 0x67, - 0x6F, 0x2D, 0x41, 0x50, 0x49, 0x2D, 0x54, 0x6F, 0x6B, 0x65, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x22, 0x69, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x68, 0x65, 0x61, 0x64, 0x65, - 0x72, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x65, 0x78, 0x61, - 0x6D, 0x70, 0x6C, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x62, 0x37, 0x65, 0x33, 0x38, 0x34, 0x64, 0x30, - 0x33, 0x31, 0x37, 0x62, 0x38, 0x30, 0x35, 0x30, 0x63, 0x65, 0x34, 0x35, 0x39, 0x30, 0x30, 0x61, - 0x39, 0x34, 0x61, 0x31, 0x39, 0x33, 0x31, 0x65, 0x32, 0x38, 0x35, 0x34, 0x30, 0x65, 0x31, 0x66, - 0x36, 0x39, 0x62, 0x32, 0x64, 0x32, 0x34, 0x32, 0x62, 0x34, 0x32, 0x34, 0x36, 0x35, 0x39, 0x63, - 0x33, 0x34, 0x31, 0x62, 0x34, 0x36, 0x39, 0x37, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, - 0x20, 0x20, 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x22, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, - 0x22, 0x3A, 0x20, 0x5B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x22, 0x61, 0x70, 0x69, 0x5F, 0x6B, 0x65, 0x79, 0x22, 0x3A, 0x20, 0x5B, 0x5D, 0x0A, 0x20, - 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x5D, 0x0A, 0x7D, + 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x20, + 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x20, + 0x74, 0x6F, 0x20, 0x27, 0x47, 0x45, 0x54, 0x20, 0x2F, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, + 0x73, 0x27, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x73, 0x63, 0x68, 0x65, + 0x6D, 0x61, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x24, 0x72, 0x65, 0x66, 0x22, 0x3A, 0x20, 0x22, 0x23, 0x2F, 0x64, 0x65, 0x66, 0x69, 0x6E, 0x69, + 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2F, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x22, 0x0A, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x7D, + 0x2C, 0x0A, 0x20, 0x20, 0x22, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x65, 0x66, + 0x69, 0x6E, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x22, 0x61, 0x70, 0x69, 0x5F, 0x6B, 0x65, 0x79, 0x22, 0x3A, 0x20, 0x7B, 0x0A, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x22, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6F, 0x6E, + 0x22, 0x3A, 0x20, 0x22, 0x47, 0x65, 0x6E, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x20, 0x68, 0x65, + 0x61, 0x64, 0x65, 0x72, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6D, 0x65, 0x74, 0x65, 0x72, 0x2E, 0x20, + 0x54, 0x68, 0x69, 0x73, 0x20, 0x74, 0x6F, 0x6B, 0x65, 0x6E, 0x20, 0x63, 0x61, 0x6E, 0x20, 0x62, + 0x65, 0x20, 0x67, 0x65, 0x6E, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x20, 0x75, 0x73, 0x69, 0x6E, + 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x6F, 0x61, 0x6C, 0x20, 0x63, 0x6F, 0x6D, 0x6D, 0x61, + 0x6E, 0x64, 0x20, 0x6C, 0x69, 0x6E, 0x65, 0x20, 0x74, 0x6F, 0x6F, 0x6C, 0x2E, 0x20, 0x45, 0x78, + 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x20, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x20, 0x3D, 0x27, 0x62, 0x37, + 0x65, 0x33, 0x38, 0x34, 0x64, 0x30, 0x33, 0x31, 0x37, 0x62, 0x38, 0x30, 0x35, 0x30, 0x63, 0x65, + 0x34, 0x35, 0x39, 0x30, 0x30, 0x61, 0x39, 0x34, 0x61, 0x31, 0x39, 0x33, 0x31, 0x65, 0x32, 0x38, + 0x35, 0x34, 0x30, 0x65, 0x31, 0x66, 0x36, 0x39, 0x62, 0x32, 0x64, 0x32, 0x34, 0x32, 0x62, 0x34, + 0x32, 0x34, 0x36, 0x35, 0x39, 0x63, 0x33, 0x34, 0x31, 0x62, 0x34, 0x36, 0x39, 0x37, 0x27, 0x22, + 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3A, 0x20, + 0x22, 0x61, 0x70, 0x69, 0x4B, 0x65, 0x79, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x22, 0x6E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x58, 0x2D, 0x41, 0x6C, 0x67, 0x6F, 0x2D, + 0x41, 0x50, 0x49, 0x2D, 0x54, 0x6F, 0x6B, 0x65, 0x6E, 0x22, 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x22, 0x69, 0x6E, 0x22, 0x3A, 0x20, 0x22, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x22, + 0x2C, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x78, 0x2D, 0x65, 0x78, 0x61, 0x6D, 0x70, + 0x6C, 0x65, 0x22, 0x3A, 0x20, 0x22, 0x62, 0x37, 0x65, 0x33, 0x38, 0x34, 0x64, 0x30, 0x33, 0x31, + 0x37, 0x62, 0x38, 0x30, 0x35, 0x30, 0x63, 0x65, 0x34, 0x35, 0x39, 0x30, 0x30, 0x61, 0x39, 0x34, + 0x61, 0x31, 0x39, 0x33, 0x31, 0x65, 0x32, 0x38, 0x35, 0x34, 0x30, 0x65, 0x31, 0x66, 0x36, 0x39, + 0x62, 0x32, 0x64, 0x32, 0x34, 0x32, 0x62, 0x34, 0x32, 0x34, 0x36, 0x35, 0x39, 0x63, 0x33, 0x34, + 0x31, 0x62, 0x34, 0x36, 0x39, 0x37, 0x22, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0A, 0x20, 0x20, + 0x7D, 0x2C, 0x0A, 0x20, 0x20, 0x22, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x22, 0x3A, + 0x20, 0x5B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7B, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, + 0x61, 0x70, 0x69, 0x5F, 0x6B, 0x65, 0x79, 0x22, 0x3A, 0x20, 0x5B, 0x5D, 0x0A, 0x20, 0x20, 0x20, + 0x20, 0x7D, 0x0A, 0x20, 0x20, 0x5D, 0x0A, 0x7D, }) } diff --git a/daemon/algod/api/server/v1/handlers/handlers.go b/daemon/algod/api/server/v1/handlers/handlers.go index abecbb5e91..c1f08ffd22 100644 --- a/daemon/algod/api/server/v1/handlers/handlers.go +++ b/daemon/algod/api/server/v1/handlers/handlers.go @@ -487,7 +487,7 @@ func blockEncode(b bookkeeping.Block, c agreement.Certificate) (v1.Block, error) Seed: crypto.Digest(b.Seed()).String(), Proposer: c.Proposal.OriginalProposer.String(), Round: uint64(b.Round()), - TransactionsRoot: b.TxnRoot.String(), + TransactionsRoot: b.TxnCommitments.NativeSha512_256Commitment.String(), // No need to support SHA256 in API V1 RewardsRate: b.RewardsRate, RewardsLevel: b.RewardsLevel, RewardsResidue: b.RewardsResidue, diff --git a/daemon/algod/api/server/v2/dryrun.go b/daemon/algod/api/server/v2/dryrun.go index 38f902ed37..d3b85de39a 100644 --- a/daemon/algod/api/server/v2/dryrun.go +++ b/daemon/algod/api/server/v2/dryrun.go @@ -507,6 +507,9 @@ func doDryrunRequest(dr *DryrunRequest, response *generated.DryrunResponse) { messages[0] = "ApprovalProgram" } pass, delta, err := ba.StatefulEval(ti, ep, appIdx, program) + if !pass { + delta = ep.TxnGroup[ti].EvalDelta + } result.Disassembly = debug.lines result.AppCallTrace = &debug.history result.GlobalDelta = StateDeltaToStateDelta(delta.GlobalDelta) @@ -538,8 +541,17 @@ func doDryrunRequest(dr *DryrunRequest, response *generated.DryrunResponse) { err = fmt.Errorf("cost budget exceeded: budget is %d but program cost was %d", allowedBudget-cumulativeCost, cost) } } - cost64 := uint64(cost) - result.Cost = &cost64 + // The cost is broken up into two fields: budgetAdded and budgetConsumed. + // This is necessary because the fields can only be represented as unsigned + // integers, so a negative cost would underflow. The two fields also provide + // more information, which can be useful for testing purposes. + // cost = budgetConsumed - budgetAdded + netCost := uint64(cost) + budgetAdded := uint64(proto.MaxAppProgramCost * numInnerTxns(delta)) + budgetConsumed := uint64(cost) + budgetAdded + result.Cost = &netCost + result.BudgetAdded = &budgetAdded + result.BudgetConsumed = &budgetConsumed maxCurrentBudget = pooledAppBudget cumulativeCost += cost @@ -621,3 +633,13 @@ func MergeAppParams(base *basics.AppParams, update *basics.AppParams) { base.GlobalStateSchema = update.GlobalStateSchema } } + +// count all inner transactions contained within the eval delta +func numInnerTxns(delta transactions.EvalDelta) (cnt int) { + cnt = len(delta.InnerTxns) + for _, itxn := range delta.InnerTxns { + cnt += numInnerTxns(itxn.EvalDelta) + } + + return +} diff --git a/daemon/algod/api/server/v2/dryrun_test.go b/daemon/algod/api/server/v2/dryrun_test.go index 287e47d19d..cfa87cb986 100644 --- a/daemon/algod/api/server/v2/dryrun_test.go +++ b/daemon/algod/api/server/v2/dryrun_test.go @@ -20,6 +20,7 @@ import ( "bytes" "encoding/base64" "encoding/json" + "fmt" "strconv" "strings" "testing" @@ -374,7 +375,7 @@ func checkLogicSigPass(t *testing.T, response *generated.DryrunResponse) { } } -func checkAppCallPass(t *testing.T, response *generated.DryrunResponse) { +func checkAppCallResponse(t *testing.T, response *generated.DryrunResponse, msg string) { if len(response.Txns) < 1 { t.Error("no response txns") } else if len(response.Txns) == 0 { @@ -387,12 +388,20 @@ func checkAppCallPass(t *testing.T, response *generated.DryrunResponse) { if response.Txns[idx].AppCallMessages != nil { messages := *response.Txns[idx].AppCallMessages assert.GreaterOrEqual(t, len(messages), 1) - assert.Equal(t, "PASS", messages[len(messages)-1]) + assert.Equal(t, msg, messages[len(messages)-1]) } } } } +func checkAppCallPass(t *testing.T, response *generated.DryrunResponse) { + checkAppCallResponse(t, response, "PASS") +} + +func checkAppCallReject(t *testing.T, response *generated.DryrunResponse) { + checkAppCallResponse(t, response, "REJECT") +} + type expectedSlotType struct { slot int tt basics.TealType @@ -1251,18 +1260,20 @@ func TestDryrunCost(t *testing.T) { msg string numHashes int }{ - {"REJECT", 12}, - {"PASS", 5}, + {"REJECT", 22}, + {"PASS", 16}, } for _, test := range tests { t.Run(test.msg, func(t *testing.T) { - costs := make([]uint64, 2) + expectedCosts := make([]int64, 3) + expectedBudgetAdded := make([]uint64, 3) ops, err := logic.AssembleString("#pragma version 5\nbyte 0x41\n" + strings.Repeat("keccak256\n", test.numHashes) + "pop\nint 1\n") require.NoError(t, err) - approval := ops.Program - costs[0] = 3 + uint64(test.numHashes)*130 + app1 := ops.Program + expectedCosts[0] = 3 + int64(test.numHashes)*130 + expectedBudgetAdded[0] = 0 ops, err = logic.AssembleString("int 1") require.NoError(t, err) @@ -1270,8 +1281,26 @@ func TestDryrunCost(t *testing.T) { ops, err = logic.AssembleString("#pragma version 5 \nint 1 \nint 2 \npop") require.NoError(t, err) - approv := ops.Program - costs[1] = 3 + app2 := ops.Program + expectedCosts[1] = 3 + expectedBudgetAdded[1] = 0 + + ops, err = logic.AssembleString(`#pragma version 6 +itxn_begin +int appl +itxn_field TypeEnum +int DeleteApplication +itxn_field OnCompletion +byte 0x068101 // #pragma version 6; int 1; +itxn_field ApprovalProgram +byte 0x068101 // #pragma version 6; int 1; +itxn_field ClearStateProgram +itxn_submit +int 1`) + require.NoError(t, err) + app3 := ops.Program + expectedCosts[2] = -687 + expectedBudgetAdded[2] = 700 var appIdx basics.AppIndex = 1 creator := randomAddress() @@ -1298,13 +1327,23 @@ func TestDryrunCost(t *testing.T) { }, }, }, + { + Txn: transactions.Transaction{ + Header: transactions.Header{Sender: sender}, + Type: protocol.ApplicationCallTx, + ApplicationCallTxnFields: transactions.ApplicationCallTxnFields{ + ApplicationID: appIdx + 2, + OnCompletion: transactions.OptInOC, + }, + }, + }, }, Apps: []generated.Application{ { Id: uint64(appIdx), Params: generated.ApplicationParams{ Creator: creator.String(), - ApprovalProgram: approval, + ApprovalProgram: app1, ClearStateProgram: clst, LocalStateSchema: &generated.ApplicationStateSchema{NumByteSlice: 1}, }, @@ -1313,7 +1352,16 @@ func TestDryrunCost(t *testing.T) { Id: uint64(appIdx + 1), Params: generated.ApplicationParams{ Creator: creator.String(), - ApprovalProgram: approv, + ApprovalProgram: app2, + ClearStateProgram: clst, + LocalStateSchema: &generated.ApplicationStateSchema{NumByteSlice: 1}, + }, + }, + { + Id: uint64(appIdx + 2), + Params: generated.ApplicationParams{ + Creator: creator.String(), + ApprovalProgram: app3, ClearStateProgram: clst, LocalStateSchema: &generated.ApplicationStateSchema{NumByteSlice: 1}, }, @@ -1331,13 +1379,15 @@ func TestDryrunCost(t *testing.T) { var response generated.DryrunResponse doDryrunRequest(&dr, &response) require.Empty(t, response.Error) - require.Equal(t, 2, len(response.Txns)) + require.Equal(t, 3, len(response.Txns)) for i, txn := range response.Txns { messages := *txn.AppCallMessages require.GreaterOrEqual(t, len(messages), 1) - require.NotNil(t, *txn.Cost) - require.Equal(t, costs[i], *txn.Cost) + cost := int64(*txn.BudgetConsumed) - int64(*txn.BudgetAdded) + require.NotNil(t, cost) + require.Equal(t, expectedCosts[i], cost) + require.Equal(t, expectedBudgetAdded[i], *txn.BudgetAdded) statusMatches := false costExceedFound := false for _, msg := range messages { @@ -1634,3 +1684,124 @@ int 1`) logResponse(t, &response) } } + +func checkEvalDelta(t *testing.T, + response generated.DryrunResponse, + expectedGlobalDelta generated.StateDelta, + expectedLocalDelta generated.AccountStateDelta, +) { + for _, rt := range response.Txns { + if rt.GlobalDelta != nil && len(*rt.GlobalDelta) > 0 { + assert.Equal(t, expectedGlobalDelta, *rt.GlobalDelta) + } else { + assert.Nil(t, expectedGlobalDelta) + } + + if rt.LocalDeltas != nil { + for _, ld := range *rt.LocalDeltas { + assert.Equal(t, expectedLocalDelta.Address, ld.Address) + assert.Equal(t, expectedLocalDelta.Delta, ld.Delta) + } + } else { + assert.Nil(t, expectedLocalDelta) + } + } +} + +func TestDryrunCheckEvalDeltasReturned(t *testing.T) { + partitiontest.PartitionTest(t) + t.Parallel() + + var dr DryrunRequest + var response generated.DryrunResponse + + // Expected responses. + expectedByte := b64("val") + expectedUint := uint64(1) + expectedGlobalDelta := generated.StateDelta{ + { + Key: b64("key"), + Value: generated.EvalDelta{ + Action: uint64(basics.SetBytesAction), + Bytes: &expectedByte, + }, + }, + } + expectedLocalDelta := generated.AccountStateDelta{ + Address: basics.Address{}.String(), + Delta: generated.StateDelta{ + { + Key: b64("key"), + Value: generated.EvalDelta{ + Action: uint64(basics.SetUintAction), + Uint: &expectedUint, + }, + }, + }, + } + + // Test that a PASS and REJECT dryrun both return the dryrun evaldelta. + for i := range []int{0, 1} { + ops, _ := logic.AssembleString(fmt.Sprintf(` +#pragma version 6 +txna ApplicationArgs 0 +txna ApplicationArgs 1 +app_global_put +int 0 +txna ApplicationArgs 0 +int %d +app_local_put +int %d`, expectedUint, i)) + dr.ProtocolVersion = string(dryrunProtoVersion) + + dr.Txns = []transactions.SignedTxn{ + { + Txn: transactions.Transaction{ + Type: protocol.ApplicationCallTx, + ApplicationCallTxnFields: transactions.ApplicationCallTxnFields{ + ApplicationID: 1, + ApplicationArgs: [][]byte{ + []byte("key"), + []byte("val"), + }, + }, + }, + }, + } + dr.Apps = []generated.Application{ + { + Id: 1, + Params: generated.ApplicationParams{ + ApprovalProgram: ops.Program, + GlobalStateSchema: &generated.ApplicationStateSchema{ + NumByteSlice: 1, + NumUint: 1, + }, + LocalStateSchema: &generated.ApplicationStateSchema{ + NumByteSlice: 1, + NumUint: 1, + }, + }, + }, + } + dr.Accounts = []generated.Account{ + { + Status: "Online", + Address: basics.Address{}.String(), + AppsLocalState: &[]generated.ApplicationLocalState{{Id: 1}}, + }, + } + + doDryrunRequest(&dr, &response) + if i == 0 { + checkAppCallReject(t, &response) + } else { + checkAppCallPass(t, &response) + } + checkEvalDelta(t, response, expectedGlobalDelta, expectedLocalDelta) + if t.Failed() { + logResponse(t, &response) + } + } + +} diff --git a/daemon/algod/api/server/v2/errors.go b/daemon/algod/api/server/v2/errors.go index 6223abad9a..9966728dc8 100644 --- a/daemon/algod/api/server/v2/errors.go +++ b/daemon/algod/api/server/v2/errors.go @@ -31,9 +31,11 @@ var ( errFailedToParseTransaction = "failed to parse transaction" errFailedToParseBlock = "failed to parse block" errFailedToParseCert = "failed to parse cert" + errFailedToParseSourcemap = "failed to parse sourcemap" errFailedToEncodeResponse = "failed to encode response" errInternalFailure = "internal failure" errNoTxnSpecified = "no transaction ID was specified" + errInvalidHashType = "invalid hash type" errTransactionNotFound = "could not find the transaction in the transaction pool or in the last 1000 confirmed rounds" errServiceShuttingDown = "operation aborted as server is shutting down" errRequestedRoundInUnsupportedRound = "requested round would reach only after the protocol upgrade which isn't supported" diff --git a/daemon/algod/api/server/v2/generated/private/routes.go b/daemon/algod/api/server/v2/generated/private/routes.go index e37b754895..72eb4a7b19 100644 --- a/daemon/algod/api/server/v2/generated/private/routes.go +++ b/daemon/algod/api/server/v2/generated/private/routes.go @@ -311,153 +311,155 @@ func RegisterHandlers(router interface { // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", } // GetSwagger returns the Swagger specification corresponding to the generated code diff --git a/daemon/algod/api/server/v2/generated/private/types.go b/daemon/algod/api/server/v2/generated/private/types.go index ff7643fdf7..17485641d5 100644 --- a/daemon/algod/api/server/v2/generated/private/types.go +++ b/daemon/algod/api/server/v2/generated/private/types.go @@ -316,7 +316,13 @@ type DryrunTxnResult struct { AppCallMessages *[]string `json:"app-call-messages,omitempty"` AppCallTrace *[]DryrunState `json:"app-call-trace,omitempty"` - // Execution cost of app call transaction + // Budget added during execution of app call transaction. + BudgetAdded *uint64 `json:"budget-added,omitempty"` + + // Budget consumed during execution of app call transaction. + BudgetConsumed *uint64 `json:"budget-consumed,omitempty"` + + // Net cost of app execution. Field is DEPRECATED and is subject for removal. Instead, use `budget-added` and `budget-consumed. Cost *uint64 `json:"cost,omitempty"` // Disassembled program line by line. @@ -610,6 +616,9 @@ type CompileResponse struct { // base64 encoded program bytes Result string `json:"result"` + + // JSON of the source map + Sourcemap *map[string]interface{} `json:"sourcemap,omitempty"` } // DisassembleResponse defines model for DisassembleResponse. @@ -711,8 +720,8 @@ type PostTransactionsResponse struct { type ProofResponse struct { // The type of hash function used to create the proof, must be one of: - // * sumhash // * sha512_256 + // * sha256 Hashtype string `json:"hashtype"` // Index of the transaction in the block's payset. diff --git a/daemon/algod/api/server/v2/generated/routes.go b/daemon/algod/api/server/v2/generated/routes.go index b819ded7db..fa62e543f5 100644 --- a/daemon/algod/api/server/v2/generated/routes.go +++ b/daemon/algod/api/server/v2/generated/routes.go @@ -52,7 +52,7 @@ type ServerInterface interface { WaitForBlock(ctx echo.Context, round uint64) error // Compile TEAL source code to binary, produce its hash // (POST /v2/teal/compile) - TealCompile(ctx echo.Context) error + TealCompile(ctx echo.Context, params TealCompileParams) error // Disassemble program bytes into the TEAL source code. // (POST /v2/teal/disassemble) TealDisassemble(ctx echo.Context) error @@ -395,8 +395,9 @@ func (w *ServerInterfaceWrapper) GetBlock(ctx echo.Context) error { func (w *ServerInterfaceWrapper) GetProof(ctx echo.Context) error { validQueryParams := map[string]bool{ - "pretty": true, - "format": true, + "pretty": true, + "hashtype": true, + "format": true, } // Check for unknown query parameters. @@ -427,6 +428,16 @@ func (w *ServerInterfaceWrapper) GetProof(ctx echo.Context) error { // Parameter object where we will unmarshal all parameters from the context var params GetProofParams + // ------------- Optional query parameter "hashtype" ------------- + if paramValue := ctx.QueryParam("hashtype"); paramValue != "" { + + } + + err = runtime.BindQueryParameter("form", true, false, "hashtype", ctx.QueryParams(), ¶ms.Hashtype) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter hashtype: %s", err)) + } + // ------------- Optional query parameter "format" ------------- if paramValue := ctx.QueryParam("format"); paramValue != "" { @@ -522,7 +533,8 @@ func (w *ServerInterfaceWrapper) WaitForBlock(ctx echo.Context) error { func (w *ServerInterfaceWrapper) TealCompile(ctx echo.Context) error { validQueryParams := map[string]bool{ - "pretty": true, + "pretty": true, + "sourcemap": true, } // Check for unknown query parameters. @@ -536,8 +548,20 @@ func (w *ServerInterfaceWrapper) TealCompile(ctx echo.Context) error { ctx.Set("api_key.Scopes", []string{""}) + // Parameter object where we will unmarshal all parameters from the context + var params TealCompileParams + // ------------- Optional query parameter "sourcemap" ------------- + if paramValue := ctx.QueryParam("sourcemap"); paramValue != "" { + + } + + err = runtime.BindQueryParameter("form", true, false, "sourcemap", ctx.QueryParams(), ¶ms.Sourcemap) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter sourcemap: %s", err)) + } + // Invoke the callback with all the unmarshalled arguments - err = w.Handler.TealCompile(ctx) + err = w.Handler.TealCompile(ctx, params) return err } @@ -764,203 +788,206 @@ func RegisterHandlers(router interface { // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", - "rSpBuRYBAA==", + "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", } // GetSwagger returns the Swagger specification corresponding to the generated code diff --git a/daemon/algod/api/server/v2/generated/types.go b/daemon/algod/api/server/v2/generated/types.go index 50bb0a3edd..53983915d6 100644 --- a/daemon/algod/api/server/v2/generated/types.go +++ b/daemon/algod/api/server/v2/generated/types.go @@ -316,7 +316,13 @@ type DryrunTxnResult struct { AppCallMessages *[]string `json:"app-call-messages,omitempty"` AppCallTrace *[]DryrunState `json:"app-call-trace,omitempty"` - // Execution cost of app call transaction + // Budget added during execution of app call transaction. + BudgetAdded *uint64 `json:"budget-added,omitempty"` + + // Budget consumed during execution of app call transaction. + BudgetConsumed *uint64 `json:"budget-consumed,omitempty"` + + // Net cost of app execution. Field is DEPRECATED and is subject for removal. Instead, use `budget-added` and `budget-consumed. Cost *uint64 `json:"cost,omitempty"` // Disassembled program line by line. @@ -610,6 +616,9 @@ type CompileResponse struct { // base64 encoded program bytes Result string `json:"result"` + + // JSON of the source map + Sourcemap *map[string]interface{} `json:"sourcemap,omitempty"` } // DisassembleResponse defines model for DisassembleResponse. @@ -711,8 +720,8 @@ type PostTransactionsResponse struct { type ProofResponse struct { // The type of hash function used to create the proof, must be one of: - // * sumhash // * sha512_256 + // * sha256 Hashtype string `json:"hashtype"` // Index of the transaction in the block's payset. @@ -815,10 +824,22 @@ type GetBlockParams struct { // GetProofParams defines parameters for GetProof. type GetProofParams struct { + // The type of hash function used to create the proof, must be one of: + // * sha512_256 + // * sha256 + Hashtype *string `json:"hashtype,omitempty"` + // Configures whether the response object is JSON or MessagePack encoded. Format *string `json:"format,omitempty"` } +// TealCompileParams defines parameters for TealCompile. +type TealCompileParams struct { + + // When set to `true`, returns the source map of the program as a JSON. Defaults to `false`. + Sourcemap *bool `json:"sourcemap,omitempty"` +} + // TealDryrunJSONBody defines parameters for TealDryrun. type TealDryrunJSONBody DryrunRequest diff --git a/daemon/algod/api/server/v2/handlers.go b/daemon/algod/api/server/v2/handlers.go index 4098bf0aa6..9e18ca7d25 100644 --- a/daemon/algod/api/server/v2/handlers.go +++ b/daemon/algod/api/server/v2/handlers.go @@ -32,6 +32,7 @@ import ( "github.com/algorand/go-algorand/agreement" "github.com/algorand/go-algorand/config" "github.com/algorand/go-algorand/crypto" + "github.com/algorand/go-algorand/crypto/merklearray" "github.com/algorand/go-algorand/daemon/algod/api/server/v2/generated" "github.com/algorand/go-algorand/daemon/algod/api/server/v2/generated/private" model "github.com/algorand/go-algorand/daemon/algod/api/spec/v2" @@ -574,6 +575,10 @@ func (v2 *Handlers) GetProof(ctx echo.Context, round uint64, txid string, params return badRequest(ctx, err, errNoTxnSpecified, v2.Log) } + if params.Hashtype != nil && *params.Hashtype != "sha512_256" && *params.Hashtype != "sha256" { + return badRequest(ctx, nil, errInvalidHashType, v2.Log) + } + ledger := v2.Node.LedgerForAPI() block, _, err := ledger.BlockCert(basics.Round(round)) if err != nil { @@ -585,35 +590,58 @@ func (v2 *Handlers) GetProof(ctx echo.Context, round uint64, txid string, params return notFound(ctx, err, "protocol does not support Merkle proofs", v2.Log) } + hashtype := "sha512_256" // default hash type for proof + if params.Hashtype != nil { + hashtype = *params.Hashtype + } + if hashtype == "sha256" && !proto.EnableSHA256TxnCommitmentHeader { + return badRequest(ctx, err, "protocol does not support sha256 vector commitment proofs", v2.Log) + } + txns, err := block.DecodePaysetFlat() if err != nil { return internalError(ctx, err, "decoding transactions", v2.Log) } for idx := range txns { - if txns[idx].Txn.ID() == txID { - tree, err := block.TxnMerkleTree() + if txns[idx].ID() != txID { + continue // skip + } + + var tree *merklearray.Tree + var stibhash crypto.Digest + + switch hashtype { + case "sha256": + tree, err = block.TxnMerkleTreeSHA256() if err != nil { - return internalError(ctx, err, "building Merkle tree", v2.Log) + return internalError(ctx, err, "building Vector Commitment (SHA256)", v2.Log) } - - proof, err := tree.ProveSingleLeaf(uint64(idx)) + stibhash = block.Payset[idx].HashSHA256() + case "sha512_256": + tree, err = block.TxnMerkleTree() if err != nil { - return internalError(ctx, err, "generating proof", v2.Log) + return internalError(ctx, err, "building Merkle tree", v2.Log) } + stibhash = block.Payset[idx].Hash() + default: + return badRequest(ctx, err, "unsupported hash type", v2.Log) + } - stibhash := block.Payset[idx].Hash() - - response := generated.ProofResponse{ - Proof: proof.GetConcatenatedProof(), - Stibhash: stibhash[:], - Idx: uint64(idx), - Treedepth: uint64(proof.TreeDepth), - Hashtype: proof.HashFactory.HashType.String(), - } + proof, err := tree.ProveSingleLeaf(uint64(idx)) + if err != nil { + return internalError(ctx, err, "generating proof", v2.Log) + } - return ctx.JSON(http.StatusOK, response) + response := generated.ProofResponse{ + Proof: proof.GetConcatenatedProof(), + Stibhash: stibhash[:], + Idx: uint64(idx), + Treedepth: uint64(proof.TreeDepth), + Hashtype: hashtype, } + + return ctx.JSON(http.StatusOK, response) } err = errors.New(errTransactionNotFound) @@ -1130,16 +1158,29 @@ func (v2 *Handlers) AbortCatchup(ctx echo.Context, catchpoint string) error { return v2.abortCatchup(ctx, catchpoint) } +// CompileResponseWithSourceMap overrides the sourcemap field in +// the CompileResponse for JSON marshalling. +type CompileResponseWithSourceMap struct { + generated.CompileResponse + Sourcemap *logic.SourceMap `json:"sourcemap,omitempty"` +} + // TealCompile compiles TEAL code to binary, return both binary and hash // (POST /v2/teal/compile) -func (v2 *Handlers) TealCompile(ctx echo.Context) error { - // return early if teal compile is not allowed in node config +func (v2 *Handlers) TealCompile(ctx echo.Context, params generated.TealCompileParams) (err error) { + // Return early if teal compile is not allowed in node config. if !v2.Node.Config().EnableDeveloperAPI { return ctx.String(http.StatusNotFound, "/teal/compile was not enabled in the configuration file by setting the EnableDeveloperAPI to true") } + if params.Sourcemap == nil { + // Backwards compatibility: set sourcemap flag to default false value. + defaultValue := false + params.Sourcemap = &defaultValue + } + buf := new(bytes.Buffer) ctx.Request().Body = http.MaxBytesReader(nil, ctx.Request().Body, maxTealSourceBytes) - _, err := buf.ReadFrom(ctx.Request().Body) + _, err = buf.ReadFrom(ctx.Request().Body) if err != nil { return badRequest(ctx, err, err.Error(), v2.Log) } @@ -1152,9 +1193,20 @@ func (v2 *Handlers) TealCompile(ctx echo.Context) error { } pd := logic.HashProgram(ops.Program) addr := basics.Address(pd) - response := generated.CompileResponse{ - Hash: addr.String(), - Result: base64.StdEncoding.EncodeToString(ops.Program), + + // If source map flag is enabled, then return the map. + var sourcemap *logic.SourceMap + if *params.Sourcemap { + rawmap := logic.GetSourceMap([]string{}, ops.OffsetToLine) + sourcemap = &rawmap + } + + response := CompileResponseWithSourceMap{ + generated.CompileResponse{ + Hash: addr.String(), + Result: base64.StdEncoding.EncodeToString(ops.Program), + }, + sourcemap, } return ctx.JSON(http.StatusOK, response) } diff --git a/daemon/algod/api/server/v2/test/handlers_test.go b/daemon/algod/api/server/v2/test/handlers_test.go index e222a5f77e..af970f4b14 100644 --- a/daemon/algod/api/server/v2/test/handlers_test.go +++ b/daemon/algod/api/server/v2/test/handlers_test.go @@ -20,16 +20,19 @@ import ( "bytes" "encoding/json" "errors" + "fmt" "io" "net/http" "net/http/httptest" "testing" "github.com/labstack/echo/v4" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/algorand/go-algorand/agreement" "github.com/algorand/go-algorand/crypto" + "github.com/algorand/go-algorand/crypto/merklearray" "github.com/algorand/go-algorand/crypto/merklesignature" v2 "github.com/algorand/go-algorand/daemon/algod/api/server/v2" "github.com/algorand/go-algorand/daemon/algod/api/server/v2/generated" @@ -117,12 +120,8 @@ func TestGetBlock(t *testing.T) { getBlockTest(t, 0, "bad format", 400) } -func TestGetBlockJsonEncoding(t *testing.T) { - partitiontest.PartitionTest(t) - t.Parallel() - +func addBlockHelper(t *testing.T) (v2.Handlers, echo.Context, *httptest.ResponseRecorder, transactions.SignedTxn, func()) { handler, c, rec, _, _, releasefunc := setupTestForMethodGet(t) - defer releasefunc() l := handler.Node.LedgerForAPI() @@ -193,24 +192,34 @@ func TestGetBlockJsonEncoding(t *testing.T) { txib, err := blk.EncodeSignedTxn(stx, ad) blk.Payset = append(blk.Payset, txib) blk.BlockHeader.TxnCounter++ - blk.TxnRoot, err = blk.PaysetCommit() + blk.TxnCommitments, err = blk.PaysetCommit() require.NoError(t, err) err = l.(*data.Ledger).AddBlock(blk, agreement.Certificate{}) require.NoError(t, err) + return handler, c, rec, stx, releasefunc +} + +func TestGetBlockJsonEncoding(t *testing.T) { + partitiontest.PartitionTest(t) + t.Parallel() + + handler, c, rec, _, releasefunc := addBlockHelper(t) + defer releasefunc() + // fetch the block and ensure it can be properly decoded with the standard JSON decoder format := "json" - err = handler.GetBlock(c, 1, generatedV2.GetBlockParams{Format: &format}) + err := handler.GetBlock(c, 1, generatedV2.GetBlockParams{Format: &format}) require.NoError(t, err) require.Equal(t, 200, rec.Code) - data := rec.Body.Bytes() + body := rec.Body.Bytes() response := struct { Block bookkeeping.Block `codec:"block"` }{} - err = json.Unmarshal(data, &response) + err = json.Unmarshal(body, &response) require.NoError(t, err) } @@ -514,7 +523,10 @@ func TestAbortCatchup(t *testing.T) { abortCatchupTest(t, badCatchPoint, 400) } -func tealCompileTest(t *testing.T, bytesToUse []byte, expectedCode int, enableDeveloperAPI bool) { +func tealCompileTest(t *testing.T, bytesToUse []byte, expectedCode int, + enableDeveloperAPI bool, params generated.TealCompileParams, + expectedSourcemap *logic.SourceMap, +) (response v2.CompileResponseWithSourceMap) { numAccounts := 1 numTransactions := 1 offlineAccounts := true @@ -532,23 +544,55 @@ func tealCompileTest(t *testing.T, bytesToUse []byte, expectedCode int, enableDe req := httptest.NewRequest(http.MethodPost, "/", bytes.NewReader(bytesToUse)) rec := httptest.NewRecorder() c := e.NewContext(req, rec) - err := handler.TealCompile(c) + err := handler.TealCompile(c, params) require.NoError(t, err) require.Equal(t, expectedCode, rec.Code) + + // Check compiled response. + if rec.Code == 200 { + data := rec.Body.Bytes() + err = protocol.DecodeJSON(data, &response) + require.NoError(t, err, string(data)) + if expectedSourcemap != nil { + require.Equal(t, *expectedSourcemap, *response.Sourcemap) + } else { + require.Nil(t, response.Sourcemap) + } + } + return } func TestTealCompile(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() - tealCompileTest(t, nil, 200, true) // nil program should work - goodProgram := `int 1` + params := generated.TealCompileParams{} + tealCompileTest(t, nil, 200, true, params, nil) // nil program should work + + goodProgram := fmt.Sprintf(`#pragma version %d +int 1 +assert +int 1`, logic.AssemblerMaxVersion) + ops, _ := logic.AssembleString(goodProgram) + expectedSourcemap := logic.GetSourceMap([]string{}, ops.OffsetToLine) goodProgramBytes := []byte(goodProgram) - tealCompileTest(t, goodProgramBytes, 200, true) - tealCompileTest(t, goodProgramBytes, 404, false) + + // Test good program with params + tealCompileTest(t, goodProgramBytes, 200, true, params, nil) + paramValue := true + params = generated.TealCompileParams{Sourcemap: ¶mValue} + tealCompileTest(t, goodProgramBytes, 200, true, params, &expectedSourcemap) + paramValue = false + params = generated.TealCompileParams{Sourcemap: ¶mValue} + tealCompileTest(t, goodProgramBytes, 200, true, params, nil) + + // Test a program without the developer API flag. + tealCompileTest(t, goodProgramBytes, 404, false, params, nil) + + // Test bad program. badProgram := "bad program" badProgramBytes := []byte(badProgram) - tealCompileTest(t, badProgramBytes, 400, true) + tealCompileTest(t, badProgramBytes, 400, true, params, nil) } func tealDisassembleTest(t *testing.T, program []byte, expectedCode int, @@ -599,7 +643,7 @@ func TestTealDisassemble(t *testing.T) { tealDisassembleTest(t, testProgram, 200, "// invalid version\n", true) // Test a valid program. - for ver := 1; ver < logic.AssemblerMaxVersion; ver++ { + for ver := 1; ver <= logic.AssemblerMaxVersion; ver++ { goodProgram := `int 1` ops, _ := logic.AssembleStringWithVersion(goodProgram, uint64(ver)) disassembledProgram, _ := logic.Disassemble(ops.Program) @@ -608,7 +652,7 @@ func TestTealDisassemble(t *testing.T) { // Test a nil program without the developer API flag. tealDisassembleTest(t, testProgram, 404, "", false) - // Test bad program + // Test bad program. badProgram := []byte{1, 99} tealDisassembleTest(t, badProgram, 400, "invalid opcode", true) } @@ -859,3 +903,64 @@ func TestAppendParticipationKeys(t *testing.T) { require.Contains(t, rec.Body.String(), expectedErr.Error()) }) } + +// TxnMerkleElemRaw this struct helps creates a hashable struct from the bytes +type TxnMerkleElemRaw struct { + Txn crypto.Digest // txn id + Stib crypto.Digest // hash value of transactions.SignedTxnInBlock +} + +func txnMerkleToRaw(txid [crypto.DigestSize]byte, stib [crypto.DigestSize]byte) (buf []byte) { + buf = make([]byte, 2*crypto.DigestSize) + copy(buf[:], txid[:]) + copy(buf[crypto.DigestSize:], stib[:]) + return +} + +// ToBeHashed implements the crypto.Hashable interface. +func (tme *TxnMerkleElemRaw) ToBeHashed() (protocol.HashID, []byte) { + return protocol.TxnMerkleLeaf, txnMerkleToRaw(tme.Txn, tme.Stib) +} + +func TestGetProofDefault(t *testing.T) { + partitiontest.PartitionTest(t) + a := assert.New(t) + + handler, c, rec, stx, releasefunc := addBlockHelper(t) + defer releasefunc() + + txid := stx.ID() + err := handler.GetProof(c, 1, txid.String(), generated.GetProofParams{}) + a.NoError(err) + + var resp generatedV2.ProofResponse + err = json.Unmarshal(rec.Body.Bytes(), &resp) + a.NoError(err) + a.Equal("sha512_256", resp.Hashtype) + + l := handler.Node.LedgerForAPI() + blkHdr, err := l.BlockHdr(1) + a.NoError(err) + + // Build merklearray.Proof from ProofResponse + var proof merklearray.Proof + proof.HashFactory = crypto.HashFactory{HashType: crypto.Sha512_256} + proof.TreeDepth = uint8(resp.Treedepth) + a.NotEqual(proof.TreeDepth, 0) + proofconcat := resp.Proof + for len(proofconcat) > 0 { + var d crypto.Digest + copy(d[:], proofconcat) + proof.Path = append(proof.Path, d[:]) + proofconcat = proofconcat[len(d):] + } + + element := TxnMerkleElemRaw{Txn: crypto.Digest(txid)} + copy(element.Stib[:], resp.Stibhash[:]) + elems := make(map[uint64]crypto.Hashable) + elems[0] = &element + + // Verifies that the default proof is using SHA512_256 + err = merklearray.Verify(blkHdr.TxnCommitments.NativeSha512_256Commitment.ToSlice(), elems, &proof) + a.NoError(err) +} diff --git a/daemon/algod/api/spec/v1/model.go b/daemon/algod/api/spec/v1/model.go index 96fc0ee05a..b01db103e4 100644 --- a/daemon/algod/api/spec/v1/model.go +++ b/daemon/algod/api/spec/v1/model.go @@ -913,8 +913,8 @@ type Block struct { // TransactionsRoot authenticates the set of transactions appearing in the block. // More specifically, it's the root of a merkle tree whose leaves are the block's Txids, in lexicographic order. // For the empty block, it's 0. - // Note that the TxnRoot does not authenticate the signatures on the transactions, only the transactions themselves. - // Two blocks with the same transactions but in a different order and with different signatures will have the same TxnRoot. + // Note that the TxnCommitments does not authenticate the signatures on the transactions, only the transactions themselves. + // Two blocks with the same transactions but in a different order and with different signatures will have the same TxnCommitments. // // required: true TransactionsRoot string `json:"txnRoot"` diff --git a/daemon/algod/api/spec/v2/msgp_gen.go b/daemon/algod/api/spec/v2/msgp_gen.go index 48590fd11d..b14d47b792 100644 --- a/daemon/algod/api/spec/v2/msgp_gen.go +++ b/daemon/algod/api/spec/v2/msgp_gen.go @@ -3,8 +3,9 @@ package v2 // Code generated by github.com/algorand/msgp DO NOT EDIT. import ( - "github.com/algorand/go-algorand/data/basics" "github.com/algorand/msgp/msgp" + + "github.com/algorand/go-algorand/data/basics" ) // The following msgp objects are implemented in this file: diff --git a/daemon/algod/api/spec/v2/msgp_gen_test.go b/daemon/algod/api/spec/v2/msgp_gen_test.go index 57bda723cf..2fc11278d5 100644 --- a/daemon/algod/api/spec/v2/msgp_gen_test.go +++ b/daemon/algod/api/spec/v2/msgp_gen_test.go @@ -1,3 +1,4 @@ +//go:build !skip_msgp_testing // +build !skip_msgp_testing package v2 @@ -7,9 +8,10 @@ package v2 import ( "testing" + "github.com/algorand/msgp/msgp" + "github.com/algorand/go-algorand/protocol" "github.com/algorand/go-algorand/test/partitiontest" - "github.com/algorand/msgp/msgp" ) func TestMarshalUnmarshalAccountApplicationModel(t *testing.T) { diff --git a/daemon/algod/api/swagger.json b/daemon/algod/api/swagger.json index 23ff8ec7a6..5a788df54d 100644 --- a/daemon/algod/api/swagger.json +++ b/daemon/algod/api/swagger.json @@ -1356,7 +1356,7 @@ "x-go-name": "Timestamp" }, "txnRoot": { - "description": "TransactionsRoot authenticates the set of transactions appearing in the block.\nMore specifically, it's the root of a merkle tree whose leaves are the block's Txids, in lexicographic order.\nFor the empty block, it's 0.\nNote that the TxnRoot does not authenticate the signatures on the transactions, only the transactions themselves.\nTwo blocks with the same transactions but in a different order and with different signatures will have the same TxnRoot.", + "description": "TransactionsRoot authenticates the set of transactions appearing in the block.\nMore specifically, it's the root of a merkle tree whose leaves are the block's Txids, in lexicographic order.\nFor the empty block, it's 0.\nNote that the TxnCommitments does not authenticate the signatures on the transactions, only the transactions themselves.\nTwo blocks with the same transactions but in a different order and with different signatures will have the same TxnCommitments.", "type": "string", "x-go-name": "TransactionsRoot" }, diff --git a/daemon/algod/server.go b/daemon/algod/server.go index d3b9ff2f57..07e206a816 100644 --- a/daemon/algod/server.go +++ b/daemon/algod/server.go @@ -203,6 +203,10 @@ func (s *Server) Start() { cfg := s.node.Config() + if cfg.EnableRuntimeMetrics { + metrics.DefaultRegistry().Register(metrics.NewRuntimeMetrics()) + } + if cfg.EnableMetricReporting { if err := s.metricCollector.Start(context.Background()); err != nil { // log this error diff --git a/data/account/msgp_gen.go b/data/account/msgp_gen.go index e9c3a521a4..5fa8daa6e5 100644 --- a/data/account/msgp_gen.go +++ b/data/account/msgp_gen.go @@ -3,8 +3,9 @@ package account // Code generated by github.com/algorand/msgp DO NOT EDIT. import ( - "github.com/algorand/go-algorand/crypto/merklesignature" "github.com/algorand/msgp/msgp" + + "github.com/algorand/go-algorand/crypto/merklesignature" ) // The following msgp objects are implemented in this file: diff --git a/data/account/msgp_gen_test.go b/data/account/msgp_gen_test.go index 9bde0e5d83..380e391fc3 100644 --- a/data/account/msgp_gen_test.go +++ b/data/account/msgp_gen_test.go @@ -1,3 +1,4 @@ +//go:build !skip_msgp_testing // +build !skip_msgp_testing package account @@ -7,9 +8,10 @@ package account import ( "testing" + "github.com/algorand/msgp/msgp" + "github.com/algorand/go-algorand/protocol" "github.com/algorand/go-algorand/test/partitiontest" - "github.com/algorand/msgp/msgp" ) func TestMarshalUnmarshalParticipationKeyIdentity(t *testing.T) { diff --git a/data/account/participationRegistry.go b/data/account/participationRegistry.go index 41b4e64a1b..d1c35c2ce3 100644 --- a/data/account/participationRegistry.go +++ b/data/account/participationRegistry.go @@ -250,6 +250,9 @@ type ParticipationRegistry interface { // GetStateProofForRound fetches a record with stateproof secrets for a particular round. GetStateProofForRound(id ParticipationID, round basics.Round) (StateProofRecordForRound, error) + // HasLiveKeys quickly tests to see if there is a valid participation key over some range of rounds + HasLiveKeys(from, to basics.Round) bool + // Register updates the EffectiveFirst and EffectiveLast fields. If there are multiple records for the account // then it is possible for multiple records to be updated. Register(id ParticipationID, on basics.Round) error @@ -726,6 +729,18 @@ func (db *participationDB) GetAll() []ParticipationRecord { return results } +func (db *participationDB) HasLiveKeys(from, to basics.Round) bool { + db.mutex.RLock() + defer db.mutex.RUnlock() + + for _, record := range db.cache { + if record.OverlapsInterval(from, to) { + return true + } + } + return false +} + // GetStateProofForRound returns the state proof data required to sign the compact certificate for this round func (db *participationDB) GetStateProofForRound(id ParticipationID, round basics.Round) (StateProofRecordForRound, error) { partRecord, err := db.GetForRound(id, round) diff --git a/data/accountManager.go b/data/accountManager.go index 2d8efb4095..7cadd071d6 100644 --- a/data/accountManager.go +++ b/data/accountManager.go @@ -92,12 +92,7 @@ func (manager *AccountManager) HasLiveKeys(from, to basics.Round) bool { manager.mu.Lock() defer manager.mu.Unlock() - for _, part := range manager.registry.GetAll() { - if part.OverlapsInterval(from, to) { - return true - } - } - return false + return manager.registry.HasLiveKeys(from, to) } // AddParticipation adds a new account.Participation to be managed. diff --git a/data/basics/msgp_gen.go b/data/basics/msgp_gen.go index f16d67caf6..53bcc659f1 100644 --- a/data/basics/msgp_gen.go +++ b/data/basics/msgp_gen.go @@ -5,9 +5,10 @@ package basics import ( "sort" + "github.com/algorand/msgp/msgp" + "github.com/algorand/go-algorand/config" "github.com/algorand/go-algorand/crypto" - "github.com/algorand/msgp/msgp" ) // The following msgp objects are implemented in this file: diff --git a/data/basics/msgp_gen_test.go b/data/basics/msgp_gen_test.go index 8756c3c4e1..c5e0f3d4a5 100644 --- a/data/basics/msgp_gen_test.go +++ b/data/basics/msgp_gen_test.go @@ -1,3 +1,4 @@ +//go:build !skip_msgp_testing // +build !skip_msgp_testing package basics @@ -7,9 +8,10 @@ package basics import ( "testing" + "github.com/algorand/msgp/msgp" + "github.com/algorand/go-algorand/protocol" "github.com/algorand/go-algorand/test/partitiontest" - "github.com/algorand/msgp/msgp" ) func TestMarshalUnmarshalAccountData(t *testing.T) { diff --git a/data/bookkeeping/block.go b/data/bookkeeping/block.go index 46f17c8ef5..584e0394df 100644 --- a/data/bookkeeping/block.go +++ b/data/bookkeeping/block.go @@ -46,10 +46,8 @@ type ( // Sortition seed Seed committee.Seed `codec:"seed"` - // TxnRoot authenticates the set of transactions appearing in the block. - // The commitment is computed based on the PaysetCommit type specified - // in the block's consensus protocol. - TxnRoot crypto.Digest `codec:"txn"` + // TxnCommitments authenticates the set of transactions appearing in the block. + TxnCommitments // TimeStamp in seconds since epoch TimeStamp int64 `codec:"ts"` @@ -131,6 +129,18 @@ type ( ParticipationUpdates } + // TxnCommitments represents the commitments computed from the transactions in the block. + // It contains multiple commitments based on different algorithms and hash functions, to support different use cases. + TxnCommitments struct { + _struct struct{} `codec:",omitempty,omitemptyarray"` + // Root of transaction merkle tree using SHA512_256 hash function. + // This commitment is computed based on the PaysetCommit type specified in the block's consensus protocol. + NativeSha512_256Commitment crypto.Digest `codec:"txn"` + + // Root of transaction vector commitment merkle tree using SHA256 hash function + Sha256Commitment crypto.Digest `codec:"txn256"` + } + // ParticipationUpdates represents participation account data that // needs to be checked/acted on by the network ParticipationUpdates struct { @@ -496,10 +506,11 @@ func MakeBlock(prev BlockHeader) Block { GenesisHash: prev.GenesisHash, }, } - blk.TxnRoot, err = blk.PaysetCommit() + blk.TxnCommitments, err = blk.PaysetCommit() if err != nil { - logging.Base().Warnf("MakeBlock: computing empty TxnRoot: %v", err) + logging.Base().Warnf("MakeBlock: computing empty TxnCommitments: %v", err) } + // We can't know the entire RewardsState yet, but we can carry over the special addresses. blk.BlockHeader.RewardsState.FeeSink = prev.RewardsState.FeeSink blk.BlockHeader.RewardsState.RewardsPool = prev.RewardsState.RewardsPool @@ -508,13 +519,29 @@ func MakeBlock(prev BlockHeader) Block { // PaysetCommit computes the commitment to the payset, using the appropriate // commitment plan based on the block's protocol. -func (block Block) PaysetCommit() (crypto.Digest, error) { +func (block Block) PaysetCommit() (TxnCommitments, error) { params, ok := config.Consensus[block.CurrentProtocol] if !ok { - return crypto.Digest{}, fmt.Errorf("unsupported protocol %v", block.CurrentProtocol) + return TxnCommitments{}, fmt.Errorf("unsupported protocol %v", block.CurrentProtocol) } - return block.paysetCommit(params.PaysetCommit) + digestSHA512_256, err := block.paysetCommit(params.PaysetCommit) + if err != nil { + return TxnCommitments{}, err + } + + var digestSHA256 crypto.Digest + if params.EnableSHA256TxnCommitmentHeader { + digestSHA256, err = block.paysetCommitSHA256() + if err != nil { + return TxnCommitments{}, err + } + } + + return TxnCommitments{ + Sha256Commitment: digestSHA256, + NativeSha512_256Commitment: digestSHA512_256, + }, nil } func (block Block) paysetCommit(t config.PaysetCommitType) (crypto.Digest, error) { @@ -539,6 +566,18 @@ func (block Block) paysetCommit(t config.PaysetCommitType) (crypto.Digest, error } } +func (block Block) paysetCommitSHA256() (crypto.Digest, error) { + tree, err := block.TxnMerkleTreeSHA256() + if err != nil { + return crypto.Digest{}, err + } + + rootSlice := tree.Root() + var rootAsByteArray crypto.Digest + copy(rootAsByteArray[:], rootSlice) + return rootAsByteArray, nil +} + // PreCheck checks if the block header bh is a valid successor to // the previous block's header, prev. func (bh BlockHeader) PreCheck(prev BlockHeader) error { @@ -605,7 +644,7 @@ func (bh BlockHeader) PreCheck(prev BlockHeader) error { return nil } -// ContentsMatchHeader checks that the TxnRoot matches what's in the header, +// ContentsMatchHeader checks that the TxnCommitments matches what's in the header, // as the header is what the block hash authenticates. // If we're given an untrusted block and a known-good hash, we can't trust the // block's transactions unless we validate this. @@ -616,7 +655,7 @@ func (block Block) ContentsMatchHeader() bool { return false } - return expected == block.TxnRoot + return expected == block.TxnCommitments } // DecodePaysetGroups decodes block.Payset using DecodeSignedTxn, and returns diff --git a/data/bookkeeping/block_test.go b/data/bookkeeping/block_test.go index 2956edb128..d57736701d 100644 --- a/data/bookkeeping/block_test.go +++ b/data/bookkeeping/block_test.go @@ -18,6 +18,7 @@ package bookkeeping import ( "bytes" + "encoding/hex" "math" "testing" "time" @@ -769,3 +770,107 @@ func TestNextRewardsRateWithFixNextRewardLevelOverflow(t *testing.T) { assert.Contains(t, string(buf.Bytes()), "could not compute next reward level") } + +func TestBlock_ContentsMatchHeader(t *testing.T) { + partitiontest.PartitionTest(t) + a := require.New(t) + + // Create a block without SHA256 TxnCommitments + var block Block + block.CurrentProtocol = protocol.ConsensusV32 + crypto.RandBytes(block.BlockHeader.GenesisHash[:]) + + for i := 0; i < 1024; i++ { + txn := transactions.Transaction{ + Type: protocol.PaymentTx, + Header: transactions.Header{ + GenesisHash: block.BlockHeader.GenesisHash, + }, + PaymentTxnFields: transactions.PaymentTxnFields{ + Amount: basics.MicroAlgos{Raw: crypto.RandUint64()}, + }, + } + + crypto.RandBytes(txn.Sender[:]) + crypto.RandBytes(txn.PaymentTxnFields.Receiver[:]) + + sigtxn := transactions.SignedTxn{Txn: txn} + ad := transactions.ApplyData{} + + stib, err := block.BlockHeader.EncodeSignedTxn(sigtxn, ad) + a.NoError(err) + + block.Payset = append(block.Payset, stib) + } + + tree, err := block.TxnMerkleTree() + a.NoError(err) + rootSliceSHA512_256 := tree.Root() + + tree, err = block.TxnMerkleTreeSHA256() + a.NoError(err) + rootSliceSHA256 := tree.Root() + + badDigestSlice := []byte("(>^-^)>") + + /* Test V32 */ + a.False(block.ContentsMatchHeader()) + + copy(block.BlockHeader.TxnCommitments.NativeSha512_256Commitment[:], rootSliceSHA512_256) + block.BlockHeader.TxnCommitments.Sha256Commitment = crypto.Digest{} + a.True(block.ContentsMatchHeader()) + + copy(block.BlockHeader.TxnCommitments.NativeSha512_256Commitment[:], rootSliceSHA512_256) + copy(block.BlockHeader.TxnCommitments.Sha256Commitment[:], rootSliceSHA256) + a.False(block.ContentsMatchHeader()) + + copy(block.BlockHeader.TxnCommitments.NativeSha512_256Commitment[:], badDigestSlice) + copy(block.BlockHeader.TxnCommitments.Sha256Commitment[:], rootSliceSHA256) + a.False(block.ContentsMatchHeader()) + + block.BlockHeader.TxnCommitments.NativeSha512_256Commitment = crypto.Digest{} + copy(block.BlockHeader.TxnCommitments.Sha256Commitment[:], rootSliceSHA256) + a.False(block.ContentsMatchHeader()) + + /* Test Consensus Future */ + // Create a block with SHA256 TxnCommitments + block.CurrentProtocol = protocol.ConsensusFuture + + block.BlockHeader.TxnCommitments.NativeSha512_256Commitment = crypto.Digest{} + block.BlockHeader.TxnCommitments.Sha256Commitment = crypto.Digest{} + a.False(block.ContentsMatchHeader()) + + // Now update the SHA256 header to its correct value + copy(block.BlockHeader.TxnCommitments.NativeSha512_256Commitment[:], rootSliceSHA512_256) + copy(block.BlockHeader.TxnCommitments.Sha256Commitment[:], rootSliceSHA256) + a.True(block.ContentsMatchHeader()) + + copy(block.BlockHeader.TxnCommitments.NativeSha512_256Commitment[:], badDigestSlice) + copy(block.BlockHeader.TxnCommitments.Sha256Commitment[:], rootSliceSHA256) + a.False(block.ContentsMatchHeader()) + + copy(block.BlockHeader.TxnCommitments.NativeSha512_256Commitment[:], rootSliceSHA512_256) + copy(block.BlockHeader.TxnCommitments.Sha256Commitment[:], badDigestSlice) + a.False(block.ContentsMatchHeader()) + + block.BlockHeader.TxnCommitments.NativeSha512_256Commitment = crypto.Digest{} + copy(block.BlockHeader.TxnCommitments.Sha256Commitment[:], rootSliceSHA256) + a.False(block.ContentsMatchHeader()) +} + +func TestBlockHeader_Serialization(t *testing.T) { + partitiontest.PartitionTest(t) + a := require.New(t) + + // This serialized block header was generated from V32 e2e test, using the old BlockHeader struct which contains only TxnCommitments SHA512_256 value + serializedBlkHdr := "8fa26363810081a16ecd0200a466656573c42007dacb4b6d9ed141b17576bd459ae6421d486da3d4ef2247c409a396b82ea221a466726163ce1dcd64fea367656ea7746573742d7631a26768c42032cb340d569e1f9e4d9690c1ba04d77759bae6f353e13af1becf42dcd7d3bdeba470726576c420a2270bc90e3cc48d56081b3b85c15d6a10e14303a6d42ca2537954ce90beec40a570726f746fa6667574757265a472617465ce0ee6b27fa3726e6402a6727763616c72ce0007a120a3727764c420ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa473656564c420a19005a25abad1ad28ec2298baeda9a17693a9ef12127a5ff3e5fa9258c7e9eba2746306a27473ce625ed0eaa374786ec420508f9330176e6064767b0fb7eb0e8bf68ffbaf995a4c7b37ca0217c5a82b4a60" + bytesBlkHdr, err := hex.DecodeString(serializedBlkHdr) + a.NoError(err) + + var blkHdr BlockHeader + err = protocol.Decode(bytesBlkHdr, &blkHdr) + a.NoError(err) + + a.Equal(crypto.Digest{}, blkHdr.TxnCommitments.Sha256Commitment) + a.NotEqual(crypto.Digest{}, blkHdr.TxnCommitments.NativeSha512_256Commitment) +} diff --git a/data/bookkeeping/genesis.go b/data/bookkeeping/genesis.go index 3b15d91d0d..d763203fe8 100644 --- a/data/bookkeeping/genesis.go +++ b/data/bookkeeping/genesis.go @@ -164,13 +164,13 @@ func MakeGenesisBlock(proto protocol.ConsensusVersion, genesisBal GenesisBalance blk := Block{ BlockHeader: BlockHeader{ - Round: 0, - Branch: BlockHash{}, - Seed: committee.Seed(genesisHash), - TxnRoot: transactions.Payset{}.CommitGenesis(), - TimeStamp: genesisBal.Timestamp, - GenesisID: genesisID, - RewardsState: genesisRewardsState, + Round: 0, + Branch: BlockHash{}, + Seed: committee.Seed(genesisHash), + TxnCommitments: TxnCommitments{NativeSha512_256Commitment: transactions.Payset{}.CommitGenesis(), Sha256Commitment: crypto.Digest{}}, + TimeStamp: genesisBal.Timestamp, + GenesisID: genesisID, + RewardsState: genesisRewardsState, UpgradeState: UpgradeState{ CurrentProtocol: proto, }, diff --git a/data/bookkeeping/msgp_gen.go b/data/bookkeeping/msgp_gen.go index e7a810e3d5..0e994fcff4 100644 --- a/data/bookkeeping/msgp_gen.go +++ b/data/bookkeeping/msgp_gen.go @@ -5,11 +5,12 @@ package bookkeeping import ( "sort" + "github.com/algorand/msgp/msgp" + "github.com/algorand/go-algorand/config" "github.com/algorand/go-algorand/crypto" "github.com/algorand/go-algorand/data/basics" "github.com/algorand/go-algorand/protocol" - "github.com/algorand/msgp/msgp" ) // The following msgp objects are implemented in this file: @@ -77,6 +78,14 @@ import ( // |-----> (*) Msgsize // |-----> (*) MsgIsZero // +// TxnCommitments +// |-----> (*) MarshalMsg +// |-----> (*) CanMarshalMsg +// |-----> (*) UnmarshalMsg +// |-----> (*) CanUnmarshalMsg +// |-----> (*) Msgsize +// |-----> (*) MsgIsZero +// // UpgradeVote // |-----> (*) MarshalMsg // |-----> (*) CanMarshalMsg @@ -90,112 +99,116 @@ import ( func (z *Block) MarshalMsg(b []byte) (o []byte) { o = msgp.Require(b, z.Msgsize()) // omitempty: check for empty values - zb0004Len := uint32(25) - var zb0004Mask uint32 /* 29 bits */ + zb0004Len := uint32(26) + var zb0004Mask uint32 /* 31 bits */ if len((*z).BlockHeader.CompactCert) == 0 { zb0004Len-- - zb0004Mask |= 0x10 + zb0004Mask |= 0x20 } if (*z).BlockHeader.RewardsState.RewardsLevel == 0 { zb0004Len-- - zb0004Mask |= 0x20 + zb0004Mask |= 0x40 } if (*z).BlockHeader.RewardsState.FeeSink.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x40 + zb0004Mask |= 0x80 } if (*z).BlockHeader.RewardsState.RewardsResidue == 0 { zb0004Len-- - zb0004Mask |= 0x80 + zb0004Mask |= 0x100 } if (*z).BlockHeader.GenesisID == "" { zb0004Len-- - zb0004Mask |= 0x100 + zb0004Mask |= 0x200 } if (*z).BlockHeader.GenesisHash.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x200 + zb0004Mask |= 0x400 } if (*z).BlockHeader.UpgradeState.NextProtocolVoteBefore.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x400 + zb0004Mask |= 0x800 } if (*z).BlockHeader.UpgradeState.NextProtocol.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x800 + zb0004Mask |= 0x1000 } if (*z).BlockHeader.UpgradeState.NextProtocolSwitchOn.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x1000 + zb0004Mask |= 0x2000 } if (*z).BlockHeader.UpgradeState.NextProtocolApprovals == 0 { zb0004Len-- - zb0004Mask |= 0x2000 + zb0004Mask |= 0x4000 } if len((*z).BlockHeader.ParticipationUpdates.ExpiredParticipationAccounts) == 0 { zb0004Len-- - zb0004Mask |= 0x4000 + zb0004Mask |= 0x8000 } if (*z).BlockHeader.Branch.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x8000 + zb0004Mask |= 0x10000 } if (*z).BlockHeader.UpgradeState.CurrentProtocol.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x10000 + zb0004Mask |= 0x20000 } if (*z).BlockHeader.RewardsState.RewardsRate == 0 { zb0004Len-- - zb0004Mask |= 0x20000 + zb0004Mask |= 0x40000 } if (*z).BlockHeader.Round.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x40000 + zb0004Mask |= 0x80000 } if (*z).BlockHeader.RewardsState.RewardsRecalculationRound.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x80000 + zb0004Mask |= 0x100000 } if (*z).BlockHeader.RewardsState.RewardsPool.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x100000 + zb0004Mask |= 0x200000 } if (*z).BlockHeader.Seed.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x200000 + zb0004Mask |= 0x400000 } if (*z).BlockHeader.TxnCounter == 0 { zb0004Len-- - zb0004Mask |= 0x400000 + zb0004Mask |= 0x800000 } if (*z).BlockHeader.TimeStamp == 0 { zb0004Len-- - zb0004Mask |= 0x800000 + zb0004Mask |= 0x1000000 } - if (*z).BlockHeader.TxnRoot.MsgIsZero() { + if (*z).BlockHeader.TxnCommitments.NativeSha512_256Commitment.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x1000000 + zb0004Mask |= 0x2000000 + } + if (*z).BlockHeader.TxnCommitments.Sha256Commitment.MsgIsZero() { + zb0004Len-- + zb0004Mask |= 0x4000000 } if (*z).Payset.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x2000000 + zb0004Mask |= 0x8000000 } if (*z).BlockHeader.UpgradeVote.UpgradeDelay.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x4000000 + zb0004Mask |= 0x10000000 } if (*z).BlockHeader.UpgradeVote.UpgradePropose.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x8000000 + zb0004Mask |= 0x20000000 } if (*z).BlockHeader.UpgradeVote.UpgradeApprove == false { zb0004Len-- - zb0004Mask |= 0x10000000 + zb0004Mask |= 0x40000000 } // variable map header, size zb0004Len o = msgp.AppendMapHeader(o, zb0004Len) if zb0004Len != 0 { - if (zb0004Mask & 0x10) == 0 { // if not empty + if (zb0004Mask & 0x20) == 0 { // if not empty // string "cc" o = append(o, 0xa2, 0x63, 0x63) if (*z).BlockHeader.CompactCert == nil { @@ -215,52 +228,52 @@ func (z *Block) MarshalMsg(b []byte) (o []byte) { o = zb0002.MarshalMsg(o) } } - if (zb0004Mask & 0x20) == 0 { // if not empty + if (zb0004Mask & 0x40) == 0 { // if not empty // string "earn" o = append(o, 0xa4, 0x65, 0x61, 0x72, 0x6e) o = msgp.AppendUint64(o, (*z).BlockHeader.RewardsState.RewardsLevel) } - if (zb0004Mask & 0x40) == 0 { // if not empty + if (zb0004Mask & 0x80) == 0 { // if not empty // string "fees" o = append(o, 0xa4, 0x66, 0x65, 0x65, 0x73) o = (*z).BlockHeader.RewardsState.FeeSink.MarshalMsg(o) } - if (zb0004Mask & 0x80) == 0 { // if not empty + if (zb0004Mask & 0x100) == 0 { // if not empty // string "frac" o = append(o, 0xa4, 0x66, 0x72, 0x61, 0x63) o = msgp.AppendUint64(o, (*z).BlockHeader.RewardsState.RewardsResidue) } - if (zb0004Mask & 0x100) == 0 { // if not empty + if (zb0004Mask & 0x200) == 0 { // if not empty // string "gen" o = append(o, 0xa3, 0x67, 0x65, 0x6e) o = msgp.AppendString(o, (*z).BlockHeader.GenesisID) } - if (zb0004Mask & 0x200) == 0 { // if not empty + if (zb0004Mask & 0x400) == 0 { // if not empty // string "gh" o = append(o, 0xa2, 0x67, 0x68) o = (*z).BlockHeader.GenesisHash.MarshalMsg(o) } - if (zb0004Mask & 0x400) == 0 { // if not empty + if (zb0004Mask & 0x800) == 0 { // if not empty // string "nextbefore" o = append(o, 0xaa, 0x6e, 0x65, 0x78, 0x74, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65) o = (*z).BlockHeader.UpgradeState.NextProtocolVoteBefore.MarshalMsg(o) } - if (zb0004Mask & 0x800) == 0 { // if not empty + if (zb0004Mask & 0x1000) == 0 { // if not empty // string "nextproto" o = append(o, 0xa9, 0x6e, 0x65, 0x78, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f) o = (*z).BlockHeader.UpgradeState.NextProtocol.MarshalMsg(o) } - if (zb0004Mask & 0x1000) == 0 { // if not empty + if (zb0004Mask & 0x2000) == 0 { // if not empty // string "nextswitch" o = append(o, 0xaa, 0x6e, 0x65, 0x78, 0x74, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68) o = (*z).BlockHeader.UpgradeState.NextProtocolSwitchOn.MarshalMsg(o) } - if (zb0004Mask & 0x2000) == 0 { // if not empty + if (zb0004Mask & 0x4000) == 0 { // if not empty // string "nextyes" o = append(o, 0xa7, 0x6e, 0x65, 0x78, 0x74, 0x79, 0x65, 0x73) o = msgp.AppendUint64(o, (*z).BlockHeader.UpgradeState.NextProtocolApprovals) } - if (zb0004Mask & 0x4000) == 0 { // if not empty + if (zb0004Mask & 0x8000) == 0 { // if not empty // string "partupdrmv" o = append(o, 0xaa, 0x70, 0x61, 0x72, 0x74, 0x75, 0x70, 0x64, 0x72, 0x6d, 0x76) if (*z).BlockHeader.ParticipationUpdates.ExpiredParticipationAccounts == nil { @@ -272,72 +285,77 @@ func (z *Block) MarshalMsg(b []byte) (o []byte) { o = (*z).BlockHeader.ParticipationUpdates.ExpiredParticipationAccounts[zb0003].MarshalMsg(o) } } - if (zb0004Mask & 0x8000) == 0 { // if not empty + if (zb0004Mask & 0x10000) == 0 { // if not empty // string "prev" o = append(o, 0xa4, 0x70, 0x72, 0x65, 0x76) o = (*z).BlockHeader.Branch.MarshalMsg(o) } - if (zb0004Mask & 0x10000) == 0 { // if not empty + if (zb0004Mask & 0x20000) == 0 { // if not empty // string "proto" o = append(o, 0xa5, 0x70, 0x72, 0x6f, 0x74, 0x6f) o = (*z).BlockHeader.UpgradeState.CurrentProtocol.MarshalMsg(o) } - if (zb0004Mask & 0x20000) == 0 { // if not empty + if (zb0004Mask & 0x40000) == 0 { // if not empty // string "rate" o = append(o, 0xa4, 0x72, 0x61, 0x74, 0x65) o = msgp.AppendUint64(o, (*z).BlockHeader.RewardsState.RewardsRate) } - if (zb0004Mask & 0x40000) == 0 { // if not empty + if (zb0004Mask & 0x80000) == 0 { // if not empty // string "rnd" o = append(o, 0xa3, 0x72, 0x6e, 0x64) o = (*z).BlockHeader.Round.MarshalMsg(o) } - if (zb0004Mask & 0x80000) == 0 { // if not empty + if (zb0004Mask & 0x100000) == 0 { // if not empty // string "rwcalr" o = append(o, 0xa6, 0x72, 0x77, 0x63, 0x61, 0x6c, 0x72) o = (*z).BlockHeader.RewardsState.RewardsRecalculationRound.MarshalMsg(o) } - if (zb0004Mask & 0x100000) == 0 { // if not empty + if (zb0004Mask & 0x200000) == 0 { // if not empty // string "rwd" o = append(o, 0xa3, 0x72, 0x77, 0x64) o = (*z).BlockHeader.RewardsState.RewardsPool.MarshalMsg(o) } - if (zb0004Mask & 0x200000) == 0 { // if not empty + if (zb0004Mask & 0x400000) == 0 { // if not empty // string "seed" o = append(o, 0xa4, 0x73, 0x65, 0x65, 0x64) o = (*z).BlockHeader.Seed.MarshalMsg(o) } - if (zb0004Mask & 0x400000) == 0 { // if not empty + if (zb0004Mask & 0x800000) == 0 { // if not empty // string "tc" o = append(o, 0xa2, 0x74, 0x63) o = msgp.AppendUint64(o, (*z).BlockHeader.TxnCounter) } - if (zb0004Mask & 0x800000) == 0 { // if not empty + if (zb0004Mask & 0x1000000) == 0 { // if not empty // string "ts" o = append(o, 0xa2, 0x74, 0x73) o = msgp.AppendInt64(o, (*z).BlockHeader.TimeStamp) } - if (zb0004Mask & 0x1000000) == 0 { // if not empty + if (zb0004Mask & 0x2000000) == 0 { // if not empty // string "txn" o = append(o, 0xa3, 0x74, 0x78, 0x6e) - o = (*z).BlockHeader.TxnRoot.MarshalMsg(o) + o = (*z).BlockHeader.TxnCommitments.NativeSha512_256Commitment.MarshalMsg(o) } - if (zb0004Mask & 0x2000000) == 0 { // if not empty + if (zb0004Mask & 0x4000000) == 0 { // if not empty + // string "txn256" + o = append(o, 0xa6, 0x74, 0x78, 0x6e, 0x32, 0x35, 0x36) + o = (*z).BlockHeader.TxnCommitments.Sha256Commitment.MarshalMsg(o) + } + if (zb0004Mask & 0x8000000) == 0 { // if not empty // string "txns" o = append(o, 0xa4, 0x74, 0x78, 0x6e, 0x73) o = (*z).Payset.MarshalMsg(o) } - if (zb0004Mask & 0x4000000) == 0 { // if not empty + if (zb0004Mask & 0x10000000) == 0 { // if not empty // string "upgradedelay" o = append(o, 0xac, 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x64, 0x65, 0x6c, 0x61, 0x79) o = (*z).BlockHeader.UpgradeVote.UpgradeDelay.MarshalMsg(o) } - if (zb0004Mask & 0x8000000) == 0 { // if not empty + if (zb0004Mask & 0x20000000) == 0 { // if not empty // string "upgradeprop" o = append(o, 0xab, 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x70, 0x72, 0x6f, 0x70) o = (*z).BlockHeader.UpgradeVote.UpgradePropose.MarshalMsg(o) } - if (zb0004Mask & 0x10000000) == 0 { // if not empty + if (zb0004Mask & 0x40000000) == 0 { // if not empty // string "upgradeyes" o = append(o, 0xaa, 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x79, 0x65, 0x73) o = msgp.AppendBool(o, (*z).BlockHeader.UpgradeVote.UpgradeApprove) @@ -390,9 +408,17 @@ func (z *Block) UnmarshalMsg(bts []byte) (o []byte, err error) { } if zb0004 > 0 { zb0004-- - bts, err = (*z).BlockHeader.TxnRoot.UnmarshalMsg(bts) + bts, err = (*z).BlockHeader.TxnCommitments.NativeSha512_256Commitment.UnmarshalMsg(bts) + if err != nil { + err = msgp.WrapError(err, "struct-from-array", "NativeSha512_256Commitment") + return + } + } + if zb0004 > 0 { + zb0004-- + bts, err = (*z).BlockHeader.TxnCommitments.Sha256Commitment.UnmarshalMsg(bts) if err != nil { - err = msgp.WrapError(err, "struct-from-array", "TxnRoot") + err = msgp.WrapError(err, "struct-from-array", "Sha256Commitment") return } } @@ -655,9 +681,15 @@ func (z *Block) UnmarshalMsg(bts []byte) (o []byte, err error) { return } case "txn": - bts, err = (*z).BlockHeader.TxnRoot.UnmarshalMsg(bts) + bts, err = (*z).BlockHeader.TxnCommitments.NativeSha512_256Commitment.UnmarshalMsg(bts) + if err != nil { + err = msgp.WrapError(err, "NativeSha512_256Commitment") + return + } + case "txn256": + bts, err = (*z).BlockHeader.TxnCommitments.Sha256Commitment.UnmarshalMsg(bts) if err != nil { - err = msgp.WrapError(err, "TxnRoot") + err = msgp.WrapError(err, "Sha256Commitment") return } case "ts": @@ -855,7 +887,7 @@ func (_ *Block) CanUnmarshalMsg(z interface{}) bool { // Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message func (z *Block) Msgsize() (s int) { - s = 3 + 4 + (*z).BlockHeader.Round.Msgsize() + 5 + (*z).BlockHeader.Branch.Msgsize() + 5 + (*z).BlockHeader.Seed.Msgsize() + 4 + (*z).BlockHeader.TxnRoot.Msgsize() + 3 + msgp.Int64Size + 4 + msgp.StringPrefixSize + len((*z).BlockHeader.GenesisID) + 3 + (*z).BlockHeader.GenesisHash.Msgsize() + 5 + (*z).BlockHeader.RewardsState.FeeSink.Msgsize() + 4 + (*z).BlockHeader.RewardsState.RewardsPool.Msgsize() + 5 + msgp.Uint64Size + 5 + msgp.Uint64Size + 5 + msgp.Uint64Size + 7 + (*z).BlockHeader.RewardsState.RewardsRecalculationRound.Msgsize() + 6 + (*z).BlockHeader.UpgradeState.CurrentProtocol.Msgsize() + 10 + (*z).BlockHeader.UpgradeState.NextProtocol.Msgsize() + 8 + msgp.Uint64Size + 11 + (*z).BlockHeader.UpgradeState.NextProtocolVoteBefore.Msgsize() + 11 + (*z).BlockHeader.UpgradeState.NextProtocolSwitchOn.Msgsize() + 12 + (*z).BlockHeader.UpgradeVote.UpgradePropose.Msgsize() + 13 + (*z).BlockHeader.UpgradeVote.UpgradeDelay.Msgsize() + 11 + msgp.BoolSize + 3 + msgp.Uint64Size + 3 + msgp.MapHeaderSize + s = 3 + 4 + (*z).BlockHeader.Round.Msgsize() + 5 + (*z).BlockHeader.Branch.Msgsize() + 5 + (*z).BlockHeader.Seed.Msgsize() + 4 + (*z).BlockHeader.TxnCommitments.NativeSha512_256Commitment.Msgsize() + 7 + (*z).BlockHeader.TxnCommitments.Sha256Commitment.Msgsize() + 3 + msgp.Int64Size + 4 + msgp.StringPrefixSize + len((*z).BlockHeader.GenesisID) + 3 + (*z).BlockHeader.GenesisHash.Msgsize() + 5 + (*z).BlockHeader.RewardsState.FeeSink.Msgsize() + 4 + (*z).BlockHeader.RewardsState.RewardsPool.Msgsize() + 5 + msgp.Uint64Size + 5 + msgp.Uint64Size + 5 + msgp.Uint64Size + 7 + (*z).BlockHeader.RewardsState.RewardsRecalculationRound.Msgsize() + 6 + (*z).BlockHeader.UpgradeState.CurrentProtocol.Msgsize() + 10 + (*z).BlockHeader.UpgradeState.NextProtocol.Msgsize() + 8 + msgp.Uint64Size + 11 + (*z).BlockHeader.UpgradeState.NextProtocolVoteBefore.Msgsize() + 11 + (*z).BlockHeader.UpgradeState.NextProtocolSwitchOn.Msgsize() + 12 + (*z).BlockHeader.UpgradeVote.UpgradePropose.Msgsize() + 13 + (*z).BlockHeader.UpgradeVote.UpgradeDelay.Msgsize() + 11 + msgp.BoolSize + 3 + msgp.Uint64Size + 3 + msgp.MapHeaderSize if (*z).BlockHeader.CompactCert != nil { for zb0001, zb0002 := range (*z).BlockHeader.CompactCert { _ = zb0001 @@ -873,7 +905,7 @@ func (z *Block) Msgsize() (s int) { // MsgIsZero returns whether this is a zero value func (z *Block) MsgIsZero() bool { - return ((*z).BlockHeader.Round.MsgIsZero()) && ((*z).BlockHeader.Branch.MsgIsZero()) && ((*z).BlockHeader.Seed.MsgIsZero()) && ((*z).BlockHeader.TxnRoot.MsgIsZero()) && ((*z).BlockHeader.TimeStamp == 0) && ((*z).BlockHeader.GenesisID == "") && ((*z).BlockHeader.GenesisHash.MsgIsZero()) && ((*z).BlockHeader.RewardsState.FeeSink.MsgIsZero()) && ((*z).BlockHeader.RewardsState.RewardsPool.MsgIsZero()) && ((*z).BlockHeader.RewardsState.RewardsLevel == 0) && ((*z).BlockHeader.RewardsState.RewardsRate == 0) && ((*z).BlockHeader.RewardsState.RewardsResidue == 0) && ((*z).BlockHeader.RewardsState.RewardsRecalculationRound.MsgIsZero()) && ((*z).BlockHeader.UpgradeState.CurrentProtocol.MsgIsZero()) && ((*z).BlockHeader.UpgradeState.NextProtocol.MsgIsZero()) && ((*z).BlockHeader.UpgradeState.NextProtocolApprovals == 0) && ((*z).BlockHeader.UpgradeState.NextProtocolVoteBefore.MsgIsZero()) && ((*z).BlockHeader.UpgradeState.NextProtocolSwitchOn.MsgIsZero()) && ((*z).BlockHeader.UpgradeVote.UpgradePropose.MsgIsZero()) && ((*z).BlockHeader.UpgradeVote.UpgradeDelay.MsgIsZero()) && ((*z).BlockHeader.UpgradeVote.UpgradeApprove == false) && ((*z).BlockHeader.TxnCounter == 0) && (len((*z).BlockHeader.CompactCert) == 0) && (len((*z).BlockHeader.ParticipationUpdates.ExpiredParticipationAccounts) == 0) && ((*z).Payset.MsgIsZero()) + return ((*z).BlockHeader.Round.MsgIsZero()) && ((*z).BlockHeader.Branch.MsgIsZero()) && ((*z).BlockHeader.Seed.MsgIsZero()) && ((*z).BlockHeader.TxnCommitments.NativeSha512_256Commitment.MsgIsZero()) && ((*z).BlockHeader.TxnCommitments.Sha256Commitment.MsgIsZero()) && ((*z).BlockHeader.TimeStamp == 0) && ((*z).BlockHeader.GenesisID == "") && ((*z).BlockHeader.GenesisHash.MsgIsZero()) && ((*z).BlockHeader.RewardsState.FeeSink.MsgIsZero()) && ((*z).BlockHeader.RewardsState.RewardsPool.MsgIsZero()) && ((*z).BlockHeader.RewardsState.RewardsLevel == 0) && ((*z).BlockHeader.RewardsState.RewardsRate == 0) && ((*z).BlockHeader.RewardsState.RewardsResidue == 0) && ((*z).BlockHeader.RewardsState.RewardsRecalculationRound.MsgIsZero()) && ((*z).BlockHeader.UpgradeState.CurrentProtocol.MsgIsZero()) && ((*z).BlockHeader.UpgradeState.NextProtocol.MsgIsZero()) && ((*z).BlockHeader.UpgradeState.NextProtocolApprovals == 0) && ((*z).BlockHeader.UpgradeState.NextProtocolVoteBefore.MsgIsZero()) && ((*z).BlockHeader.UpgradeState.NextProtocolSwitchOn.MsgIsZero()) && ((*z).BlockHeader.UpgradeVote.UpgradePropose.MsgIsZero()) && ((*z).BlockHeader.UpgradeVote.UpgradeDelay.MsgIsZero()) && ((*z).BlockHeader.UpgradeVote.UpgradeApprove == false) && ((*z).BlockHeader.TxnCounter == 0) && (len((*z).BlockHeader.CompactCert) == 0) && (len((*z).BlockHeader.ParticipationUpdates.ExpiredParticipationAccounts) == 0) && ((*z).Payset.MsgIsZero()) } // MarshalMsg implements msgp.Marshaler @@ -908,108 +940,112 @@ func (z *BlockHash) MsgIsZero() bool { func (z *BlockHeader) MarshalMsg(b []byte) (o []byte) { o = msgp.Require(b, z.Msgsize()) // omitempty: check for empty values - zb0004Len := uint32(24) - var zb0004Mask uint32 /* 28 bits */ + zb0004Len := uint32(25) + var zb0004Mask uint32 /* 30 bits */ if len((*z).CompactCert) == 0 { zb0004Len-- - zb0004Mask |= 0x10 + zb0004Mask |= 0x20 } if (*z).RewardsState.RewardsLevel == 0 { zb0004Len-- - zb0004Mask |= 0x20 + zb0004Mask |= 0x40 } if (*z).RewardsState.FeeSink.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x40 + zb0004Mask |= 0x80 } if (*z).RewardsState.RewardsResidue == 0 { zb0004Len-- - zb0004Mask |= 0x80 + zb0004Mask |= 0x100 } if (*z).GenesisID == "" { zb0004Len-- - zb0004Mask |= 0x100 + zb0004Mask |= 0x200 } if (*z).GenesisHash.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x200 + zb0004Mask |= 0x400 } if (*z).UpgradeState.NextProtocolVoteBefore.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x400 + zb0004Mask |= 0x800 } if (*z).UpgradeState.NextProtocol.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x800 + zb0004Mask |= 0x1000 } if (*z).UpgradeState.NextProtocolSwitchOn.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x1000 + zb0004Mask |= 0x2000 } if (*z).UpgradeState.NextProtocolApprovals == 0 { zb0004Len-- - zb0004Mask |= 0x2000 + zb0004Mask |= 0x4000 } if len((*z).ParticipationUpdates.ExpiredParticipationAccounts) == 0 { zb0004Len-- - zb0004Mask |= 0x4000 + zb0004Mask |= 0x8000 } if (*z).Branch.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x8000 + zb0004Mask |= 0x10000 } if (*z).UpgradeState.CurrentProtocol.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x10000 + zb0004Mask |= 0x20000 } if (*z).RewardsState.RewardsRate == 0 { zb0004Len-- - zb0004Mask |= 0x20000 + zb0004Mask |= 0x40000 } if (*z).Round.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x40000 + zb0004Mask |= 0x80000 } if (*z).RewardsState.RewardsRecalculationRound.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x80000 + zb0004Mask |= 0x100000 } if (*z).RewardsState.RewardsPool.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x100000 + zb0004Mask |= 0x200000 } if (*z).Seed.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x200000 + zb0004Mask |= 0x400000 } if (*z).TxnCounter == 0 { zb0004Len-- - zb0004Mask |= 0x400000 + zb0004Mask |= 0x800000 } if (*z).TimeStamp == 0 { zb0004Len-- - zb0004Mask |= 0x800000 + zb0004Mask |= 0x1000000 } - if (*z).TxnRoot.MsgIsZero() { + if (*z).TxnCommitments.NativeSha512_256Commitment.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x1000000 + zb0004Mask |= 0x2000000 + } + if (*z).TxnCommitments.Sha256Commitment.MsgIsZero() { + zb0004Len-- + zb0004Mask |= 0x4000000 } if (*z).UpgradeVote.UpgradeDelay.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x2000000 + zb0004Mask |= 0x8000000 } if (*z).UpgradeVote.UpgradePropose.MsgIsZero() { zb0004Len-- - zb0004Mask |= 0x4000000 + zb0004Mask |= 0x10000000 } if (*z).UpgradeVote.UpgradeApprove == false { zb0004Len-- - zb0004Mask |= 0x8000000 + zb0004Mask |= 0x20000000 } // variable map header, size zb0004Len o = msgp.AppendMapHeader(o, zb0004Len) if zb0004Len != 0 { - if (zb0004Mask & 0x10) == 0 { // if not empty + if (zb0004Mask & 0x20) == 0 { // if not empty // string "cc" o = append(o, 0xa2, 0x63, 0x63) if (*z).CompactCert == nil { @@ -1029,52 +1065,52 @@ func (z *BlockHeader) MarshalMsg(b []byte) (o []byte) { o = zb0002.MarshalMsg(o) } } - if (zb0004Mask & 0x20) == 0 { // if not empty + if (zb0004Mask & 0x40) == 0 { // if not empty // string "earn" o = append(o, 0xa4, 0x65, 0x61, 0x72, 0x6e) o = msgp.AppendUint64(o, (*z).RewardsState.RewardsLevel) } - if (zb0004Mask & 0x40) == 0 { // if not empty + if (zb0004Mask & 0x80) == 0 { // if not empty // string "fees" o = append(o, 0xa4, 0x66, 0x65, 0x65, 0x73) o = (*z).RewardsState.FeeSink.MarshalMsg(o) } - if (zb0004Mask & 0x80) == 0 { // if not empty + if (zb0004Mask & 0x100) == 0 { // if not empty // string "frac" o = append(o, 0xa4, 0x66, 0x72, 0x61, 0x63) o = msgp.AppendUint64(o, (*z).RewardsState.RewardsResidue) } - if (zb0004Mask & 0x100) == 0 { // if not empty + if (zb0004Mask & 0x200) == 0 { // if not empty // string "gen" o = append(o, 0xa3, 0x67, 0x65, 0x6e) o = msgp.AppendString(o, (*z).GenesisID) } - if (zb0004Mask & 0x200) == 0 { // if not empty + if (zb0004Mask & 0x400) == 0 { // if not empty // string "gh" o = append(o, 0xa2, 0x67, 0x68) o = (*z).GenesisHash.MarshalMsg(o) } - if (zb0004Mask & 0x400) == 0 { // if not empty + if (zb0004Mask & 0x800) == 0 { // if not empty // string "nextbefore" o = append(o, 0xaa, 0x6e, 0x65, 0x78, 0x74, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65) o = (*z).UpgradeState.NextProtocolVoteBefore.MarshalMsg(o) } - if (zb0004Mask & 0x800) == 0 { // if not empty + if (zb0004Mask & 0x1000) == 0 { // if not empty // string "nextproto" o = append(o, 0xa9, 0x6e, 0x65, 0x78, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f) o = (*z).UpgradeState.NextProtocol.MarshalMsg(o) } - if (zb0004Mask & 0x1000) == 0 { // if not empty + if (zb0004Mask & 0x2000) == 0 { // if not empty // string "nextswitch" o = append(o, 0xaa, 0x6e, 0x65, 0x78, 0x74, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68) o = (*z).UpgradeState.NextProtocolSwitchOn.MarshalMsg(o) } - if (zb0004Mask & 0x2000) == 0 { // if not empty + if (zb0004Mask & 0x4000) == 0 { // if not empty // string "nextyes" o = append(o, 0xa7, 0x6e, 0x65, 0x78, 0x74, 0x79, 0x65, 0x73) o = msgp.AppendUint64(o, (*z).UpgradeState.NextProtocolApprovals) } - if (zb0004Mask & 0x4000) == 0 { // if not empty + if (zb0004Mask & 0x8000) == 0 { // if not empty // string "partupdrmv" o = append(o, 0xaa, 0x70, 0x61, 0x72, 0x74, 0x75, 0x70, 0x64, 0x72, 0x6d, 0x76) if (*z).ParticipationUpdates.ExpiredParticipationAccounts == nil { @@ -1086,67 +1122,72 @@ func (z *BlockHeader) MarshalMsg(b []byte) (o []byte) { o = (*z).ParticipationUpdates.ExpiredParticipationAccounts[zb0003].MarshalMsg(o) } } - if (zb0004Mask & 0x8000) == 0 { // if not empty + if (zb0004Mask & 0x10000) == 0 { // if not empty // string "prev" o = append(o, 0xa4, 0x70, 0x72, 0x65, 0x76) o = (*z).Branch.MarshalMsg(o) } - if (zb0004Mask & 0x10000) == 0 { // if not empty + if (zb0004Mask & 0x20000) == 0 { // if not empty // string "proto" o = append(o, 0xa5, 0x70, 0x72, 0x6f, 0x74, 0x6f) o = (*z).UpgradeState.CurrentProtocol.MarshalMsg(o) } - if (zb0004Mask & 0x20000) == 0 { // if not empty + if (zb0004Mask & 0x40000) == 0 { // if not empty // string "rate" o = append(o, 0xa4, 0x72, 0x61, 0x74, 0x65) o = msgp.AppendUint64(o, (*z).RewardsState.RewardsRate) } - if (zb0004Mask & 0x40000) == 0 { // if not empty + if (zb0004Mask & 0x80000) == 0 { // if not empty // string "rnd" o = append(o, 0xa3, 0x72, 0x6e, 0x64) o = (*z).Round.MarshalMsg(o) } - if (zb0004Mask & 0x80000) == 0 { // if not empty + if (zb0004Mask & 0x100000) == 0 { // if not empty // string "rwcalr" o = append(o, 0xa6, 0x72, 0x77, 0x63, 0x61, 0x6c, 0x72) o = (*z).RewardsState.RewardsRecalculationRound.MarshalMsg(o) } - if (zb0004Mask & 0x100000) == 0 { // if not empty + if (zb0004Mask & 0x200000) == 0 { // if not empty // string "rwd" o = append(o, 0xa3, 0x72, 0x77, 0x64) o = (*z).RewardsState.RewardsPool.MarshalMsg(o) } - if (zb0004Mask & 0x200000) == 0 { // if not empty + if (zb0004Mask & 0x400000) == 0 { // if not empty // string "seed" o = append(o, 0xa4, 0x73, 0x65, 0x65, 0x64) o = (*z).Seed.MarshalMsg(o) } - if (zb0004Mask & 0x400000) == 0 { // if not empty + if (zb0004Mask & 0x800000) == 0 { // if not empty // string "tc" o = append(o, 0xa2, 0x74, 0x63) o = msgp.AppendUint64(o, (*z).TxnCounter) } - if (zb0004Mask & 0x800000) == 0 { // if not empty + if (zb0004Mask & 0x1000000) == 0 { // if not empty // string "ts" o = append(o, 0xa2, 0x74, 0x73) o = msgp.AppendInt64(o, (*z).TimeStamp) } - if (zb0004Mask & 0x1000000) == 0 { // if not empty + if (zb0004Mask & 0x2000000) == 0 { // if not empty // string "txn" o = append(o, 0xa3, 0x74, 0x78, 0x6e) - o = (*z).TxnRoot.MarshalMsg(o) + o = (*z).TxnCommitments.NativeSha512_256Commitment.MarshalMsg(o) } - if (zb0004Mask & 0x2000000) == 0 { // if not empty + if (zb0004Mask & 0x4000000) == 0 { // if not empty + // string "txn256" + o = append(o, 0xa6, 0x74, 0x78, 0x6e, 0x32, 0x35, 0x36) + o = (*z).TxnCommitments.Sha256Commitment.MarshalMsg(o) + } + if (zb0004Mask & 0x8000000) == 0 { // if not empty // string "upgradedelay" o = append(o, 0xac, 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x64, 0x65, 0x6c, 0x61, 0x79) o = (*z).UpgradeVote.UpgradeDelay.MarshalMsg(o) } - if (zb0004Mask & 0x4000000) == 0 { // if not empty + if (zb0004Mask & 0x10000000) == 0 { // if not empty // string "upgradeprop" o = append(o, 0xab, 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x70, 0x72, 0x6f, 0x70) o = (*z).UpgradeVote.UpgradePropose.MarshalMsg(o) } - if (zb0004Mask & 0x8000000) == 0 { // if not empty + if (zb0004Mask & 0x20000000) == 0 { // if not empty // string "upgradeyes" o = append(o, 0xaa, 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x79, 0x65, 0x73) o = msgp.AppendBool(o, (*z).UpgradeVote.UpgradeApprove) @@ -1199,9 +1240,17 @@ func (z *BlockHeader) UnmarshalMsg(bts []byte) (o []byte, err error) { } if zb0004 > 0 { zb0004-- - bts, err = (*z).TxnRoot.UnmarshalMsg(bts) + bts, err = (*z).TxnCommitments.NativeSha512_256Commitment.UnmarshalMsg(bts) if err != nil { - err = msgp.WrapError(err, "struct-from-array", "TxnRoot") + err = msgp.WrapError(err, "struct-from-array", "NativeSha512_256Commitment") + return + } + } + if zb0004 > 0 { + zb0004-- + bts, err = (*z).TxnCommitments.Sha256Commitment.UnmarshalMsg(bts) + if err != nil { + err = msgp.WrapError(err, "struct-from-array", "Sha256Commitment") return } } @@ -1456,9 +1505,15 @@ func (z *BlockHeader) UnmarshalMsg(bts []byte) (o []byte, err error) { return } case "txn": - bts, err = (*z).TxnRoot.UnmarshalMsg(bts) + bts, err = (*z).TxnCommitments.NativeSha512_256Commitment.UnmarshalMsg(bts) if err != nil { - err = msgp.WrapError(err, "TxnRoot") + err = msgp.WrapError(err, "NativeSha512_256Commitment") + return + } + case "txn256": + bts, err = (*z).TxnCommitments.Sha256Commitment.UnmarshalMsg(bts) + if err != nil { + err = msgp.WrapError(err, "Sha256Commitment") return } case "ts": @@ -1650,7 +1705,7 @@ func (_ *BlockHeader) CanUnmarshalMsg(z interface{}) bool { // Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message func (z *BlockHeader) Msgsize() (s int) { - s = 3 + 4 + (*z).Round.Msgsize() + 5 + (*z).Branch.Msgsize() + 5 + (*z).Seed.Msgsize() + 4 + (*z).TxnRoot.Msgsize() + 3 + msgp.Int64Size + 4 + msgp.StringPrefixSize + len((*z).GenesisID) + 3 + (*z).GenesisHash.Msgsize() + 5 + (*z).RewardsState.FeeSink.Msgsize() + 4 + (*z).RewardsState.RewardsPool.Msgsize() + 5 + msgp.Uint64Size + 5 + msgp.Uint64Size + 5 + msgp.Uint64Size + 7 + (*z).RewardsState.RewardsRecalculationRound.Msgsize() + 6 + (*z).UpgradeState.CurrentProtocol.Msgsize() + 10 + (*z).UpgradeState.NextProtocol.Msgsize() + 8 + msgp.Uint64Size + 11 + (*z).UpgradeState.NextProtocolVoteBefore.Msgsize() + 11 + (*z).UpgradeState.NextProtocolSwitchOn.Msgsize() + 12 + (*z).UpgradeVote.UpgradePropose.Msgsize() + 13 + (*z).UpgradeVote.UpgradeDelay.Msgsize() + 11 + msgp.BoolSize + 3 + msgp.Uint64Size + 3 + msgp.MapHeaderSize + s = 3 + 4 + (*z).Round.Msgsize() + 5 + (*z).Branch.Msgsize() + 5 + (*z).Seed.Msgsize() + 4 + (*z).TxnCommitments.NativeSha512_256Commitment.Msgsize() + 7 + (*z).TxnCommitments.Sha256Commitment.Msgsize() + 3 + msgp.Int64Size + 4 + msgp.StringPrefixSize + len((*z).GenesisID) + 3 + (*z).GenesisHash.Msgsize() + 5 + (*z).RewardsState.FeeSink.Msgsize() + 4 + (*z).RewardsState.RewardsPool.Msgsize() + 5 + msgp.Uint64Size + 5 + msgp.Uint64Size + 5 + msgp.Uint64Size + 7 + (*z).RewardsState.RewardsRecalculationRound.Msgsize() + 6 + (*z).UpgradeState.CurrentProtocol.Msgsize() + 10 + (*z).UpgradeState.NextProtocol.Msgsize() + 8 + msgp.Uint64Size + 11 + (*z).UpgradeState.NextProtocolVoteBefore.Msgsize() + 11 + (*z).UpgradeState.NextProtocolSwitchOn.Msgsize() + 12 + (*z).UpgradeVote.UpgradePropose.Msgsize() + 13 + (*z).UpgradeVote.UpgradeDelay.Msgsize() + 11 + msgp.BoolSize + 3 + msgp.Uint64Size + 3 + msgp.MapHeaderSize if (*z).CompactCert != nil { for zb0001, zb0002 := range (*z).CompactCert { _ = zb0001 @@ -1667,7 +1722,7 @@ func (z *BlockHeader) Msgsize() (s int) { // MsgIsZero returns whether this is a zero value func (z *BlockHeader) MsgIsZero() bool { - return ((*z).Round.MsgIsZero()) && ((*z).Branch.MsgIsZero()) && ((*z).Seed.MsgIsZero()) && ((*z).TxnRoot.MsgIsZero()) && ((*z).TimeStamp == 0) && ((*z).GenesisID == "") && ((*z).GenesisHash.MsgIsZero()) && ((*z).RewardsState.FeeSink.MsgIsZero()) && ((*z).RewardsState.RewardsPool.MsgIsZero()) && ((*z).RewardsState.RewardsLevel == 0) && ((*z).RewardsState.RewardsRate == 0) && ((*z).RewardsState.RewardsResidue == 0) && ((*z).RewardsState.RewardsRecalculationRound.MsgIsZero()) && ((*z).UpgradeState.CurrentProtocol.MsgIsZero()) && ((*z).UpgradeState.NextProtocol.MsgIsZero()) && ((*z).UpgradeState.NextProtocolApprovals == 0) && ((*z).UpgradeState.NextProtocolVoteBefore.MsgIsZero()) && ((*z).UpgradeState.NextProtocolSwitchOn.MsgIsZero()) && ((*z).UpgradeVote.UpgradePropose.MsgIsZero()) && ((*z).UpgradeVote.UpgradeDelay.MsgIsZero()) && ((*z).UpgradeVote.UpgradeApprove == false) && ((*z).TxnCounter == 0) && (len((*z).CompactCert) == 0) && (len((*z).ParticipationUpdates.ExpiredParticipationAccounts) == 0) + return ((*z).Round.MsgIsZero()) && ((*z).Branch.MsgIsZero()) && ((*z).Seed.MsgIsZero()) && ((*z).TxnCommitments.NativeSha512_256Commitment.MsgIsZero()) && ((*z).TxnCommitments.Sha256Commitment.MsgIsZero()) && ((*z).TimeStamp == 0) && ((*z).GenesisID == "") && ((*z).GenesisHash.MsgIsZero()) && ((*z).RewardsState.FeeSink.MsgIsZero()) && ((*z).RewardsState.RewardsPool.MsgIsZero()) && ((*z).RewardsState.RewardsLevel == 0) && ((*z).RewardsState.RewardsRate == 0) && ((*z).RewardsState.RewardsResidue == 0) && ((*z).RewardsState.RewardsRecalculationRound.MsgIsZero()) && ((*z).UpgradeState.CurrentProtocol.MsgIsZero()) && ((*z).UpgradeState.NextProtocol.MsgIsZero()) && ((*z).UpgradeState.NextProtocolApprovals == 0) && ((*z).UpgradeState.NextProtocolVoteBefore.MsgIsZero()) && ((*z).UpgradeState.NextProtocolSwitchOn.MsgIsZero()) && ((*z).UpgradeVote.UpgradePropose.MsgIsZero()) && ((*z).UpgradeVote.UpgradeDelay.MsgIsZero()) && ((*z).UpgradeVote.UpgradeApprove == false) && ((*z).TxnCounter == 0) && (len((*z).CompactCert) == 0) && (len((*z).ParticipationUpdates.ExpiredParticipationAccounts) == 0) } // MarshalMsg implements msgp.Marshaler @@ -2672,6 +2727,135 @@ func (z *RewardsState) MsgIsZero() bool { return ((*z).FeeSink.MsgIsZero()) && ((*z).RewardsPool.MsgIsZero()) && ((*z).RewardsLevel == 0) && ((*z).RewardsRate == 0) && ((*z).RewardsResidue == 0) && ((*z).RewardsRecalculationRound.MsgIsZero()) } +// MarshalMsg implements msgp.Marshaler +func (z *TxnCommitments) MarshalMsg(b []byte) (o []byte) { + o = msgp.Require(b, z.Msgsize()) + // omitempty: check for empty values + zb0001Len := uint32(2) + var zb0001Mask uint8 /* 3 bits */ + if (*z).NativeSha512_256Commitment.MsgIsZero() { + zb0001Len-- + zb0001Mask |= 0x2 + } + if (*z).Sha256Commitment.MsgIsZero() { + zb0001Len-- + zb0001Mask |= 0x4 + } + // variable map header, size zb0001Len + o = append(o, 0x80|uint8(zb0001Len)) + if zb0001Len != 0 { + if (zb0001Mask & 0x2) == 0 { // if not empty + // string "txn" + o = append(o, 0xa3, 0x74, 0x78, 0x6e) + o = (*z).NativeSha512_256Commitment.MarshalMsg(o) + } + if (zb0001Mask & 0x4) == 0 { // if not empty + // string "txn256" + o = append(o, 0xa6, 0x74, 0x78, 0x6e, 0x32, 0x35, 0x36) + o = (*z).Sha256Commitment.MarshalMsg(o) + } + } + return +} + +func (_ *TxnCommitments) CanMarshalMsg(z interface{}) bool { + _, ok := (z).(*TxnCommitments) + return ok +} + +// UnmarshalMsg implements msgp.Unmarshaler +func (z *TxnCommitments) UnmarshalMsg(bts []byte) (o []byte, err error) { + var field []byte + _ = field + var zb0001 int + var zb0002 bool + zb0001, zb0002, bts, err = msgp.ReadMapHeaderBytes(bts) + if _, ok := err.(msgp.TypeError); ok { + zb0001, zb0002, bts, err = msgp.ReadArrayHeaderBytes(bts) + if err != nil { + err = msgp.WrapError(err) + return + } + if zb0001 > 0 { + zb0001-- + bts, err = (*z).NativeSha512_256Commitment.UnmarshalMsg(bts) + if err != nil { + err = msgp.WrapError(err, "struct-from-array", "NativeSha512_256Commitment") + return + } + } + if zb0001 > 0 { + zb0001-- + bts, err = (*z).Sha256Commitment.UnmarshalMsg(bts) + if err != nil { + err = msgp.WrapError(err, "struct-from-array", "Sha256Commitment") + return + } + } + if zb0001 > 0 { + err = msgp.ErrTooManyArrayFields(zb0001) + if err != nil { + err = msgp.WrapError(err, "struct-from-array") + return + } + } + } else { + if err != nil { + err = msgp.WrapError(err) + return + } + if zb0002 { + (*z) = TxnCommitments{} + } + for zb0001 > 0 { + zb0001-- + field, bts, err = msgp.ReadMapKeyZC(bts) + if err != nil { + err = msgp.WrapError(err) + return + } + switch string(field) { + case "txn": + bts, err = (*z).NativeSha512_256Commitment.UnmarshalMsg(bts) + if err != nil { + err = msgp.WrapError(err, "NativeSha512_256Commitment") + return + } + case "txn256": + bts, err = (*z).Sha256Commitment.UnmarshalMsg(bts) + if err != nil { + err = msgp.WrapError(err, "Sha256Commitment") + return + } + default: + err = msgp.ErrNoField(string(field)) + if err != nil { + err = msgp.WrapError(err) + return + } + } + } + } + o = bts + return +} + +func (_ *TxnCommitments) CanUnmarshalMsg(z interface{}) bool { + _, ok := (z).(*TxnCommitments) + return ok +} + +// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message +func (z *TxnCommitments) Msgsize() (s int) { + s = 1 + 4 + (*z).NativeSha512_256Commitment.Msgsize() + 7 + (*z).Sha256Commitment.Msgsize() + return +} + +// MsgIsZero returns whether this is a zero value +func (z *TxnCommitments) MsgIsZero() bool { + return ((*z).NativeSha512_256Commitment.MsgIsZero()) && ((*z).Sha256Commitment.MsgIsZero()) +} + // MarshalMsg implements msgp.Marshaler func (z *UpgradeVote) MarshalMsg(b []byte) (o []byte) { o = msgp.Require(b, z.Msgsize()) diff --git a/data/bookkeeping/msgp_gen_test.go b/data/bookkeeping/msgp_gen_test.go index 8bad965935..cdf62e5c7a 100644 --- a/data/bookkeeping/msgp_gen_test.go +++ b/data/bookkeeping/msgp_gen_test.go @@ -1,3 +1,4 @@ +//go:build !skip_msgp_testing // +build !skip_msgp_testing package bookkeeping @@ -7,9 +8,10 @@ package bookkeeping import ( "testing" + "github.com/algorand/msgp/msgp" + "github.com/algorand/go-algorand/protocol" "github.com/algorand/go-algorand/test/partitiontest" - "github.com/algorand/msgp/msgp" ) func TestMarshalUnmarshalBlock(t *testing.T) { @@ -432,6 +434,66 @@ func BenchmarkUnmarshalRewardsState(b *testing.B) { } } +func TestMarshalUnmarshalTxnCommitments(t *testing.T) { + partitiontest.PartitionTest(t) + v := TxnCommitments{} + bts := v.MarshalMsg(nil) + left, err := v.UnmarshalMsg(bts) + if err != nil { + t.Fatal(err) + } + if len(left) > 0 { + t.Errorf("%d bytes left over after UnmarshalMsg(): %q", len(left), left) + } + + left, err = msgp.Skip(bts) + if err != nil { + t.Fatal(err) + } + if len(left) > 0 { + t.Errorf("%d bytes left over after Skip(): %q", len(left), left) + } +} + +func TestRandomizedEncodingTxnCommitments(t *testing.T) { + protocol.RunEncodingTest(t, &TxnCommitments{}) +} + +func BenchmarkMarshalMsgTxnCommitments(b *testing.B) { + v := TxnCommitments{} + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + v.MarshalMsg(nil) + } +} + +func BenchmarkAppendMsgTxnCommitments(b *testing.B) { + v := TxnCommitments{} + bts := make([]byte, 0, v.Msgsize()) + bts = v.MarshalMsg(bts[0:0]) + b.SetBytes(int64(len(bts))) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + bts = v.MarshalMsg(bts[0:0]) + } +} + +func BenchmarkUnmarshalTxnCommitments(b *testing.B) { + v := TxnCommitments{} + bts := v.MarshalMsg(nil) + b.ReportAllocs() + b.SetBytes(int64(len(bts))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := v.UnmarshalMsg(bts) + if err != nil { + b.Fatal(err) + } + } +} + func TestMarshalUnmarshalUpgradeVote(t *testing.T) { partitiontest.PartitionTest(t) v := UpgradeVote{} diff --git a/data/bookkeeping/txn_merkle.go b/data/bookkeeping/txn_merkle.go index 9a806708e3..cfaf95ad8d 100644 --- a/data/bookkeeping/txn_merkle.go +++ b/data/bookkeeping/txn_merkle.go @@ -31,13 +31,23 @@ import ( // header), or to generate proofs of membership for transactions that are // in this block. func (block Block) TxnMerkleTree() (*merklearray.Tree, error) { - return merklearray.Build(&txnMerkleArray{block: block}, crypto.HashFactory{HashType: crypto.Sha512_256}) + return merklearray.Build(&txnMerkleArray{block: block, hashType: crypto.Sha512_256}, crypto.HashFactory{HashType: crypto.Sha512_256}) +} + +// TxnMerkleTreeSHA256 returns a cryptographic commitment to the transactions in the +// block, along with their ApplyData, as a Merkle tree vector commitment, using SHA256. This allows the +// caller to either extract the root hash (for inclusion in the block +// header), or to generate proofs of membership for transactions that are +// in this block. +func (block Block) TxnMerkleTreeSHA256() (*merklearray.Tree, error) { + return merklearray.BuildVectorCommitmentTree(&txnMerkleArray{block: block, hashType: crypto.Sha256}, crypto.HashFactory{HashType: crypto.Sha256}) } // txnMerkleArray is a representation of the transactions in this block, // along with their ApplyData, as an array for the merklearray package. type txnMerkleArray struct { - block Block + block Block + hashType crypto.HashType } // Length implements the merklearray.Array interface. @@ -52,6 +62,7 @@ func (tma *txnMerkleArray) Marshal(pos uint64) (crypto.Hashable, error) { } var elem txnMerkleElem + elem.hashType = tma.hashType elem.stib = tma.block.Payset[pos] stxn, _, err := tma.block.DecodeSignedTxn(elem.stib) @@ -63,13 +74,6 @@ func (tma *txnMerkleArray) Marshal(pos uint64) (crypto.Hashable, error) { return &elem, nil } -// txnMerkleElem represents a leaf in the Merkle tree of all transactions -// in a block. -type txnMerkleElem struct { - txn transactions.Transaction - stib transactions.SignedTxnInBlock -} - func txnMerkleToRaw(txid [crypto.DigestSize]byte, stib [crypto.DigestSize]byte) (buf []byte) { buf = make([]byte, 2*crypto.DigestSize) copy(buf[:], txid[:]) @@ -77,14 +81,27 @@ func txnMerkleToRaw(txid [crypto.DigestSize]byte, stib [crypto.DigestSize]byte) return } +// txnMerkleElem represents a leaf in the Merkle tree of all transactions +// in a block. +type txnMerkleElem struct { + txn transactions.Transaction + stib transactions.SignedTxnInBlock + hashType crypto.HashType +} + +func (tme *txnMerkleElem) RawLeaf() []byte { + if tme.hashType == crypto.Sha512_256 { + return txnMerkleToRaw(tme.txn.ID(), tme.stib.Hash()) + } + // else: hashType == crypto.Sha256 + return txnMerkleToRaw(tme.txn.IDSha256(), tme.stib.HashSHA256()) +} + // ToBeHashed implements the crypto.Hashable interface. func (tme *txnMerkleElem) ToBeHashed() (protocol.HashID, []byte) { // The leaf contains two hashes: the transaction ID (hash of the // transaction itself), and the hash of the entire SignedTxnInBlock. - txid := tme.txn.ID() - stib := tme.stib.Hash() - - return protocol.TxnMerkleLeaf, txnMerkleToRaw(txid, stib) + return protocol.TxnMerkleLeaf, tme.RawLeaf() } // Hash implements an optimized version of crypto.HashObj(tme). @@ -93,12 +110,9 @@ func (tme *txnMerkleElem) Hash() crypto.Digest { } func (tme *txnMerkleElem) HashRepresentation() []byte { - txid := tme.txn.ID() - stib := tme.stib.Hash() - var buf [len(protocol.TxnMerkleLeaf) + 2*crypto.DigestSize]byte s := buf[:0] s = append(s, protocol.TxnMerkleLeaf...) - s = append(s, txnMerkleToRaw(txid, stib)...) + s = append(s, tme.RawLeaf()...) return s } diff --git a/data/bookkeeping/txn_merkle_test.go b/data/bookkeeping/txn_merkle_test.go index 2dabd07bd0..977af620d5 100644 --- a/data/bookkeeping/txn_merkle_test.go +++ b/data/bookkeeping/txn_merkle_test.go @@ -68,6 +68,7 @@ func TestTxnMerkle(t *testing.T) { b.Payset = append(b.Payset, stib) var e txnMerkleElem + e.hashType = crypto.Sha512_256 e.txn = txn e.stib = stib elems = append(elems, e) @@ -88,6 +89,57 @@ func TestTxnMerkle(t *testing.T) { } } +func TestBlock_TxnMerkleTreeSHA256(t *testing.T) { + partitiontest.PartitionTest(t) + + for ntxn := uint64(0); ntxn < 128; ntxn++ { + var b Block + b.CurrentProtocol = protocol.ConsensusFuture + crypto.RandBytes(b.BlockHeader.GenesisHash[:]) + + var elems []txnMerkleElem + + for i := uint64(0); i < ntxn; i++ { + txn := transactions.Transaction{ + Type: protocol.PaymentTx, + Header: transactions.Header{ + GenesisHash: b.BlockHeader.GenesisHash, + }, + PaymentTxnFields: transactions.PaymentTxnFields{ + Amount: basics.MicroAlgos{Raw: i}, + }, + } + + sigtxn := transactions.SignedTxn{Txn: txn} + ad := transactions.ApplyData{} + + stib, err := b.BlockHeader.EncodeSignedTxn(sigtxn, ad) + require.NoError(t, err) + + b.Payset = append(b.Payset, stib) + + var e txnMerkleElem + e.hashType = crypto.Sha256 + e.txn = txn + e.stib = stib + elems = append(elems, e) + } + + tree, err := b.TxnMerkleTreeSHA256() + require.NoError(t, err) + + root := tree.Root() + for i := uint64(0); i < ntxn; i++ { + proof, err := tree.Prove([]uint64{i}) + require.NoError(t, err) + elemVerif := make(map[uint64]crypto.Hashable) + elemVerif[i] = &elems[i] + err = merklearray.VerifyVectorCommitment(root, elemVerif, proof) + require.NoError(t, err) + } + } +} + func BenchmarkTxnRoots(b *testing.B) { var blk Block blk.CurrentProtocol = protocol.ConsensusCurrentVersion diff --git a/data/committee/msgp_gen_test.go b/data/committee/msgp_gen_test.go index 7a8946a6cb..fc6b79ce76 100644 --- a/data/committee/msgp_gen_test.go +++ b/data/committee/msgp_gen_test.go @@ -1,3 +1,4 @@ +//go:build !skip_msgp_testing // +build !skip_msgp_testing package committee @@ -7,9 +8,10 @@ package committee import ( "testing" + "github.com/algorand/msgp/msgp" + "github.com/algorand/go-algorand/protocol" "github.com/algorand/go-algorand/test/partitiontest" - "github.com/algorand/msgp/msgp" ) func TestMarshalUnmarshalCredential(t *testing.T) { diff --git a/data/hashable/msgp_gen_test.go b/data/hashable/msgp_gen_test.go index 131eaebe03..50178fac0e 100644 --- a/data/hashable/msgp_gen_test.go +++ b/data/hashable/msgp_gen_test.go @@ -1,3 +1,4 @@ +//go:build !skip_msgp_testing // +build !skip_msgp_testing package hashable @@ -7,9 +8,10 @@ package hashable import ( "testing" + "github.com/algorand/msgp/msgp" + "github.com/algorand/go-algorand/protocol" "github.com/algorand/go-algorand/test/partitiontest" - "github.com/algorand/msgp/msgp" ) func TestMarshalUnmarshalMessage(t *testing.T) { diff --git a/data/ledger_test.go b/data/ledger_test.go index 6af896e976..934fb4b6da 100644 --- a/data/ledger_test.go +++ b/data/ledger_test.go @@ -103,7 +103,7 @@ func testGenerateInitState(tb testing.TB, proto protocol.ConsensusVersion) (gene }, } var err error - initBlock.TxnRoot, err = initBlock.PaysetCommit() + initBlock.TxnCommitments, err = initBlock.PaysetCommit() require.NoError(tb, err) if params.SupportGenesisHash { initBlock.BlockHeader.GenesisHash = crypto.Hash([]byte(tb.Name())) @@ -658,7 +658,7 @@ func getEmptyBlock(afterRound basics.Round, l *ledger.Ledger, genesisID string, blk.FeeSink = testSinkAddr blk.CurrentProtocol = lastBlock.CurrentProtocol - blk.TxnRoot, err = blk.PaysetCommit() + blk.TxnCommitments, err = blk.PaysetCommit() if err != nil { return } diff --git a/data/pools/transactionPool_test.go b/data/pools/transactionPool_test.go index a16a7d30fa..2f1bd75b6c 100644 --- a/data/pools/transactionPool_test.go +++ b/data/pools/transactionPool_test.go @@ -80,7 +80,7 @@ func mockLedger(t TestingT, initAccounts map[basics.Address]basics.AccountData, } var err error - initBlock.TxnRoot, err = initBlock.PaysetCommit() + initBlock.TxnCommitments, err = initBlock.PaysetCommit() require.NoError(t, err) fn := fmt.Sprintf("/tmp/%s.%d.sqlite3", t.Name(), crypto.RandUint64()) diff --git a/data/transactions/logic/README.md b/data/transactions/logic/README.md index 96b771f7ca..44d68bd1ee 100644 --- a/data/transactions/logic/README.md +++ b/data/transactions/logic/README.md @@ -180,6 +180,9 @@ _available_. associated account of a contract that was created earlier in the group is _available_. + * Since v7, the account associated with any contract present in the + `txn.ForeignApplications` field is _available_. + ## Constants Constants can be pushed onto the stack in two different ways: @@ -273,6 +276,9 @@ return stack matches the name of the input value. | `ecdsa_verify v` | for (data A, signature B, C and pubkey D, E) verify the signature of the data against the pubkey => {0 or 1} | | `ecdsa_pk_recover v` | for (data A, recovery id B, signature C, D) recover a public key | | `ecdsa_pk_decompress v` | decompress pubkey A into components X, Y | +| `bn256_add` | for (curve points A and B) return the curve point A + B | +| `bn256_scalar_mul` | for (curve point A, scalar K) return the curve point KA | +| `bn256_pairing` | for (points in G1 group G1s, points in G2 group G2s), return whether they are paired => {0 or 1} | | `+` | A plus B. Fail on overflow. | | `-` | A minus B. Fail if B > A. | | `/` | A divided by B (truncated division). Fail if B == 0. | diff --git a/data/transactions/logic/README_in.md b/data/transactions/logic/README_in.md index 87b7c15d7e..8464ec2dc7 100644 --- a/data/transactions/logic/README_in.md +++ b/data/transactions/logic/README_in.md @@ -180,6 +180,9 @@ _available_. associated account of a contract that was created earlier in the group is _available_. + * Since v7, the account associated with any contract present in the + `txn.ForeignApplications` field is _available_. + ## Constants Constants can be pushed onto the stack in two different ways: diff --git a/data/transactions/logic/TEAL_opcodes.md b/data/transactions/logic/TEAL_opcodes.md index 5ac8198bcd..de7c8d8bdd 100644 --- a/data/transactions/logic/TEAL_opcodes.md +++ b/data/transactions/logic/TEAL_opcodes.md @@ -1097,6 +1097,36 @@ The notation A,B indicates that A and B are interpreted as a uint128 value, with - **Cost**: 130 - Availability: v7 +## bn256_add + +- Opcode: 0x99 +- Stack: ..., A: []byte, B: []byte → ..., []byte +- for (curve points A and B) return the curve point A + B +- **Cost**: 70 +- Availability: v7 + +A, B are curve points in G1 group. Each point consists of (X, Y) where X and Y are 256 bit integers, big-endian encoded. The encoded point is 64 bytes from concatenation of 32 byte X and 32 byte Y. + +## bn256_scalar_mul + +- Opcode: 0x9a +- Stack: ..., A: []byte, B: []byte → ..., []byte +- for (curve point A, scalar K) return the curve point KA +- **Cost**: 970 +- Availability: v7 + +A is a curve point in G1 Group and encoded as described in `bn256_add`. Scalar K is a big-endian encoded big integer that has no padding zeros. + +## bn256_pairing + +- Opcode: 0x9b +- Stack: ..., A: []byte, B: []byte → ..., uint64 +- for (points in G1 group G1s, points in G2 group G2s), return whether they are paired => {0 or 1} +- **Cost**: 8700 +- Availability: v7 + +G1s are encoded by the concatenation of encoded G1 points, as described in `bn256_add`. G2s are encoded by the concatenation of encoded G2 points. Each G2 is in form (XA0+i*XA1, YA0+i*YA1) and encoded by big-endian field element XA0, XA1, YA0 and YA1 in sequence. + ## b+ - Opcode: 0xa0 diff --git a/data/transactions/logic/assembler_test.go b/data/transactions/logic/assembler_test.go index 609366ed2d..8c719bbfe0 100644 --- a/data/transactions/logic/assembler_test.go +++ b/data/transactions/logic/assembler_test.go @@ -376,11 +376,18 @@ pushbytes 0x012345 dup dup ed25519verify_bare +pushbytes 0x012345 +dup +bn256_add +dup +bn256_scalar_mul +dup +bn256_pairing ` const v6Compiled = "2004010002b7a60c26050242420c68656c6c6f20776f726c6421070123456789abcd208dae2087fbba51304eb02b91f656948397a7946390e8cb70fc9ea4d95f92251d047465737400320032013202320380021234292929292b0431003101310231043105310731083109310a310b310c310d310e310f3111311231133114311533000033000133000233000433000533000733000833000933000a33000b33000c33000d33000e33000f3300113300123300133300143300152d2e01022581f8acd19181cf959a1281f8acd19181cf951a81f8acd19181cf1581f8acd191810f082209240a220b230c240d250e230f23102311231223132314181b1c28171615400003290349483403350222231d4a484848482b50512a632223524100034200004322602261222704634848222862482864286548482228246628226723286828692322700048482371004848361c0037001a0031183119311b311d311e311f312023221e312131223123312431253126312731283129312a312b312c312d312e312f447825225314225427042455220824564c4d4b0222382124391c0081e80780046a6f686e2281d00f23241f880003420001892224902291922494249593a0a1a2a3a4a5a6a7a8a9aaabacadae24af3a00003b003c003d816472064e014f012a57000823810858235b235a2359b03139330039b1b200b322c01a23c1001a2323c21a23c3233e233f8120af06002a494905002a49490700b53a03b6b7043cb8033a0c2349c42a9631007300810881088120978101c53a8101c6003a" -const v7Compiled = v6Compiled + "5c005d018120af060180070123456789abcd49490501988003012345494984" +const v7Compiled = v6Compiled + "5c005d018120af060180070123456789abcd4949050198800301234549498480030123454999499a499b" var nonsense = map[uint64]string{ 1: v1Nonsense, @@ -574,6 +581,7 @@ func testLine(t *testing.T, line string, ver uint64, expected string) { func TestAssembleTxna(t *testing.T) { partitiontest.PartitionTest(t) + t.Parallel() testLine(t, "txna Accounts 256", AssemblerMaxVersion, "txna i beyond 255: 256") testLine(t, "txna ApplicationArgs 256", AssemblerMaxVersion, "txna i beyond 255: 256") @@ -606,6 +614,7 @@ func TestAssembleTxna(t *testing.T) { func TestAssembleGlobal(t *testing.T) { partitiontest.PartitionTest(t) + t.Parallel() testLine(t, "global", AssemblerMaxVersion, "global expects 1 immediate argument") testLine(t, "global a", AssemblerMaxVersion, "global unknown field: \"a\"") @@ -619,6 +628,7 @@ func TestAssembleGlobal(t *testing.T) { func TestAssembleDefault(t *testing.T) { partitiontest.PartitionTest(t) + t.Parallel() source := `byte 0x1122334455 int 1 @@ -635,6 +645,7 @@ func mutateProgVersion(version uint64, prog string) string { func TestOpUint(t *testing.T) { partitiontest.PartitionTest(t) + t.Parallel() for v := uint64(1); v <= AssemblerMaxVersion; v++ { t.Run(fmt.Sprintf("v=%d", v), func(t *testing.T) { @@ -651,8 +662,8 @@ func TestOpUint(t *testing.T) { func TestOpUint64(t *testing.T) { partitiontest.PartitionTest(t) - t.Parallel() + for v := uint64(1); v <= AssemblerMaxVersion; v++ { t.Run(fmt.Sprintf("v=%d", v), func(t *testing.T) { t.Parallel() @@ -668,8 +679,8 @@ func TestOpUint64(t *testing.T) { func TestOpBytes(t *testing.T) { partitiontest.PartitionTest(t) - t.Parallel() + for v := uint64(1); v <= AssemblerMaxVersion; v++ { t.Run(fmt.Sprintf("v=%d", v), func(t *testing.T) { ops := newOpStream(v) @@ -684,7 +695,6 @@ func TestOpBytes(t *testing.T) { func TestAssembleInt(t *testing.T) { partitiontest.PartitionTest(t) - t.Parallel() expectedDefaultConsts := "012001bef5fad70c22" @@ -717,8 +727,8 @@ base64.b16encode(raw.encode()) func TestAssembleBytes(t *testing.T) { partitiontest.PartitionTest(t) - t.Parallel() + variations := []string{ "byte b32 MFRGGZDFMY", "byte base32 MFRGGZDFMY", @@ -776,6 +786,7 @@ func TestAssembleBytes(t *testing.T) { func TestAssembleBytesString(t *testing.T) { partitiontest.PartitionTest(t) + t.Parallel() for v := uint64(1); v <= AssemblerMaxVersion; v++ { t.Run(fmt.Sprintf("v=%d", v), func(t *testing.T) { @@ -787,7 +798,6 @@ func TestAssembleBytesString(t *testing.T) { func TestAssembleOptimizedConstants(t *testing.T) { partitiontest.PartitionTest(t) - t.Parallel() t.Run("Bytes", func(t *testing.T) { @@ -996,7 +1006,6 @@ bytec_1 // 0x0103 func TestAssembleOptimizedUint(t *testing.T) { partitiontest.PartitionTest(t) - t.Parallel() program := ` @@ -1020,6 +1029,7 @@ int ClearState func TestFieldsFromLine(t *testing.T) { partitiontest.PartitionTest(t) + t.Parallel() line := "op arg" fields := fieldsFromLine(line) @@ -1228,8 +1238,8 @@ func TestFieldsFromLine(t *testing.T) { func TestAssembleRejectNegJump(t *testing.T) { partitiontest.PartitionTest(t) - t.Parallel() + source := `wat: int 1 bnz wat @@ -1248,8 +1258,8 @@ int 2` func TestAssembleBase64(t *testing.T) { partitiontest.PartitionTest(t) - t.Parallel() + text := `byte base64 //GWRM+yy3BCavBDXO/FYTNZ6o2Jai5edsMCBdDEz+0= byte base64 avGWRM+yy3BCavBDXO/FYTNZ6o2Jai5edsMCBdDEz//= // @@ -1283,8 +1293,8 @@ byte b64 avGWRM+yy3BCavBDXO/FYTNZ6o2Jai5edsMCBdDEz//= func TestAssembleRejectUnkLabel(t *testing.T) { partitiontest.PartitionTest(t) - t.Parallel() + source := `int 1 bnz nowhere int 2` @@ -1297,8 +1307,8 @@ int 2` func TestAssembleJumpToTheEnd(t *testing.T) { partitiontest.PartitionTest(t) - t.Parallel() + source := `intcblock 1 intc 0 intc 0 @@ -1313,8 +1323,8 @@ done:` func TestMultipleErrors(t *testing.T) { partitiontest.PartitionTest(t) - t.Parallel() + source := `int 1 bnz nowhere // comment @@ -1331,9 +1341,9 @@ int 2` func TestAssembleDisassemble(t *testing.T) { partitiontest.PartitionTest(t) + t.Parallel() // Specifically constructed program text that should be recreated by Disassemble() - t.Parallel() text := fmt.Sprintf(`#pragma version %d intcblock 0 1 2 3 4 5 bytecblock 0xcafed00d 0x1337 0x68656c6c6f 0xdeadbeef 0x70077007 0x0102030405060708091011121314151617181920212223242526272829303132 @@ -1459,11 +1469,10 @@ itxn LastLog func TestAssembleDisassembleCycle(t *testing.T) { partitiontest.PartitionTest(t) + t.Parallel() // Test that disassembly re-assembles to the same program bytes. // Disassembly won't necessarily perfectly recreate the source text, but assembling the result of Disassemble() should be the same program bytes. - t.Parallel() - // This confirms that each program compiles to the same bytes // (except the leading version indicator), when compiled under // original version, unspecified version (so it should pick up @@ -1489,7 +1498,6 @@ func TestAssembleDisassembleCycle(t *testing.T) { func TestConstantDisassembly(t *testing.T) { partitiontest.PartitionTest(t) - t.Parallel() ops := testProg(t, "int 47", AssemblerMaxVersion) @@ -1522,6 +1530,7 @@ func TestConstantDisassembly(t *testing.T) { func TestConstantArgs(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() + for v := uint64(1); v <= AssemblerMaxVersion; v++ { testProg(t, "int", v, Expect{1, "int needs one argument"}) testProg(t, "intc", v, Expect{1, "intc operation needs one argument"}) @@ -1538,7 +1547,6 @@ func TestConstantArgs(t *testing.T) { func TestAssembleDisassembleErrors(t *testing.T) { partitiontest.PartitionTest(t) - t.Parallel() source := `txn Sender` @@ -1656,8 +1664,8 @@ func TestAssembleDisassembleErrors(t *testing.T) { func TestAssembleVersions(t *testing.T) { partitiontest.PartitionTest(t) - t.Parallel() + testLine(t, "txna Accounts 0", AssemblerMaxVersion, "") testLine(t, "txna Accounts 0", 2, "") testLine(t, "txna Accounts 0", 1, "txna opcode was introduced in TEAL v2") @@ -1665,7 +1673,6 @@ func TestAssembleVersions(t *testing.T) { func TestAssembleBalance(t *testing.T) { partitiontest.PartitionTest(t) - t.Parallel() source := `byte 0x00 @@ -1682,7 +1689,6 @@ int 1 func TestAssembleMinBalance(t *testing.T) { partitiontest.PartitionTest(t) - t.Parallel() source := `byte 0x00 @@ -1699,8 +1705,8 @@ int 1 func TestAssembleAsset(t *testing.T) { partitiontest.PartitionTest(t) - t.Parallel() + for v := uint64(2); v <= AssemblerMaxVersion; v++ { testProg(t, "asset_holding_get ABC 1", v, Expect{1, "asset_holding_get ABC 1 expects 2 stack arguments..."}) @@ -1729,7 +1735,6 @@ func TestAssembleAsset(t *testing.T) { func TestDisassembleSingleOp(t *testing.T) { partitiontest.PartitionTest(t) - t.Parallel() for v := uint64(1); v <= AssemblerMaxVersion; v++ { @@ -1746,8 +1751,8 @@ func TestDisassembleSingleOp(t *testing.T) { func TestDisassembleInt(t *testing.T) { partitiontest.PartitionTest(t) - t.Parallel() + txnSample := fmt.Sprintf("#pragma version %d\nint 17\nint 27\nint 37\nint 47\nint 5\nint 17\n", AssemblerMaxVersion) ops := testProg(t, txnSample, AssemblerMaxVersion) disassembled, err := Disassemble(ops.Program) @@ -1764,8 +1769,8 @@ func TestDisassembleInt(t *testing.T) { func TestDisassembleTxna(t *testing.T) { partitiontest.PartitionTest(t) - t.Parallel() + // txn was 1, but this tests both introduction := OpsByName[LogicVersion]["gtxna"].Version for v := introduction; v <= AssemblerMaxVersion; v++ { @@ -1793,8 +1798,8 @@ func TestDisassembleTxna(t *testing.T) { func TestDisassembleGtxna(t *testing.T) { partitiontest.PartitionTest(t) - t.Parallel() + // check gtxn and gtxna are properly disassembled introduction := OpsByName[LogicVersion]["gtxna"].Version @@ -1822,8 +1827,8 @@ func TestDisassembleGtxna(t *testing.T) { func TestDisassemblePushConst(t *testing.T) { partitiontest.PartitionTest(t) - t.Parallel() + // check pushint and pushbytes are properly disassembled intSample := fmt.Sprintf("#pragma version %d\npushint 1\n", AssemblerMaxVersion) expectedIntSample := intSample @@ -1852,7 +1857,6 @@ func TestDisassemblePushConst(t *testing.T) { func TestDisassembleLastLabel(t *testing.T) { partitiontest.PartitionTest(t) - t.Parallel() // starting from TEAL v2 branching to the last line are legal @@ -1875,8 +1879,8 @@ label1: func TestAssembleOffsets(t *testing.T) { partitiontest.PartitionTest(t) - t.Parallel() + source := "err" ops := testProg(t, source, AssemblerMaxVersion) require.Equal(t, 2, len(ops.Program)) @@ -1975,8 +1979,8 @@ err func TestHasStatefulOps(t *testing.T) { partitiontest.PartitionTest(t) - t.Parallel() + source := "int 1" ops, err := AssembleStringWithVersion(source, AssemblerMaxVersion) require.NoError(t, err) @@ -1998,8 +2002,8 @@ err func TestStringLiteralParsing(t *testing.T) { partitiontest.PartitionTest(t) - t.Parallel() + s := `"test"` e := []byte(`test`) result, err := parseStringLiteral(s) @@ -2095,8 +2099,8 @@ func TestStringLiteralParsing(t *testing.T) { func TestPragmas(t *testing.T) { partitiontest.PartitionTest(t) - t.Parallel() + for v := uint64(1); v <= AssemblerMaxVersion; v++ { text := fmt.Sprintf("#pragma version %d", v) ops := testProg(t, text, v) @@ -2162,8 +2166,8 @@ func TestPragmas(t *testing.T) { func TestAssemblePragmaVersion(t *testing.T) { partitiontest.PartitionTest(t) - t.Parallel() + text := `#pragma version 1 int 1 ` @@ -2216,8 +2220,8 @@ len func TestAssembleConstants(t *testing.T) { partitiontest.PartitionTest(t) - t.Parallel() + for v := uint64(1); v <= AssemblerMaxVersion; v++ { t.Run(fmt.Sprintf("v=%d", v), func(t *testing.T) { testLine(t, "intc 1", v, "intc 1 is not defined") @@ -2231,6 +2235,7 @@ func TestAssembleConstants(t *testing.T) { func TestErrShortBytecblock(t *testing.T) { partitiontest.PartitionTest(t) + t.Parallel() text := `intcblock 0x1234567812345678 0x1234567812345671 0x1234567812345672 0x1234567812345673 4 5 6 7 8` ops, err := AssembleStringWithVersion(text, 1) @@ -2246,6 +2251,7 @@ func TestErrShortBytecblock(t *testing.T) { func TestMethodWarning(t *testing.T) { partitiontest.PartitionTest(t) + t.Parallel() tests := []struct { method string @@ -2292,6 +2298,7 @@ func TestMethodWarning(t *testing.T) { func TestBranchAssemblyTypeCheck(t *testing.T) { partitiontest.PartitionTest(t) + t.Parallel() text := ` int 0 // current app id [0] @@ -2326,6 +2333,7 @@ flip: // [x] func TestSwapTypeCheck(t *testing.T) { partitiontest.PartitionTest(t) t.Parallel() + /* reconfirm that we detect this type error */ testProg(t, "int 1; byte 0x1234; +", AssemblerMaxVersion, Expect{3, "+ arg 1..."}) /* despite swap, we track types */ @@ -2424,6 +2432,8 @@ func TestTxTypes(t *testing.T) { } func TestBadInnerFields(t *testing.T) { + partitiontest.PartitionTest(t) + t.Parallel() testProg(t, "itxn_begin; int 1000; itxn_field FirstValid", 5, Expect{3, "...is not allowed."}) testProg(t, "itxn_begin; int 1000; itxn_field FirstValidTime", 5, Expect{3, "...is not allowed."}) testProg(t, "itxn_begin; int 1000; itxn_field LastValid", 5, Expect{3, "...is not allowed."}) diff --git a/data/transactions/logic/doc.go b/data/transactions/logic/doc.go index fdad625488..a8badee03f 100644 --- a/data/transactions/logic/doc.go +++ b/data/transactions/logic/doc.go @@ -32,6 +32,9 @@ var opDocByName = map[string]string{ "ecdsa_verify": "for (data A, signature B, C and pubkey D, E) verify the signature of the data against the pubkey => {0 or 1}", "ecdsa_pk_decompress": "decompress pubkey A into components X, Y", "ecdsa_pk_recover": "for (data A, recovery id B, signature C, D) recover a public key", + "bn256_add": "for (curve points A and B) return the curve point A + B", + "bn256_scalar_mul": "for (curve point A, scalar K) return the curve point KA", + "bn256_pairing": "for (points in G1 group G1s, points in G2 group G2s), return whether they are paired => {0 or 1}", "+": "A plus B. Fail on overflow.", "-": "A minus B. Fail if B > A.", @@ -262,6 +265,9 @@ var opDocExtras = map[string]string{ "ecdsa_verify": "The 32 byte Y-component of a public key is the last element on the stack, preceded by X-component of a pubkey, preceded by S and R components of a signature, preceded by the data that is fifth element on the stack. All values are big-endian encoded. The signed data must be 32 bytes long, and signatures in lower-S form are only accepted.", "ecdsa_pk_decompress": "The 33 byte public key in a compressed form to be decompressed into X and Y (top) components. All values are big-endian encoded.", "ecdsa_pk_recover": "S (top) and R elements of a signature, recovery id and data (bottom) are expected on the stack and used to deriver a public key. All values are big-endian encoded. The signed data must be 32 bytes long.", + "bn256_add": "A, B are curve points in G1 group. Each point consists of (X, Y) where X and Y are 256 bit integers, big-endian encoded. The encoded point is 64 bytes from concatenation of 32 byte X and 32 byte Y.", + "bn256_scalar_mul": "A is a curve point in G1 Group and encoded as described in `bn256_add`. Scalar K is a big-endian encoded big integer that has no padding zeros.", + "bn256_pairing": "G1s are encoded by the concatenation of encoded G1 points, as described in `bn256_add`. G2s are encoded by the concatenation of encoded G2 points. Each G2 is in form (XA0+i*XA1, YA0+i*YA1) and encoded by big-endian field element XA0, XA1, YA0 and YA1 in sequence.", "bnz": "The `bnz` instruction opcode 0x40 is followed by two immediate data bytes which are a high byte first and low byte second which together form a 16 bit offset which the instruction may branch to. For a bnz instruction at `pc`, if the last element of the stack is not zero then branch to instruction at `pc + 3 + N`, else proceed to next instruction at `pc + 3`. Branch targets must be aligned instructions. (e.g. Branching to the second byte of a 2 byte op will be rejected.) Starting at v4, the offset is treated as a signed 16 bit integer allowing for backward branches and looping. In prior version (v1 to v3), branch offsets are limited to forward branches only, 0-0x7fff.\n\nAt v2 it became allowed to branch to the end of the program exactly after the last instruction: bnz to byte N (with 0-indexing) was illegal for a TEAL program with N bytes before v2, and is legal after it. This change eliminates the need for a last instruction of no-op as a branch target at the end. (Branching beyond the end--in other words, to a byte larger than N--is still illegal and will cause the program to fail.)", "bz": "See `bnz` for details on how branches work. `bz` inverts the behavior of `bnz`.", "b": "See `bnz` for details on how branches work. `b` always jumps to the offset.", @@ -319,7 +325,7 @@ func OpDocExtra(opName string) string { // here is the order args opcodes are presented, so place related // opcodes consecutively, even if their opcode values are not. var OpGroups = map[string][]string{ - "Arithmetic": {"sha256", "keccak256", "sha512_256", "sha3_256", "ed25519verify", "ed25519verify_bare", "ecdsa_verify", "ecdsa_pk_recover", "ecdsa_pk_decompress", "+", "-", "/", "*", "<", ">", "<=", ">=", "&&", "||", "shl", "shr", "sqrt", "bitlen", "exp", "==", "!=", "!", "len", "itob", "btoi", "%", "|", "&", "^", "~", "mulw", "addw", "divw", "divmodw", "expw", "getbit", "setbit", "getbyte", "setbyte", "concat"}, + "Arithmetic": {"sha256", "keccak256", "sha512_256", "sha3_256", "ed25519verify", "ed25519verify_bare", "ecdsa_verify", "ecdsa_pk_recover", "ecdsa_pk_decompress", "bn256_add", "bn256_scalar_mul", "bn256_pairing", "+", "-", "/", "*", "<", ">", "<=", ">=", "&&", "||", "shl", "shr", "sqrt", "bitlen", "exp", "==", "!=", "!", "len", "itob", "btoi", "%", "|", "&", "^", "~", "mulw", "addw", "divw", "divmodw", "expw", "getbit", "setbit", "getbyte", "setbyte", "concat"}, "Byte Array Manipulation": {"substring", "substring3", "extract", "extract3", "extract_uint16", "extract_uint32", "extract_uint64", "base64_decode", "json_ref"}, "Byte Array Arithmetic": {"b+", "b-", "b/", "b*", "b<", "b>", "b<=", "b>=", "b==", "b!=", "b%", "bsqrt"}, "Byte Array Logic": {"b|", "b&", "b^", "b~"}, diff --git a/data/transactions/logic/eval.go b/data/transactions/logic/eval.go index 3a38c58876..f55b61bc93 100644 --- a/data/transactions/logic/eval.go +++ b/data/transactions/logic/eval.go @@ -271,7 +271,8 @@ type EvalParams struct { // Cache the txid hashing, but do *not* share this into inner EvalParams, as // the key is just the index in the txgroup. - txidCache map[int]transactions.Txid + txidCache map[int]transactions.Txid + innerTxidCache map[int]transactions.Txid // The calling context, if this is an inner app call caller *EvalContext @@ -2185,23 +2186,84 @@ func TxnFieldToTealValue(txn *transactions.Transaction, groupIndex int, field Tx return sv.toTealValue(), err } -func (cx *EvalContext) getTxID(txn *transactions.Transaction, groupIndex int) transactions.Txid { +// currentTxID is a convenience method to get the Txid for the txn being evaluated +func (cx *EvalContext) currentTxID() transactions.Txid { + if cx.Proto.UnifyInnerTxIDs { + // can't just return cx.txn.ID() because I might be an inner txn + return cx.getTxID(&cx.txn.Txn, cx.groupIndex, false) + } + + // original behavior, for backwards comatability + return cx.txn.ID() +} + +// getTxIDNotUnified is a backwards-compatible getTxID used when the consensus param UnifyInnerTxIDs +// is false. DO NOT call directly, and DO NOT change its behavior +func (cx *EvalContext) getTxIDNotUnified(txn *transactions.Transaction, groupIndex int) transactions.Txid { + if cx.EvalParams.txidCache == nil { + cx.EvalParams.txidCache = make(map[int]transactions.Txid, len(cx.TxnGroup)) + } + + txid, ok := cx.EvalParams.txidCache[groupIndex] + if !ok { + if cx.caller != nil { + innerOffset := len(cx.caller.txn.EvalDelta.InnerTxns) + txid = txn.InnerID(cx.caller.txn.ID(), innerOffset+groupIndex) + } else { + txid = txn.ID() + } + cx.EvalParams.txidCache[groupIndex] = txid + } + + return txid +} + +func (cx *EvalContext) getTxID(txn *transactions.Transaction, groupIndex int, inner bool) transactions.Txid { + // inner indicates that groupIndex is an index into the most recent inner txn group + if cx.EvalParams == nil { // Special case, called through TxnFieldToTealValue. No EvalParams, no caching. return txn.ID() } + if !cx.Proto.UnifyInnerTxIDs { + // original behavior, for backwards comatability + return cx.getTxIDNotUnified(txn, groupIndex) + } + + if inner { + // Initialize innerTxidCache if necessary + if cx.EvalParams.innerTxidCache == nil { + cx.EvalParams.innerTxidCache = make(map[int]transactions.Txid) + } + + txid, ok := cx.EvalParams.innerTxidCache[groupIndex] + if !ok { + // We're referencing an inner and the current txn is the parent + myTxid := cx.currentTxID() + lastGroupLen := len(cx.getLastInnerGroup()) + // innerIndex is the referenced inner txn's index in cx.txn.EvalDelta.InnerTxns + innerIndex := len(cx.txn.EvalDelta.InnerTxns) - lastGroupLen + groupIndex + txid = txn.InnerID(myTxid, innerIndex) + cx.EvalParams.innerTxidCache[groupIndex] = txid + } + + return txid + } + // Initialize txidCache if necessary if cx.EvalParams.txidCache == nil { cx.EvalParams.txidCache = make(map[int]transactions.Txid, len(cx.TxnGroup)) } - // Hashes are expensive, so we cache computed TxIDs txid, ok := cx.EvalParams.txidCache[groupIndex] if !ok { if cx.caller != nil { - innerOffset := len(cx.caller.txn.EvalDelta.InnerTxns) - txid = txn.InnerID(cx.caller.txn.ID(), innerOffset+groupIndex) + // We're referencing a peer txn, not my inner, but I am an inner + parentTxid := cx.caller.currentTxID() + innerIndex := len(cx.caller.txn.EvalDelta.InnerTxns) + groupIndex + txid = txn.InnerID(parentTxid, innerIndex) } else { + // We're referencing a peer txn and I am not an inner txid = txn.ID() } cx.EvalParams.txidCache[groupIndex] = txid @@ -2276,7 +2338,7 @@ func (cx *EvalContext) txnFieldToStack(stxn *transactions.SignedTxnWithAD, fs *t case GroupIndex: sv.Uint = uint64(groupIndex) case TxID: - txid := cx.getTxID(txn, groupIndex) + txid := cx.getTxID(txn, groupIndex, inner) sv.Bytes = txid[:] case Lease: sv.Bytes = txn.Lease[:] @@ -3462,12 +3524,12 @@ func opExtract64Bits(cx *EvalContext) error { } // accountReference yields the address and Accounts offset designated by a -// stackValue. If the stackValue is the app account or an account of an app in -// created.apps, and it is not be in the Accounts array, then len(Accounts) + 1 -// is returned as the index. This would let us catch the mistake if the index is -// used for set/del. If the txn somehow "psychically" predicted the address, and -// therefore it IS in txn.Accounts, then happy day, we can set/del it. Return -// the proper index. +// stackValue. If the stackValue is the app account, an account of an app in +// created.apps, or an account of an app in foreignApps, and it is not in the +// Accounts array, then len(Accounts) + 1 is returned as the index. This would +// let us catch the mistake if the index is used for set/del. If the txn somehow +// "psychically" predicted the address, and therefore it IS in txn.Accounts, +// then happy day, we can set/del it. Return the proper index. // If we ever want apps to be able to change local state on these accounts // (which includes this app's own account!), we will need a change to @@ -3496,6 +3558,16 @@ func (cx *EvalContext) accountReference(account stackValue) (basics.Address, uin } } + // Allow an address for an app that was provided in the foreign apps array. + if err != nil && cx.version >= appAddressAvailableVersion { + for _, appID := range cx.txn.Txn.ForeignApps { + foreignAddress := cx.getApplicationAddress(appID) + if addr == foreignAddress { + return addr, invalidIndex, nil + } + } + } + // this app's address is also allowed if err != nil { appAddr := cx.getApplicationAddress(cx.appID) @@ -4495,7 +4567,7 @@ func opItxnSubmit(cx *EvalContext) error { var parent transactions.Txid isGroup := len(cx.subtxns) > 1 if isGroup { - parent = cx.txn.ID() + parent = cx.currentTxID() } for itx := range cx.subtxns { // The goal is to follow the same invariants used by the @@ -4579,6 +4651,9 @@ func opItxnSubmit(cx *EvalContext) error { if isGroup { innerOffset := len(cx.txn.EvalDelta.InnerTxns) + if cx.Proto.UnifyInnerTxIDs { + innerOffset += itx + } group.TxGroupHashes = append(group.TxGroupHashes, crypto.Digest(cx.subtxns[itx].Txn.InnerID(parent, innerOffset))) } @@ -4609,6 +4684,8 @@ func opItxnSubmit(cx *EvalContext) error { } cx.txn.EvalDelta.InnerTxns = append(cx.txn.EvalDelta.InnerTxns, ep.TxnGroup...) cx.subtxns = nil + // must clear the inner txid cache, otherwise prior inner txids will be returned for this group + cx.innerTxidCache = nil return nil } @@ -4649,6 +4726,21 @@ func base64Decode(encoded []byte, encoding *base64.Encoding) ([]byte, error) { return decoded[:n], err } +// base64padded returns true iff `encoded` has padding chars at the end +func base64padded(encoded []byte) bool { + for i := len(encoded) - 1; i > 0; i-- { + switch encoded[i] { + case '=': + return true + case '\n', '\r': + /* nothing */ + default: + return false + } + } + return false +} + func opBase64Decode(cx *EvalContext) error { last := len(cx.stack) - 1 encodingField := Base64Encoding(cx.program[cx.pc+1]) @@ -4661,8 +4753,11 @@ func opBase64Decode(cx *EvalContext) error { if encodingField == StdEncoding { encoding = base64.StdEncoding } - encoding = encoding.Strict() - bytes, err := base64Decode(cx.stack[last].Bytes, encoding) + encoded := cx.stack[last].Bytes + if !base64padded(encoded) { + encoding = encoding.WithPadding(base64.NoPadding) + } + bytes, err := base64Decode(encoded, encoding.Strict()) if err != nil { return err } diff --git a/data/transactions/logic/evalAppTxn_test.go b/data/transactions/logic/evalAppTxn_test.go index 2ccd94e3e7..f1ae3c40df 100644 --- a/data/transactions/logic/evalAppTxn_test.go +++ b/data/transactions/logic/evalAppTxn_test.go @@ -22,6 +22,7 @@ import ( "strings" "testing" + "github.com/algorand/go-algorand/crypto" "github.com/algorand/go-algorand/data/basics" "github.com/algorand/go-algorand/data/transactions" . "github.com/algorand/go-algorand/data/transactions/logic" @@ -1276,16 +1277,81 @@ func TestInnerTxIDs(t *testing.T) { itxn_begin int appl; itxn_field TypeEnum int 222; itxn_field ApplicationID -itxn_submit; +itxn_submit + +itxn TxID +itxn Logs 0 +== + itxn Logs 0 itxn_begin int appl; itxn_field TypeEnum int 222; itxn_field ApplicationID -itxn_submit; +itxn_submit + +itxn Logs 0 +!= +&& + +itxn TxID itxn Logs 0 +== +&& +`, ep) + + TestApp(t, ` +itxn_begin +int appl; itxn_field TypeEnum +int 222; itxn_field ApplicationID +itxn_next +int appl; itxn_field TypeEnum +int 222; itxn_field ApplicationID +itxn_submit + +gitxn 0 Logs 0 +gitxn 1 Logs 0 +!= + +gitxn 0 Logs 0 +gitxn 0 TxID +== +&& + +gitxn 1 Logs 0 +gitxn 1 TxID +== +&& + +gitxn 1 Logs 0 +gitxn 0 Logs 0 +itxn_begin +int appl; itxn_field TypeEnum +int 222; itxn_field ApplicationID +itxn_next +int appl; itxn_field TypeEnum +int 222; itxn_field ApplicationID +itxn_submit + +gitxn 0 Logs 0 +!= + +gitxn 1 Logs 0 +uncover 2 != +&& +&& + +gitxn 0 Logs 0 +gitxn 0 TxID +== +&& + +gitxn 1 Logs 0 +gitxn 1 TxID +== +&& `, ep) } @@ -1352,6 +1418,834 @@ itxn Logs 0 `, ep) } +// TestTxIDAndGroupIDCalculation tests that the TxIDs reported with `txn TxID` and group IDs +// reported with `global GroupID` are correct for top-level and inner transactions +func TestTxIDAndGroupIDCalculation(t *testing.T) { + partitiontest.PartitionTest(t) + t.Parallel() + + withoutGroupID := func(txn transactions.Transaction) transactions.Transaction { + txn.Group = crypto.Digest{} + return txn + } + + type actualInfo struct { + txn transactions.Transaction + claimedTxID []byte + claimedGroup []byte + } + + type expectedInfo struct { + expectedTxID transactions.Txid + expectedGroup crypto.Digest + } + + // this test performs a 3-level fanout of transactions: + // + // Parent + // ├─ Child A + // │ ├── atomic group + // │ ├─ Grandchild A-A + // │ ├─ Grandchild A-B + // │ ├── atomic group + // │ ├─ Grandchild A-C + // │ ├─ Grandchild A-D + // ├─ Child B + // │ ├── atomic group + // │ ├─ Grandchild B-A + // │ ├─ Grandchild B-B + // │ ├── atomic group + // │ ├─ Grandchild B-C + // │ ├─ Grandchild B-D + // + // When linearized, we use the following breadth-first search ordering: + // Parent, Child A, Child B, Grandchild A-A, Grandchild A-B, Grandchild A-C, Grandchild A-D, + // Grandchild B-A, Grandchild B-B, Grandchild B-C, Grandchild B-D + + // verifyTxIDs takes the linear ordering of transactions and their claimed TxIDs and GroupIDs in + // the txnInfo array and verifies that the claimed IDs are correct + verifyTxIDs := func(t *testing.T, unified bool, actual [11]actualInfo) { + parentIndex := 0 + childAIndex := 1 + childBIndex := 2 + grandchildAAIndex := 3 + grandchildABIndex := 4 + grandchildACIndex := 5 + grandchildADIndex := 6 + grandchildBAIndex := 7 + grandchildBBIndex := 8 + grandchildBCIndex := 9 + grandchildBDIndex := 10 + + var expected [11]expectedInfo + + parentTxID := actual[parentIndex].txn.ID() + require.Equal(t, transactions.Txid{0x7c, 0x68, 0xa2, 0xfd, 0xcc, 0xd4, 0x1b, 0x17, 0xc4, 0xc1, 0x8a, 0x2, 0xf6, 0x2f, 0x6a, 0x85, 0xce, 0x7a, 0x71, 0xe0, 0x60, 0x9a, 0xb9, 0x85, 0xa2, 0x39, 0xc7, 0x78, 0x83, 0x41, 0xf2, 0x2}, parentTxID) + expected[parentIndex].expectedTxID = parentTxID + + childAtxn := actual[childAIndex].txn + childAtxid := childAtxn.InnerID(parentTxID, 0) + require.Equal(t, transactions.Txid{0x6f, 0x8, 0xf1, 0x5f, 0xfc, 0xa5, 0x4a, 0x58, 0x6c, 0xc0, 0x80, 0x13, 0xb4, 0xb4, 0x4c, 0x19, 0x68, 0x5a, 0x66, 0xfc, 0xef, 0xe2, 0xed, 0x3c, 0xbd, 0xd5, 0x54, 0x8c, 0xb9, 0x28, 0xd0, 0x72}, childAtxid) + expected[childAIndex].expectedTxID = childAtxid + + childBtxn := actual[childBIndex].txn + childBtxid := childBtxn.InnerID(parentTxID, 1) + require.Equal(t, transactions.Txid{0xcc, 0x6f, 0x61, 0xbd, 0xd5, 0x76, 0x92, 0xa0, 0x56, 0x8d, 0x45, 0xbc, 0x2c, 0x95, 0x9d, 0xe4, 0x41, 0x29, 0x2d, 0x9c, 0xd1, 0x4, 0xbb, 0xa7, 0x52, 0x63, 0x9a, 0xe3, 0x22, 0xa9, 0xf0, 0xc5}, childBtxid) + expected[childBIndex].expectedTxID = childBtxid + + var gcAAtxid, gcABtxid, gcACtxid, gcADtxid, gcBAtxid, gcBBtxid, gcBCtxid, gcBDtxid transactions.Txid + var gcAABgroup, gcACDgroup, gcBABgroup, gcBCDgroup crypto.Digest + + if unified { + gcAAtxid = actual[grandchildAAIndex].txn.InnerID(childAtxid, 0) + require.Equal(t, transactions.Txid{0x6a, 0xef, 0x5f, 0x69, 0x2b, 0xce, 0xfc, 0x5b, 0x43, 0xa, 0x23, 0x79, 0x52, 0x49, 0xc7, 0x40, 0x66, 0x29, 0xf0, 0xbe, 0x4, 0x48, 0xe4, 0x55, 0x48, 0x8, 0x53, 0xdc, 0xb, 0x8c, 0x22, 0x48}, gcAAtxid) + gcABtxid = actual[grandchildABIndex].txn.InnerID(childAtxid, 1) + require.Equal(t, transactions.Txid{0xd4, 0x5d, 0xf0, 0xd8, 0x24, 0x15, 0x75, 0xfc, 0xea, 0x1d, 0x5f, 0x60, 0xd4, 0x77, 0x94, 0xe4, 0xb8, 0x48, 0xbd, 0x40, 0x2d, 0xf2, 0x82, 0x8d, 0x88, 0xd5, 0xaf, 0xd0, 0xa3, 0x29, 0x63, 0xd3}, gcABtxid) + gcAABgroup = crypto.HashObj(transactions.TxGroup{ + TxGroupHashes: []crypto.Digest{ + crypto.Digest(withoutGroupID(actual[grandchildAAIndex].txn).InnerID(childAtxid, 0)), + crypto.Digest(withoutGroupID(actual[grandchildABIndex].txn).InnerID(childAtxid, 1)), + }, + }) + require.Equal(t, crypto.Digest{0xb4, 0x0, 0x71, 0x2a, 0xee, 0x7f, 0x4, 0x20, 0x55, 0xf8, 0xf9, 0x8f, 0xaf, 0x12, 0x82, 0x57, 0x2, 0x45, 0xe9, 0x16, 0x45, 0x22, 0xc3, 0x22, 0xfb, 0x1a, 0x23, 0x4d, 0x78, 0xfe, 0xa1, 0x42}, gcAABgroup) + + gcACtxid = actual[grandchildACIndex].txn.InnerID(childAtxid, 2) + require.Equal(t, transactions.Txid{0xb3, 0xb1, 0xac, 0xbe, 0x41, 0x5, 0x32, 0x9f, 0x8d, 0x22, 0x5, 0x5, 0xfe, 0x2d, 0x3, 0xb5, 0x7e, 0xcd, 0x8e, 0xbc, 0x8d, 0xf, 0x63, 0x89, 0xca, 0xa7, 0xe1, 0xdf, 0x82, 0x89, 0xd0, 0x71}, gcACtxid) + gcADtxid = actual[grandchildADIndex].txn.InnerID(childAtxid, 3) + require.Equal(t, transactions.Txid{0xc6, 0x8, 0x14, 0xd, 0x8f, 0xf0, 0xcf, 0xb1, 0xf4, 0x52, 0xb0, 0x3f, 0xd9, 0x15, 0x28, 0xba, 0x1c, 0xed, 0xb6, 0x8c, 0x62, 0x5e, 0x5e, 0x77, 0xde, 0xd, 0xdc, 0x26, 0xc7, 0x80, 0xbe, 0x82}, gcADtxid) + gcACDgroup = crypto.HashObj(transactions.TxGroup{ + TxGroupHashes: []crypto.Digest{ + crypto.Digest(withoutGroupID(actual[grandchildACIndex].txn).InnerID(childAtxid, 2)), + crypto.Digest(withoutGroupID(actual[grandchildADIndex].txn).InnerID(childAtxid, 3)), + }, + }) + require.Equal(t, crypto.Digest{0x45, 0xce, 0x49, 0xe6, 0xa6, 0xbe, 0xa7, 0x4d, 0xb1, 0x66, 0x5d, 0xaa, 0xf6, 0xf0, 0xda, 0x78, 0x77, 0x3d, 0x6f, 0x97, 0x65, 0xd7, 0x27, 0x1, 0x82, 0x6a, 0x2c, 0xe0, 0x4c, 0xd8, 0x3b, 0x2}, gcACDgroup) + + gcBAtxid = actual[grandchildBAIndex].txn.InnerID(childBtxid, 0) + require.Equal(t, transactions.Txid{0x13, 0x3c, 0x92, 0xab, 0x12, 0xee, 0x1c, 0xf0, 0x24, 0xd1, 0x76, 0x2e, 0x7a, 0x56, 0xcb, 0xef, 0x45, 0x19, 0x42, 0xce, 0xe5, 0x6f, 0xbc, 0xaa, 0xb3, 0x17, 0x5e, 0x59, 0x18, 0x64, 0x9e, 0xe4}, gcBAtxid) + gcBBtxid = actual[grandchildBBIndex].txn.InnerID(childBtxid, 1) + require.Equal(t, transactions.Txid{0x6c, 0x44, 0x79, 0x59, 0x22, 0x51, 0x5a, 0x79, 0xfe, 0xd3, 0x7c, 0xbc, 0xc4, 0x68, 0xac, 0x32, 0x77, 0x61, 0x89, 0xd0, 0xbb, 0xbd, 0xaa, 0x8d, 0xeb, 0xd4, 0x2, 0xe8, 0xd6, 0x45, 0x50, 0xf6}, gcBBtxid) + gcBABgroup = crypto.HashObj(transactions.TxGroup{ + TxGroupHashes: []crypto.Digest{ + crypto.Digest(withoutGroupID(actual[grandchildBAIndex].txn).InnerID(childBtxid, 0)), + crypto.Digest(withoutGroupID(actual[grandchildBBIndex].txn).InnerID(childBtxid, 1)), + }, + }) + require.Equal(t, crypto.Digest{0x48, 0x7c, 0x9, 0x76, 0xbc, 0x43, 0x65, 0x7a, 0x1d, 0xdc, 0xfb, 0x68, 0x47, 0x12, 0x8b, 0x80, 0xd2, 0xdd, 0xff, 0x22, 0x1b, 0xe1, 0x89, 0xcc, 0xb5, 0xb3, 0x94, 0xa4, 0x49, 0x63, 0xd8, 0x10}, gcBABgroup) + + gcBCtxid = actual[grandchildBCIndex].txn.InnerID(childBtxid, 2) + require.Equal(t, transactions.Txid{0x77, 0x48, 0x58, 0x4d, 0x94, 0x14, 0x7a, 0xf3, 0x75, 0x7f, 0x1e, 0x4d, 0xd5, 0x8, 0x21, 0x55, 0x47, 0x69, 0x67, 0x59, 0xd2, 0x48, 0xe6, 0x92, 0x1b, 0xf5, 0xae, 0x1, 0x10, 0xbe, 0x29, 0x5a}, gcBCtxid) + gcBDtxid = actual[grandchildBDIndex].txn.InnerID(childBtxid, 3) + require.Equal(t, transactions.Txid{0xcd, 0x15, 0x47, 0x3f, 0x42, 0xf5, 0x9c, 0x4a, 0x11, 0xa4, 0xe3, 0x92, 0x30, 0xf, 0x97, 0x1d, 0x3b, 0x1, 0x7, 0xbc, 0x1f, 0x3f, 0xcc, 0x9d, 0x43, 0x5b, 0xb2, 0xa4, 0x15, 0x8b, 0x89, 0x4e}, gcBDtxid) + gcBCDgroup = crypto.HashObj(transactions.TxGroup{ + TxGroupHashes: []crypto.Digest{ + crypto.Digest(withoutGroupID(actual[grandchildBCIndex].txn).InnerID(childBtxid, 2)), + crypto.Digest(withoutGroupID(actual[grandchildBDIndex].txn).InnerID(childBtxid, 3)), + }, + }) + require.Equal(t, crypto.Digest{0x96, 0x90, 0x1, 0x64, 0x24, 0xa5, 0xda, 0x4, 0x3d, 0xd, 0x40, 0xc9, 0xf6, 0xfa, 0xc3, 0xa6, 0x26, 0x19, 0xd3, 0xf0, 0xb7, 0x28, 0x87, 0xf8, 0x5a, 0xd1, 0xa7, 0xbc, 0x1d, 0xad, 0x8b, 0xfc}, gcBCDgroup) + } else { + // these calculations are "wrong," but they're here to maintain backwards compatability with the original implementation + + gcAAtxid = actual[grandchildAAIndex].txn.InnerID(childAtxn.ID(), 0) + require.Equal(t, transactions.Txid{0xb5, 0xa, 0x16, 0x90, 0x78, 0x21, 0xf6, 0x96, 0x1b, 0x9c, 0x72, 0x5e, 0xf4, 0x8b, 0xe7, 0xb8, 0x2b, 0xd, 0x74, 0xd4, 0x71, 0xa2, 0x43, 0xb0, 0xfc, 0x19, 0xbc, 0x1c, 0xda, 0x95, 0x8f, 0xd0}, gcAAtxid) + gcABtxid = actual[grandchildABIndex].txn.InnerID(childAtxn.ID(), 1) + require.Equal(t, transactions.Txid{0xb3, 0x9, 0x9e, 0x95, 0x79, 0xe4, 0xe4, 0x58, 0xed, 0xee, 0x1b, 0xdb, 0x21, 0x7, 0x0, 0x7b, 0x35, 0xfc, 0x19, 0xef, 0xd6, 0x61, 0xde, 0x9b, 0xf3, 0x1b, 0x4a, 0x84, 0xa, 0xa, 0x7, 0x42}, gcABtxid) + gcAABgroup = crypto.HashObj(transactions.TxGroup{ + TxGroupHashes: []crypto.Digest{ + crypto.Digest(withoutGroupID(actual[grandchildAAIndex].txn).InnerID(childAtxn.ID(), 0)), + crypto.Digest(withoutGroupID(actual[grandchildABIndex].txn).InnerID(childAtxn.ID(), 0)), + }, + }) + require.Equal(t, crypto.Digest{0xbc, 0xd8, 0xa1, 0xff, 0x96, 0xd4, 0x2b, 0x39, 0xc3, 0x1e, 0x9b, 0x26, 0xf3, 0xc, 0x78, 0x18, 0x83, 0x40, 0xe0, 0xf0, 0xa5, 0xeb, 0xc3, 0x63, 0xc8, 0xac, 0xec, 0xdb, 0x1, 0x36, 0xf9, 0xa}, gcAABgroup) + + gcACtxid = actual[grandchildACIndex].txn.InnerID(childAtxn.ID(), 2) + require.Equal(t, transactions.Txid{0xf5, 0x62, 0x52, 0xc, 0xe7, 0x4b, 0x49, 0x11, 0xd9, 0x96, 0xdb, 0x7b, 0xdc, 0x43, 0xf0, 0x89, 0x82, 0x65, 0xa9, 0x40, 0xc1, 0x1b, 0x6a, 0x5, 0x50, 0xd6, 0x96, 0x29, 0x6d, 0xe8, 0x23, 0x21}, gcACtxid) + gcADtxid = actual[grandchildADIndex].txn.InnerID(childAtxn.ID(), 3) + require.Equal(t, transactions.Txid{0xb2, 0x0, 0x9c, 0xae, 0x29, 0x18, 0x71, 0x19, 0xa1, 0xae, 0x82, 0x4a, 0x1d, 0xb2, 0x75, 0xaa, 0xe7, 0xbc, 0x1f, 0xcd, 0xd3, 0x9e, 0x48, 0xbb, 0x57, 0xc7, 0xbc, 0xf3, 0xab, 0xba, 0xf8, 0x3e}, gcADtxid) + gcACDgroup = crypto.HashObj(transactions.TxGroup{ + TxGroupHashes: []crypto.Digest{ + crypto.Digest(withoutGroupID(actual[grandchildACIndex].txn).InnerID(childAtxn.ID(), 2)), + crypto.Digest(withoutGroupID(actual[grandchildADIndex].txn).InnerID(childAtxn.ID(), 2)), + }, + }) + require.Equal(t, crypto.Digest{0x72, 0x6d, 0xad, 0x41, 0x1c, 0x6b, 0x71, 0x1d, 0x4a, 0xe8, 0xf8, 0x82, 0x7, 0xf6, 0x37, 0xb9, 0x5d, 0x80, 0xc7, 0xf8, 0x86, 0x2d, 0xd5, 0xa1, 0x16, 0x29, 0x77, 0xc9, 0x44, 0xf7, 0x0, 0xb2}, gcACDgroup) + + gcBAtxid = actual[grandchildBAIndex].txn.InnerID(childBtxn.ID(), 0) + require.Equal(t, transactions.Txid{0xb5, 0xa, 0x16, 0x90, 0x78, 0x21, 0xf6, 0x96, 0x1b, 0x9c, 0x72, 0x5e, 0xf4, 0x8b, 0xe7, 0xb8, 0x2b, 0xd, 0x74, 0xd4, 0x71, 0xa2, 0x43, 0xb0, 0xfc, 0x19, 0xbc, 0x1c, 0xda, 0x95, 0x8f, 0xd0}, gcBAtxid) + gcBBtxid = actual[grandchildBBIndex].txn.InnerID(childBtxn.ID(), 1) + require.Equal(t, transactions.Txid{0xb3, 0x9, 0x9e, 0x95, 0x79, 0xe4, 0xe4, 0x58, 0xed, 0xee, 0x1b, 0xdb, 0x21, 0x7, 0x0, 0x7b, 0x35, 0xfc, 0x19, 0xef, 0xd6, 0x61, 0xde, 0x9b, 0xf3, 0x1b, 0x4a, 0x84, 0xa, 0xa, 0x7, 0x42}, gcBBtxid) + gcBABgroup = crypto.HashObj(transactions.TxGroup{ + TxGroupHashes: []crypto.Digest{ + crypto.Digest(withoutGroupID(actual[grandchildBAIndex].txn).InnerID(childBtxn.ID(), 0)), + crypto.Digest(withoutGroupID(actual[grandchildBBIndex].txn).InnerID(childBtxn.ID(), 0)), + }, + }) + require.Equal(t, crypto.Digest{0xbc, 0xd8, 0xa1, 0xff, 0x96, 0xd4, 0x2b, 0x39, 0xc3, 0x1e, 0x9b, 0x26, 0xf3, 0xc, 0x78, 0x18, 0x83, 0x40, 0xe0, 0xf0, 0xa5, 0xeb, 0xc3, 0x63, 0xc8, 0xac, 0xec, 0xdb, 0x1, 0x36, 0xf9, 0xa}, gcBABgroup) + + gcBCtxid = actual[grandchildBCIndex].txn.InnerID(childBtxn.ID(), 2) + require.Equal(t, transactions.Txid{0xf5, 0x62, 0x52, 0xc, 0xe7, 0x4b, 0x49, 0x11, 0xd9, 0x96, 0xdb, 0x7b, 0xdc, 0x43, 0xf0, 0x89, 0x82, 0x65, 0xa9, 0x40, 0xc1, 0x1b, 0x6a, 0x5, 0x50, 0xd6, 0x96, 0x29, 0x6d, 0xe8, 0x23, 0x21}, gcBCtxid) + gcBDtxid = actual[grandchildBDIndex].txn.InnerID(childBtxn.ID(), 3) + require.Equal(t, transactions.Txid{0xb2, 0x0, 0x9c, 0xae, 0x29, 0x18, 0x71, 0x19, 0xa1, 0xae, 0x82, 0x4a, 0x1d, 0xb2, 0x75, 0xaa, 0xe7, 0xbc, 0x1f, 0xcd, 0xd3, 0x9e, 0x48, 0xbb, 0x57, 0xc7, 0xbc, 0xf3, 0xab, 0xba, 0xf8, 0x3e}, gcBDtxid) + gcBCDgroup = crypto.HashObj(transactions.TxGroup{ + TxGroupHashes: []crypto.Digest{ + crypto.Digest(withoutGroupID(actual[grandchildBCIndex].txn).InnerID(childBtxn.ID(), 2)), + crypto.Digest(withoutGroupID(actual[grandchildBDIndex].txn).InnerID(childBtxn.ID(), 2)), + }, + }) + require.Equal(t, crypto.Digest{0x72, 0x6d, 0xad, 0x41, 0x1c, 0x6b, 0x71, 0x1d, 0x4a, 0xe8, 0xf8, 0x82, 0x7, 0xf6, 0x37, 0xb9, 0x5d, 0x80, 0xc7, 0xf8, 0x86, 0x2d, 0xd5, 0xa1, 0x16, 0x29, 0x77, 0xc9, 0x44, 0xf7, 0x0, 0xb2}, gcBCDgroup) + } + + expected[grandchildAAIndex] = expectedInfo{ + expectedTxID: gcAAtxid, + expectedGroup: gcAABgroup, + } + expected[grandchildABIndex] = expectedInfo{ + expectedTxID: gcABtxid, + expectedGroup: gcAABgroup, + } + expected[grandchildACIndex] = expectedInfo{ + expectedTxID: gcACtxid, + expectedGroup: gcACDgroup, + } + expected[grandchildADIndex] = expectedInfo{ + expectedTxID: gcADtxid, + expectedGroup: gcACDgroup, + } + expected[grandchildBAIndex] = expectedInfo{ + expectedTxID: gcBAtxid, + expectedGroup: gcBABgroup, + } + expected[grandchildBBIndex] = expectedInfo{ + expectedTxID: gcBBtxid, + expectedGroup: gcBABgroup, + } + expected[grandchildBCIndex] = expectedInfo{ + expectedTxID: gcBCtxid, + expectedGroup: gcBCDgroup, + } + expected[grandchildBDIndex] = expectedInfo{ + expectedTxID: gcBDtxid, + expectedGroup: gcBCDgroup, + } + + for i := range actual { + require.Equal(t, expected[i].expectedTxID[:], actual[i].claimedTxID, fmt.Sprintf("index=%d", i)) + require.Equal(t, expected[i].expectedGroup[:], actual[i].claimedGroup, fmt.Sprintf("index=%d", i)) + require.Equal(t, expected[i].expectedGroup, actual[i].txn.Group, fmt.Sprintf("index=%d", i)) + } + } + + parentAppID := basics.AppIndex(888) + childAppID := basics.AppIndex(222) + grandchildAppID := basics.AppIndex(333) + + grandchildSource := ` +txn TxID +log + +global GroupID +log + +int 1 +` + + childSource := ` +txn TxID +log + +global GroupID +log + +itxn_begin +int appl; itxn_field TypeEnum +int 333; itxn_field ApplicationID +itxn_next +int appl; itxn_field TypeEnum +int 333; itxn_field ApplicationID +itxn_submit + +itxn_begin +int appl; itxn_field TypeEnum +int 333; itxn_field ApplicationID +itxn_next +int appl; itxn_field TypeEnum +int 333; itxn_field ApplicationID +itxn_submit + +int 1 +` + + parentSource := ` +txn TxID +log + +global GroupID +log + +itxn_begin +int appl; itxn_field TypeEnum +int 222; itxn_field ApplicationID +int 333; itxn_field Applications +itxn_submit + +itxn_begin +int appl; itxn_field TypeEnum +int 222; itxn_field ApplicationID +int 333; itxn_field Applications +itxn_submit + +int 1 +` + + for _, unified := range []bool{true, false} { + t.Run(fmt.Sprintf("unified=%t", unified), func(t *testing.T) { + t.Parallel() + + ep, parentTx, ledger := MakeSampleEnv() + ep.Proto.UnifyInnerTxIDs = unified + + parentTx.ApplicationID = parentAppID + parentTx.ForeignApps = []basics.AppIndex{ + childAppID, + grandchildAppID, + } + + grandchild := TestProg(t, grandchildSource, AssemblerMaxVersion) + ledger.NewApp(parentTx.Receiver, grandchildAppID, basics.AppParams{ + ApprovalProgram: grandchild.Program, + }) + + child := TestProg(t, childSource, AssemblerMaxVersion) + ledger.NewApp(parentTx.Receiver, childAppID, basics.AppParams{ + ApprovalProgram: child.Program, + }) + ledger.NewAccount(childAppID.Address(), 50_000) + + ledger.NewApp(parentTx.Receiver, parentAppID, basics.AppParams{}) + ledger.NewAccount(parentAppID.Address(), 50_000) + + parentEd := TestApp(t, parentSource, ep) + + require.Len(t, parentEd.Logs, 2) + require.Len(t, parentEd.InnerTxns, 2) + + childA := parentEd.InnerTxns[0] + require.Len(t, childA.EvalDelta.Logs, 2) + require.Len(t, childA.EvalDelta.InnerTxns, 4) + + childB := parentEd.InnerTxns[1] + require.Len(t, childB.EvalDelta.Logs, 2) + require.Len(t, childB.EvalDelta.InnerTxns, 4) + + gcAA := childA.EvalDelta.InnerTxns[0] + require.Len(t, gcAA.EvalDelta.Logs, 2) + require.Len(t, gcAA.EvalDelta.InnerTxns, 0) + + gcAB := childA.EvalDelta.InnerTxns[1] + require.Len(t, gcAB.EvalDelta.Logs, 2) + require.Len(t, gcAB.EvalDelta.InnerTxns, 0) + + gcAC := childA.EvalDelta.InnerTxns[2] + require.Len(t, gcAC.EvalDelta.Logs, 2) + require.Len(t, gcAC.EvalDelta.InnerTxns, 0) + + gcAD := childA.EvalDelta.InnerTxns[3] + require.Len(t, gcAD.EvalDelta.Logs, 2) + require.Len(t, gcAD.EvalDelta.InnerTxns, 0) + + gcBA := childB.EvalDelta.InnerTxns[0] + require.Len(t, gcBA.EvalDelta.Logs, 2) + require.Len(t, gcBA.EvalDelta.InnerTxns, 0) + + gcBB := childB.EvalDelta.InnerTxns[1] + require.Len(t, gcBB.EvalDelta.Logs, 2) + require.Len(t, gcBB.EvalDelta.InnerTxns, 0) + + gcBC := childB.EvalDelta.InnerTxns[2] + require.Len(t, gcBC.EvalDelta.Logs, 2) + require.Len(t, gcBC.EvalDelta.InnerTxns, 0) + + gcBD := childB.EvalDelta.InnerTxns[3] + require.Len(t, gcBD.EvalDelta.Logs, 2) + require.Len(t, gcBD.EvalDelta.InnerTxns, 0) + + toVerify := [...]actualInfo{ + { + txn: *parentTx, + claimedTxID: []byte(parentEd.Logs[0]), + claimedGroup: []byte(parentEd.Logs[1]), + }, + { + txn: childA.Txn, + claimedTxID: []byte(childA.EvalDelta.Logs[0]), + claimedGroup: []byte(childA.EvalDelta.Logs[1]), + }, + { + txn: childB.Txn, + claimedTxID: []byte(childB.EvalDelta.Logs[0]), + claimedGroup: []byte(childB.EvalDelta.Logs[1]), + }, + { + txn: gcAA.Txn, + claimedTxID: []byte(gcAA.EvalDelta.Logs[0]), + claimedGroup: []byte(gcAA.EvalDelta.Logs[1]), + }, + { + txn: gcAB.Txn, + claimedTxID: []byte(gcAB.EvalDelta.Logs[0]), + claimedGroup: []byte(gcAB.EvalDelta.Logs[1]), + }, + { + txn: gcAC.Txn, + claimedTxID: []byte(gcAC.EvalDelta.Logs[0]), + claimedGroup: []byte(gcAC.EvalDelta.Logs[1]), + }, + { + txn: gcAD.Txn, + claimedTxID: []byte(gcAD.EvalDelta.Logs[0]), + claimedGroup: []byte(gcAD.EvalDelta.Logs[1]), + }, + { + txn: gcBA.Txn, + claimedTxID: []byte(gcBA.EvalDelta.Logs[0]), + claimedGroup: []byte(gcBA.EvalDelta.Logs[1]), + }, + { + txn: gcBB.Txn, + claimedTxID: []byte(gcBB.EvalDelta.Logs[0]), + claimedGroup: []byte(gcBB.EvalDelta.Logs[1]), + }, + { + txn: gcBC.Txn, + claimedTxID: []byte(gcBC.EvalDelta.Logs[0]), + claimedGroup: []byte(gcBC.EvalDelta.Logs[1]), + }, + { + txn: gcBD.Txn, + claimedTxID: []byte(gcBD.EvalDelta.Logs[0]), + claimedGroup: []byte(gcBD.EvalDelta.Logs[1]), + }, + } + + verifyTxIDs(t, unified, toVerify) + }) + } +} + +// TestInnerTxIDCalculation tests that the TxIDs reported with `itxn TxID` and `gitxn X TxID` are +// correct for inner transactions +func TestInnerTxIDCalculation(t *testing.T) { + partitiontest.PartitionTest(t) + t.Parallel() + + type actualInfo struct { + txn transactions.Transaction + claimedTxID []byte + } + + // this test performs a 3-level fanout of transactions: + // + // Parent + // ├─ Child A + // │ ├── atomic group + // │ ├─ Grandchild A-A + // │ ├─ Grandchild A-B + // │ ├── atomic group + // │ ├─ Grandchild A-C + // │ ├─ Grandchild A-D + // ├─ Child B + // │ ├── atomic group + // │ ├─ Grandchild B-A + // │ ├─ Grandchild B-B + // │ ├── atomic group + // │ ├─ Grandchild B-C + // │ ├─ Grandchild B-D + // + // When linearized, we use the following breadth-first search ordering: + // Parent, Child A, Child B, Grandchild A-A, Grandchild A-B, Grandchild A-C, Grandchild A-D, + // Grandchild B-A, Grandchild B-B, Grandchild B-C, Grandchild B-D + + // verifyTxIDs takes the linear ordering of transactions and their claimed TxIDs in the txnInfo + // array and verifies that the claimed IDs are correct + verifyTxIDs := func(t *testing.T, unified bool, actual [11]actualInfo) { + parentIndex := 0 + childAIndex := 1 + childBIndex := 2 + grandchildAAIndex := 3 + grandchildABIndex := 4 + grandchildACIndex := 5 + grandchildADIndex := 6 + grandchildBAIndex := 7 + grandchildBBIndex := 8 + grandchildBCIndex := 9 + grandchildBDIndex := 10 + + var expected [11]transactions.Txid + + parentTxID := actual[parentIndex].txn.ID() + require.Equal(t, transactions.Txid{0x7c, 0x68, 0xa2, 0xfd, 0xcc, 0xd4, 0x1b, 0x17, 0xc4, 0xc1, 0x8a, 0x2, 0xf6, 0x2f, 0x6a, 0x85, 0xce, 0x7a, 0x71, 0xe0, 0x60, 0x9a, 0xb9, 0x85, 0xa2, 0x39, 0xc7, 0x78, 0x83, 0x41, 0xf2, 0x2}, parentTxID) + // leave expected[parentIndex] as the zero value since we don't want to test it + + childAtxn := actual[childAIndex].txn + childBtxn := actual[childBIndex].txn + + var childAtxid, childBtxid, gcAAtxid, gcABtxid, gcACtxid, gcADtxid, gcBAtxid, gcBBtxid, gcBCtxid, gcBDtxid transactions.Txid + + if unified { + childAtxid = childAtxn.InnerID(parentTxID, 0) + require.Equal(t, transactions.Txid{0x6f, 0x8, 0xf1, 0x5f, 0xfc, 0xa5, 0x4a, 0x58, 0x6c, 0xc0, 0x80, 0x13, 0xb4, 0xb4, 0x4c, 0x19, 0x68, 0x5a, 0x66, 0xfc, 0xef, 0xe2, 0xed, 0x3c, 0xbd, 0xd5, 0x54, 0x8c, 0xb9, 0x28, 0xd0, 0x72}, childAtxid) + childBtxid = childBtxn.InnerID(parentTxID, 1) + require.Equal(t, transactions.Txid{0xcc, 0x6f, 0x61, 0xbd, 0xd5, 0x76, 0x92, 0xa0, 0x56, 0x8d, 0x45, 0xbc, 0x2c, 0x95, 0x9d, 0xe4, 0x41, 0x29, 0x2d, 0x9c, 0xd1, 0x4, 0xbb, 0xa7, 0x52, 0x63, 0x9a, 0xe3, 0x22, 0xa9, 0xf0, 0xc5}, childBtxid) + + gcAAtxid = actual[grandchildAAIndex].txn.InnerID(childAtxid, 0) + require.Equal(t, transactions.Txid{0x6a, 0xef, 0x5f, 0x69, 0x2b, 0xce, 0xfc, 0x5b, 0x43, 0xa, 0x23, 0x79, 0x52, 0x49, 0xc7, 0x40, 0x66, 0x29, 0xf0, 0xbe, 0x4, 0x48, 0xe4, 0x55, 0x48, 0x8, 0x53, 0xdc, 0xb, 0x8c, 0x22, 0x48}, gcAAtxid) + gcABtxid = actual[grandchildABIndex].txn.InnerID(childAtxid, 1) + require.Equal(t, transactions.Txid{0xd4, 0x5d, 0xf0, 0xd8, 0x24, 0x15, 0x75, 0xfc, 0xea, 0x1d, 0x5f, 0x60, 0xd4, 0x77, 0x94, 0xe4, 0xb8, 0x48, 0xbd, 0x40, 0x2d, 0xf2, 0x82, 0x8d, 0x88, 0xd5, 0xaf, 0xd0, 0xa3, 0x29, 0x63, 0xd3}, gcABtxid) + + gcACtxid = actual[grandchildACIndex].txn.InnerID(childAtxid, 2) + require.Equal(t, transactions.Txid{0xb3, 0xb1, 0xac, 0xbe, 0x41, 0x5, 0x32, 0x9f, 0x8d, 0x22, 0x5, 0x5, 0xfe, 0x2d, 0x3, 0xb5, 0x7e, 0xcd, 0x8e, 0xbc, 0x8d, 0xf, 0x63, 0x89, 0xca, 0xa7, 0xe1, 0xdf, 0x82, 0x89, 0xd0, 0x71}, gcACtxid) + gcADtxid = actual[grandchildADIndex].txn.InnerID(childAtxid, 3) + require.Equal(t, transactions.Txid{0xc6, 0x8, 0x14, 0xd, 0x8f, 0xf0, 0xcf, 0xb1, 0xf4, 0x52, 0xb0, 0x3f, 0xd9, 0x15, 0x28, 0xba, 0x1c, 0xed, 0xb6, 0x8c, 0x62, 0x5e, 0x5e, 0x77, 0xde, 0xd, 0xdc, 0x26, 0xc7, 0x80, 0xbe, 0x82}, gcADtxid) + + gcBAtxid = actual[grandchildBAIndex].txn.InnerID(childBtxid, 0) + require.Equal(t, transactions.Txid{0x13, 0x3c, 0x92, 0xab, 0x12, 0xee, 0x1c, 0xf0, 0x24, 0xd1, 0x76, 0x2e, 0x7a, 0x56, 0xcb, 0xef, 0x45, 0x19, 0x42, 0xce, 0xe5, 0x6f, 0xbc, 0xaa, 0xb3, 0x17, 0x5e, 0x59, 0x18, 0x64, 0x9e, 0xe4}, gcBAtxid) + gcBBtxid = actual[grandchildBBIndex].txn.InnerID(childBtxid, 1) + require.Equal(t, transactions.Txid{0x6c, 0x44, 0x79, 0x59, 0x22, 0x51, 0x5a, 0x79, 0xfe, 0xd3, 0x7c, 0xbc, 0xc4, 0x68, 0xac, 0x32, 0x77, 0x61, 0x89, 0xd0, 0xbb, 0xbd, 0xaa, 0x8d, 0xeb, 0xd4, 0x2, 0xe8, 0xd6, 0x45, 0x50, 0xf6}, gcBBtxid) + + gcBCtxid = actual[grandchildBCIndex].txn.InnerID(childBtxid, 2) + require.Equal(t, transactions.Txid{0x77, 0x48, 0x58, 0x4d, 0x94, 0x14, 0x7a, 0xf3, 0x75, 0x7f, 0x1e, 0x4d, 0xd5, 0x8, 0x21, 0x55, 0x47, 0x69, 0x67, 0x59, 0xd2, 0x48, 0xe6, 0x92, 0x1b, 0xf5, 0xae, 0x1, 0x10, 0xbe, 0x29, 0x5a}, gcBCtxid) + gcBDtxid = actual[grandchildBDIndex].txn.InnerID(childBtxid, 3) + require.Equal(t, transactions.Txid{0xcd, 0x15, 0x47, 0x3f, 0x42, 0xf5, 0x9c, 0x4a, 0x11, 0xa4, 0xe3, 0x92, 0x30, 0xf, 0x97, 0x1d, 0x3b, 0x1, 0x7, 0xbc, 0x1f, 0x3f, 0xcc, 0x9d, 0x43, 0x5b, 0xb2, 0xa4, 0x15, 0x8b, 0x89, 0x4e}, gcBDtxid) + } else { + // these calculations are "wrong," but they're here to maintain backwards compatability with the original implementation + + childAtxid = childAtxn.ID() + require.Equal(t, transactions.Txid{0xc9, 0xa4, 0x41, 0xff, 0x9c, 0x62, 0x40, 0x6e, 0x63, 0xd9, 0x5, 0x19, 0x3b, 0x32, 0x43, 0x3d, 0xba, 0x80, 0x9f, 0xa3, 0xe4, 0xed, 0x2f, 0xa4, 0x19, 0x2b, 0x3f, 0x21, 0x96, 0xe2, 0xec, 0x21}, childAtxid) + childBtxid = childBtxn.ID() + require.Equal(t, transactions.Txid{0xc9, 0xa4, 0x41, 0xff, 0x9c, 0x62, 0x40, 0x6e, 0x63, 0xd9, 0x5, 0x19, 0x3b, 0x32, 0x43, 0x3d, 0xba, 0x80, 0x9f, 0xa3, 0xe4, 0xed, 0x2f, 0xa4, 0x19, 0x2b, 0x3f, 0x21, 0x96, 0xe2, 0xec, 0x21}, childBtxid) + + gcAAtxid = actual[grandchildAAIndex].txn.InnerID(parentTxID, 0) + require.Equal(t, transactions.Txid{0x9e, 0xfb, 0xb7, 0x5f, 0x2b, 0x9a, 0x59, 0x5f, 0xce, 0x3c, 0x90, 0x60, 0x66, 0x40, 0x4e, 0x80, 0x81, 0x90, 0x79, 0x51, 0xd2, 0x8f, 0xfe, 0xbf, 0x71, 0x76, 0x23, 0xc8, 0xd8, 0xb0, 0x28, 0x7d}, gcAAtxid) + gcABtxid = actual[grandchildABIndex].txn.InnerID(parentTxID, 1) + require.Equal(t, transactions.Txid{0x91, 0x9d, 0xdc, 0x8, 0xde, 0x4e, 0x86, 0xe8, 0xba, 0xa3, 0x2, 0xf6, 0x7, 0xe9, 0x1a, 0x6, 0x63, 0xe9, 0x46, 0xa8, 0xe4, 0xa1, 0x3e, 0xd3, 0x3e, 0xa4, 0x5c, 0xcb, 0xc0, 0xc5, 0x40, 0x55}, gcABtxid) + + // because of caching, these are the same :( + gcACtxid = gcAAtxid + gcADtxid = gcABtxid + + gcBAtxid = actual[grandchildBAIndex].txn.InnerID(parentTxID, 1) + require.Equal(t, transactions.Txid{0x91, 0x9d, 0xdc, 0x8, 0xde, 0x4e, 0x86, 0xe8, 0xba, 0xa3, 0x2, 0xf6, 0x7, 0xe9, 0x1a, 0x6, 0x63, 0xe9, 0x46, 0xa8, 0xe4, 0xa1, 0x3e, 0xd3, 0x3e, 0xa4, 0x5c, 0xcb, 0xc0, 0xc5, 0x40, 0x55}, gcBAtxid) + gcBBtxid = actual[grandchildBBIndex].txn.InnerID(parentTxID, 2) + require.Equal(t, transactions.Txid{0xa6, 0x90, 0x75, 0xf9, 0x20, 0x15, 0xd7, 0xf5, 0xa2, 0xca, 0xaa, 0x4b, 0x55, 0xdf, 0x8e, 0xa9, 0x97, 0xd8, 0x62, 0xc9, 0xb8, 0xdf, 0xc2, 0x8f, 0x9c, 0x60, 0x67, 0x2a, 0xdb, 0x27, 0xaa, 0x4d}, gcBBtxid) + + gcBCtxid = gcBAtxid + gcBDtxid = gcBBtxid + } + + expected[childBIndex] = childBtxid + expected[childAIndex] = childAtxid + expected[grandchildAAIndex] = gcAAtxid + expected[grandchildABIndex] = gcABtxid + expected[grandchildACIndex] = gcACtxid + expected[grandchildADIndex] = gcADtxid + expected[grandchildBAIndex] = gcBAtxid + expected[grandchildBBIndex] = gcBBtxid + expected[grandchildBCIndex] = gcBCtxid + expected[grandchildBDIndex] = gcBDtxid + + for i := range actual { + if i == 0 { + // don't test parent TxID + continue + } + require.Equal(t, expected[i][:], actual[i].claimedTxID, fmt.Sprintf("index=%d", i)) + } + } + + parentAppID := basics.AppIndex(888) + childAppID := basics.AppIndex(222) + grandchildAppID := basics.AppIndex(333) + + grandchildSource := "int 1" + childSource := ` +itxn_begin +int appl; itxn_field TypeEnum +int 333; itxn_field ApplicationID +itxn_next +int appl; itxn_field TypeEnum +int 333; itxn_field ApplicationID +itxn_submit + +gitxn 0 TxID +log +gitxn 1 TxID +log + +itxn_begin +int appl; itxn_field TypeEnum +int 333; itxn_field ApplicationID +itxn_next +int appl; itxn_field TypeEnum +int 333; itxn_field ApplicationID +itxn_submit + +gitxn 0 TxID +log +gitxn 1 TxID +log + +int 1 +` + parentSource := ` +itxn_begin +int appl; itxn_field TypeEnum +int 222; itxn_field ApplicationID +int 333; itxn_field Applications +itxn_submit + +itxn TxID +log + +itxn_begin +int appl; itxn_field TypeEnum +int 222; itxn_field ApplicationID +int 333; itxn_field Applications +itxn_submit + +itxn TxID +log + +int 1 +` + + for _, unified := range []bool{true, false} { + t.Run(fmt.Sprintf("unified=%t", unified), func(t *testing.T) { + t.Parallel() + + ep, parentTx, ledger := MakeSampleEnv() + ep.Proto.UnifyInnerTxIDs = unified + + parentTx.ApplicationID = parentAppID + parentTx.ForeignApps = []basics.AppIndex{ + childAppID, + grandchildAppID, + } + + grandchild := TestProg(t, grandchildSource, AssemblerMaxVersion) + ledger.NewApp(parentTx.Receiver, grandchildAppID, basics.AppParams{ + ApprovalProgram: grandchild.Program, + }) + + child := TestProg(t, childSource, AssemblerMaxVersion) + ledger.NewApp(parentTx.Receiver, childAppID, basics.AppParams{ + ApprovalProgram: child.Program, + }) + ledger.NewAccount(childAppID.Address(), 50_000) + + ledger.NewApp(parentTx.Receiver, parentAppID, basics.AppParams{}) + ledger.NewAccount(parentAppID.Address(), 50_000) + + parentEd := TestApp(t, parentSource, ep) + + require.Len(t, parentEd.Logs, 2) + require.Len(t, parentEd.InnerTxns, 2) + + childA := parentEd.InnerTxns[0] + require.Len(t, childA.EvalDelta.Logs, 4) + require.Len(t, childA.EvalDelta.InnerTxns, 4) + + childB := parentEd.InnerTxns[1] + require.Len(t, childB.EvalDelta.Logs, 4) + require.Len(t, childB.EvalDelta.InnerTxns, 4) + + gcAA := childA.EvalDelta.InnerTxns[0] + require.Len(t, gcAA.EvalDelta.Logs, 0) + require.Len(t, gcAA.EvalDelta.InnerTxns, 0) + + gcAB := childA.EvalDelta.InnerTxns[1] + require.Len(t, gcAB.EvalDelta.Logs, 0) + require.Len(t, gcAB.EvalDelta.InnerTxns, 0) + + gcAC := childA.EvalDelta.InnerTxns[2] + require.Len(t, gcAC.EvalDelta.Logs, 0) + require.Len(t, gcAC.EvalDelta.InnerTxns, 0) + + gcAD := childA.EvalDelta.InnerTxns[3] + require.Len(t, gcAD.EvalDelta.Logs, 0) + require.Len(t, gcAD.EvalDelta.InnerTxns, 0) + + gcBA := childB.EvalDelta.InnerTxns[0] + require.Len(t, gcBA.EvalDelta.Logs, 0) + require.Len(t, gcBA.EvalDelta.InnerTxns, 0) + + gcBB := childB.EvalDelta.InnerTxns[1] + require.Len(t, gcBB.EvalDelta.Logs, 0) + require.Len(t, gcBB.EvalDelta.InnerTxns, 0) + + gcBC := childB.EvalDelta.InnerTxns[2] + require.Len(t, gcBC.EvalDelta.Logs, 0) + require.Len(t, gcBC.EvalDelta.InnerTxns, 0) + + gcBD := childB.EvalDelta.InnerTxns[3] + require.Len(t, gcBD.EvalDelta.Logs, 0) + require.Len(t, gcBD.EvalDelta.InnerTxns, 0) + + toVerify := [...]actualInfo{ + { + txn: *parentTx, + // leave claimedTxID as the zero value since we don't want to test it + }, + { + txn: childA.Txn, + claimedTxID: []byte(parentEd.Logs[0]), + }, + { + txn: childB.Txn, + claimedTxID: []byte(parentEd.Logs[1]), + }, + { + txn: gcAA.Txn, + claimedTxID: []byte(childA.EvalDelta.Logs[0]), + }, + { + txn: gcAB.Txn, + claimedTxID: []byte(childA.EvalDelta.Logs[1]), + }, + { + txn: gcAC.Txn, + claimedTxID: []byte(childA.EvalDelta.Logs[2]), + }, + { + txn: gcAD.Txn, + claimedTxID: []byte(childA.EvalDelta.Logs[3]), + }, + { + txn: gcBA.Txn, + claimedTxID: []byte(childB.EvalDelta.Logs[0]), + }, + { + txn: gcBB.Txn, + claimedTxID: []byte(childB.EvalDelta.Logs[1]), + }, + { + txn: gcBC.Txn, + claimedTxID: []byte(childB.EvalDelta.Logs[2]), + }, + { + txn: gcBD.Txn, + claimedTxID: []byte(childB.EvalDelta.Logs[3]), + }, + } + + verifyTxIDs(t, unified, toVerify) + }) + } +} + +func TestInnerTxIDCaching(t *testing.T) { + partitiontest.PartitionTest(t) + t.Parallel() + + parentAppID := basics.AppIndex(888) + childAppID := basics.AppIndex(222) + + for _, unified := range []bool{true, false} { + t.Run(fmt.Sprintf("unified=%t", unified), func(t *testing.T) { + t.Parallel() + + ep, parentTx, ledger := MakeSampleEnv() + ep.Proto.UnifyInnerTxIDs = unified + + shouldIDsBeEqual := byte(1) + if unified { + shouldIDsBeEqual = 0 + } + + parentTx.ApplicationID = parentAppID + parentTx.ForeignApps = []basics.AppIndex{childAppID} + parentTx.ApplicationArgs = [][]byte{{shouldIDsBeEqual}} + + child := TestProg(t, "int 1", AssemblerMaxVersion) + ledger.NewApp(parentTx.Receiver, childAppID, basics.AppParams{ + ApprovalProgram: child.Program, + }) + ledger.NewAccount(childAppID.Address(), 50_000) + + ledger.NewApp(parentTx.Receiver, parentAppID, basics.AppParams{}) + ledger.NewAccount(parentAppID.Address(), 50_000) + + // does `gitxn 0 TxID` hit the cache for `gtxn 0 TxID`? + TestApp(t, ` +gtxn 0 TxID +txn TxID +== +assert + +itxn_begin +int appl; itxn_field TypeEnum +int 222; itxn_field ApplicationID +itxn_next +int appl; itxn_field TypeEnum +int 222; itxn_field ApplicationID +itxn_submit + +gitxn 0 TxID +gtxn 0 TxID +== +txn ApplicationArgs 0 +btoi +== +`, ep) + + // does `gtxn 0 TxID` hit the cache for `gitxn 0 TxID`? + TestApp(t, ` +itxn_begin +int appl; itxn_field TypeEnum +int 222; itxn_field ApplicationID +itxn_next +int appl; itxn_field TypeEnum +int 222; itxn_field ApplicationID +itxn_submit + +gitxn 0 TxID +gtxn 0 TxID +== +txn ApplicationArgs 0 +btoi +== +`, ep) + + // does the cache for `gitxn 0 TxID` reset after another inner executes? + TestApp(t, ` +itxn_begin +int appl; itxn_field TypeEnum +int 222; itxn_field ApplicationID +itxn_next +int appl; itxn_field TypeEnum +int 222; itxn_field ApplicationID +itxn_submit + +gitxn 0 TxID + +itxn_begin +int appl; itxn_field TypeEnum +int 222; itxn_field ApplicationID +itxn_next +int appl; itxn_field TypeEnum +int 222; itxn_field ApplicationID +itxn_submit + +gitxn 0 TxID +== +txn ApplicationArgs 0 +btoi +== +`, ep) + }) + } +} + // TestGtixn confirms access to itxn groups func TestGtixn(t *testing.T) { partitiontest.PartitionTest(t) @@ -2013,3 +2907,30 @@ itxn_submit TestApp(t, source, ep, "appl depth (8) exceeded") } + +func TestForeignAppAccountAccess(t *testing.T) { + partitiontest.PartitionTest(t) + + ep, tx, ledger := MakeSampleEnv() + ledger.NewAccount(appAddr(888), 50_000) + tx.ForeignApps = []basics.AppIndex{basics.AppIndex(111)} + + ledger.NewApp(tx.Sender, 111, basics.AppParams{ + ApprovalProgram: TestProg(t, "int 1", AssemblerMaxVersion).Program, + ClearStateProgram: TestProg(t, "int 1", AssemblerMaxVersion).Program, + }) + + TestApp(t, ` +itxn_begin +int pay +itxn_field TypeEnum +int 100 +itxn_field Amount +txn Applications 1 +app_params_get AppAddress +assert +itxn_field Receiver +itxn_submit +int 1 +`, ep) +} diff --git a/data/transactions/logic/evalCrypto_test.go b/data/transactions/logic/evalCrypto_test.go index 6d7734897a..84a88f6e40 100644 --- a/data/transactions/logic/evalCrypto_test.go +++ b/data/transactions/logic/evalCrypto_test.go @@ -25,9 +25,11 @@ import ( "encoding/hex" "fmt" "math/big" + mrand "math/rand" "strconv" "testing" + "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/stretchr/testify/require" "github.com/algorand/go-algorand/crypto" @@ -771,3 +773,129 @@ int 1` benchmarkEcdsa(b, source, Secp256k1) }) } + +type benchmarkBn256Data struct { + a []byte + k []byte + g1 []byte + g2 []byte + programs []byte +} + +func benchmarkBn256DataGenData(b *testing.B) (data []benchmarkBn256Data) { + data = make([]benchmarkBn256Data, b.N) + var g1Gen bn254.G1Jac + var g1GenAff bn254.G1Affine + g1Gen.X.SetString("1") + g1Gen.Y.SetString("2") + g1Gen.Z.SetString("1") + g1GenAff.FromJacobian(&g1Gen) + var a bn254.G1Affine + a.ScalarMultiplication(&g1GenAff, new(big.Int).SetUint64(mrand.Uint64())) + + for i := 0; i < b.N; i++ { + var a bn254.G1Affine + a.ScalarMultiplication(&g1GenAff, new(big.Int).SetUint64(mrand.Uint64())) + + data[i].a = bN254G1ToBytes(&a) + data[i].k = new(big.Int).SetUint64(mrand.Uint64()).Bytes() + + // Pair one g1 and one g2 + data[i].g1, _ = hex.DecodeString("0ebc9fc712b13340c800793386a88385e40912a21bacad2cc7db17d36e54c802238449426931975cced7200f08681ab9a86a2e5c2336cf625451cf2413318e32") + data[i].g2, _ = hex.DecodeString("217fbd9a9db5719cfbe3580e3d8750cada058fdfffe95c440a0528ffc608f36e05d6a67604658d40b3e4cac3c46150f2702d87739b7774d79a8147f7271773b420f9429ee13c1843404bfd70e75efa886c173e57dde32970274d8bc53dfd562403f6276318990d053785b4ca342ebc4581a23a39285804bb74e079aa2ef3ba66") + } + return data +} + +func benchmarkBn256(b *testing.B, source string) { + data := benchmarkBn256DataGenData(b) + ops, err := AssembleStringWithVersion(source, 7) + require.NoError(b, err) + for i := 0; i < b.N; i++ { + data[i].programs = ops.Program + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + var txn transactions.SignedTxn + txn.Lsig.Logic = data[i].programs + txn.Lsig.Args = [][]byte{data[i].a, data[i].k, data[i].g1, data[i].g2} + ep := defaultEvalParams(&txn) + pass, err := EvalSignature(0, ep) + if !pass { + b.Log(hex.EncodeToString(data[i].programs)) + b.Log(ep.Trace.String()) + } + if err != nil { + require.NoError(b, err) + } + if !pass { + require.True(b, pass) + } + } +} + +func BenchmarkBn256AddRaw(b *testing.B) { + data := benchmarkBn256DataGenData(b) + a1 := bytesToBN254G1(data[0].g1) + a2 := bytesToBN254G1(data[0].g1) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = new(bn254.G1Affine).Add(&a1, &a2) + } +} + +func BenchmarkBn256AddWithMarshal(b *testing.B) { + b.ResetTimer() + var v [][]byte + v = make([][]byte, b.N) + g1, _ := hex.DecodeString("0ebc9fc712b13340c800793386a88385e40912a21bacad2cc7db17d36e54c802238449426931975cced7200f08681ab9a86a2e5c2336cf625451cf2413318e32") + + for i := 0; i < b.N; i++ { + a1 := bytesToBN254G1(g1) + a2 := bytesToBN254G1(g1) + r := new(bn254.G1Affine).Add(&a1, &a2) + v[i] = r.Marshal() + } +} + +func BenchmarkBn256PairingRaw(b *testing.B) { + data := benchmarkBn256DataGenData(b) + g1s := bytesToBN254G1s(data[0].g1) + g2s := bytesToBN254G2s(data[0].g2) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + ok, _ := bn254.PairingCheck(g1s, g2s) + require.False(b, ok) + } +} + +func BenchmarkBn256(b *testing.B) { + b.Run("bn256 add", func(b *testing.B) { + benchmarkOperation(b, "byte 0x0ebc9fc712b13340c800793386a88385e40912a21bacad2cc7db17d36e54c802238449426931975cced7200f08681ab9a86a2e5c2336cf625451cf2413318e32", "dup; bn256_add", "pop; int 1") + }) + + b.Run("bn256 scalar mul", func(b *testing.B) { + source := `#pragma version 7 +arg 0 +arg 1 +bn256_scalar_mul +pop +int 1 +` + benchmarkBn256(b, source) + }) + + b.Run("bn256 pairing", func(b *testing.B) { + source := `#pragma version 7 +arg 2 +arg 3 +bn256_pairing +pop +int 1 +` + benchmarkBn256(b, source) + }) +} diff --git a/data/transactions/logic/evalStateful_test.go b/data/transactions/logic/evalStateful_test.go index 730978fd82..e861883a37 100644 --- a/data/transactions/logic/evalStateful_test.go +++ b/data/transactions/logic/evalStateful_test.go @@ -2388,6 +2388,10 @@ func TestReturnTypes(t *testing.T) { "ecdsa_verify": true, "ecdsa_pk_recover": true, "ecdsa_pk_decompress": true, + + "bn256_add": true, + "bn256_scalar_mul": true, + "bn256_pairing": true, } byName := OpsByName[LogicVersion] diff --git a/data/transactions/logic/eval_test.go b/data/transactions/logic/eval_test.go index df4f43856b..9e54e7b291 100644 --- a/data/transactions/logic/eval_test.go +++ b/data/transactions/logic/eval_test.go @@ -101,6 +101,8 @@ func makeTestProtoV(version uint64) *config.ConsensusParams { MinInnerApplVersion: 4, SupportBecomeNonParticipatingTransactions: true, + + UnifyInnerTxIDs: true, } } @@ -4647,12 +4649,12 @@ By Herman Melville`, "", {"cGFk=", "StdEncoding", "pad", "input byte 4"}, {"cGFk==", "StdEncoding", "pad", "input byte 4"}, {"cGFk===", "StdEncoding", "pad", "input byte 4"}, - // Ensures that even correct padding is illegal if not needed + // Ensures that extra padding, even if 0%4 {"cGFk====", "StdEncoding", "pad", "input byte 4"}, - // Test that padding must be present to make len = 0 mod 4. + // Test that padding must be correct or absent {"bm9wYWQ=", "StdEncoding", "nopad", ""}, - {"bm9wYWQ", "StdEncoding", "nopad", "illegal"}, + {"bm9wYWQ", "StdEncoding", "nopad", ""}, {"bm9wYWQ==", "StdEncoding", "nopad", "illegal"}, {"YWJjMTIzIT8kKiYoKSctPUB+", "StdEncoding", "abc123!?$*&()'-=@~", ""}, @@ -4688,15 +4690,15 @@ By Herman Melville`, "", {"\rS\r\nQ=\n=\r\r\n", "StdEncoding", "I", ""}, {"\rS\r\nQ=\n=\r\r\n", "URLEncoding", "I", ""}, - // Padding necessary? - Yes it is! And exactly the expected place and amount. + // If padding is there, it must be correct, but if absent, that's fine. {"SQ==", "StdEncoding", "I", ""}, {"SQ==", "URLEncoding", "I", ""}, {"S=Q=", "StdEncoding", "", "byte 1"}, {"S=Q=", "URLEncoding", "", "byte 1"}, {"=SQ=", "StdEncoding", "", "byte 0"}, {"=SQ=", "URLEncoding", "", "byte 0"}, - {"SQ", "StdEncoding", "", "byte 0"}, - {"SQ", "URLEncoding", "", "byte 0"}, + {"SQ", "StdEncoding", "I", ""}, + {"SQ", "URLEncoding", "I", ""}, {"SQ=", "StdEncoding", "", "byte 3"}, {"SQ=", "URLEncoding", "", "byte 3"}, {"SQ===", "StdEncoding", "", "byte 4"}, @@ -4719,17 +4721,6 @@ By Herman Melville`, "", if LogicVersion < fidoVersion { testProg(t, source, AssemblerMaxVersion, Expect{0, "unknown opcode..."}) } else { - // sanity check - test the helper function first: - encoding := base64.URLEncoding - if tc.alph == "StdEncoding" { - encoding = base64.StdEncoding - } - encoding = encoding.Strict() - decoded, err := base64Decode([]byte(tc.encoded), encoding) - require.NoError(t, err) - require.Equal(t, string(decoded), tc.decoded) - - // now check eval: testAccepts(t, source, fidoVersion) } } else { @@ -4737,6 +4728,7 @@ By Herman Melville`, "", testProg(t, source, AssemblerMaxVersion, Expect{0, "unknown opcode..."}) } else { err := testPanics(t, source, fidoVersion) + require.Error(t, err) require.Contains(t, err.Error(), tc.error) } } diff --git a/data/transactions/logic/langspec.json b/data/transactions/logic/langspec.json index 7a6cef2d9a..1d978db8ec 100644 --- a/data/transactions/logic/langspec.json +++ b/data/transactions/logic/langspec.json @@ -1637,6 +1637,42 @@ "Arithmetic" ] }, + { + "Opcode": 153, + "Name": "bn256_add", + "Args": "BB", + "Returns": "B", + "Size": 1, + "Doc": "for (curve points A and B) return the curve point A + B", + "DocExtra": "A, B are curve points in G1 group. Each point consists of (X, Y) where X and Y are 256 bit integers, big-endian encoded. The encoded point is 64 bytes from concatenation of 32 byte X and 32 byte Y.", + "Groups": [ + "Arithmetic" + ] + }, + { + "Opcode": 154, + "Name": "bn256_scalar_mul", + "Args": "BB", + "Returns": "B", + "Size": 1, + "Doc": "for (curve point A, scalar K) return the curve point KA", + "DocExtra": "A is a curve point in G1 Group and encoded as described in `bn256_add`. Scalar K is a big-endian encoded big integer that has no padding zeros.", + "Groups": [ + "Arithmetic" + ] + }, + { + "Opcode": 155, + "Name": "bn256_pairing", + "Args": "BB", + "Returns": "U", + "Size": 1, + "Doc": "for (points in G1 group G1s, points in G2 group G2s), return whether they are paired =\u003e {0 or 1}", + "DocExtra": "G1s are encoded by the concatenation of encoded G1 points, as described in `bn256_add`. G2s are encoded by the concatenation of encoded G2 points. Each G2 is in form (XA0+i*XA1, YA0+i*YA1) and encoded by big-endian field element XA0, XA1, YA0 and YA1 in sequence.", + "Groups": [ + "Arithmetic" + ] + }, { "Opcode": 160, "Name": "b+", diff --git a/data/transactions/logic/opcodes.go b/data/transactions/logic/opcodes.go index a486a8d3d1..1d26d437a0 100644 --- a/data/transactions/logic/opcodes.go +++ b/data/transactions/logic/opcodes.go @@ -57,8 +57,16 @@ const txnEffectsVersion = 6 // the Foreign arrays. const createdResourcesVersion = 6 -// experimental- -const fidoVersion = 7 // base64, json, secp256r1 +// appAddressAvailableVersion is the first version that allows access to the +// accounts of applications that were provided in the foreign apps transaction +// field. +const appAddressAvailableVersion = 7 + +// EXPERIMENTAL. These should be revisited whenever a new LogiSigVersion is +// moved from vFuture to a new consensus version. If they remain unready, bump +// their version. +const fidoVersion = 7 // base64, json, secp256r1 +const pairingVersion = 7 // bn256 opcodes. will add bls12-381, and unify the available opcodes.// experimental- type linearCost struct { baseCost int @@ -532,11 +540,15 @@ var OpSpecs = []OpSpec{ {0x96, "bsqrt", opBytesSqrt, proto("b:b"), 6, costly(40)}, {0x97, "divw", opDivw, proto("iii:i"), 6, opDefault()}, {0x98, "sha3_256", opSHA3_256, proto("b:b"), 7, costly(130)}, - /* Will end up following keccak256 - {0x98, "sha3_256", opSHA3_256, proto("b:b"), unlimitedStorage, costByLength(58, 4, 8)},}, */ + {0x99, "bn256_add", opBn256Add, proto("bb:b"), pairingVersion, costly(70)}, + {0x9a, "bn256_scalar_mul", opBn256ScalarMul, proto("bb:b"), pairingVersion, costly(970)}, + {0x9b, "bn256_pairing", opBn256Pairing, proto("bb:i"), pairingVersion, costly(8700)}, + // leave room here for eip-2537 style opcodes + // Byteslice math. {0xa0, "b+", opBytesPlus, proto("bb:b"), 4, costly(10)}, {0xa1, "b-", opBytesMinus, proto("bb:b"), 4, costly(10)}, diff --git a/data/transactions/logic/pairing.go b/data/transactions/logic/pairing.go new file mode 100644 index 0000000000..cb43efeb5e --- /dev/null +++ b/data/transactions/logic/pairing.go @@ -0,0 +1,116 @@ +// Copyright (C) 2019-2022 Algorand, Inc. +// This file is part of go-algorand +// +// go-algorand 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. +// +// go-algorand 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 go-algorand. If not, see . + +package logic + +import ( + "errors" + "math/big" + + "github.com/consensys/gnark-crypto/ecc/bn254" + "github.com/consensys/gnark-crypto/ecc/bn254/fp" +) + +func bytesToBN254Field(b []byte) (ret fp.Element) { + ret.SetBytes(b) + return +} + +func bytesToBN254G1(b []byte) (ret bn254.G1Affine) { + ret.X = bytesToBN254Field(b[:32]) + ret.Y = bytesToBN254Field(b[32:64]) + return +} + +func bytesToBN254G1s(b []byte) (ret []bn254.G1Affine) { + for i := 0; i < len(b)/64; i++ { + ret = append(ret, bytesToBN254G1(b[(i*64):(i*64+64)])) + } + return +} + +func bytesToBN254G2(b []byte) (ret bn254.G2Affine) { + ret.X.A0 = bytesToBN254Field(b[:32]) + ret.X.A1 = bytesToBN254Field(b[32:64]) + ret.Y.A0 = bytesToBN254Field(b[64:96]) + ret.Y.A1 = bytesToBN254Field(b[96:128]) + return +} + +func bytesToBN254G2s(b []byte) (ret []bn254.G2Affine) { + for i := 0; i < len(b)/128; i++ { + ret = append(ret, bytesToBN254G2(b[(i*128):(i*128+128)])) + } + return +} + +func bN254G1ToBytes(g1 *bn254.G1Affine) (ret []byte) { + retX := g1.X.Bytes() + retY := g1.Y.Bytes() + ret = append(retX[:], retY[:]...) + return +} + +func opBn256Add(cx *EvalContext) error { + last := len(cx.stack) - 1 + prev := last - 1 + aBytes := cx.stack[prev].Bytes + bBytes := cx.stack[last].Bytes + if len(aBytes) != 64 || len(bBytes) != 64 { + return errors.New("expect G1 in 64 bytes") + } + a := bytesToBN254G1(aBytes) + b := bytesToBN254G1(bBytes) + res := new(bn254.G1Affine).Add(&a, &b) + resBytes := bN254G1ToBytes(res) + cx.stack = cx.stack[:last] + cx.stack[prev].Bytes = resBytes + return nil +} + +func opBn256ScalarMul(cx *EvalContext) error { + last := len(cx.stack) - 1 + prev := last - 1 + aBytes := cx.stack[prev].Bytes + if len(aBytes) != 64 { + return errors.New("expect G1 in 64 bytes") + } + a := bytesToBN254G1(aBytes) + kBytes := cx.stack[last].Bytes + k := new(big.Int).SetBytes(kBytes[:]) + res := new(bn254.G1Affine).ScalarMultiplication(&a, k) + resBytes := bN254G1ToBytes(res) + cx.stack = cx.stack[:last] + cx.stack[prev].Bytes = resBytes + return nil +} + +func opBn256Pairing(cx *EvalContext) error { + last := len(cx.stack) - 1 + prev := last - 1 + g1Bytes := cx.stack[prev].Bytes + g2Bytes := cx.stack[last].Bytes + g1 := bytesToBN254G1s(g1Bytes) + g2 := bytesToBN254G2s(g2Bytes) + ok, err := bn254.PairingCheck(g1, g2) + if err != nil { + return errors.New("pairing failed") + } + cx.stack = cx.stack[:last] + cx.stack[prev].Uint = boolToUint(ok) + cx.stack[prev].Bytes = nil + return nil +} diff --git a/data/transactions/logic/teal.tmLanguage.json b/data/transactions/logic/teal.tmLanguage.json index efc093602d..5219dbcd45 100644 --- a/data/transactions/logic/teal.tmLanguage.json +++ b/data/transactions/logic/teal.tmLanguage.json @@ -76,7 +76,7 @@ }, { "name": "keyword.operator.teal", - "match": "^(\\!|\\!\\=|%|\u0026|\u0026\u0026|\\*|\\+|\\-|/|\\\u003c|\\\u003c\\=|\\=\\=|\\\u003e|\\\u003e\\=|\\^|addw|bitlen|btoi|concat|divmodw|divw|ecdsa_pk_decompress|ecdsa_pk_recover|ecdsa_verify|ed25519verify|ed25519verify_bare|exp|expw|getbit|getbyte|itob|keccak256|len|mulw|setbit|setbyte|sha256|sha3_256|sha512_256|shl|shr|sqrt|\\||\\|\\||\\~|b\\!\\=|b%|b\\*|b\\+|b\\-|b/|b\\\u003c|b\\\u003c\\=|b\\=\\=|b\\\u003e|b\\\u003e\\=|bsqrt|b\u0026|b\\^|b\\||b\\~|base64_decode|extract|extract3|extract_uint16|extract_uint32|extract_uint64|json_ref|substring|substring3|gitxn|gitxna|gitxnas|itxn|itxn_begin|itxn_field|itxn_next|itxn_submit|itxna|itxnas)\\b" + "match": "^(\\!|\\!\\=|%|\u0026|\u0026\u0026|\\*|\\+|\\-|/|\\\u003c|\\\u003c\\=|\\=\\=|\\\u003e|\\\u003e\\=|\\^|addw|bitlen|bn256_add|bn256_pairing|bn256_scalar_mul|btoi|concat|divmodw|divw|ecdsa_pk_decompress|ecdsa_pk_recover|ecdsa_verify|ed25519verify|ed25519verify_bare|exp|expw|getbit|getbyte|itob|keccak256|len|mulw|setbit|setbyte|sha256|sha3_256|sha512_256|shl|shr|sqrt|\\||\\|\\||\\~|b\\!\\=|b%|b\\*|b\\+|b\\-|b/|b\\\u003c|b\\\u003c\\=|b\\=\\=|b\\\u003e|b\\\u003e\\=|bsqrt|b\u0026|b\\^|b\\||b\\~|base64_decode|extract|extract3|extract_uint16|extract_uint32|extract_uint64|json_ref|substring|substring3|gitxn|gitxna|gitxnas|itxn|itxn_begin|itxn_field|itxn_next|itxn_submit|itxna|itxnas)\\b" } ] }, diff --git a/data/transactions/msgp_gen.go b/data/transactions/msgp_gen.go index 381c032c27..299d4da243 100644 --- a/data/transactions/msgp_gen.go +++ b/data/transactions/msgp_gen.go @@ -5,10 +5,11 @@ package transactions import ( "sort" + "github.com/algorand/msgp/msgp" + "github.com/algorand/go-algorand/config" "github.com/algorand/go-algorand/crypto" "github.com/algorand/go-algorand/data/basics" - "github.com/algorand/msgp/msgp" ) // The following msgp objects are implemented in this file: diff --git a/data/transactions/msgp_gen_test.go b/data/transactions/msgp_gen_test.go index d92a29cf8f..daf552f982 100644 --- a/data/transactions/msgp_gen_test.go +++ b/data/transactions/msgp_gen_test.go @@ -1,3 +1,4 @@ +//go:build !skip_msgp_testing // +build !skip_msgp_testing package transactions @@ -7,9 +8,10 @@ package transactions import ( "testing" + "github.com/algorand/msgp/msgp" + "github.com/algorand/go-algorand/protocol" "github.com/algorand/go-algorand/test/partitiontest" - "github.com/algorand/msgp/msgp" ) func TestMarshalUnmarshalApplicationCallTxnFields(t *testing.T) { diff --git a/data/transactions/signedtxn.go b/data/transactions/signedtxn.go index 8f4f55ba46..08ce6fad95 100644 --- a/data/transactions/signedtxn.go +++ b/data/transactions/signedtxn.go @@ -17,6 +17,7 @@ package transactions import ( + "crypto/sha256" "errors" "github.com/algorand/go-algorand/crypto" @@ -117,9 +118,18 @@ func (s *SignedTxnInBlock) ToBeHashed() (protocol.HashID, []byte) { func (s *SignedTxnInBlock) Hash() crypto.Digest { enc := s.MarshalMsg(append(protocol.GetEncodingBuf(), []byte(protocol.SignedTxnInBlock)...)) defer protocol.PutEncodingBuf(enc) + return crypto.Hash(enc) } +// HashSHA256 implements an optimized version of crypto.HashObj(s) using SHA256 instead of the default SHA512_256. +func (s *SignedTxnInBlock) HashSHA256() crypto.Digest { + enc := s.MarshalMsg(append(protocol.GetEncodingBuf(), []byte(protocol.SignedTxnInBlock)...)) + defer protocol.PutEncodingBuf(enc) + + return sha256.Sum256(enc) +} + // WrapSignedTxnsWithAD takes an array SignedTxn and returns the same as SignedTxnWithAD // Each txn's ApplyData is the default empty state. func WrapSignedTxnsWithAD(txgroup []SignedTxn) []SignedTxnWithAD { diff --git a/data/transactions/transaction.go b/data/transactions/transaction.go index a2c1de3694..5c67f64dd2 100644 --- a/data/transactions/transaction.go +++ b/data/transactions/transaction.go @@ -17,6 +17,7 @@ package transactions import ( + "crypto/sha256" "encoding/binary" "errors" "fmt" @@ -161,6 +162,7 @@ type TxGroup struct { // together, sequentially, in a block in order for the group to be // valid. Each hash in the list is a hash of a transaction with // the `Group` field omitted. + // These are all `Txid` which is equivalent to `crypto.Digest` TxGroupHashes []crypto.Digest `codec:"txlist,allocbound=config.MaxTxGroupSize"` } @@ -181,6 +183,13 @@ func (tx Transaction) ID() Txid { return Txid(crypto.Hash(enc)) } +// IDSha256 returns the digest (i.e., hash) of the transaction. +func (tx Transaction) IDSha256() crypto.Digest { + enc := tx.MarshalMsg(append(protocol.GetEncodingBuf(), []byte(protocol.Transaction)...)) + defer protocol.PutEncodingBuf(enc) + return sha256.Sum256(enc) +} + // InnerID returns something akin to Txid, but folds in the parent Txid and the // index of the inner call. func (tx Transaction) InnerID(parent Txid, index int) Txid { diff --git a/data/transactions/transaction_test.go b/data/transactions/transaction_test.go index 5a7321c698..4536fb122c 100644 --- a/data/transactions/transaction_test.go +++ b/data/transactions/transaction_test.go @@ -552,6 +552,24 @@ func TestWellFormedErrors(t *testing.T) { } } +// TestTransactionHash checks that Transaction.ID() is equivalent to the old simpler crypto.HashObj() implementation. +func TestTransactionHash(t *testing.T) { + partitiontest.PartitionTest(t) + + var txn Transaction + txn.Sender[1] = 3 + txn.Fee.Raw = 1234 + txid := txn.ID() + txid2 := Txid(crypto.HashObj(txn)) + require.Equal(t, txid, txid2) + + txn.LastValid = 4321 + txid3 := txn.ID() + txid2 = Txid(crypto.HashObj(txn)) + require.NotEqual(t, txid, txid3) + require.Equal(t, txid3, txid2) +} + var generateFlag = flag.Bool("generate", false, "") // running test with -generate would generate the matrix used in the test ( without the "correct" errors ) diff --git a/data/txntest/txn.go b/data/txntest/txn.go index 6b72cb080e..c137b171ff 100644 --- a/data/txntest/txn.go +++ b/data/txntest/txn.go @@ -269,19 +269,20 @@ func SignedTxns(txns ...*Txn) []transactions.SignedTxn { txgroup := transactions.TxGroup{ TxGroupHashes: make([]crypto.Digest, len(txns)), } + stxns := make([]transactions.SignedTxn, len(txns)) for i, txn := range txns { - txn.Group = crypto.Digest{} - txgroup.TxGroupHashes[i] = crypto.HashObj(txn.Txn()) + stxns[i] = txn.SignedTxn() + } + for i, txn := range stxns { + txn.Txn.Group = crypto.Digest{} + txgroup.TxGroupHashes[i] = crypto.Digest(txn.ID()) } group := crypto.HashObj(txgroup) - for _, txn := range txns { + for i, txn := range txns { txn.Group = group + stxns[i].Txn.Group = group } - stxns := make([]transactions.SignedTxn, len(txns)) - for i, txn := range txns { - stxns[i] = txn.SignedTxn() - } return stxns } diff --git a/go.mod b/go.mod index c917e62adf..5ab3759566 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/algorand/go-algorand -go 1.16 +go 1.17 require ( github.com/algorand/falcon v0.0.0-20220130164023-c9e1d466f123 @@ -8,46 +8,67 @@ require ( github.com/algorand/go-deadlock v0.2.2 github.com/algorand/go-sumhash v0.1.0 github.com/algorand/graphtrace v0.1.0 - github.com/algorand/msgp v1.1.50 + github.com/algorand/msgp v1.1.52 github.com/algorand/oapi-codegen v1.3.7 github.com/algorand/websocket v1.4.5 github.com/aws/aws-sdk-go v1.16.5 github.com/chrismcguire/gobberish v0.0.0-20150821175641-1d8adb509a0e - github.com/cpuguy83/go-md2man v1.0.8 // indirect + github.com/consensys/gnark-crypto v0.7.0 github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018 github.com/dchest/siphash v1.2.1 github.com/fatih/color v1.7.0 - github.com/fortytw2/leaktest v1.3.0 // indirect github.com/gen2brain/beeep v0.0.0-20180718162406-4e430518395f github.com/getkin/kin-openapi v0.22.0 - github.com/godbus/dbus v0.0.0-20181101234600-2ff6f7ffd60f // indirect github.com/gofrs/flock v0.7.0 github.com/google/go-querystring v1.0.0 - github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e // indirect - github.com/gopherjs/gopherwasm v1.0.1 // indirect - github.com/gorilla/context v1.1.1 // indirect github.com/gorilla/mux v1.6.2 - github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/jmoiron/sqlx v1.2.0 github.com/karalabe/usb v0.0.2 github.com/labstack/echo/v4 v4.1.17 - github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-sqlite3 v1.10.0 github.com/miekg/dns v1.1.27 - github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect - github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect github.com/olivere/elastic v6.2.14+incompatible - github.com/russross/blackfriday v1.5.2 // indirect github.com/sirupsen/logrus v1.8.1 github.com/spf13/cobra v0.0.3 - github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/testify v1.7.1 - golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 - golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 + golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064 + golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 golang.org/x/text v0.3.7 + gopkg.in/sohlich/elogrus.v3 v3.0.0-20180410122755-1fa29e2f2009 +) + +require ( + github.com/cpuguy83/go-md2man v1.0.8 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect + github.com/fortytw2/leaktest v1.3.0 // indirect + github.com/ghodss/yaml v1.0.0 // indirect + github.com/godbus/dbus v0.0.0-20181101234600-2ff6f7ffd60f // indirect + github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e // indirect + github.com/gopherjs/gopherwasm v1.0.1 // indirect + github.com/gorilla/context v1.1.1 // indirect + github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/labstack/gommon v0.3.0 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/mattn/go-colorable v0.1.7 // indirect + github.com/mattn/go-isatty v0.0.12 // indirect + github.com/mmcloughlin/addchain v0.4.0 // indirect + github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect + github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect + github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/russross/blackfriday v1.5.2 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasttemplate v1.2.1 // indirect + golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect + golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect google.golang.org/appengine v1.6.7 // indirect gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect - gopkg.in/sohlich/elogrus.v3 v3.0.0-20180410122755-1fa29e2f2009 gopkg.in/toast.v1 v1.0.0-20180812000517-0a84660828b2 // indirect - gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect + gopkg.in/yaml.v2 v2.3.0 // indirect + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect ) diff --git a/go.sum b/go.sum index 73e446a9f5..93b075f404 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,5 @@ github.com/algorand/falcon v0.0.0-20220130164023-c9e1d466f123 h1:cnUjJ/iqUjJNbhUzgmxbfwHMVFnz+DLnNQx8uJcGaks= github.com/algorand/falcon v0.0.0-20220130164023-c9e1d466f123/go.mod h1:OkQyHlGvS0kLNcIWbC21/uQcnbfwSOQm+wiqWwBG9pQ= -github.com/algorand/go-codec v1.1.8 h1:XDSreeeZY8gMst6Edz4RBkl08/DGMJOeHYkoXL2B7wI= github.com/algorand/go-codec v1.1.8/go.mod h1:XhzVs6VVyWMLu6cApb9/192gBjGRVGm5cX5j203Heg4= github.com/algorand/go-codec/codec v1.1.8 h1:lsFuhcOH2LiEhpBH3BVUUkdevVmwCRyvb7FCAAPeY6U= github.com/algorand/go-codec/codec v1.1.8/go.mod h1:tQ3zAJ6ijTps6V+wp8KsGDnPC2uhHVC7ANyrtkIY0bA= @@ -10,8 +9,8 @@ github.com/algorand/go-sumhash v0.1.0 h1:b/QRhyLuF//vOcicBIxBXYW8bERNoeLxieht/dU github.com/algorand/go-sumhash v0.1.0/go.mod h1:OOe7jdDWUhLkuP1XytkK5gnLu9entAviN5DfDZh6XAc= github.com/algorand/graphtrace v0.1.0 h1:QemP1iT0W56SExD0NfiU6rsG34/v0Je6bg5UZnptEUM= github.com/algorand/graphtrace v0.1.0/go.mod h1:HscLQrzBdH1BH+5oehs3ICd8SYcXvnSL9BjfTu8WHCc= -github.com/algorand/msgp v1.1.50 h1:Mvsjs5LCE6HsXXbwJXD8ol1Y+c+QMoFNM4j0CY+mFGo= -github.com/algorand/msgp v1.1.50/go.mod h1:R5sJrW9krk4YwNo+rs82Kq6V55q/zNgACwWqt3sQBM4= +github.com/algorand/msgp v1.1.52 h1:Tw2OCCikKy0jaTWEIHwIfvThYHlJf9moviyKw+7PVVM= +github.com/algorand/msgp v1.1.52/go.mod h1:5K3d58/poT5fPmtiwuQft6GjgSrVEM46KoXdLrID8ZU= github.com/algorand/oapi-codegen v1.3.7 h1:TdXeGljgrnLXSCGPdeY6g6+i/G0Rr5CkjBgUJY6ht48= github.com/algorand/oapi-codegen v1.3.7/go.mod h1:UvOtAiP3hc0M2GUKBnZVTjLe3HKGDKh6y9rs3e3JyOg= github.com/algorand/websocket v1.4.5 h1:Cs6UTaCReAl02evYxmN8k57cNHmBILRcspfSxYg4AJE= @@ -20,6 +19,8 @@ github.com/aws/aws-sdk-go v1.16.5 h1:NVxzZXIuwX828VcJrpNxxWjur1tlOBISdMdDdHIKHcc github.com/aws/aws-sdk-go v1.16.5/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/chrismcguire/gobberish v0.0.0-20150821175641-1d8adb509a0e h1:CHPYEbz71w8DqJ7DRIq+MXyCQsdibK08vdcQTY4ufas= github.com/chrismcguire/gobberish v0.0.0-20150821175641-1d8adb509a0e/go.mod h1:6Xhs0ZlsRjXLIiSMLKafbZxML/j30pg9Z1priLuha5s= +github.com/consensys/gnark-crypto v0.7.0 h1:rwdy8+ssmLYRqKp+ryRRgQJl/rCq2uv+n83cOydm5UE= +github.com/consensys/gnark-crypto v0.7.0/go.mod h1:KPSuJzyxkJA8xZ/+CV47tyqkr9MmpZA3PXivK4VPrVg= github.com/cpuguy83/go-md2man v1.0.8 h1:DwoNytLphI8hzS2Af4D0dfaEaiSq2bN05mEm4R6vf8M= github.com/cpuguy83/go-md2man v1.0.8/go.mod h1:N6JayAiVKtlHSnuTCeuLSQVs75hb8q+dYQLjr7cDsKY= github.com/cyberdelia/templates v0.0.0-20191230040416-20a325f050d4/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= @@ -54,6 +55,7 @@ github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/gopherjs/gopherjs v0.0.0-20180825215210-0210a2f0f73c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -75,13 +77,14 @@ github.com/karalabe/usb v0.0.2 h1:M6QQBNxF+CQ8OFvxrT90BA0qBOXymndZnk5q235mFc4= github.com/karalabe/usb v0.0.2/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/labstack/echo/v4 v4.1.16/go.mod h1:awO+5TzAjvL8XpibdsfXxPgHr+orhtXZJZIQCVjogKI= github.com/labstack/echo/v4 v4.1.17 h1:PQIBaRplyRy3OjwILGkPg89JRtH2x5bssi59G2EL3fo= github.com/labstack/echo/v4 v4.1.17/go.mod h1:Tn2yRQL/UclUalpb5rPdXDevbkJ+lp/2svdyFBg6CHQ= github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= +github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= @@ -100,6 +103,9 @@ github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK86 github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/miekg/dns v1.1.27 h1:aEH/kqUzUxGJ/UHcEKdJY+ugH6WEzsEBBSPa8zuy1aM= github.com/miekg/dns v1.1.27/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= +github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= +github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ= @@ -127,7 +133,6 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31/go.mod h1:onvgF043R+lC5RZ8IT9rBXDaEDnpnw/Cl+HFiw+v/7Q= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= @@ -142,8 +147,9 @@ golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064 h1:S25/rfnfsMVgORT4/J61MJ7rdyseOZOyvLIrZEZ7s6s= +golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= @@ -155,8 +161,9 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= @@ -175,8 +182,9 @@ golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 h1:OH54vjqzRWmbJ62fjuhxy7AxFFgoHN0/DPc/UrL8cAs= +golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -209,5 +217,5 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ= -gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/installer/config.json.example b/installer/config.json.example index b7369acfa8..c569e4c93d 100644 --- a/installer/config.json.example +++ b/installer/config.json.example @@ -1,5 +1,5 @@ { - "Version": 21, + "Version": 22, "AccountUpdatesStatsInterval": 5000000000, "AccountsRebuildSynchronousMode": 1, "AgreementIncomingBundlesQueueLength": 7, @@ -47,6 +47,7 @@ "EnableProcessBlockStats": false, "EnableProfiler": false, "EnableRequestLogger": false, + "EnableRuntimeMetrics": false, "EnableTopAccountsReporting": false, "EnableVerbosedTransactionSyncLogging": false, "EndpointAddress": "127.0.0.1:0", diff --git a/installer/external/node_exporter-stable-darwin-x86_64.tar.gz b/installer/external/node_exporter-stable-darwin-x86_64.tar.gz index 26faf2d514..2b25a6e301 100644 Binary files a/installer/external/node_exporter-stable-darwin-x86_64.tar.gz and b/installer/external/node_exporter-stable-darwin-x86_64.tar.gz differ diff --git a/installer/external/node_exporter-stable-linux-x86_64.tar.gz b/installer/external/node_exporter-stable-linux-x86_64.tar.gz index e3e7290b60..c9368910cf 100644 Binary files a/installer/external/node_exporter-stable-linux-x86_64.tar.gz and b/installer/external/node_exporter-stable-linux-x86_64.tar.gz differ diff --git a/ledger/applications_test.go b/ledger/applications_test.go index 364d9a9d51..d96a9a659c 100644 --- a/ledger/applications_test.go +++ b/ledger/applications_test.go @@ -585,7 +585,7 @@ return` a.NoError(err) blk.TxnCounter = blk.TxnCounter + 2 blk.Payset = append(blk.Payset, txib1, txib2) - blk.TxnRoot, err = blk.PaysetCommit() + blk.TxnCommitments, err = blk.PaysetCommit() a.NoError(err) err = l.appendUnvalidated(blk) a.NoError(err) @@ -730,7 +730,7 @@ return` a.NoError(err) blk.TxnCounter = blk.TxnCounter + 2 blk.Payset = append(blk.Payset, txib1, txib2) - blk.TxnRoot, err = blk.PaysetCommit() + blk.TxnCommitments, err = blk.PaysetCommit() a.NoError(err) err = l.appendUnvalidated(blk) a.NoError(err) @@ -867,7 +867,7 @@ return` a.NoError(err) blk.TxnCounter = blk.TxnCounter + 2 blk.Payset = append(blk.Payset, txib1, txib2) - blk.TxnRoot, err = blk.PaysetCommit() + blk.TxnCommitments, err = blk.PaysetCommit() a.NoError(err) err = l.appendUnvalidated(blk) a.NoError(err) diff --git a/ledger/catchpointtracker.go b/ledger/catchpointtracker.go index a2a5aa6889..f4c3e9ea55 100644 --- a/ledger/catchpointtracker.go +++ b/ledger/catchpointtracker.go @@ -413,20 +413,18 @@ func (ct *catchpointTracker) postCommit(ctx context.Context, dcc *deferredCommit } } + ct.catchpointsMu.Lock() + ct.roundDigest = ct.roundDigest[dcc.offset:] if dcc.isCatchpointRound && dcc.catchpointLabel != "" { ct.lastCatchpointLabel = dcc.catchpointLabel } + ct.catchpointsMu.Unlock() + dcc.updatingBalancesDuration = time.Since(dcc.flushTime) if dcc.updateStats { dcc.stats.MemoryUpdatesDuration = time.Duration(time.Now().UnixNano()) } - - ct.catchpointsMu.Lock() - - ct.roundDigest = ct.roundDigest[dcc.offset:] - - ct.catchpointsMu.Unlock() } func (ct *catchpointTracker) postCommitUnlocked(ctx context.Context, dcc *deferredCommitContext) { diff --git a/ledger/internal/apptxn_test.go b/ledger/internal/apptxn_test.go index a4d9da8e07..4e2b64c1a3 100644 --- a/ledger/internal/apptxn_test.go +++ b/ledger/internal/apptxn_test.go @@ -3058,3 +3058,202 @@ check: txns(t, l, eval, &fundA, &callA) endBlock(t, l, eval) } + +func TestForeignAppAccountsAccessible(t *testing.T) { + partitiontest.PartitionTest(t) + + genBalances, addrs, _ := ledgertesting.NewTestGenesis() + testConsensusRange(t, 32, 0, func(t *testing.T, ver int) { + dl := NewDoubleLedger(t, genBalances, consensusByNumber[ver]) + defer dl.Close() + + appA := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + } + + appB := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApprovalProgram: main(` +itxn_begin + int pay; itxn_field TypeEnum + int 100; itxn_field Amount + txn Applications 1 + app_params_get AppAddress + assert + itxn_field Receiver +itxn_submit +`), + } + + vb := dl.fullBlock(&appA, &appB) + index0 := vb.Block().Payset[0].ApplicationID + index1 := vb.Block().Payset[1].ApplicationID + + fund1 := txntest.Txn{ + Type: "pay", + Sender: addrs[0], + Receiver: index1.Address(), + Amount: 1_000_000_000, + } + fund0 := fund1 + fund0.Receiver = index0.Address() + + callTx := txntest.Txn{ + Type: "appl", + Sender: addrs[2], + ApplicationID: index1, + ForeignApps: []basics.AppIndex{index0}, + } + + dl.beginBlock() + if ver <= 32 { + dl.txgroup("invalid Account reference", &fund0, &fund1, &callTx) + dl.endBlock() + return + } + + dl.txgroup("", &fund0, &fund1, &callTx) + vb = dl.endBlock() + + require.Equal(t, index0.Address(), vb.Block().Payset[2].EvalDelta.InnerTxns[0].Txn.Receiver) + require.Equal(t, uint64(100), vb.Block().Payset[2].EvalDelta.InnerTxns[0].Txn.Amount.Raw) + }) +} + +// While accounts of foreign apps are available in most contexts, they still +// cannot be used as mutable references; ie the accounts cannot be used by +// opcodes that modify local storage. +func TestForeignAppAccountsImmutable(t *testing.T) { + partitiontest.PartitionTest(t) + + genBalances, addrs, _ := ledgertesting.NewTestGenesis() + testConsensusRange(t, 32, 0, func(t *testing.T, ver int) { + dl := NewDoubleLedger(t, genBalances, consensusByNumber[ver]) + defer dl.Close() + + appA := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + } + + appB := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApprovalProgram: main(` +txn Applications 1 +app_params_get AppAddress +byte "X" +byte "ABC" +app_local_put +int 1 +`), + } + + vb := dl.fullBlock(&appA, &appB) + index0 := vb.Block().Payset[0].ApplicationID + index1 := vb.Block().Payset[1].ApplicationID + + fund1 := txntest.Txn{ + Type: "pay", + Sender: addrs[0], + Receiver: index1.Address(), + Amount: 1_000_000_000, + } + fund0 := fund1 + fund0.Receiver = index0.Address() + + callTx := txntest.Txn{ + Type: "appl", + Sender: addrs[2], + ApplicationID: index1, + ForeignApps: []basics.AppIndex{index0}, + } + + dl.beginBlock() + dl.txgroup("invalid Account reference", &fund0, &fund1, &callTx) + dl.endBlock() + }) +} + +// In the case where the foreign app account is also provided in the +// transaction's account field, mutable references should be allowed. +func TestForeignAppAccountsMutable(t *testing.T) { + partitiontest.PartitionTest(t) + + genBalances, addrs, _ := ledgertesting.NewTestGenesis() + testConsensusRange(t, 32, 0, func(t *testing.T, ver int) { + dl := NewDoubleLedger(t, genBalances, consensusByNumber[ver]) + defer dl.Close() + + appA := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApprovalProgram: main(` +itxn_begin + int appl + itxn_field TypeEnum + txn Applications 1 + itxn_field ApplicationID + int OptIn + itxn_field OnCompletion +itxn_submit +`), + } + + appB := txntest.Txn{ + Type: "appl", + Sender: addrs[0], + ApprovalProgram: main(` +txn OnCompletion +int OptIn +== +bnz done +txn Applications 1 +app_params_get AppAddress +assert +byte "X" +byte "Y" +app_local_put +done: +`), + LocalStateSchema: basics.StateSchema{ + NumByteSlice: 1, + }, + } + + vb := dl.fullBlock(&appA, &appB) + index0 := vb.Block().Payset[0].ApplicationID + index1 := vb.Block().Payset[1].ApplicationID + + fund1 := txntest.Txn{ + Type: "pay", + Sender: addrs[0], + Receiver: index1.Address(), + Amount: 1_000_000_000, + } + fund0 := fund1 + fund0.Receiver = index0.Address() + fund1.Receiver = index1.Address() + + callA := txntest.Txn{ + Type: "appl", + Sender: addrs[2], + ApplicationID: index0, + ForeignApps: []basics.AppIndex{index1}, + } + + callB := txntest.Txn{ + Type: "appl", + Sender: addrs[2], + ApplicationID: index1, + ForeignApps: []basics.AppIndex{index0}, + Accounts: []basics.Address{index0.Address()}, + } + + vb = dl.fullBlock(&fund0, &fund1, &callA, &callB) + + require.Equal(t, "Y", vb.Block().Payset[3].EvalDelta.LocalDeltas[1]["X"].Bytes) + }) +} diff --git a/ledger/internal/eval.go b/ledger/internal/eval.go index 20206239f5..20c6f5d5ab 100644 --- a/ledger/internal/eval.go +++ b/ledger/internal/eval.go @@ -871,7 +871,7 @@ func (eval *BlockEvaluator) TestTransactionGroup(txgroup []transactions.SignedTx txWithoutGroup := txn.Txn txWithoutGroup.Group = crypto.Digest{} - group.TxGroupHashes = append(group.TxGroupHashes, crypto.HashObj(txWithoutGroup)) + group.TxGroupHashes = append(group.TxGroupHashes, crypto.Digest(txWithoutGroup.ID())) } else if len(txgroup) > 1 { return fmt.Errorf("transactionGroup: [%d] had zero Group but was submitted in a group of %d", gi, len(txgroup)) } @@ -981,7 +981,7 @@ func (eval *BlockEvaluator) transactionGroup(txgroup []transactions.SignedTxnWit txWithoutGroup := txad.SignedTxn.Txn txWithoutGroup.Group = crypto.Digest{} - group.TxGroupHashes = append(group.TxGroupHashes, crypto.HashObj(txWithoutGroup)) + group.TxGroupHashes = append(group.TxGroupHashes, crypto.Digest(txWithoutGroup.ID())) } else if len(txgroup) > 1 { return fmt.Errorf("transactionGroup: [%d] had zero Group but was submitted in a group of %d", gi, len(txgroup)) } @@ -1230,7 +1230,7 @@ func (eval *BlockEvaluator) TestingTxnCounter() uint64 { func (eval *BlockEvaluator) endOfBlock() error { if eval.generate { var err error - eval.block.TxnRoot, err = eval.block.PaysetCommit() + eval.block.TxnCommitments, err = eval.block.PaysetCommit() if err != nil { return err } @@ -1275,8 +1275,8 @@ func (eval *BlockEvaluator) endOfBlock() error { if err != nil { return err } - if txnRoot != eval.block.TxnRoot { - return fmt.Errorf("txn root wrong: %v != %v", txnRoot, eval.block.TxnRoot) + if txnRoot != eval.block.TxnCommitments { + return fmt.Errorf("txn root wrong: %v != %v", txnRoot, eval.block.TxnCommitments) } var expectedTxnCount uint64 diff --git a/ledger/ledger_test.go b/ledger/ledger_test.go index b48be3676f..53e475980c 100644 --- a/ledger/ledger_test.go +++ b/ledger/ledger_test.go @@ -129,7 +129,7 @@ func makeNewEmptyBlock(t *testing.T, l *Ledger, GenesisID string, initAccounts m // UpgradeVote: empty, } - blk.TxnRoot, err = blk.PaysetCommit() + blk.TxnCommitments, err = blk.PaysetCommit() require.NoError(t, err) if proto.SupportGenesisHash { @@ -155,7 +155,7 @@ func (l *Ledger) appendUnvalidatedSignedTx(t *testing.T, initAccounts map[basics blk.TxnCounter = blk.TxnCounter + 1 } blk.Payset = append(blk.Payset, txib) - blk.TxnRoot, err = blk.PaysetCommit() + blk.TxnCommitments, err = blk.PaysetCommit() require.NoError(t, err) return l.appendUnvalidated(blk) } @@ -174,7 +174,7 @@ func (l *Ledger) addBlockTxns(t *testing.T, accounts map[basics.Address]basics.A blk.Payset = append(blk.Payset, txib) } var err error - blk.TxnRoot, err = blk.PaysetCommit() + blk.TxnCommitments, err = blk.PaysetCommit() require.NoError(t, err) return l.AddBlock(blk, agreement.Certificate{}) } @@ -231,7 +231,7 @@ func TestLedgerBlockHeaders(t *testing.T) { emptyBlock := bookkeeping.Block{ BlockHeader: correctHeader, } - correctHeader.TxnRoot, err = emptyBlock.PaysetCommit() + correctHeader.TxnCommitments, err = emptyBlock.PaysetCommit() require.NoError(t, err) correctHeader.RewardsPool = testPoolAddr @@ -324,11 +324,11 @@ func TestLedgerBlockHeaders(t *testing.T) { // TODO test rewards cases with changing poolAddr money, with changing round, and with changing total reward units badBlock = bookkeeping.Block{BlockHeader: correctHeader} - badBlock.BlockHeader.TxnRoot = crypto.Hash([]byte{0}) + badBlock.BlockHeader.TxnCommitments.NativeSha512_256Commitment = crypto.Hash([]byte{0}) a.Error(l.appendUnvalidated(badBlock), "added block header with empty transaction root") badBlock = bookkeeping.Block{BlockHeader: correctHeader} - badBlock.BlockHeader.TxnRoot[0]++ + badBlock.BlockHeader.TxnCommitments.NativeSha512_256Commitment[0]++ a.Error(l.appendUnvalidated(badBlock), "added block header with invalid transaction root") correctBlock := bookkeeping.Block{BlockHeader: correctHeader} @@ -996,7 +996,7 @@ int 1 // [1] a.NoError(err) blk.TxnCounter = blk.TxnCounter + 2 blk.Payset = append(blk.Payset, txib1, txib2) - blk.TxnRoot, err = blk.PaysetCommit() + blk.TxnCommitments, err = blk.PaysetCommit() a.NoError(err) err = l.appendUnvalidated(blk) a.NoError(err) @@ -1245,7 +1245,7 @@ func testLedgerSingleTxApplyData(t *testing.T, version protocol.ConsensusVersion initNextBlockHeader(&correctHeader, lastBlock, proto) correctBlock := bookkeeping.Block{BlockHeader: correctHeader} - correctBlock.TxnRoot, err = correctBlock.PaysetCommit() + correctBlock.TxnCommitments, err = correctBlock.PaysetCommit() a.NoError(err) a.NoError(l.appendUnvalidated(correctBlock), "could not add block with correct header") diff --git a/ledger/ledgercore/msgp_gen_test.go b/ledger/ledgercore/msgp_gen_test.go index 99ad64e4de..3dc6a7409e 100644 --- a/ledger/ledgercore/msgp_gen_test.go +++ b/ledger/ledgercore/msgp_gen_test.go @@ -1,3 +1,4 @@ +//go:build !skip_msgp_testing // +build !skip_msgp_testing package ledgercore @@ -7,9 +8,10 @@ package ledgercore import ( "testing" + "github.com/algorand/msgp/msgp" + "github.com/algorand/go-algorand/protocol" "github.com/algorand/go-algorand/test/partitiontest" - "github.com/algorand/msgp/msgp" ) func TestMarshalUnmarshalAccountTotals(t *testing.T) { diff --git a/ledger/msgp_gen.go b/ledger/msgp_gen.go index 5e0a025671..31c0c8224b 100644 --- a/ledger/msgp_gen.go +++ b/ledger/msgp_gen.go @@ -5,9 +5,10 @@ package ledger import ( "sort" + "github.com/algorand/msgp/msgp" + "github.com/algorand/go-algorand/config" "github.com/algorand/go-algorand/data/basics" - "github.com/algorand/msgp/msgp" ) // The following msgp objects are implemented in this file: diff --git a/ledger/msgp_gen_test.go b/ledger/msgp_gen_test.go index 92b54bc521..140b1e8827 100644 --- a/ledger/msgp_gen_test.go +++ b/ledger/msgp_gen_test.go @@ -1,3 +1,4 @@ +//go:build !skip_msgp_testing // +build !skip_msgp_testing package ledger @@ -7,9 +8,10 @@ package ledger import ( "testing" + "github.com/algorand/msgp/msgp" + "github.com/algorand/go-algorand/protocol" "github.com/algorand/go-algorand/test/partitiontest" - "github.com/algorand/msgp/msgp" ) func TestMarshalUnmarshalCatchpointFileHeader(t *testing.T) { diff --git a/ledger/perf_test.go b/ledger/perf_test.go index 53cc2cb494..50c407c676 100644 --- a/ledger/perf_test.go +++ b/ledger/perf_test.go @@ -141,7 +141,7 @@ func BenchmarkValidate(b *testing.B) { newblk.Payset = append(newblk.Payset, txib) } - newblk.BlockHeader.TxnRoot, err = newblk.PaysetCommit() + newblk.BlockHeader.TxnCommitments, err = newblk.PaysetCommit() require.NoError(b, err) b.StartTimer() diff --git a/ledger/testing/initState.go b/ledger/testing/initState.go index 29b9767dc5..883517a5e6 100644 --- a/ledger/testing/initState.go +++ b/ledger/testing/initState.go @@ -96,7 +96,7 @@ func GenerateInitState(tb testing.TB, proto protocol.ConsensusVersion, baseAlgoP } var err error - initBlock.TxnRoot, err = initBlock.PaysetCommit() + initBlock.TxnCommitments, err = initBlock.PaysetCommit() require.NoError(tb, err) if params.SupportGenesisHash { diff --git a/libgoal/libgoal.go b/libgoal/libgoal.go index 2fa488ec98..f766363f2d 100644 --- a/libgoal/libgoal.go +++ b/libgoal/libgoal.go @@ -1185,10 +1185,10 @@ func (c *Client) Dryrun(data []byte) (resp generatedV2.DryrunResponse, err error } // TxnProof returns a Merkle proof for a transaction in a block. -func (c *Client) TxnProof(txid string, round uint64) (resp generatedV2.ProofResponse, err error) { +func (c *Client) TxnProof(txid string, round uint64, hashType crypto.HashType) (resp generatedV2.ProofResponse, err error) { algod, err := c.ensureAlgodClient() if err == nil { - return algod.Proof(txid, round) + return algod.Proof(txid, round, hashType) } return } diff --git a/libgoal/lockedFileLinux.go b/libgoal/lockedFileLinux.go index 989972873c..9c60ca028d 100644 --- a/libgoal/lockedFileLinux.go +++ b/libgoal/lockedFileLinux.go @@ -14,6 +14,7 @@ // You should have received a copy of the GNU Affero General Public License // along with go-algorand. If not, see . +//go:build linux // +build linux package libgoal diff --git a/libgoal/lockedFileUnix.go b/libgoal/lockedFileUnix.go index 70262a15ca..b32af5def4 100644 --- a/libgoal/lockedFileUnix.go +++ b/libgoal/lockedFileUnix.go @@ -17,6 +17,7 @@ // Support all unix system except linux // in https://github.com/golang/sys/blob/master/unix/syscall_unix.go +//go:build aix || darwin || dragonfly || freebsd || netbsd || openbsd || solaris // +build aix darwin dragonfly freebsd netbsd openbsd solaris package libgoal diff --git a/libgoal/lockedFileWindows.go b/libgoal/lockedFileWindows.go index efc6de0ade..c89785d80a 100644 --- a/libgoal/lockedFileWindows.go +++ b/libgoal/lockedFileWindows.go @@ -14,6 +14,7 @@ // You should have received a copy of the GNU Affero General Public License // along with go-algorand. If not, see . +//go:build windows // +build windows package libgoal diff --git a/libgoal/transactions.go b/libgoal/transactions.go index c689d5c59e..bf704cc9ef 100644 --- a/libgoal/transactions.go +++ b/libgoal/transactions.go @@ -752,7 +752,7 @@ func (c *Client) GroupID(txgroup []transactions.Transaction) (gid crypto.Digest, return } - group.TxGroupHashes = append(group.TxGroupHashes, crypto.HashObj(tx)) + group.TxGroupHashes = append(group.TxGroupHashes, crypto.Digest(tx.ID())) } return crypto.HashObj(group), nil diff --git a/netdeploy/networkTemplate.go b/netdeploy/networkTemplate.go index dc485879e4..293fbaa865 100644 --- a/netdeploy/networkTemplate.go +++ b/netdeploy/networkTemplate.go @@ -246,6 +246,7 @@ func createConfigFile(node remote.NodeConfigGoal, configFile string, numNodes in cfg.EndpointAddress = "127.0.0.1:0" cfg.DNSBootstrapID = "" cfg.EnableProfiler = true + cfg.EnableRuntimeMetrics = true if relaysCount == 0 { cfg.DisableNetworking = true } diff --git a/netdeploy/remote/deployedNetwork.go b/netdeploy/remote/deployedNetwork.go index 65021cd2cd..dcad2d3902 100644 --- a/netdeploy/remote/deployedNetwork.go +++ b/netdeploy/remote/deployedNetwork.go @@ -555,7 +555,7 @@ func createBlock(src basics.Address, prev bookkeeping.Block, roundTxnCnt uint64, payset = append(payset, txibs...) bootstrappedNet.txnCount += uint64(len(payset)) block.Payset = payset - block.TxnRoot, err = block.PaysetCommit() + block.TxnCommitments, err = block.PaysetCommit() if err != nil { return bookkeeping.Block{}, err } diff --git a/network/messagetracer/graphtrace.go b/network/messagetracer/graphtrace.go index 8a92698011..68c465914b 100644 --- a/network/messagetracer/graphtrace.go +++ b/network/messagetracer/graphtrace.go @@ -14,6 +14,7 @@ // You should have received a copy of the GNU Affero General Public License // along with go-algorand. If not, see . // +//go:build msgtrace // +build msgtrace package messagetracer diff --git a/network/wsNetwork.go b/network/wsNetwork.go index 59de32eefb..68394a924c 100644 --- a/network/wsNetwork.go +++ b/network/wsNetwork.go @@ -301,6 +301,19 @@ func Propagate(msg IncomingMessage) OutgoingMessage { // Contains {genesisID} param to be handled by gorilla/mux const GossipNetworkPath = "/v1/{genesisID}/gossip" +// NodeInfo helps the network get information about the node it is running on +type NodeInfo interface { + // IsParticipating returns true if this node has stake and may vote on blocks or propose blocks. + IsParticipating() bool +} + +type nopeNodeInfo struct { +} + +func (nnni *nopeNodeInfo) IsParticipating() bool { + return false +} + // WebsocketNetwork implements GossipNode type WebsocketNetwork struct { listener net.Listener @@ -397,21 +410,34 @@ type WebsocketNetwork struct { // to be sent to new peers. This is filled in at network start, // at which point messagesOfInterestEncoded is set to prevent // further changes. - messagesOfInterestEnc []byte - messagesOfInterestEncoded bool + messagesOfInterestEnc []byte + messagesOfInterestEncoded bool + messagesOfInterestGeneration uint32 // messagesOfInterestMu protects messagesOfInterest and ensures // that messagesOfInterestEnc does not change once it is set during // network start. - messagesOfInterestMu deadlock.Mutex + messagesOfInterestMu deadlock.Mutex + messagesOfInterestCond *sync.Cond // peersConnectivityCheckTicker is the timer for testing that all the connected peers // are still transmitting or receiving information. The channel produced by this ticker // is consumed by any of the messageHandlerThread(s). The ticker itself is created during // Start(), and being shut down when Stop() is called. peersConnectivityCheckTicker *time.Ticker + + nodeInfo NodeInfo + + // atomic {0:unknown, 1:yes, 2:no} + wantTXGossip uint32 } +const ( + wantTXGossipUnk = 0 + wantTXGossipYes = 1 + wantTXGossipNo = 2 +) + type broadcastRequest struct { tags []Tag data [][]byte @@ -661,6 +687,9 @@ func (wn *WebsocketNetwork) setup() { if wn.config.DNSSecurityRelayAddrEnforced() { preferredResolver = dnssec.MakeDefaultDnssecResolver(wn.config.FallbackDNSResolverAddress, wn.log) } + if wn.nodeInfo == nil { + wn.nodeInfo = &nopeNodeInfo{} + } maxIdleConnsPerHost := int(wn.config.ConnectionsRateLimitingCount) wn.dialer = makeRateLimitingDialer(wn.phonebook, preferredResolver) wn.transport = makeRateLimitingTransport(wn.phonebook, 10*time.Second, &wn.dialer, maxIdleConnsPerHost) @@ -684,6 +713,9 @@ func (wn *WebsocketNetwork) setup() { wn.server.MaxHeaderBytes = httpServerMaxHeaderBytes wn.ctx, wn.ctxCancel = context.WithCancel(context.Background()) wn.relayMessages = wn.config.NetAddress != "" || wn.config.ForceRelayMessages + if wn.relayMessages || wn.config.ForceFetchTransactions { + wn.wantTXGossip = wantTXGossipYes + } // roughly estimate the number of messages that could be seen at any given moment. // For the late/redo/down committee, which happen in parallel, we need to allocate // extra space there. @@ -732,6 +764,8 @@ func (wn *WebsocketNetwork) setup() { SupportedProtocolVersions = []string{wn.config.NetworkProtocolVersion} } + wn.messagesOfInterestCond = sync.NewCond(&wn.messagesOfInterestMu) + wn.messagesOfInterestGeneration = 1 // something nonzero so that any new wsPeer needs updating if wn.relayMessages { wn.RegisterMessageInterest(protocol.CompactCertSigTag) } @@ -798,6 +832,9 @@ func (wn *WebsocketNetwork) Start() { wn.wg.Add(1) go wn.prioWeightRefresh() } + + go wn.postMessagesOfInterestThread() + wn.log.Infof("serving genesisID=%s on %#v with RandomID=%s", wn.GenesisID, wn.PublicAddress(), wn.RandomID) } @@ -1123,18 +1160,29 @@ func (wn *WebsocketNetwork) ServeHTTP(response http.ResponseWriter, request *htt InstanceName: trackedRequest.otherInstanceName, }) - // We are careful to encode this prior to starting the server to avoid needing 'messagesOfInterestMu' here. - if wn.messagesOfInterestEnc != nil { - err = peer.Unicast(wn.ctx, wn.messagesOfInterestEnc, protocol.MsgOfInterestTag) - if err != nil { - wn.log.Infof("ws send msgOfInterest: %v", err) - } - } + wn.maybeSendMessagesOfInterest(peer, nil) peers.Set(float64(wn.NumPeers()), nil) incomingPeers.Set(float64(wn.numIncomingPeers()), nil) } +func (wn *WebsocketNetwork) maybeSendMessagesOfInterest(peer *wsPeer, messagesOfInterestEnc []byte) { + messagesOfInterestGeneration := atomic.LoadUint32(&wn.messagesOfInterestGeneration) + peerMessagesOfInterestGeneration := atomic.LoadUint32(&peer.messagesOfInterestGeneration) + if peerMessagesOfInterestGeneration != messagesOfInterestGeneration { + if messagesOfInterestEnc == nil { + wn.messagesOfInterestMu.Lock() + messagesOfInterestEnc = wn.messagesOfInterestEnc + wn.messagesOfInterestMu.Unlock() + } + if messagesOfInterestEnc != nil { + peer.sendMessagesOfInterest(messagesOfInterestGeneration, messagesOfInterestEnc) + } else { + wn.log.Infof("msgOfInterest Enc=nil") + } + } +} + func (wn *WebsocketNetwork) messageHandlerThread(peersConnectivityCheckCh <-chan time.Time) { defer wn.wg.Done() @@ -1677,6 +1725,17 @@ func (wn *WebsocketNetwork) OnNetworkAdvance() { wn.lastNetworkAdvanceMu.Lock() defer wn.lastNetworkAdvanceMu.Unlock() wn.lastNetworkAdvance = time.Now().UTC() + if wn.nodeInfo != nil && !wn.relayMessages && !wn.config.ForceFetchTransactions { + // if we're not a relay, and not participating, we don't need txn pool + wantTXGossip := wn.nodeInfo.IsParticipating() + if wantTXGossip && (wn.wantTXGossip != wantTXGossipYes) { + wn.RegisterMessageInterest(protocol.TxnTag) + wn.wantTXGossip = wantTXGossipYes + } else if !wantTXGossip && (wn.wantTXGossip != wantTXGossipNo) { + wn.DeregisterMessageInterest(protocol.TxnTag) + wn.wantTXGossip = wantTXGossipNo + } + } } // sendPeerConnectionsTelemetryStatus sends a snapshot of the currently connected peers @@ -2046,6 +2105,8 @@ func (wn *WebsocketNetwork) tryConnect(addr, gossipAddr string) { Endpoint: peer.GetAddress(), }) + wn.maybeSendMessagesOfInterest(peer, nil) + peers.Set(float64(wn.NumPeers()), nil) outgoingPeers.Set(float64(wn.numOutgoingPeers()), nil) @@ -2085,7 +2146,7 @@ func (wn *WebsocketNetwork) SetPeerData(peer Peer, key string, value interface{} } // NewWebsocketNetwork constructor for websockets based gossip network -func NewWebsocketNetwork(log logging.Logger, config config.Local, phonebookAddresses []string, genesisID string, networkID protocol.NetworkID) (wn *WebsocketNetwork, err error) { +func NewWebsocketNetwork(log logging.Logger, config config.Local, phonebookAddresses []string, genesisID string, networkID protocol.NetworkID, nodeInfo NodeInfo) (wn *WebsocketNetwork, err error) { phonebook := MakePhonebook(config.ConnectionsRateLimitingCount, time.Duration(config.ConnectionsRateLimitingWindowSeconds)*time.Second) phonebook.ReplacePeerList(phonebookAddresses, config.DNSBootstrapID, PhoneBookEntryRelayRole) @@ -2095,6 +2156,7 @@ func NewWebsocketNetwork(log logging.Logger, config config.Local, phonebookAddre phonebook: phonebook, GenesisID: genesisID, NetworkID: networkID, + nodeInfo: nodeInfo, } wn.setup() @@ -2103,7 +2165,7 @@ func NewWebsocketNetwork(log logging.Logger, config config.Local, phonebookAddre // NewWebsocketGossipNode constructs a websocket network node and returns it as a GossipNode interface implementation func NewWebsocketGossipNode(log logging.Logger, config config.Local, phonebookAddresses []string, genesisID string, networkID protocol.NetworkID) (gn GossipNode, err error) { - return NewWebsocketNetwork(log, config, phonebookAddresses, genesisID, networkID) + return NewWebsocketNetwork(log, config, phonebookAddresses, genesisID, networkID, nil) } // SetPrioScheme specifies the network priority scheme for a network node @@ -2254,10 +2316,23 @@ func (wn *WebsocketNetwork) RegisterMessageInterest(t protocol.Tag) error { wn.messagesOfInterestMu.Lock() defer wn.messagesOfInterestMu.Unlock() - if wn.messagesOfInterestEncoded { - return fmt.Errorf("network already started") + if wn.messagesOfInterest == nil { + wn.messagesOfInterest = make(map[protocol.Tag]bool) + for tag, flag := range defaultSendMessageTags { + wn.messagesOfInterest[tag] = flag + } } + wn.messagesOfInterest[t] = true + wn.updateMessagesOfInterestEnc() + return nil +} + +// DeregisterMessageInterest will tell peers to no longer send us traffic with a protocol Tag +func (wn *WebsocketNetwork) DeregisterMessageInterest(t protocol.Tag) error { + wn.messagesOfInterestMu.Lock() + defer wn.messagesOfInterestMu.Unlock() + if wn.messagesOfInterest == nil { wn.messagesOfInterest = make(map[protocol.Tag]bool) for tag, flag := range defaultSendMessageTags { @@ -2265,10 +2340,32 @@ func (wn *WebsocketNetwork) RegisterMessageInterest(t protocol.Tag) error { } } - wn.messagesOfInterest[t] = true + delete(wn.messagesOfInterest, t) + wn.updateMessagesOfInterestEnc() return nil } +func (wn *WebsocketNetwork) updateMessagesOfInterestEnc() { + // must run inside wn.messagesOfInterestMu.Lock + wn.messagesOfInterestEnc = MarshallMessageOfInterestMap(wn.messagesOfInterest) + wn.messagesOfInterestEncoded = true + atomic.AddUint32(&wn.messagesOfInterestGeneration, 1) + wn.messagesOfInterestCond.Broadcast() +} + +func (wn *WebsocketNetwork) postMessagesOfInterestThread() { + var peers []*wsPeer + wn.messagesOfInterestMu.Lock() + defer wn.messagesOfInterestMu.Unlock() + for { + wn.messagesOfInterestCond.Wait() + peers, _ = wn.peerSnapshot(peers) + for _, peer := range peers { + wn.maybeSendMessagesOfInterest(peer, wn.messagesOfInterestEnc) + } + } +} + // SubstituteGenesisID substitutes the "{genesisID}" with their network-specific genesisID. func (wn *WebsocketNetwork) SubstituteGenesisID(rawURL string) string { return strings.Replace(rawURL, "{genesisID}", wn.GenesisID, -1) diff --git a/network/wsNetwork_test.go b/network/wsNetwork_test.go index f7e5db2da3..02294f0c01 100644 --- a/network/wsNetwork_test.go +++ b/network/wsNetwork_test.go @@ -1456,11 +1456,24 @@ func TestSlowPeerDisconnection(t *testing.T) { peers, _ = netA.peerSnapshot(peers) require.Equalf(t, len(peers), 1, "Expected number of peers should be 1") peer := peers[0] + // On connection may send a MOI message, wait for it to go out + now := time.Now() + expire := now.Add(5 * time.Second) + for { + time.Sleep(time.Millisecond) + if len(peer.sendBufferHighPrio)+len(peer.sendBufferBulk) == 0 { + break + } + now = time.Now() + if now.After(expire) { + t.Errorf("wait for empty peer outbound queue expired") + } + } // modify the peer on netA and beforeLoopTime := time.Now() atomic.StoreInt64(&peer.intermittentOutgoingMessageEnqueueTime, beforeLoopTime.Add(-maxMessageQueueDuration).Add(time.Second).UnixNano()) // wait up to 10 seconds for the monitor to figure out it needs to disconnect. - expire := beforeLoopTime.Add(2 * slowWritingPeerMonitorInterval) + expire = beforeLoopTime.Add(2 * slowWritingPeerMonitorInterval) for { peers, _ = netA.peerSnapshot(peers) if len(peers) == 0 || peers[0] != peer { @@ -1707,6 +1720,15 @@ func TestWebsocketNetworkTopicRoundtrip(t *testing.T) { assert.Equal(t, 5, int(sum[0])) } +var ( + ft1 = protocol.Tag("F1") + ft2 = protocol.Tag("F2") + ft3 = protocol.Tag("F3") + ft4 = protocol.Tag("F4") + + testTags = []protocol.Tag{ft1, ft2, ft3, ft4} +) + // Set up two nodes, have one of them request a certain message tag mask, and verify the other follow that. func TestWebsocketNetworkMessageOfInterest(t *testing.T) { partitiontest.PartitionTest(t) @@ -1727,6 +1749,143 @@ func TestWebsocketNetworkMessageOfInterest(t *testing.T) { netB.Start() defer func() { t.Log("stopping B"); netB.Stop(); t.Log("B done") }() + incomingMsgSync := deadlock.Mutex{} + msgCounters := make(map[protocol.Tag]int) + expectedCounts := make(map[protocol.Tag]int) + expectedCounts[ft1] = 5 + expectedCounts[ft2] = 5 + var failed uint32 + messageArriveWg := sync.WaitGroup{} + msgHandler := func(msg IncomingMessage) (out OutgoingMessage) { + t.Logf("A->B %s", msg.Tag) + incomingMsgSync.Lock() + defer incomingMsgSync.Unlock() + expected := expectedCounts[msg.Tag] + if expected < 1 { + atomic.StoreUint32(&failed, 1) + t.Logf("UNEXPECTED A->B %s", msg.Tag) + return + } + msgCounters[msg.Tag] = msgCounters[msg.Tag] + 1 + messageArriveWg.Done() + return + } + messageFilterArriveWg := sync.WaitGroup{} + messageFilterArriveWg.Add(1) + waitMessageArriveHandler := func(msg IncomingMessage) (out OutgoingMessage) { + messageFilterArriveWg.Done() + return + } + + // register all the handlers. + taggedHandlers := []TaggedMessageHandler{} + for _, tag := range testTags { + taggedHandlers = append(taggedHandlers, TaggedMessageHandler{ + Tag: tag, + MessageHandler: HandlerFunc(msgHandler), + }) + } + netB.RegisterHandlers(taggedHandlers) + netA.RegisterHandlers([]TaggedMessageHandler{ + { + Tag: protocol.VoteBundleTag, + MessageHandler: HandlerFunc(waitMessageArriveHandler), + }}) + + readyTimeout := time.NewTimer(2 * time.Second) + waitReady(t, netA, readyTimeout.C) + waitReady(t, netB, readyTimeout.C) + + // have netB asking netA to send it only AgreementVoteTag and ProposalPayloadTag + require.NoError(t, netB.RegisterMessageInterest(ft1)) + require.NoError(t, netB.RegisterMessageInterest(ft2)) + // send another message which we can track, so that we'll know that the first message was delivered. + netB.Broadcast(context.Background(), protocol.VoteBundleTag, []byte{0, 1, 2, 3, 4}, true, nil) + messageFilterArriveWg.Wait() + // okay, but now we need to wait for asynchronous thread within netA to _apply_ the MOI to its peer for netB... + timeout := time.Now().Add(100 * time.Millisecond) + waiting := true + for waiting { + time.Sleep(1 * time.Millisecond) + peers := netA.GetPeers(PeersConnectedIn) + for _, pg := range peers { + wp := pg.(*wsPeer) + if len(wp.sendBufferHighPrio)+len(wp.sendBufferBulk) == 0 { + waiting = false + break + } + } + if time.Now().After(timeout) { + for _, pg := range peers { + wp := pg.(*wsPeer) + if len(wp.sendBufferHighPrio)+len(wp.sendBufferBulk) == 0 { + t.Fatalf("netA peer buff empty timeout len(high)=%d, len(bulk)=%d", len(wp.sendBufferHighPrio), len(wp.sendBufferBulk)) + } + } + } + } + + messageArriveWg.Add(5 * 2) // we're expecting exactly 10 messages. + // send 5 messages of few types. + for i := 0; i < 5; i++ { + if atomic.LoadUint32(&failed) != 0 { + t.Errorf("failed") + break + } + netA.Broadcast(context.Background(), ft1, []byte{0, 1, 2, 3, 4}, true, nil) + netA.Broadcast(context.Background(), ft3, []byte{0, 1, 2, 3, 4}, true, nil) // NOT in MOI + netA.Broadcast(context.Background(), ft2, []byte{0, 1, 2, 3, 4}, true, nil) + netA.Broadcast(context.Background(), ft4, []byte{0, 1, 2, 3, 4}, true, nil) // NOT in MOI + } + if atomic.LoadUint32(&failed) != 0 { + t.Errorf("failed") + } + // wait until all the expected messages arrive. + messageArriveWg.Wait() + incomingMsgSync.Lock() + defer incomingMsgSync.Unlock() + require.Equal(t, 2, len(msgCounters)) + for tag, count := range msgCounters { + if atomic.LoadUint32(&failed) != 0 { + t.Errorf("failed") + break + } + if tag == ft1 || tag == ft2 { + require.Equal(t, 5, count) + } else { + require.Equal(t, 0, count) + } + } +} + +// Set up two nodes, have one of them work through TX gossip message-of-interest logic +// test: +// * wn.config.ForceFetchTransactions +// * wn.config.ForceRelayMessages +// * NodeInfo.IsParticipating() + WebsocketNetwork.OnNetworkAdvance() +func TestWebsocketNetworkTXMessageOfInterestRelay(t *testing.T) { + // Tests that A->B follows MOI + partitiontest.PartitionTest(t) + + netA := makeTestWebsocketNode(t) + netA.config.GossipFanout = 1 + netA.config.EnablePingHandler = false + + netA.Start() + defer func() { t.Log("stopping A"); netA.Stop(); t.Log("A done") }() + bConfig := defaultConfig + bConfig.NetAddress = "" + bConfig.ForceRelayMessages = true + netB := makeTestWebsocketNodeWithConfig(t, bConfig) + netB.config.GossipFanout = 1 + netB.config.EnablePingHandler = false + addrA, postListen := netA.Address() + require.True(t, postListen) + t.Log(addrA) + netB.phonebook.ReplacePeerList([]string{addrA}, "default", PhoneBookEntryRelayRole) + netB.Start() + defer func() { t.Log("stopping B"); netB.Stop(); t.Log("B done") }() + incomingMsgSync := deadlock.Mutex{} msgCounters := make(map[protocol.Tag]int) messageArriveWg := sync.WaitGroup{} @@ -1763,13 +1922,94 @@ func TestWebsocketNetworkMessageOfInterest(t *testing.T) { waitReady(t, netA, readyTimeout.C) waitReady(t, netB, readyTimeout.C) - // have netB asking netA to send it only AgreementVoteTag and ProposalPayloadTag - netB.Broadcast(context.Background(), protocol.MsgOfInterestTag, MarshallMessageOfInterest([]protocol.Tag{protocol.AgreementVoteTag, protocol.ProposalPayloadTag}), true, nil) + netB.OnNetworkAdvance() // send another message which we can track, so that we'll know that the first message was delivered. netB.Broadcast(context.Background(), protocol.AgreementVoteTag, []byte{0, 1, 2, 3, 4}, true, nil) messageFilterArriveWg.Wait() - messageArriveWg.Add(5 * 2) // we're expecting exactly 10 messages. + messageArriveWg.Add(5 * 4) // we're expecting exactly 20 messages. + // send 5 messages of few types. + for i := 0; i < 5; i++ { + netA.Broadcast(context.Background(), protocol.AgreementVoteTag, []byte{0, 1, 2, 3, 4}, true, nil) + netA.Broadcast(context.Background(), protocol.TxnTag, []byte{0, 1, 2, 3, 4}, true, nil) + netA.Broadcast(context.Background(), protocol.ProposalPayloadTag, []byte{0, 1, 2, 3, 4}, true, nil) + netA.Broadcast(context.Background(), protocol.VoteBundleTag, []byte{0, 1, 2, 3, 4}, true, nil) + } + // wait until all the expected messages arrive. + messageArriveWg.Wait() + incomingMsgSync.Lock() + require.Equal(t, 4, len(msgCounters)) + for _, count := range msgCounters { + require.Equal(t, 5, count) + } + incomingMsgSync.Unlock() +} + +func TestWebsocketNetworkTXMessageOfInterestForceTx(t *testing.T) { + // Tests that A->B follows MOI + partitiontest.PartitionTest(t) + + netA := makeTestWebsocketNode(t) + netA.config.GossipFanout = 1 + netA.config.EnablePingHandler = false + + netA.Start() + defer func() { t.Log("stopping A"); netA.Stop(); t.Log("A done") }() + bConfig := defaultConfig + bConfig.NetAddress = "" + bConfig.ForceFetchTransactions = true + netB := makeTestWebsocketNodeWithConfig(t, bConfig) + netB.config.GossipFanout = 1 + netB.config.EnablePingHandler = false + addrA, postListen := netA.Address() + require.True(t, postListen) + t.Log(addrA) + netB.phonebook.ReplacePeerList([]string{addrA}, "default", PhoneBookEntryRelayRole) + netB.Start() + defer func() { t.Log("stopping B"); netB.Stop(); t.Log("B done") }() + + incomingMsgSync := deadlock.Mutex{} + msgCounters := make(map[protocol.Tag]int) + messageArriveWg := sync.WaitGroup{} + msgHandler := func(msg IncomingMessage) (out OutgoingMessage) { + incomingMsgSync.Lock() + defer incomingMsgSync.Unlock() + msgCounters[msg.Tag] = msgCounters[msg.Tag] + 1 + messageArriveWg.Done() + return + } + messageFilterArriveWg := sync.WaitGroup{} + messageFilterArriveWg.Add(1) + waitMessageArriveHandler := func(msg IncomingMessage) (out OutgoingMessage) { + messageFilterArriveWg.Done() + return + } + + // register all the handlers. + taggedHandlers := []TaggedMessageHandler{} + for tag := range defaultSendMessageTags { + taggedHandlers = append(taggedHandlers, TaggedMessageHandler{ + Tag: tag, + MessageHandler: HandlerFunc(msgHandler), + }) + } + netB.RegisterHandlers(taggedHandlers) + netA.RegisterHandlers([]TaggedMessageHandler{ + { + Tag: protocol.AgreementVoteTag, + MessageHandler: HandlerFunc(waitMessageArriveHandler), + }}) + + readyTimeout := time.NewTimer(2 * time.Second) + waitReady(t, netA, readyTimeout.C) + waitReady(t, netB, readyTimeout.C) + + netB.OnNetworkAdvance() + // send another message which we can track, so that we'll know that the first message was delivered. + netB.Broadcast(context.Background(), protocol.AgreementVoteTag, []byte{0, 1, 2, 3, 4}, true, nil) + messageFilterArriveWg.Wait() + + messageArriveWg.Add(5 * 4) // we're expecting exactly 20 messages. // send 5 messages of few types. for i := 0; i < 5; i++ { netA.Broadcast(context.Background(), protocol.AgreementVoteTag, []byte{0, 1, 2, 3, 4}, true, nil) @@ -1779,13 +2019,199 @@ func TestWebsocketNetworkMessageOfInterest(t *testing.T) { } // wait until all the expected messages arrive. messageArriveWg.Wait() + incomingMsgSync.Lock() + require.Equal(t, 4, len(msgCounters)) + for _, count := range msgCounters { + require.Equal(t, 5, count) + } + incomingMsgSync.Unlock() +} +func TestWebsocketNetworkTXMessageOfInterestNPN(t *testing.T) { + // Tests that A->B follows MOI + partitiontest.PartitionTest(t) + + netA := makeTestWebsocketNode(t) + netA.config.GossipFanout = 1 + netA.config.EnablePingHandler = false + netA.Start() + defer func() { t.Log("stopping A"); netA.Stop(); t.Log("A done") }() + + bConfig := defaultConfig + bConfig.NetAddress = "" + netB := makeTestWebsocketNodeWithConfig(t, bConfig) + netB.config.GossipFanout = 1 + netB.config.EnablePingHandler = false + addrA, postListen := netA.Address() + require.True(t, postListen) + t.Log(addrA) + netB.phonebook.ReplacePeerList([]string{addrA}, "default", PhoneBookEntryRelayRole) + netB.Start() + defer func() { t.Log("stopping B"); netB.Stop(); t.Log("B done") }() + require.False(t, netB.relayMessages) + require.Equal(t, uint32(wantTXGossipUnk), netB.wantTXGossip) + + incomingMsgSync := deadlock.Mutex{} + msgCounters := make(map[protocol.Tag]int) + messageArriveWg := sync.WaitGroup{} + msgHandler := func(msg IncomingMessage) (out OutgoingMessage) { + incomingMsgSync.Lock() + defer incomingMsgSync.Unlock() + msgCounters[msg.Tag] = msgCounters[msg.Tag] + 1 + messageArriveWg.Done() + return + } + messageFilterArriveWg := sync.WaitGroup{} + messageFilterArriveWg.Add(1) + waitMessageArriveHandler := func(msg IncomingMessage) (out OutgoingMessage) { + messageFilterArriveWg.Done() + return + } + + // register all the handlers. + taggedHandlers := []TaggedMessageHandler{} + for tag := range defaultSendMessageTags { + taggedHandlers = append(taggedHandlers, TaggedMessageHandler{ + Tag: tag, + MessageHandler: HandlerFunc(msgHandler), + }) + } + netB.RegisterHandlers(taggedHandlers) + netA.RegisterHandlers([]TaggedMessageHandler{ + { + Tag: protocol.AgreementVoteTag, + MessageHandler: HandlerFunc(waitMessageArriveHandler), + }}) + + readyTimeout := time.NewTimer(2 * time.Second) + waitReady(t, netA, readyTimeout.C) + waitReady(t, netB, readyTimeout.C) + + netB.OnNetworkAdvance() + // TODO: better event driven thing for netB sending new MOI + time.Sleep(10 * time.Millisecond) + require.Equal(t, uint32(wantTXGossipNo), netB.wantTXGossip) + // send another message which we can track, so that we'll know that the first message was delivered. + netB.Broadcast(context.Background(), protocol.AgreementVoteTag, []byte{0, 1, 2, 3, 4}, true, nil) + messageFilterArriveWg.Wait() + + messageArriveWg.Add(5 * 3) // we're expecting exactly 15 messages. + // send 5 messages of few types. + for i := 0; i < 5; i++ { + netA.Broadcast(context.Background(), protocol.AgreementVoteTag, []byte{0, 1, 2, 3, 4}, true, nil) + netA.Broadcast(context.Background(), protocol.TxnTag, []byte{0, 1, 2, 3, 4}, true, nil) // THESE WILL BE DROPPED + netA.Broadcast(context.Background(), protocol.ProposalPayloadTag, []byte{0, 1, 2, 3, 4}, true, nil) + netA.Broadcast(context.Background(), protocol.VoteBundleTag, []byte{0, 1, 2, 3, 4}, true, nil) + } + // wait until all the expected messages arrive. + messageArriveWg.Wait() + incomingMsgSync.Lock() + require.Equal(t, 3, len(msgCounters)) for tag, count := range msgCounters { - if tag == protocol.AgreementVoteTag || tag == protocol.ProposalPayloadTag { + if tag == protocol.TxnTag { + require.Equal(t, 0, count) + } else { + require.Equal(t, 5, count) + } + } + incomingMsgSync.Unlock() +} + +type participatingNodeInfo struct { +} + +func (nnni *participatingNodeInfo) IsParticipating() bool { + return true +} + +func TestWebsocketNetworkTXMessageOfInterestPN(t *testing.T) { + // Tests that A->B follows MOI + partitiontest.PartitionTest(t) + + netA := makeTestWebsocketNode(t) + netA.config.GossipFanout = 1 + netA.config.EnablePingHandler = false + netA.Start() + defer func() { t.Log("stopping A"); netA.Stop(); t.Log("A done") }() + + bConfig := defaultConfig + bConfig.NetAddress = "" + netB := makeTestWebsocketNodeWithConfig(t, bConfig) + netB.nodeInfo = &participatingNodeInfo{} + netB.config.GossipFanout = 1 + netB.config.EnablePingHandler = false + addrA, postListen := netA.Address() + require.True(t, postListen) + t.Log(addrA) + netB.phonebook.ReplacePeerList([]string{addrA}, "default", PhoneBookEntryRelayRole) + netB.Start() + defer func() { t.Log("stopping B"); netB.Stop(); t.Log("B done") }() + require.False(t, netB.relayMessages) + require.Equal(t, uint32(wantTXGossipUnk), netB.wantTXGossip) + + incomingMsgSync := deadlock.Mutex{} + msgCounters := make(map[protocol.Tag]int) + messageArriveWg := sync.WaitGroup{} + msgHandler := func(msg IncomingMessage) (out OutgoingMessage) { + incomingMsgSync.Lock() + defer incomingMsgSync.Unlock() + msgCounters[msg.Tag] = msgCounters[msg.Tag] + 1 + messageArriveWg.Done() + return + } + messageFilterArriveWg := sync.WaitGroup{} + messageFilterArriveWg.Add(1) + waitMessageArriveHandler := func(msg IncomingMessage) (out OutgoingMessage) { + messageFilterArriveWg.Done() + return + } + + // register all the handlers. + taggedHandlers := []TaggedMessageHandler{} + for tag := range defaultSendMessageTags { + taggedHandlers = append(taggedHandlers, TaggedMessageHandler{ + Tag: tag, + MessageHandler: HandlerFunc(msgHandler), + }) + } + netB.RegisterHandlers(taggedHandlers) + netA.RegisterHandlers([]TaggedMessageHandler{ + { + Tag: protocol.AgreementVoteTag, + MessageHandler: HandlerFunc(waitMessageArriveHandler), + }}) + + readyTimeout := time.NewTimer(2 * time.Second) + waitReady(t, netA, readyTimeout.C) + waitReady(t, netB, readyTimeout.C) + + netB.OnNetworkAdvance() + // TODO: better event driven thing for netB sending new MOI + time.Sleep(10 * time.Millisecond) + require.Equal(t, uint32(wantTXGossipYes), netB.wantTXGossip) + // send another message which we can track, so that we'll know that the first message was delivered. + netB.Broadcast(context.Background(), protocol.AgreementVoteTag, []byte{0, 1, 2, 3, 4}, true, nil) + messageFilterArriveWg.Wait() + + messageArriveWg.Add(5 * 4) // we're expecting exactly 20 messages. + // send 5 messages of few types. + for i := 0; i < 5; i++ { + netA.Broadcast(context.Background(), protocol.AgreementVoteTag, []byte{0, 1, 2, 3, 4}, true, nil) + netA.Broadcast(context.Background(), protocol.TxnTag, []byte{0, 1, 2, 3, 4}, true, nil) + netA.Broadcast(context.Background(), protocol.ProposalPayloadTag, []byte{0, 1, 2, 3, 4}, true, nil) + netA.Broadcast(context.Background(), protocol.VoteBundleTag, []byte{0, 1, 2, 3, 4}, true, nil) + } + // wait until all the expected messages arrive. + messageArriveWg.Wait() + incomingMsgSync.Lock() + require.Equal(t, 4, len(msgCounters)) + for tag, count := range msgCounters { + if tag == protocol.TxnTag { require.Equal(t, 5, count) } else { - require.Equal(t, 0, count) + require.Equal(t, 5, count) } } + incomingMsgSync.Unlock() } // Set up two nodes, have one of them disconnect from the other, and monitor disconnection error on the side that did not issue the disconnection. diff --git a/network/wsPeer.go b/network/wsPeer.go index 337dae07b3..2b451478e8 100644 --- a/network/wsPeer.go +++ b/network/wsPeer.go @@ -48,14 +48,14 @@ const averageMessageLength = 2 * 1024 // Most of the messages are smaller tha const msgsInReadBufferPerPeer = 10 var networkSentBytesTotal = metrics.MakeCounter(metrics.NetworkSentBytesTotal) -var networkSentBytesByTag = metrics.NewTagCounter("algod_network_sent_bytes_{TAG}", "Number of bytes that were sent over the network per message tag") +var networkSentBytesByTag = metrics.NewTagCounter("algod_network_sent_bytes_{TAG}", "Number of bytes that were sent over the network for {TAG} messages") var networkReceivedBytesTotal = metrics.MakeCounter(metrics.NetworkReceivedBytesTotal) -var networkReceivedBytesByTag = metrics.NewTagCounter("algod_network_received_bytes_{TAG}", "Number of bytes that were received from the network per message tag") +var networkReceivedBytesByTag = metrics.NewTagCounter("algod_network_received_bytes_{TAG}", "Number of bytes that were received from the network for {TAG} messages") var networkMessageReceivedTotal = metrics.MakeCounter(metrics.NetworkMessageReceivedTotal) -var networkMessageReceivedByTag = metrics.NewTagCounter("algod_network_message_received_{TAG}", "Number of complete messages that were received from the network per message tag") +var networkMessageReceivedByTag = metrics.NewTagCounter("algod_network_message_received_{TAG}", "Number of complete messages that were received from the network for {TAG} messages") var networkMessageSentTotal = metrics.MakeCounter(metrics.NetworkMessageSentTotal) -var networkMessageSentByTag = metrics.NewTagCounter("algod_network_message_sent_{TAG}", "Number of complete messages that were sent to the network per message tag") +var networkMessageSentByTag = metrics.NewTagCounter("algod_network_message_sent_{TAG}", "Number of complete messages that were sent to the network for {TAG} messages") var networkConnectionsDroppedTotal = metrics.MakeCounter(metrics.NetworkConnectionsDroppedTotal) var networkMessageQueueMicrosTotal = metrics.MakeCounter(metrics.MetricName{Name: "algod_network_message_sent_queue_micros_total", Description: "Total microseconds message spent waiting in queue to be sent"}) @@ -206,6 +206,9 @@ type wsPeer struct { // only gurentee is that it's being accessed only during startup and/or by the sending loop go routine. sendMessageTag map[protocol.Tag]bool + // messagesOfInterestGeneration is this node's messagesOfInterest version that we have seent to this peer. + messagesOfInterestGeneration uint32 + // connMonitor used to measure the relative performance of the connection // compared to the other outgoing connections. Incoming connections would have this // field set to nil. @@ -877,3 +880,12 @@ func (wp *wsPeer) setPeerData(key string, value interface{}) { wp.clientDataStore[key] = value } } + +func (wp *wsPeer) sendMessagesOfInterest(messagesOfInterestGeneration uint32, messagesOfInterestEnc []byte) { + err := wp.Unicast(wp.net.ctx, messagesOfInterestEnc, protocol.MsgOfInterestTag) + if err != nil { + wp.net.log.Errorf("ws send msgOfInterest: %v", err) + } else { + atomic.StoreUint32(&wp.messagesOfInterestGeneration, messagesOfInterestGeneration) + } +} diff --git a/network/wsPeer_test.go b/network/wsPeer_test.go index 60a0e3a799..550eb5fbda 100644 --- a/network/wsPeer_test.go +++ b/network/wsPeer_test.go @@ -22,6 +22,7 @@ import ( "time" "unsafe" + "github.com/algorand/go-algorand/logging" "github.com/algorand/go-algorand/test/partitiontest" "github.com/stretchr/testify/require" ) @@ -32,6 +33,9 @@ func TestCheckSlowWritingPeer(t *testing.T) { now := time.Now() peer := wsPeer{ intermittentOutgoingMessageEnqueueTime: 0, + wsPeerCore: wsPeerCore{net: &WebsocketNetwork{ + log: logging.TestingLog(t), + }}, } require.Equal(t, peer.CheckSlowWritingPeer(now), false) diff --git a/node/msgp_gen_test.go b/node/msgp_gen_test.go index e72b128ee6..46590cb228 100644 --- a/node/msgp_gen_test.go +++ b/node/msgp_gen_test.go @@ -1,3 +1,4 @@ +//go:build !skip_msgp_testing // +build !skip_msgp_testing package node @@ -7,9 +8,10 @@ package node import ( "testing" + "github.com/algorand/msgp/msgp" + "github.com/algorand/go-algorand/protocol" "github.com/algorand/go-algorand/test/partitiontest" - "github.com/algorand/msgp/msgp" ) func TestMarshalUnmarshalnetPrioResponse(t *testing.T) { diff --git a/node/node.go b/node/node.go index f173853d48..156f8fe336 100644 --- a/node/node.go +++ b/node/node.go @@ -175,7 +175,7 @@ func MakeFull(log logging.Logger, rootDir string, cfg config.Local, phonebookAdd node.config = cfg // tie network, block fetcher, and agreement services together - p2pNode, err := network.NewWebsocketNetwork(node.log, node.config, phonebookAddresses, genesis.ID(), genesis.Network) + p2pNode, err := network.NewWebsocketNetwork(node.log, node.config, phonebookAddresses, genesis.ID(), genesis.Network, node) if err != nil { log.Errorf("could not create websocket node: %v", err) return nil, err @@ -407,11 +407,11 @@ func (node *AlgorandFullNode) startMonitoringRoutines() { // PKI TODO: Remove this with #2596 // Periodically check for new participation keys - go node.checkForParticipationKeys() + go node.checkForParticipationKeys(node.ctx.Done()) - go node.txPoolGaugeThread() + go node.txPoolGaugeThread(node.ctx.Done()) // Delete old participation keys - go node.oldKeyDeletionThread() + go node.oldKeyDeletionThread(node.ctx.Done()) // TODO re-enable with configuration flag post V1 //go logging.UsageLogThread(node.ctx, node.log, 100*time.Millisecond, nil) @@ -782,7 +782,7 @@ func ensureParticipationDB(genesisDir string, log logging.Logger) (account.Parti } // Reload participation keys from disk periodically -func (node *AlgorandFullNode) checkForParticipationKeys() { +func (node *AlgorandFullNode) checkForParticipationKeys(done <-chan struct{}) { defer node.monitoringRoutinesWaitGroup.Done() ticker := time.NewTicker(node.config.ParticipationKeysRefreshInterval) for { @@ -792,7 +792,7 @@ func (node *AlgorandFullNode) checkForParticipationKeys() { if err != nil { node.log.Errorf("Could not refresh participation keys: %v", err) } - case <-node.ctx.Done(): + case <-done: ticker.Stop() return } @@ -1032,7 +1032,7 @@ func insertStateProofToRegistry(part account.PersistedParticipation, node *Algor var txPoolGuage = metrics.MakeGauge(metrics.MetricName{Name: "algod_tx_pool_count", Description: "current number of available transactions in pool"}) -func (node *AlgorandFullNode) txPoolGaugeThread() { +func (node *AlgorandFullNode) txPoolGaugeThread(done <-chan struct{}) { defer node.monitoringRoutinesWaitGroup.Done() ticker := time.NewTicker(10 * time.Second) defer ticker.Stop() @@ -1040,7 +1040,7 @@ func (node *AlgorandFullNode) txPoolGaugeThread() { select { case <-ticker.C: txPoolGuage.Set(float64(node.transactionPool.PendingCount()), nil) - case <-node.ctx.Done(): + case <-done: return } } @@ -1071,11 +1071,11 @@ func (node *AlgorandFullNode) OnNewBlock(block bookkeeping.Block, delta ledgerco // oldKeyDeletionThread keeps deleting old participation keys. // It runs in a separate thread so that, during catchup, we // don't have to delete key for each block we received. -func (node *AlgorandFullNode) oldKeyDeletionThread() { +func (node *AlgorandFullNode) oldKeyDeletionThread(done <-chan struct{}) { defer node.monitoringRoutinesWaitGroup.Done() for { select { - case <-node.ctx.Done(): + case <-done: return case <-node.oldKeyDeletionNotify: } @@ -1379,3 +1379,20 @@ func (node *AlgorandFullNode) VotingKeys(votingRound, keysRound basics.Round) [] func (node *AlgorandFullNode) Record(account basics.Address, round basics.Round, participationType account.ParticipationAction) { node.accountManager.Record(account, round, participationType) } + +// IsParticipating implements network.NodeInfo +// +// This function is not fully precise. node.ledger and +// node.accountManager might move relative to each other and there is +// no synchronization. This is good-enough for current uses of +// IsParticipating() which is used in networking code to determine if +// the node should ask for transaction gossip (or skip it to save +// bandwidth). The current transaction pool size is about 3 +// rounds. Starting to receive transaction gossip 10 rounds in the +// future when we might propose or vote on blocks in that future is a +// little extra buffer but seems reasonable at this time. -- bolson +// 2022-05-18 +func (node *AlgorandFullNode) IsParticipating() bool { + round := node.ledger.Latest() + 1 + return node.accountManager.HasLiveKeys(round, round+10) +} diff --git a/nodecontrol/kmdControl_common.go b/nodecontrol/kmdControl_common.go index a73c75746f..151ea79633 100644 --- a/nodecontrol/kmdControl_common.go +++ b/nodecontrol/kmdControl_common.go @@ -14,6 +14,7 @@ // You should have received a copy of the GNU Affero General Public License // along with go-algorand. If not, see . +//go:build !windows // +build !windows package nodecontrol diff --git a/protocol/msgp_gen_test.go b/protocol/msgp_gen_test.go index 4bdc805908..e9cbe36b16 100644 --- a/protocol/msgp_gen_test.go +++ b/protocol/msgp_gen_test.go @@ -1,3 +1,4 @@ +//go:build !skip_msgp_testing // +build !skip_msgp_testing package protocol diff --git a/protocol/test/msgp_gen_test.go b/protocol/test/msgp_gen_test.go index d87b778e07..7ee90531d1 100644 --- a/protocol/test/msgp_gen_test.go +++ b/protocol/test/msgp_gen_test.go @@ -1,3 +1,4 @@ +//go:build !skip_msgp_testing // +build !skip_msgp_testing package test @@ -7,9 +8,10 @@ package test import ( "testing" + "github.com/algorand/msgp/msgp" + "github.com/algorand/go-algorand/protocol" "github.com/algorand/go-algorand/test/partitiontest" - "github.com/algorand/msgp/msgp" ) func TestMarshalUnmarshaltestSlice(t *testing.T) { diff --git a/rpcs/blockService_test.go b/rpcs/blockService_test.go index e9c8791ae5..f05c0f6efb 100644 --- a/rpcs/blockService_test.go +++ b/rpcs/blockService_test.go @@ -363,7 +363,7 @@ func addBlock(t *testing.T, ledger *data.Ledger) { require.NoError(t, err) blk.BlockHeader.Round++ blk.BlockHeader.TimeStamp += int64(crypto.RandUint64() % 100 * 1000) - blk.TxnRoot, err = blk.PaysetCommit() + blk.TxnCommitments, err = blk.PaysetCommit() require.NoError(t, err) var cert agreement.Certificate diff --git a/rpcs/msgp_gen_test.go b/rpcs/msgp_gen_test.go index 46ec99aaf3..d88b73039b 100644 --- a/rpcs/msgp_gen_test.go +++ b/rpcs/msgp_gen_test.go @@ -1,3 +1,4 @@ +//go:build !skip_msgp_testing // +build !skip_msgp_testing package rpcs @@ -7,9 +8,10 @@ package rpcs import ( "testing" + "github.com/algorand/msgp/msgp" + "github.com/algorand/go-algorand/protocol" "github.com/algorand/go-algorand/test/partitiontest" - "github.com/algorand/msgp/msgp" ) func TestMarshalUnmarshalEncodedBlockCert(t *testing.T) { diff --git a/scripts/buildtools/go.mod b/scripts/buildtools/go.mod deleted file mode 100644 index cf29e9304c..0000000000 --- a/scripts/buildtools/go.mod +++ /dev/null @@ -1,12 +0,0 @@ -module github.com/algorand/go-algorand/scripts/buildtools - -go 1.16 - -require ( - github.com/algorand/msgp v1.1.50 - github.com/algorand/oapi-codegen v1.3.7 - github.com/go-swagger/go-swagger v0.25.0 - golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect - golang.org/x/tools v0.1.1 // indirect - gotest.tools/gotestsum v1.6.4 -) diff --git a/scripts/buildtools/go.sum b/scripts/buildtools/go.sum deleted file mode 100644 index bf37828f37..0000000000 --- a/scripts/buildtools/go.sum +++ /dev/null @@ -1,630 +0,0 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= -github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/algorand/msgp v1.1.50 h1:Mvsjs5LCE6HsXXbwJXD8ol1Y+c+QMoFNM4j0CY+mFGo= -github.com/algorand/msgp v1.1.50/go.mod h1:R5sJrW9krk4YwNo+rs82Kq6V55q/zNgACwWqt3sQBM4= -github.com/algorand/oapi-codegen v1.3.7 h1:TdXeGljgrnLXSCGPdeY6g6+i/G0Rr5CkjBgUJY6ht48= -github.com/algorand/oapi-codegen v1.3.7/go.mod h1:UvOtAiP3hc0M2GUKBnZVTjLe3HKGDKh6y9rs3e3JyOg= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= -github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 h1:4daAzAu0S6Vi7/lbWECcX0j45yZReDZ56BQsrVBOEEY= -github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-oidc v2.2.1+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/cyberdelia/templates v0.0.0-20191230040416-20a325f050d4/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/dnephin/pflag v1.0.7 h1:oxONGlWxhmUct0YzKTgrpQv9AUA1wtPBn7zuSjJqptk= -github.com/dnephin/pflag v1.0.7/go.mod h1:uxE91IoWURlOiTUIA8Mq5ZZkAv3dPUfZNaT80Zm7OQE= -github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= -github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/getkin/kin-openapi v0.3.1 h1:9mLtayAmieqUnNACL0HqHbxkTc+z1+15sxXpLoJOGEQ= -github.com/getkin/kin-openapi v0.3.1/go.mod h1:W8dhxZgpE84ciM+VIItFqkmZ4eHtuomrdIHtASQIqi0= -github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= -github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= -github.com/go-chi/chi v4.1.1+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= -github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= -github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= -github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= -github.com/go-openapi/analysis v0.19.4/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= -github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU= -github.com/go-openapi/analysis v0.19.10 h1:5BHISBAXOc/aJK25irLZnx2D3s6WyYaY9D4gmuz9fdE= -github.com/go-openapi/analysis v0.19.10/go.mod h1:qmhS3VNFxBlquFJ0RGoDtylO9y4pgTAUNE9AEEMdlJQ= -github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= -github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= -github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= -github.com/go-openapi/errors v0.19.3/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= -github.com/go-openapi/errors v0.19.6 h1:xZMThgv5SQ7SMbWtKFkCf9bBdvR2iEyw9k3zGZONuys= -github.com/go-openapi/errors v0.19.6/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= -github.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4= -github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4= -github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= -github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= -github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= -github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= -github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= -github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= -github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= -github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= -github.com/go-openapi/jsonreference v0.19.4 h1:3Vw+rh13uq2JFNxgnMTGE1rnoieU9FmyE1gvnyylsYg= -github.com/go-openapi/jsonreference v0.19.4/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= -github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs= -github.com/go-openapi/loads v0.19.3/go.mod h1:YVfqhUCdahYwR3f3iiwQLhicVRvLlU/WO5WPaZvcvSI= -github.com/go-openapi/loads v0.19.5 h1:jZVYWawIQiA1NBnHla28ktg6hrcfTHsCE+3QLVRBIls= -github.com/go-openapi/loads v0.19.5/go.mod h1:dswLCAdonkRufe/gSUC3gN8nTSaB9uaS2es0x5/IbjY= -github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= -github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64= -github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4= -github.com/go-openapi/runtime v0.19.15/go.mod h1:dhGWCTKRXlAfGnQG0ONViOZpjfg0m2gUt9nTQPQZuoo= -github.com/go-openapi/runtime v0.19.20 h1:J/t+QIjbcoq8WJvjGxRKiFBhqUE8slS9SbmD0Oi/raQ= -github.com/go-openapi/runtime v0.19.20/go.mod h1:Lm9YGCeecBnUUkFTxPC4s1+lwrkJ0pthx8YvyjCfkgk= -github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= -github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= -github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= -github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= -github.com/go-openapi/spec v0.19.6/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= -github.com/go-openapi/spec v0.19.8 h1:qAdZLh1r6QF/hI/gTq+TJTvsQUodZsM7KLqkAJdiJNg= -github.com/go-openapi/spec v0.19.8/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= -github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= -github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= -github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= -github.com/go-openapi/strfmt v0.19.2/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= -github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= -github.com/go-openapi/strfmt v0.19.4/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= -github.com/go-openapi/strfmt v0.19.5 h1:0utjKrw+BAh8s57XE9Xz8DUBsVvPmRUB6styvl9wWIM= -github.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= -github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= -github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= -github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.7/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY= -github.com/go-openapi/swag v0.19.9 h1:1IxuqvBUU3S2Bi4YC7tlP9SJF1gVpCvqN0T2Qof4azE= -github.com/go-openapi/swag v0.19.9/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY= -github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= -github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= -github.com/go-openapi/validate v0.19.3/go.mod h1:90Vh6jjkTn+OT1Eefm0ZixWNFjhtOH7vS9k0lo6zwJo= -github.com/go-openapi/validate v0.19.10 h1:tG3SZ5DC5KF4cyt7nqLVcQXGj5A7mpaYkAcNPlDK+Yk= -github.com/go-openapi/validate v0.19.10/go.mod h1:RKEZTUWDkxKQxN2jDT7ZnZi2bhZlbNMAuKvKB+IaGx8= -github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-swagger/go-swagger v0.25.0 h1:FxhyrWWV8V/A9P6GtI5szWordAdbb6Y0nqdY/y9So2w= -github.com/go-swagger/go-swagger v0.25.0/go.mod h1:9639ioXrPX9E6BbnbaDklGXjNz7upAXoNBwL4Ok11Vk= -github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013/go.mod h1:b65mBPzqzZWxOZGxSWrqs4GInLIn+u99Q9q7p+GKni0= -github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= -github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= -github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= -github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= -github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= -github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs= -github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= -github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= -github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk= -github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28= -github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo= -github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk= -github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw= -github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360= -github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg= -github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE= -github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8= -github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= -github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= -github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= -github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= -github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= -github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= -github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= -github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/handlers v1.4.2 h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YARg= -github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= -github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= -github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= -github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/labstack/echo/v4 v4.1.16 h1:8swiwjE5Jkai3RPfZoahp8kjVCRNq+y7Q0hPji2Kz0o= -github.com/labstack/echo/v4 v4.1.16/go.mod h1:awO+5TzAjvL8XpibdsfXxPgHr+orhtXZJZIQCVjogKI= -github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0= -github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= -github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= -github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.1 h1:mdxE1MF9o53iCb2Ghj1VfWvh7ZOwHpnVG/xwXrV90U8= -github.com/mailru/easyjson v0.7.1/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= -github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= -github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= -github.com/matryer/moq v0.0.0-20200310130814-7721994d1b54/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= -github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= -github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.3.2 h1:mRS76wmkOn3KkKAyXDu42V+6ebnXWIztFSYGN7GeoRg= -github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= -github.com/pelletier/go-toml v1.8.0 h1:Keo9qb7iRJs2voHvunFtuuYFsbWeOBh8/P9v/kVMFtw= -github.com/pelletier/go-toml v1.8.0/go.mod h1:D6yutnOGMveHEPV7VQOuvI/gXY61bv+9bAOTRnLElKs= -github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.3.2 h1:GDarE4TJQI52kYSbSAmLiId1Elfj+xgSDqrUZxFhxlU= -github.com/spf13/afero v1.3.2/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= -github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= -github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM= -github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= -github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/toqueteos/webbrowser v1.2.0 h1:tVP/gpK69Fx+qMJKsLE7TD8LuGWPnEV71wBN9rrstGQ= -github.com/toqueteos/webbrowser v1.2.0/go.mod h1:XWoZq4cyp9WeUeak7w7LXRUQf1F1ATJMir8RTqb4ayM= -github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31 h1:OXcKh35JaYsGMRzpvFkLv/MEyPuL49CThT1pZ8aSml4= -github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31/go.mod h1:onvgF043R+lC5RZ8IT9rBXDaEDnpnw/Cl+HFiw+v/7Q= -github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= -github.com/valyala/fasttemplate v1.1.0 h1:RZqt0yGBsps8NGvLSGW804QQqCUYYLsaOjTVHy1Ocw4= -github.com/valyala/fasttemplate v1.1.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= -github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= -github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= -go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= -go.mongodb.org/mongo-driver v1.3.0/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE= -go.mongodb.org/mongo-driver v1.3.4/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE= -go.mongodb.org/mongo-driver v1.3.5 h1:S0ZOruh4YGHjD7JoN7mIsTrNjnQbOjrmgrx6l6pZN7I= -go.mongodb.org/mongo-driver v1.3.5/go.mod h1:Ual6Gkco7ZGQw8wE1t4tLnvBsf6yVSM60qW6TgOeJ5c= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899 h1:DZhuSZLsGlFL4CmhA8BcRA0mnthyA/nZ00AqCUo7vHg= -golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200423205358-59e73619c742/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200717024301-6ddee64345a6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.1 h1:wGiQel/hW0NnEkJUk8lbzkX2gFJU6PFxf1v5OlCfuOs= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.57.0 h1:9unxIsFcTt4I55uWluz+UmL95q4kdJ0buvQ1ZIqVQww= -gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools/gotestsum v1.6.4 h1:HFkapG0hK/HWiOxWS78SbR/JK5EpbH8hFzUuCvvfbfQ= -gotest.tools/gotestsum v1.6.4/go.mod h1:fTR9ZhxC/TLAAx2/WMk/m3TkMB9eEI89gdEzhiRVJT8= -gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= -gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/scripts/buildtools/install_buildtools.sh b/scripts/buildtools/install_buildtools.sh index edd346b383..2e0db63537 100755 --- a/scripts/buildtools/install_buildtools.sh +++ b/scripts/buildtools/install_buildtools.sh @@ -53,7 +53,7 @@ cd ${SCRIPTPATH} function get_go_version { cd "${SCRIPTPATH}" - VERSION=$( grep "$1" 2>/dev/null < ./go.mod | awk -F " " '{print $2}') + VERSION=$( grep "$1" 2>/dev/null < ./versions | awk -F " " '{print $2}') echo "$VERSION" return } @@ -67,11 +67,11 @@ function install_go_module { MODULE=$1 fi - # Check for version to go.mod version + # Check for version VERSION=$(get_go_version "$1") if [ -z "$VERSION" ]; then - echo "Unable to install requested package '$1' (${MODULE}): no version listed in ${SCRIPTPATH}/go.mod" + echo "Unable to install requested package '$1' (${MODULE}): no version listed in ${SCRIPTPATH}/versions" exit 1 else OUTPUT=$(go install "${MODULE}@${VERSION}" 2>&1) diff --git a/scripts/buildtools/versions b/scripts/buildtools/versions new file mode 100644 index 0000000000..c5a247b036 --- /dev/null +++ b/scripts/buildtools/versions @@ -0,0 +1,6 @@ +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 +golang.org/x/tools v0.1.5 +github.com/algorand/msgp v1.1.52 +github.com/algorand/oapi-codegen v1.3.7 +github.com/go-swagger/go-swagger v0.25.0 +gotest.tools/gotestsum v1.6.4 diff --git a/scripts/check_deps.sh b/scripts/check_deps.sh index ea178fbb54..4752108a29 100755 --- a/scripts/check_deps.sh +++ b/scripts/check_deps.sh @@ -70,7 +70,7 @@ if [ $MISSING -eq 0 ] then echo "$GREEN_FG[$0]$END_FG_COLOR Required dependencies installed." else - echo -e "$RED_FG[$0]$END_FG_COLOR Required dependencies missing. Run \`${TEAL_FG}./scripts/configure_dev.sh$END_FG_COLOR\` to install." + echo -e "$RED_FG[$0]$END_FG_COLOR Required dependencies missing. Run \`${TEAL_FG}./scripts/configure_dev.sh$END_FG_COLOR\` and/or \`${TEAL_FG}./scripts/buildtools/install_buildtools.sh$END_FG_COLOR\` to install." exit 1 fi diff --git a/scripts/compute_branch.sh b/scripts/compute_branch.sh index abfbf472e8..f0ff025d90 100755 --- a/scripts/compute_branch.sh +++ b/scripts/compute_branch.sh @@ -1,7 +1,16 @@ #!/usr/bin/env bash -if [ -z "${TRAVIS_BRANCH}" ]; then - BRANCH=$(git rev-parse --abbrev-ref HEAD) +if [[ -n $(git status --porcelain) ]]; then + # If the branch isn't clean, default to HEAD to match old behavior. + BRANCH="HEAD" +elif [ -z "${TRAVIS_BRANCH}" ]; then + # if there is no travis branch, set based on tag or branch + case "$(git describe --tags)" in + *"beta") BRANCH="rel/beta" ;; + *"stable") BRANCH="rel/stable" ;; + *"nightly") BRANCH="rel/nightly" ;; + *) BRANCH=$(git rev-parse --abbrev-ref HEAD) + esac else BRANCH="${TRAVIS_BRANCH}" fi diff --git a/scripts/get_golang_version.sh b/scripts/get_golang_version.sh index 1dd22eda46..390847ed4d 100755 --- a/scripts/get_golang_version.sh +++ b/scripts/get_golang_version.sh @@ -11,9 +11,9 @@ # Our build task-runner `mule` will refer to this script and will automatically # build a new image whenever the version number has been changed. -BUILD=1.16.15 - MIN=1.16 - GO_MOD_SUPPORT=1.16 +BUILD=1.17.9 + MIN=1.17 + GO_MOD_SUPPORT=1.17 if [ "$1" = all ] then diff --git a/scripts/travis/codegen_verification.sh b/scripts/travis/codegen_verification.sh index d8af12231f..53c3fee2fb 100755 --- a/scripts/travis/codegen_verification.sh +++ b/scripts/travis/codegen_verification.sh @@ -84,11 +84,14 @@ echo "Regenerate REST server" touch daemon/algod/api/algod.oas2.json make -C daemon/algod/api generate +echo "Regenerate msgp files" +make msgp + echo Checking Enlistment... if [[ -n $(git status --porcelain) ]]; then echo Enlistment is dirty - did you forget to run make? git status -s - git diff + git --no-pager diff exit 1 else echo Enlistment is clean diff --git a/test/e2e-go/cli/goal/expect/goalDryrunRestTest.exp b/test/e2e-go/cli/goal/expect/goalDryrunRestTest.exp index 75d81faeba..26a2b24e11 100644 --- a/test/e2e-go/cli/goal/expect/goalDryrunRestTest.exp +++ b/test/e2e-go/cli/goal/expect/goalDryrunRestTest.exp @@ -9,7 +9,7 @@ proc TestGoalDryrun { DRREQ_FILE TEST_PRIMARY_NODE_DIR } { spawn goal clerk dryrun-remote -d $TEST_PRIMARY_NODE_DIR -D $DRREQ_FILE -v expect { timeout { ::AlgorandGoal::Abort "goal clerk dryrun-remote timeout" } - "cost:" {set COST 1; exp_continue} + "budget consumed:" {set COST 1; exp_continue} -re {(ApprovalProgram)} {set PROGRAM_TYPE $expect_out(1,string); exp_continue} "PASS" {set PASSED 1; close} } diff --git a/test/e2e-go/features/transactions/proof_test.go b/test/e2e-go/features/transactions/proof_test.go index 118e725f74..9cbc151078 100644 --- a/test/e2e-go/features/transactions/proof_test.go +++ b/test/e2e-go/features/transactions/proof_test.go @@ -20,8 +20,10 @@ import ( "path/filepath" "testing" + "github.com/algorand/go-algorand/config" "github.com/algorand/go-algorand/crypto" "github.com/algorand/go-algorand/crypto/merklearray" + "github.com/algorand/go-algorand/daemon/algod/api/server/v2/generated" "github.com/algorand/go-algorand/protocol" "github.com/algorand/go-algorand/test/framework/fixtures" "github.com/algorand/go-algorand/test/partitiontest" @@ -90,29 +92,35 @@ func TestTxnMerkleProof(t *testing.T) { a.NoError(err) txid := tx.ID() + txidSHA256 := tx.IDSha256() // only used for verification confirmedTx, err := fixture.WaitForConfirmedTxn(status.LastRound+10, baseAcct, txid.String()) a.NoError(err) - proofresp, err := client.TxnProof(txid.String(), confirmedTx.ConfirmedRound) + blk, err := client.BookkeepingBlock(confirmedTx.ConfirmedRound) + a.NoError(err) + + proofresp, err := client.TxnProof(txid.String(), confirmedTx.ConfirmedRound, crypto.Sha512_256) a.NoError(err) - hashtype, err := crypto.UnmarshalHashType(proofresp.Hashtype) + proofrespSHA256, err := client.TxnProof(txid.String(), confirmedTx.ConfirmedRound, crypto.Sha256) a.NoError(err) - var proof merklearray.Proof - proof.HashFactory = crypto.HashFactory{HashType: hashtype} - proof.TreeDepth = uint8(proofresp.Treedepth) - a.NotEqual(proof.TreeDepth, 0) - proofconcat := []byte(proofresp.Proof) - for len(proofconcat) > 0 { - var d crypto.Digest - copy(d[:], proofconcat) - proof.Path = append(proof.Path, d[:]) - proofconcat = proofconcat[len(d):] + generateProof := func(h crypto.HashType, prfRsp generated.ProofResponse) (p merklearray.Proof) { + p.HashFactory = crypto.HashFactory{HashType: h} + p.TreeDepth = uint8(prfRsp.Treedepth) + a.NotEqual(p.TreeDepth, 0) + proofconcat := prfRsp.Proof + for len(proofconcat) > 0 { + var d crypto.Digest + copy(d[:], proofconcat) + p.Path = append(p.Path, d[:]) + proofconcat = proofconcat[len(d):] + } + return } - blk, err := client.BookkeepingBlock(confirmedTx.ConfirmedRound) - a.NoError(err) + proof := generateProof(crypto.Sha512_256, proofresp) + proofSHA256 := generateProof(crypto.Sha256, proofrespSHA256) element := TxnMerkleElemRaw{Txn: crypto.Digest(txid)} copy(element.Stib[:], proofresp.Stibhash[:]) @@ -120,10 +128,78 @@ func TestTxnMerkleProof(t *testing.T) { elems := make(map[uint64]crypto.Hashable) elems[proofresp.Idx] = &element - err = merklearray.Verify(blk.TxnRoot.ToSlice(), elems, &proof) + err = merklearray.Verify(blk.TxnCommitments.NativeSha512_256Commitment.ToSlice(), elems, &proof) if err != nil { - t.Logf("blk.TxnRoot : %v \nproof path %v \ndepth: %d \nStibhash %v\nIndex: %d", blk.TxnRoot.ToSlice(), proof.Path, proof.TreeDepth, proofresp.Stibhash, proofresp.Idx) + t.Logf("blk.TxnCommitments : %v \nproof path %v \ndepth: %d \nStibhash %v\nIndex: %d", blk.TxnCommitments.NativeSha512_256Commitment.ToSlice(), proof.Path, proof.TreeDepth, proofresp.Stibhash, proofresp.Idx) + a.NoError(err) + } + + element = TxnMerkleElemRaw{Txn: crypto.Digest(txidSHA256)} + copy(element.Stib[:], proofrespSHA256.Stibhash[:]) + + elems = make(map[uint64]crypto.Hashable) + + elems[proofrespSHA256.Idx] = &element + err = merklearray.VerifyVectorCommitment(blk.TxnCommitments.Sha256Commitment.ToSlice(), elems, &proofSHA256) + if err != nil { + t.Logf("blk.TxnCommitments : %v \nproof path %v \ndepth: %d \nStibhash %v\nIndex: %d", blk.TxnCommitments.Sha256Commitment.ToSlice(), proofSHA256.Path, proofSHA256.TreeDepth, proofrespSHA256.Stibhash, proofrespSHA256.Idx) + a.NoError(err) + } +} + +// make sure transaction proof SHA256 does not exist in current consensus version (until we upgrade) +func TestTxnMerkleProofSHA256(t *testing.T) { + partitiontest.PartitionTest(t) + defer fixtures.ShutdownSynchronizedTest(t) + + t.Parallel() + a := require.New(fixtures.SynchronizedTest(t)) + + var fixture fixtures.RestClientFixture + fixture.Setup(t, filepath.Join("nettemplates", "TwoNodes50EachV32.json")) + defer fixture.Shutdown() + client := fixture.LibGoalClient + + // We will create three new accounts, transfer some amount of money into + // the first account, and then transfer a smaller amount to the second + // account while closing out the rest into the third. + + accountList, err := fixture.GetWalletsSortedByBalance() + a.NoError(err) + baseAcct := accountList[0].Address + + walletHandle, err := client.GetUnencryptedWalletHandle() + a.NoError(err) + + acct0, err := client.GenerateAddress(walletHandle) + a.NoError(err) + + status, err := client.Status() + a.NoError(err) + + // Transfer some money to acct0, as well as other random accounts to + // fill up the Merkle tree with more than one element. + // we do not want to have a full tree in order the catch an empty element edge case + for i := 0; i < 5; i++ { + accti, err := client.GenerateAddress(walletHandle) + a.NoError(err) + + _, err = client.SendPaymentFromUnencryptedWallet(baseAcct, accti, 1000, 10000000, nil) a.NoError(err) } + tx, err := client.SendPaymentFromUnencryptedWallet(baseAcct, acct0, 1000, 10000000, nil) + a.NoError(err) + + txid := tx.ID() + confirmedTx, err := fixture.WaitForConfirmedTxn(status.LastRound+10, baseAcct, txid.String()) + a.NoError(err) + + blk, err := client.BookkeepingBlock(confirmedTx.ConfirmedRound) + a.NoError(err) + proto := config.Consensus[blk.CurrentProtocol] + a.False(proto.EnableSHA256TxnCommitmentHeader) + + a.NotEqual(crypto.Digest{}, blk.TxnCommitments.NativeSha512_256Commitment) + a.Equal(crypto.Digest{}, blk.TxnCommitments.Sha256Commitment) // should be empty since not yet supported } diff --git a/test/framework/fixtures/baseFixture.go b/test/framework/fixtures/baseFixture.go index c14203f159..37086e5365 100644 --- a/test/framework/fixtures/baseFixture.go +++ b/test/framework/fixtures/baseFixture.go @@ -20,6 +20,8 @@ import ( "fmt" "io/ioutil" "os" + "path" + "runtime" "testing" "github.com/algorand/go-algorand/config" @@ -35,6 +37,15 @@ type baseFixture struct { instance Fixture } +func getTestDir() string { + _, filename, _, ok := runtime.Caller(0) + if ok { + return path.Join(path.Dir(filename), "..", "..") + } + // fallback to the legacy GOPATH location. + return os.ExpandEnv("${GOPATH}/src/github.com/algorand/go-algorand/test/") +} + func (f *baseFixture) initialize(instance Fixture) { f.instance = instance f.Config = config.Protocol @@ -49,7 +60,7 @@ func (f *baseFixture) initialize(instance Fixture) { } f.testDataDir = os.Getenv("TESTDATADIR") if f.testDataDir == "" { - f.testDataDir = os.ExpandEnv("${GOPATH}/src/github.com/algorand/go-algorand/test/testdata") + f.testDataDir = path.Join(getTestDir(), "testdata") } } diff --git a/test/framework/fixtures/expectFixture.go b/test/framework/fixtures/expectFixture.go index 8d5bc9d5b1..f1134296af 100644 --- a/test/framework/fixtures/expectFixture.go +++ b/test/framework/fixtures/expectFixture.go @@ -25,7 +25,6 @@ import ( "path" "path/filepath" "regexp" - "runtime" "strings" "testing" @@ -58,9 +57,7 @@ func (ef *ExpectFixture) initialize(t *testing.T) (err error) { } ef.testDataDir = os.Getenv("TESTDATADIR") if ef.testDataDir == "" { - // Default to test/testdata in the source tree being tested - _, path, _, _ := runtime.Caller(0) - ef.testDataDir = filepath.Join(filepath.Dir(path), "../../testdata") + ef.testDataDir = filepath.Join(getTestDir(), "testdata") } ef.testFilter = os.Getenv("TESTFILTER") diff --git a/test/scripts/e2e.sh b/test/scripts/e2e.sh index 0d4a63d7ed..e9a6b251b6 100755 --- a/test/scripts/e2e.sh +++ b/test/scripts/e2e.sh @@ -165,7 +165,7 @@ if [ -z "$E2E_TEST_FILTER" ] || [ "$E2E_TEST_FILTER" == "SCRIPTS" ]; then # If the platform is arm64, we want to pass "--keep-temps" into e2e_client_runner.py # so that we can keep the temporary test artifact for use in the indexer e2e tests. # The file is located at ${TEMPDIR}/net_done.tar.bz2 - if [ $E2E_PLATFORM == "arm64" ]; then + if [ "$E2E_PLATFORM" == "arm64" ]; then KEEP_TEMPS_CMD_STR="--keep-temps" fi diff --git a/test/scripts/e2e_client_runner.py b/test/scripts/e2e_client_runner.py index 79b53a291b..0156bc7ae8 100755 --- a/test/scripts/e2e_client_runner.py +++ b/test/scripts/e2e_client_runner.py @@ -372,6 +372,7 @@ def xrun(cmd, *args, **kwargs): timeout = kwargs.pop('timeout', None) kwargs['stdout'] = subprocess.PIPE kwargs['stderr'] = subprocess.STDOUT + stdout = stderr = None try: p = subprocess.Popen(cmd, *args, **kwargs) except Exception as e: diff --git a/test/scripts/transition_mix_test.py b/test/scripts/transition_mix_test.py new file mode 100644 index 0000000000..5112eac5bc --- /dev/null +++ b/test/scripts/transition_mix_test.py @@ -0,0 +1,626 @@ +#!/usr/bin/env python3 +# +# Test for a network in transition. +# Runs a 6 node network with the following topology: +# +# New Leaf 1 New Leaf 2 +# > New Relay - Old Relay < +# Old Leaf 1 Old Leaf 2 +# +# "New" and "Old" can mean different algod/goal/kmd binary versions. +# It can also or separately mean config.json updates. (set --old-bin +# and --new-bin to the same dir, set --new-config or --old-config to +# overlay json onto the net temlplate generated config.json of new or +# old nodes. +# +# In the test each leaf submits a simple payment transaction from its +# unlocked wallet to a dummy account '\x00...\x0N'. A few rounds are +# waited then each leaf verifies that it can see all the expected +# account values. +# +# The test then waits 100 rounds and checks that the 4 leaves are each +# a block proposer a reasonable fraction of the 100 rounds. + +import argparse +import atexit +import glob +import json +import logging +import os +import re +import shutil +import statistics +import subprocess +import sys +import tempfile +import threading +import time + +# pip install py-algorand-sdk +import algosdk + +logger = logging.getLogger(__name__) + +scriptdir = os.path.dirname(os.path.realpath(__file__)) +repodir = os.path.join(scriptdir, "..", "..") + +_onbranch = 'On branch ' + +def getbranch(rd): + result = subprocess.run(['git', 'status', '-b'], cwd=rd, capture_output=True, timeout=3) + for line in result.stdout.decode().splitlines(): + if line.startswith(_onbranch): + return line[len(_onbranch):] + return None + +def get_go_env(): + out = {} + result = subprocess.run(['go', 'env'], capture_output=True) + for line in result.stdout.decode().splitlines(): + line = line.strip() + # TODO: is there a better way to parse sh-like k=v (possibly with quoting)? + k,v = line.split('=', 1) + if v.startswith('"') and v.endswith('"'): + v = v[1:-1] + out[k] = v + return out + +def openkmd(algodata): + kmdnetpath = sorted(glob.glob(os.path.join(algodata,'kmd-*','kmd.net')))[-1] + kmdnet = open(kmdnetpath, 'rt').read().strip() + kmdtokenpath = sorted(glob.glob(os.path.join(algodata,'kmd-*','kmd.token')))[-1] + kmdtoken = open(kmdtokenpath, 'rt').read().strip() + kmd = algosdk.kmd.KMDClient(kmdtoken, 'http://' + kmdnet) + return kmd + +def openalgod(algodata): + algodnetpath = os.path.join(algodata,'algod.net') + algodnet = open(algodnetpath, 'rt').read().strip() + algodtokenpath = os.path.join(algodata,'algod.token') + algodtoken = open(algodtokenpath, 'rt').read().strip() + algod = algosdk.v2client.algod.AlgodClient(algodtoken, 'http://' + algodnet) + return algod + + +def maybedecode(x): + if not x: + return x + if hasattr(x, 'decode'): + return x.decode() + return x + +def reportcomms(p, stdout, stderr): + cmdr = repr(p.args) + if not stdout and p.stdout: + stdout = p.stdout.read() + if not stderr and p.stderr: + stderr = p.stderr.read() + if stdout: + sys.stderr.write('output from {}:\n{}\n\n'.format(cmdr, maybedecode(stdout))) + if stderr: + sys.stderr.write('stderr from {}:\n{}\n\n'.format(cmdr, maybedecode(stderr))) + +def xrun(cmd, *args, **kwargs): + timeout = kwargs.pop('timeout', None) + kwargs['stdout'] = subprocess.PIPE + kwargs['stderr'] = subprocess.STDOUT + try: + logger.debug('xrun: %r', cmd) + p = subprocess.Popen(cmd, *args, **kwargs) + except Exception as e: + logger.error('subprocess failed {!r}'.format(cmd), exc_info=True) + raise + try: + if timeout: + stdout,stderr = p.communicate(timeout=timeout) + else: + stdout,stderr = p.communicate() + except subprocess.TimeoutExpired as te: + logger.error('subprocess timed out {!r}'.format(cmd), exc_info=True) + reportcomms(p, stdout, stderr) + raise + except Exception as e: + logger.error('subprocess exception {!r}'.format(cmd), exc_info=True) + reportcomms(p, stdout, stderr) + raise + if p.returncode != 0: + cmdr = repr(cmd) + logger.error('cmd failed {}'.format(cmdr)) + reportcomms(p, stdout, stderr) + raise Exception('error: cmd failed: {}'.format(cmdr)) + + +def startdaemon(cmd): + try: + logger.debug('start: %r', cmd) + p = subprocess.Popen(cmd) + return p + except Exception as e: + logger.error('subprocess failed {!r}'.format(cmd), exc_info=True) + raise + +def wait_for_transaction(algod, txid, round, timeout=15): + start = time.time() + ti = algod.pending_transaction_info(txid) + logger.debug('ti %s %r', txid, ti) + while True: + if ti and ti.get('confirmed-round'): + # txn was committed + return True + if timeout and ((time.time() - start) > timeout): + return False + time.sleep(1) + st = algod.status_after_block(round) + logger.debug('st %r', st) + round = st['last-round'] + ti = algod.pending_transaction_info(txid) + logger.debug('ti %r', ti) + +class NodeContext: + def __init__(self, bindir, env=None, algodata=None, proc=None): + self.proc = proc + self.bindir = bindir + self.algodata = algodata + self.env = env + if env and not algodata: + self.algodata = env['ALGORAND_DATA'] + self.kmd = None + self.algod = None + self.pubw = None + self.maxpubaddr = None + self.lock = threading.Lock() + return + + def _connect(self): + # should run from inside self.lock + if self.algod and self.kmd: + return + + goal = os.path.join(self.bindir, 'goal') + xrun([goal, 'kmd', 'start', '-t', '3600','-d', self.algodata], env=self.env, timeout=5) + self.kmd = openkmd(self.algodata) + self.algod = openalgod(self.algodata) + + def connect(self): + with self.lock: + self._connect() + return self.algod, self.kmd + + def get_pub_wallet(self): + with self.lock: + self._connect() + if not (self.pubw and self.maxpubaddr): + # find private test node public wallet and its richest account + wallets = self.kmd.list_wallets() + pubwid = None + for xw in wallets: + if xw['name'] == 'unencrypted-default-wallet': + pubwid = xw['id'] + pubw = self.kmd.init_wallet_handle(pubwid, '') + pubaddrs = self.kmd.list_keys(pubw) + pubbalances = [] + maxamount = 0 + maxpubaddr = None + for pa in pubaddrs: + pai = self.algod.account_info(pa) + if pai['amount'] > maxamount: + maxamount = pai['amount'] + maxpubaddr = pai['address'] + self.pubw = pubw + self.maxpubaddr = maxpubaddr + return self.pubw, self.maxpubaddr + + def terminate(self): + self.proc.terminate() + +def get_block_proposers(algod, lastRound, expected_proposers): + oprops = {} + for i in range(1,lastRound+1): + try: + b2b = algod.block_info(i, response_format='msgpack') + b2 = algosdk.encoding.msgpack.unpackb(b2b) + oprop = b2['cert']['prop']['oprop'] + oprops[oprop] = oprops.get(oprop, 0) + 1 + except Exception as e: + print(e) + break + logger.debug('oprops %r', oprops) + assert(len(oprops) == expected_proposers) + mean = statistics.mean(oprops.values()) + var_limit = mean / 2 + ok = [] + bad = [] + for op,count in oprops.items(): + line = '{}\t{}'.format(algosdk.encoding.encode_address(op), count) + if abs(count-mean) > var_limit: + bad.append(line) + else: + ok.append(line) + if bad: + for line in ok: + print(line) + print("ERROR:") + for line in bad: + print(line) + raise Exception("too much variance in block proposers, wanted [{} - {}]".format(mean-var_limit, mean+var_limit)) + return + +def start_algod(algodata, bindir, relay_addr=None): + algod_path = os.path.join(bindir, 'algod') + cmd = [algod_path, '-d', algodata] + if relay_addr: + cmd += ['-p', relay_addr] + proc = startdaemon(cmd) + #atexit.register(proc.terminate) + return NodeContext(bindir, algodata=algodata, proc=proc) + + +def bindir_missing(bindir): + out = [] + for p in ('algod', 'goal', 'kmd'): + path = os.path.join(bindir, p) + if not os.path.exists(path): + out.append(p) + if not out: + return None + return out + +def build(args, repodir, newbin, oldbin): + curbranch = getbranch(repodir) + goenv = get_go_env() + gopath = goenv['GOPATH'] + newalgod = os.path.join(newbin , 'algod') + oldalgod = os.path.join(oldbin, 'algod') + os.makedirs(newbin, exist_ok=True) + os.makedirs(oldbin, exist_ok=True) + changeBack = False + try: + newbin_missing = bindir_missing(newbin) + logger.debug('%s missing %r', newbin, newbin_missing) + if newbin_missing: + if args.no_build: + raise Exception('new bin dir {} missing {} but --no-build set'.format(newbin, newbin_missing)) + xrun(['git', 'checkout', args.new_branch], cwd=repodir) + changeBack = True + xrun(['make'], cwd=repodir) + for bn in ('algod', 'goal', 'kmd'): + shutil.copy(os.path.join(gopath, 'bin', bn), os.path.join(newbin, bn)) + oldbin_missing = bindir_missing(oldbin) + logger.debug('%s missing %r', oldbin, oldbin_missing) + if oldbin_missing: + if args.no_build: + raise Exception('old bin dir {} missing {} but --no-build set'.format(oldbin, oldbin_missing)) + xrun(['git', 'checkout', args.old_branch], cwd=repodir) + changeBack = True + xrun(['make'], cwd=repodir) + for bn in ('algod', 'goal', 'kmd'): + shutil.copy(os.path.join(gopath, 'bin', bn), os.path.join(oldbin, bn)) + finally: + if changeBack: + xrun(['git', 'checkout', curbranch]) + +# return algod relay host:port or raise Exception +def wait_relay_addr(algodata, timeout=10): + relay_addr_path = os.path.join(algodata, 'algod-listen.net') + timeout = time.time() + timeout + while True: + if os.path.exists(relay_addr_path): + with open(relay_addr_path) as fin: + relay_addr = fin.read().strip() + return relay_addr + if time.time() > timeout: + raise Exception('never found relay_addr at {}'.format(relay_addr_path)) + time.sleep(0.1) + +# accept literal or filename +def json_arg(arg): + if not arg: + return None + if arg[0] == '{': + return json.loads(arg) + if arg[0] == '@': + with open(arg[1:]) as fin: + return json.load(fin) + if os.path.exists(arg): + with open(arg) as fin: + return json.load(fin) + raise Exception("don't know how to get json from {!r}".format(arg)) + +def json_overlay(arg, netdir, subdirs): + if not arg: + return + nc = json_arg(arg) + if not nc: + return + for subdir in subdirs: + with open(os.path.join(netdir, subdir, 'config.json')) as fin: + config = json.load(fin) + config.update(nc) + with open(os.path.join(netdir, subdir, 'config.json'), 'w') as fout: + json.dump(config, fout) + +_logging_format = '%(asctime)s :%(lineno)d %(message)s' +_logging_datefmt = '%Y%m%d_%H%M%S' + +def main(): + start = time.time() + ap = argparse.ArgumentParser() + ap.add_argument('--new-branch', default=None, help='`git checkout {new-branch}` and build') + ap.add_argument('--old-branch', default=None, help='`git checkout {new-branch}` and build') + ap.add_argument('--new-config', help='json to overlay on config.json, json literal or filename') + ap.add_argument('--old-config', help='json to overlay on config.json, json literal or filename') + ap.add_argument('--new-bin', help='path to directory holding new version of algod,kmd,goal') + ap.add_argument('--old-bin', help='path to directory holding old version of algod,kmd,goal') + ap.add_argument('--no-build', default=False, action='store_true') + ap.add_argument('--work-dir') + ap.add_argument('--keep-temps', default=False, action='store_true', help='if set, keep all the test files') + ap.add_argument('--verbose', default=False, action='store_true') + args = ap.parse_args() + + if args.verbose: + logging.basicConfig(format=_logging_format, datefmt=_logging_datefmt, level=logging.DEBUG) + else: + logging.basicConfig(format=_logging_format, datefmt=_logging_datefmt, level=logging.INFO) + + # TODO: default old_branch to the highest git tag like 'v3.5.1-stable' + # TODO: default new_branch to whatever is currently checked out + + # start with a copy when making env for child processes + env = dict(os.environ) + + tempdir = args.work_dir + if not tempdir: + tempdir = os.getenv('TEMPDIR') + if not tempdir: + tempdir = tempfile.mkdtemp() + env['TEMPDIR'] = tempdir + logger.info('created TEMPDIR %r', tempdir) + if not args.keep_temps: + # If we created a tmpdir and we're not keeping it, clean it up. + # If an outer process specified $TEMPDIR, let them clean it up. + atexit.register(shutil.rmtree, tempdir, onerror=lambda efn, epath, excinfo: logger.error('rmtree error %r %r %s', efn, epath, excinfo)) + else: + atexit.register(print, 'keeping temps. to clean up:\nrm -rf {}'.format(tempdir)) + + newbin = args.new_bin or os.path.join(tempdir, 'newbin') + oldbin = args.old_bin or os.path.join(tempdir, 'oldbin') + build(args, repodir, newbin, oldbin) + + netdir = os.path.join(tempdir, 'net') + run_test6(args, netdir, oldbin, newbin) + # algod_bins = { + # 'Primary': oldbin, + # 'Node1': oldbin, + # 'Node2': newbin, + # } + # run_test(netdir, oldbin, newbin, algod_bins) + # algod_bins = { + # 'Primary': newbin, + # 'Node1': oldbin, + # 'Node2': newbin, + # } + # run_test(netdir, oldbin, newbin, algod_bins) + dt = time.time() - start + print('DONE OK {:.1f} seconds'.format(dt)) + # wait a moment for terminated algod to clean up their files + time.sleep(1) + return 0 + +def nop(*args, **kwargs): + pass + +def run_defers(defers, reraise=True, keep_going=False): + if defers is None: + return + for di in defers: + try: + di() + except Exception as ie: + if reraise: + raise + logger.error('exception in defer:', exc_info=True) + if not keep_going: + break + +def defer_wrap(fn): + def _wrapped(*args, **kwargs): + out = None + try: + defers = None + if '_defer' not in kwargs: + defers = [] + kwargs['_defer'] = lambda x: defers.append(x) + out = fn(*args, **kwargs) + except: + run_defers(defers, reraise=False) + raise + run_defers(defers, reraise=True) + return out + return _wrapped + +# Test topology: 1 relay, to leaf nodes. +# one leaf node each for oldbin, newbin +# relay as either oldbin or newbin +@defer_wrap +def run_test(netdir, oldbin, newbin, algod_bins, _defer=nop): + shutil.rmtree(netdir, ignore_errors=True) + xrun([os.path.join(oldbin, 'goal'), 'network', 'create', '-r', netdir, '-n', 'tbd', '-t', os.path.join(repodir, 'test/testdata/nettemplates/ThreeNodesEvenDist.json')], timeout=90) + + relay = start_algod(os.path.join(netdir, 'Primary'), algod_bins['Primary']) + _defer(relay.terminate) + relay_addr = wait_relay_addr(relay.algodata) + + n1 = start_algod(os.path.join(netdir, 'Node1'), algod_bins['Node1'], relay_addr=relay_addr) + _defer(n1.terminate) + + n2 = start_algod(os.path.join(netdir, 'Node2'), algod_bins['Node2'], relay_addr=relay_addr) + _defer(n2.terminate) + + n1algod, n1kmd = n1.connect() + n2algod, n2kmd = n2.connect() + time.sleep(5) + status = n1algod.status() + # TODO: timeout? + #print('status {!r}'.format(status)) + n1algod.status_after_block(status['last-round']) + + tryi = 0 + while True: + try: + pubw, maxpubaddr = n1.get_pub_wallet() + break + except: + if tryi >= 5: + raise + tryi += 1 + print('n1 get pub wallet retry sleep...') + time.sleep(1) + + a1i = n1algod.account_info(maxpubaddr) + pubw2, maxpubaddr2 = n2.get_pub_wallet() + a2i = n2algod.account_info(maxpubaddr2) + + # test txn on n1 account submitted through n1, seen at n2 + tx1amt = 999000 + params = n1algod.suggested_params() + round = params.first + max_init_wait_rounds = 5 + txn = algosdk.transaction.PaymentTxn(sender=maxpubaddr, fee=params.min_fee, first=round, last=round+max_init_wait_rounds, gh=params.gh, receiver=maxpubaddr2, amt=tx1amt, flat_fee=True) + stxn = n1kmd.sign_transaction(pubw, '', txn) + txid = n1algod.send_transaction(stxn) + wait_for_transaction(n1algod, txid, round) + + a2i2 = n2algod.account_info(maxpubaddr2) + logger.debug('a2i %r', a2i) + logger.debug('a2i2 %r', a2i2) + # check that recipient got it + assert(a2i2['amount'] - a2i['amount'] == tx1amt) + + # test txn on n2 account submitted through n2, seen at n1 + a1i = n1algod.account_info(maxpubaddr) + tx2amt = 3000000 + params = n2algod.suggested_params() + round = params.first + txn = algosdk.transaction.PaymentTxn(sender=maxpubaddr2, fee=params.min_fee, first=round, last=round+max_init_wait_rounds, gh=params.gh, receiver=maxpubaddr, amt=tx2amt, flat_fee=True) + stxn = n2kmd.sign_transaction(pubw2, '', txn) + txid = n2algod.send_transaction(stxn) + wait_for_transaction(n2algod, txid, round) + + a1i2 = n1algod.account_info(maxpubaddr) + # check that recipient got it + assert(a1i2['amount'] - a1i['amount'] == tx2amt) + + # run for a bunch of rounds and ensure that block proposers are well distributed + ralgod, _ = relay.connect() + st = ralgod.status() + while st['last-round'] < 100: + st = ralgod.status_after_block(st['last-round']) + print(st['last-round']) + get_block_proposers(ralgod, st['last-round'], 3) + + print("OK") + return 0 + +class testaddrs: + def __init__(self): + self.i = 1 + self.sent = {} + self.buf = [0] * 32 + def get(self): + self.buf[31] = self.i + addr = algosdk.encoding.encode_address(bytes(self.buf)) + amt = 1000000 + self.i + self.sent[addr] = amt + self.i += 1 + return addr,amt + + +def wait_round(algod, waitround, st=None, printround=False): + if st is None: + st = algod.status() + lr = st['last-round'] + if lr >= waitround: + return st + nrounds = waitround - lr + timeout = time.time() + (nrounds * 22) + while st['last-round'] < waitround: + if time.time() > timeout: + raise Exception("too long waiting for round {}, last-round={}".format(waitround, st['last-round'])) + st = algod.status_after_block(st['last-round']) + if printround: + print(st['last-round']) + return st + + +# test topology: 2 relays, 4 leafs +# (leaf old 1, leaf new 1) <-> (relay old) <-> (relay new) <-> (leaf old 2, leaf new 2) +@defer_wrap +def run_test6(args, netdir, oldbin, newbin, _defer=nop): + test_addr = testaddrs() + + shutil.rmtree(netdir, ignore_errors=True) + xrun([os.path.join(oldbin, 'goal'), 'network', 'create', '-r', netdir, '-n', 'tbd', '-t', os.path.join(repodir, 'test/testdata/nettemplates/TransitionSix.json')], timeout=90) + + json_overlay(args.new_config, netdir, ('RelayNew', 'New1', 'New2')) + json_overlay(args.old_config, netdir, ('RelayOld', 'Old1', 'Old2')) + + relay_old = start_algod(os.path.join(netdir, 'RelayOld'), oldbin) + _defer(relay_old.terminate) + relay_old_addr = wait_relay_addr(relay_old.algodata) + + relay_new = start_algod(os.path.join(netdir, 'RelayNew'), newbin, relay_addr=relay_old_addr) + _defer(relay_new.terminate) + relay_new_addr = wait_relay_addr(relay_new.algodata) + + new1 = start_algod(os.path.join(netdir, 'New1'), newbin, relay_addr=relay_old_addr) + _defer(new1.terminate) + old1 = start_algod(os.path.join(netdir, 'Old1'), oldbin, relay_addr=relay_old_addr) + _defer(old1.terminate) + + new2 = start_algod(os.path.join(netdir, 'New2'), newbin, relay_addr=relay_new_addr) + _defer(new2.terminate) + old2 = start_algod(os.path.join(netdir, 'Old2'), oldbin, relay_addr=relay_new_addr) + _defer(old2.terminate) + + time.sleep(1) + + leafs = [new1, old1, new2, old2] + + n1algod, n1kmd = new1.connect() + + status = n1algod.status() + logger.debug('waiting for round after %s', status['last-round']) + status = n1algod.status_after_block(status['last-round']) + logger.debug('status %r', status) + + sent_txid = [] + + # send a txn from each leaf + for leaf in leafs: + algod, kmd = leaf.connect() + pubw, maxpubaddr = leaf.get_pub_wallet() + params = algod.suggested_params() + receiver, amt = test_addr.get() + txn = algosdk.transaction.PaymentTxn(sender=maxpubaddr, fee=params.min_fee, first=params.first, last=params.first+10, gh=params.gh, receiver=receiver, amt=amt, flat_fee=True) + stxn = kmd.sign_transaction(pubw, '', txn) + txid = algod.send_transaction(stxn) + sent_txid.append(txid) + + ralgod, _ = relay_old.connect() + st = wait_round(ralgod, status['last-round'] + 12, st=status) + + for leaf in leafs: + for addr, amt in test_addr.sent.items(): + algod, _ = leaf.connect() + ast = algod.account_info(addr) + assert(ast['amount'] == amt) + + st = wait_round(ralgod, 100, printround=True, st=st) + get_block_proposers(ralgod, st['last-round'], 4) + + print("OK") + return 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/test/testdata/configs/config-v22.json b/test/testdata/configs/config-v22.json new file mode 100644 index 0000000000..c569e4c93d --- /dev/null +++ b/test/testdata/configs/config-v22.json @@ -0,0 +1,105 @@ +{ + "Version": 22, + "AccountUpdatesStatsInterval": 5000000000, + "AccountsRebuildSynchronousMode": 1, + "AgreementIncomingBundlesQueueLength": 7, + "AgreementIncomingProposalsQueueLength": 25, + "AgreementIncomingVotesQueueLength": 10000, + "AnnounceParticipationKey": true, + "Archival": false, + "BaseLoggerDebugLevel": 4, + "BlockServiceCustomFallbackEndpoints": "", + "BroadcastConnectionsLimit": -1, + "CadaverSizeTarget": 1073741824, + "CatchpointFileHistoryLength": 365, + "CatchpointInterval": 10000, + "CatchpointTracking": 0, + "CatchupBlockDownloadRetryAttempts": 1000, + "CatchupBlockValidateMode": 0, + "CatchupFailurePeerRefreshRate": 10, + "CatchupGossipBlockFetchTimeoutSec": 4, + "CatchupHTTPBlockFetchTimeoutSec": 4, + "CatchupLedgerDownloadRetryAttempts": 50, + "CatchupParallelBlocks": 16, + "ConnectionsRateLimitingCount": 60, + "ConnectionsRateLimitingWindowSeconds": 1, + "DNSBootstrapID": ".algorand.network", + "DNSSecurityFlags": 1, + "DeadlockDetection": 0, + "DeadlockDetectionThreshold": 30, + "DisableLocalhostConnectionRateLimit": true, + "DisableNetworking": false, + "DisableOutgoingConnectionThrottling": false, + "EnableAccountUpdatesStats": false, + "EnableAgreementReporting": false, + "EnableAgreementTimeMetrics": false, + "EnableAssembleStats": false, + "EnableBlockService": false, + "EnableBlockServiceFallbackToArchiver": true, + "EnableCatchupFromArchiveServers": false, + "EnableDeveloperAPI": false, + "EnableGossipBlockService": true, + "EnableIncomingMessageFilter": false, + "EnableLedgerService": false, + "EnableMetricReporting": false, + "EnableOutgoingNetworkMessageFiltering": true, + "EnablePingHandler": true, + "EnableProcessBlockStats": false, + "EnableProfiler": false, + "EnableRequestLogger": false, + "EnableRuntimeMetrics": false, + "EnableTopAccountsReporting": false, + "EnableVerbosedTransactionSyncLogging": false, + "EndpointAddress": "127.0.0.1:0", + "FallbackDNSResolverAddress": "", + "ForceFetchTransactions": false, + "ForceRelayMessages": false, + "GossipFanout": 4, + "IncomingConnectionsLimit": 800, + "IncomingMessageFilterBucketCount": 5, + "IncomingMessageFilterBucketSize": 512, + "IsIndexerActive": false, + "LedgerSynchronousMode": 2, + "LogArchiveMaxAge": "", + "LogArchiveName": "node.archive.log", + "LogSizeLimit": 1073741824, + "MaxAPIResourcesPerAccount": 100000, + "MaxCatchpointDownloadDuration": 7200000000000, + "MaxConnectionsPerIP": 30, + "MinCatchpointFileDownloadBytesPerSecond": 20480, + "NetAddress": "", + "NetworkMessageTraceServer": "", + "NetworkProtocolVersion": "", + "NodeExporterListenAddress": ":9100", + "NodeExporterPath": "./node_exporter", + "OptimizeAccountsDatabaseOnStartup": false, + "OutgoingMessageFilterBucketCount": 3, + "OutgoingMessageFilterBucketSize": 128, + "ParticipationKeysRefreshInterval": 60000000000, + "PeerConnectionsUpdateInterval": 3600, + "PeerPingPeriodSeconds": 0, + "PriorityPeers": {}, + "ProposalAssemblyTime": 250000000, + "PublicAddress": "", + "ReconnectTime": 60000000000, + "ReservedFDs": 256, + "RestConnectionsHardLimit": 2048, + "RestConnectionsSoftLimit": 1024, + "RestReadTimeoutSeconds": 15, + "RestWriteTimeoutSeconds": 120, + "RunHosted": false, + "SuggestedFeeBlockHistory": 3, + "SuggestedFeeSlidingWindowSize": 50, + "TLSCertFile": "", + "TLSKeyFile": "", + "TelemetryToLog": true, + "TransactionSyncDataExchangeRate": 0, + "TransactionSyncSignificantMessageThreshold": 0, + "TxPoolExponentialIncreaseFactor": 2, + "TxPoolSize": 15000, + "TxSyncIntervalSeconds": 60, + "TxSyncServeResponseSize": 1000000, + "TxSyncTimeoutSeconds": 30, + "UseXForwardedForAddressField": "", + "VerifiedTranscationsCacheSize": 30000 +} diff --git a/test/testdata/deployednettemplates/recipes/bootstrappedScenario/net.json b/test/testdata/deployednettemplates/recipes/bootstrappedScenario/net.json index b971cdce54..0afb4418ae 100644 --- a/test/testdata/deployednettemplates/recipes/bootstrappedScenario/net.json +++ b/test/testdata/deployednettemplates/recipes/bootstrappedScenario/net.json @@ -16,7 +16,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": true, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"EnableIncomingMessageFilter\": true, \"CadaverSizeTarget\": 0, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"EnableIncomingMessageFilter\": true, \"CadaverSizeTarget\": 0, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"EnableAccountUpdatesStats\": true}" } ] }, @@ -36,7 +36,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": true, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"EnableIncomingMessageFilter\": true, \"CadaverSizeTarget\": 0, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"EnableIncomingMessageFilter\": true, \"CadaverSizeTarget\": 0, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"EnableAccountUpdatesStats\": true}" } ] }, @@ -56,7 +56,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": true, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"EnableIncomingMessageFilter\": true, \"CadaverSizeTarget\": 0, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"EnableIncomingMessageFilter\": true, \"CadaverSizeTarget\": 0, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"EnableAccountUpdatesStats\": true}" } ] }, @@ -76,7 +76,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": true, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"EnableIncomingMessageFilter\": true, \"CadaverSizeTarget\": 0, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"EnableIncomingMessageFilter\": true, \"CadaverSizeTarget\": 0, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"EnableAccountUpdatesStats\": true}" } ] }, @@ -96,7 +96,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": true, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"EnableIncomingMessageFilter\": true, \"CadaverSizeTarget\": 0, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"EnableIncomingMessageFilter\": true, \"CadaverSizeTarget\": 0, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"EnableAccountUpdatesStats\": true}" } ] }, @@ -116,7 +116,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": true, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"EnableIncomingMessageFilter\": true, \"CadaverSizeTarget\": 0, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"EnableIncomingMessageFilter\": true, \"CadaverSizeTarget\": 0, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"EnableAccountUpdatesStats\": true}" } ] }, @@ -136,7 +136,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": true, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"EnableIncomingMessageFilter\": true, \"CadaverSizeTarget\": 0, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"EnableIncomingMessageFilter\": true, \"CadaverSizeTarget\": 0, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"EnableAccountUpdatesStats\": true}" } ] }, @@ -156,7 +156,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": true, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"EnableIncomingMessageFilter\": true, \"CadaverSizeTarget\": 0, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"EnableIncomingMessageFilter\": true, \"CadaverSizeTarget\": 0, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"EnableAccountUpdatesStats\": true}" } ] }, @@ -179,7 +179,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node21", @@ -196,7 +196,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node41", @@ -213,7 +213,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": true, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0,\"EnableAccountUpdatesStats\": true }" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0,\"EnableAccountUpdatesStats\": true }" }, { "Name": "node61", @@ -230,7 +230,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node81", @@ -247,7 +247,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" } ] }, @@ -270,7 +270,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node22", @@ -287,7 +287,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node42", @@ -304,7 +304,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node62", @@ -321,7 +321,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node82", @@ -338,7 +338,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" } ] }, @@ -361,7 +361,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node23", @@ -378,7 +378,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node43", @@ -395,7 +395,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node63", @@ -412,7 +412,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node83", @@ -429,7 +429,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": true, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0,\"EnableAccountUpdatesStats\": true }" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0,\"EnableAccountUpdatesStats\": true }" } ] }, @@ -452,7 +452,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node24", @@ -469,7 +469,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node44", @@ -486,7 +486,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node64", @@ -503,7 +503,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node84", @@ -520,7 +520,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" } ] }, @@ -543,7 +543,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node25", @@ -560,7 +560,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node45", @@ -577,7 +577,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node65", @@ -594,7 +594,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": true, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0,\"EnableAccountUpdatesStats\": true }" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0,\"EnableAccountUpdatesStats\": true }" }, { "Name": "node85", @@ -611,7 +611,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" } ] }, @@ -634,7 +634,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node26", @@ -651,7 +651,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node46", @@ -668,7 +668,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node66", @@ -685,7 +685,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node86", @@ -702,7 +702,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" } ] }, @@ -725,7 +725,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": true, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0,\"EnableAccountUpdatesStats\": true }" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0,\"EnableAccountUpdatesStats\": true }" }, { "Name": "node27", @@ -742,7 +742,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node47", @@ -759,7 +759,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node67", @@ -776,7 +776,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node87", @@ -793,7 +793,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" } ] }, @@ -816,7 +816,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": true, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0,\"EnableAccountUpdatesStats\": true }" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0,\"EnableAccountUpdatesStats\": true }" }, { "Name": "node28", @@ -833,7 +833,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node48", @@ -850,7 +850,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node68", @@ -867,7 +867,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node88", @@ -884,7 +884,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" } ] }, @@ -907,7 +907,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": true, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0,\"EnableAccountUpdatesStats\": true }" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0,\"EnableAccountUpdatesStats\": true }" }, { "Name": "node29", @@ -924,7 +924,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node49", @@ -941,7 +941,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node69", @@ -958,7 +958,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node89", @@ -975,7 +975,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": true, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0,\"EnableAccountUpdatesStats\": true }" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0,\"EnableAccountUpdatesStats\": true }" } ] }, @@ -998,7 +998,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node30", @@ -1015,7 +1015,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node50", @@ -1032,7 +1032,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node70", @@ -1049,7 +1049,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node90", @@ -1066,7 +1066,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" } ] }, @@ -1089,7 +1089,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node31", @@ -1106,7 +1106,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node51", @@ -1123,7 +1123,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node71", @@ -1140,7 +1140,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": true, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0,\"EnableAccountUpdatesStats\": true }" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0,\"EnableAccountUpdatesStats\": true }" }, { "Name": "node91", @@ -1157,7 +1157,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" } ] }, @@ -1180,7 +1180,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node32", @@ -1197,7 +1197,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": true, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0,\"EnableAccountUpdatesStats\": true }" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0,\"EnableAccountUpdatesStats\": true }" }, { "Name": "node52", @@ -1214,7 +1214,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node72", @@ -1231,7 +1231,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node92", @@ -1248,7 +1248,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" } ] }, @@ -1271,7 +1271,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node33", @@ -1288,7 +1288,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": true, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0,\"EnableAccountUpdatesStats\": true }" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0,\"EnableAccountUpdatesStats\": true }" }, { "Name": "node53", @@ -1305,7 +1305,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node73", @@ -1322,7 +1322,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node93", @@ -1339,7 +1339,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" } ] }, @@ -1362,7 +1362,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node34", @@ -1379,7 +1379,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node54", @@ -1396,7 +1396,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": true, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0,\"EnableAccountUpdatesStats\": true }" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0,\"EnableAccountUpdatesStats\": true }" }, { "Name": "node74", @@ -1413,7 +1413,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node94", @@ -1430,7 +1430,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" } ] }, @@ -1453,7 +1453,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node35", @@ -1470,7 +1470,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node55", @@ -1487,7 +1487,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node75", @@ -1504,7 +1504,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node95", @@ -1521,7 +1521,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": true, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0,\"EnableAccountUpdatesStats\": true }" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0,\"EnableAccountUpdatesStats\": true }" } ] }, @@ -1544,7 +1544,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node36", @@ -1561,7 +1561,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": true, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0,\"EnableAccountUpdatesStats\": true }" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0,\"EnableAccountUpdatesStats\": true }" }, { "Name": "node56", @@ -1578,7 +1578,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": true, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0,\"EnableAccountUpdatesStats\": true }" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0,\"EnableAccountUpdatesStats\": true }" }, { "Name": "node76", @@ -1595,7 +1595,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node96", @@ -1612,7 +1612,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" } ] }, @@ -1635,7 +1635,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node37", @@ -1652,7 +1652,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node57", @@ -1669,7 +1669,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node77", @@ -1686,7 +1686,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node97", @@ -1703,7 +1703,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" } ] }, @@ -1726,7 +1726,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node38", @@ -1743,7 +1743,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": true, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0,\"EnableAccountUpdatesStats\": true }" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0,\"EnableAccountUpdatesStats\": true }" }, { "Name": "node58", @@ -1760,7 +1760,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node78", @@ -1777,7 +1777,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node98", @@ -1794,7 +1794,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": true, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0,\"EnableAccountUpdatesStats\": true }" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0,\"EnableAccountUpdatesStats\": true }" } ] }, @@ -1817,7 +1817,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node39", @@ -1834,7 +1834,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node59", @@ -1851,7 +1851,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node79", @@ -1868,7 +1868,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node99", @@ -1885,7 +1885,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" } ] }, @@ -1908,7 +1908,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node40", @@ -1925,7 +1925,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node60", @@ -1942,7 +1942,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node80", @@ -1959,7 +1959,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" }, { "Name": "node100", @@ -1976,7 +1976,7 @@ "MetricsURI": "{{MetricsURI}}", "EnableService": false, "EnableBlockStats": false, - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}" } ] }, diff --git a/test/testdata/deployednettemplates/recipes/bootstrappedScenario/node.json b/test/testdata/deployednettemplates/recipes/bootstrappedScenario/node.json index 412f2937a0..10e25e767f 100644 --- a/test/testdata/deployednettemplates/recipes/bootstrappedScenario/node.json +++ b/test/testdata/deployednettemplates/recipes/bootstrappedScenario/node.json @@ -5,7 +5,7 @@ "TelemetryURI": "{{TelemetryURI}}", "EnableMetrics": false, "MetricsURI": "{{MetricsURI}}", - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}", + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0, \"EnableAccountUpdatesStats\": true}", "AltConfigs": [ { "APIToken": "{{APIToken}}", @@ -14,7 +14,7 @@ "TelemetryURI": "{{TelemetryURI}}", "EnableMetrics": true, "MetricsURI": "{{MetricsURI}}", - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0,\"EnableAccountUpdatesStats\": true }", + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0,\"EnableAccountUpdatesStats\": true }", "FractionApply": 0.2 } ] diff --git a/test/testdata/deployednettemplates/recipes/bootstrappedScenario/relay.json b/test/testdata/deployednettemplates/recipes/bootstrappedScenario/relay.json index db8fb939d8..563543a7bf 100644 --- a/test/testdata/deployednettemplates/recipes/bootstrappedScenario/relay.json +++ b/test/testdata/deployednettemplates/recipes/bootstrappedScenario/relay.json @@ -7,5 +7,5 @@ "TelemetryURI": "{{TelemetryURI}}", "EnableMetrics": true, "MetricsURI": "{{MetricsURI}}", - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"EnableIncomingMessageFilter\": true, \"CadaverSizeTarget\": 0, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableAccountUpdatesStats\": true}" + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"EnableIncomingMessageFilter\": true, \"CadaverSizeTarget\": 0, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"EnableAccountUpdatesStats\": true}" } diff --git a/test/testdata/deployednettemplates/recipes/custom/configs/node.json b/test/testdata/deployednettemplates/recipes/custom/configs/node.json index 4cfd52b5c8..0b310ce098 100644 --- a/test/testdata/deployednettemplates/recipes/custom/configs/node.json +++ b/test/testdata/deployednettemplates/recipes/custom/configs/node.json @@ -6,7 +6,7 @@ "TelemetryURI": "{{TelemetryURI}}", "EnableMetrics": false, "MetricsURI": "{{MetricsURI}}", - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0 }", + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0 }", "AltConfigs": [ { "APIEndpoint": "{{APIEndpoint}}", @@ -16,7 +16,7 @@ "TelemetryURI": "{{TelemetryURI}}", "EnableMetrics": true, "MetricsURI": "{{MetricsURI}}", - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0 }", + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0 }", "FractionApply": 1.0 } ] diff --git a/test/testdata/deployednettemplates/recipes/custom/example/configs/node.json b/test/testdata/deployednettemplates/recipes/custom/example/configs/node.json index a61c7506d5..85238047cc 100644 --- a/test/testdata/deployednettemplates/recipes/custom/example/configs/node.json +++ b/test/testdata/deployednettemplates/recipes/custom/example/configs/node.json @@ -5,7 +5,7 @@ "TelemetryURI": "{{TelemetryURI}}", "EnableMetrics": false, "MetricsURI": "{{MetricsURI}}", - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0 }", + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0 }", "AltConfigs": [ { "APIToken": "{{APIToken}}", @@ -14,7 +14,7 @@ "TelemetryURI": "{{TelemetryURI}}", "EnableMetrics": true, "MetricsURI": "{{MetricsURI}}", - "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"CadaverSizeTarget\": 0 }", + "ConfigJSONOverride": "{ \"TxPoolExponentialIncreaseFactor\": 1, \"DNSBootstrapID\": \".algodev.network\", \"DeadlockDetection\": -1, \"PeerPingPeriodSeconds\": 30, \"EnableAgreementReporting\": true, \"EnableAgreementTimeMetrics\": true, \"EnableAssembleStats\": true, \"EnableProcessBlockStats\": true, \"BaseLoggerDebugLevel\": 4, \"EnableProfiler\": true, \"EnableRuntimeMetrics\": true, \"CadaverSizeTarget\": 0 }", "FractionApply": 1.0 } ] diff --git a/test/testdata/nettemplates/TransitionSix.json b/test/testdata/nettemplates/TransitionSix.json new file mode 100644 index 0000000000..a20e07f0b2 --- /dev/null +++ b/test/testdata/nettemplates/TransitionSix.json @@ -0,0 +1,66 @@ +{ + "Genesis": { + "NetworkName": "tbd", + "LastPartKeyRound": 3000, + "Wallets": [ + { + "Name": "Wallet1", + "Stake": 25, + "Online": true + }, + { + "Name": "Wallet2", + "Stake": 25, + "Online": true + }, + { + "Name": "Wallet3", + "Stake": 25, + "Online": true + }, + { + "Name": "Wallet4", + "Stake": 25, + "Online": true + } + ] + }, + "Nodes": [ + { + "Name": "RelayOld", + "IsRelay": true + }, + { + "Name": "RelayNew", + "IsRelay": true + }, + { + "Name": "Old1", + "Wallets": [ + { "Name": "Wallet1", + "ParticipationOnly": false } + ] + }, + { + "Name": "New1", + "Wallets": [ + { "Name": "Wallet2", + "ParticipationOnly": false } + ] + }, + { + "Name": "Old2", + "Wallets": [ + { "Name": "Wallet3", + "ParticipationOnly": false } + ] + }, + { + "Name": "New2", + "Wallets": [ + { "Name": "Wallet4", + "ParticipationOnly": false } + ] + } + ] +} diff --git a/test/testdata/nettemplates/TwoNodes50EachV32.json b/test/testdata/nettemplates/TwoNodes50EachV32.json new file mode 100644 index 0000000000..3de4536d31 --- /dev/null +++ b/test/testdata/nettemplates/TwoNodes50EachV32.json @@ -0,0 +1,30 @@ +{ + "Genesis": { + "NetworkName": "tbd", + "ConsensusProtocol": "https://github.com/algorandfoundation/specs/tree/d5ac876d7ede07367dbaa26e149aa42589aac1f7", + "LastPartKeyRound": 3000, + "Wallets": [ + { + "Name": "Wallet1", + "Stake": 50, + "Online": true + }, + { + "Name": "Wallet2", + "Stake": 50, + "Online": true + } + ] + }, + "Nodes": [ + { + "Name": "Primary", + "IsRelay": true, + "Wallets": [{ "Name": "Wallet1", "ParticipationOnly": false }] + }, + { + "Name": "Node", + "Wallets": [{ "Name": "Wallet2", "ParticipationOnly": false }] + } + ] + } diff --git a/tools/network/dnssec/config_unix.go b/tools/network/dnssec/config_unix.go index bb328cde6a..4a8c574de1 100644 --- a/tools/network/dnssec/config_unix.go +++ b/tools/network/dnssec/config_unix.go @@ -14,6 +14,7 @@ // You should have received a copy of the GNU Affero General Public License // along with go-algorand. If not, see . +//go:build !windows // +build !windows package dnssec diff --git a/tools/network/dnssec/config_unix_test.go b/tools/network/dnssec/config_unix_test.go index c6699e67f8..c757b5369f 100644 --- a/tools/network/dnssec/config_unix_test.go +++ b/tools/network/dnssec/config_unix_test.go @@ -14,6 +14,7 @@ // You should have received a copy of the GNU Affero General Public License // along with go-algorand. If not, see . +//go:build !windows // +build !windows package dnssec diff --git a/tools/network/dnssec/config_windows.go b/tools/network/dnssec/config_windows.go index 357f1aa1f1..41d6950070 100644 --- a/tools/network/dnssec/config_windows.go +++ b/tools/network/dnssec/config_windows.go @@ -14,6 +14,7 @@ // You should have received a copy of the GNU Affero General Public License // along with go-algorand. If not, see . +//go:build windows // +build windows package dnssec diff --git a/util/metrics/counter.go b/util/metrics/counter.go index 73debb3e91..06ea4b0c44 100644 --- a/util/metrics/counter.go +++ b/util/metrics/counter.go @@ -155,9 +155,6 @@ func (counter *Counter) WriteMetric(buf *strings.Builder, parentLabels string) { counter.Lock() defer counter.Unlock() - if len(counter.values) < 1 { - return - } buf.WriteString("# HELP ") buf.WriteString(counter.name) buf.WriteString(" ") @@ -165,6 +162,17 @@ func (counter *Counter) WriteMetric(buf *strings.Builder, parentLabels string) { buf.WriteString("\n# TYPE ") buf.WriteString(counter.name) buf.WriteString(" counter\n") + // if counter is zero, report 0 using parentLabels and no tags + if len(counter.values) == 0 { + buf.WriteString(counter.name) + if len(parentLabels) > 0 { + buf.WriteString("{" + parentLabels + "}") + } + buf.WriteString(" 0") + buf.WriteString("\n") + return + } + // otherwise iterate through values and write one line per label for _, l := range counter.values { buf.WriteString(counter.name) buf.WriteString("{") diff --git a/util/metrics/counter_test.go b/util/metrics/counter_test.go index 43ef0c27aa..75512b80e0 100644 --- a/util/metrics/counter_test.go +++ b/util/metrics/counter_test.go @@ -19,6 +19,7 @@ package metrics import ( "context" "fmt" + "strings" "testing" "time" @@ -67,7 +68,7 @@ func TestMetricCounter(t *testing.T) { defer test.Unlock() // the the loop above we've created a single metric name with five different labels set ( host0, host1 .. host 4) // let's see if we received all the 5 different labels. - require.Equal(t, 5, len(test.metrics), "Missing metric counts were reported.") + require.Equal(t, 5, len(test.metrics), "Missing metric counts were reported: %+v", test.metrics) for k, v := range test.metrics { // we have increased each one of the labels exactly 4 times. See that the counter was counting correctly. @@ -114,7 +115,7 @@ func TestMetricCounterFastInts(t *testing.T) { defer test.Unlock() // the the loop above we've created a single metric name with five different labels set ( host0, host1 .. host 4) // let's see if we received all the 5 different labels. - require.Equal(t, 1, len(test.metrics), "Missing metric counts were reported.") + require.Equal(t, 1, len(test.metrics), "Missing metric counts were reported: %+v", test.metrics) for k, v := range test.metrics { // we have increased each one of the labels exactly 4 times. See that the counter was counting correctly. @@ -163,7 +164,7 @@ func TestMetricCounterMixed(t *testing.T) { defer test.Unlock() // the the loop above we've created a single metric name with five different labels set ( host0, host1 .. host 4) // let's see if we received all the 5 different labels. - require.Equal(t, 1, len(test.metrics), "Missing metric counts were reported.") + require.Equal(t, 1, len(test.metrics), "Missing metric counts were reported: %+v", test.metrics) for k, v := range test.metrics { // we have increased each one of the labels exactly 4 times. See that the counter was counting correctly. @@ -171,3 +172,29 @@ func TestMetricCounterMixed(t *testing.T) { require.Equal(t, "35.5", v, fmt.Sprintf("The metric '%s' reached value '%s'", k, v)) } } + +func TestCounterWriteMetric(t *testing.T) { + partitiontest.PartitionTest(t) + + c := MakeCounter(MetricName{Name: "testname", Description: "testhelp"}) + c.Deregister(nil) + + // ensure 0 counters are still logged + sbOut := strings.Builder{} + c.WriteMetric(&sbOut, `host="myhost"`) + expected := `# HELP testname testhelp +# TYPE testname counter +testname{host="myhost"} 0 +` + require.Equal(t, expected, sbOut.String()) + + c.Add(2.3, nil) + // ensure non-zero counters are logged + sbOut = strings.Builder{} + c.WriteMetric(&sbOut, `host="myhost"`) + expected = `# HELP testname testhelp +# TYPE testname counter +testname{host="myhost"} 2.3 +` + require.Equal(t, expected, sbOut.String()) +} diff --git a/util/metrics/gauge_test.go b/util/metrics/gauge_test.go index 301ae22a74..9a228c0670 100644 --- a/util/metrics/gauge_test.go +++ b/util/metrics/gauge_test.go @@ -68,7 +68,7 @@ func TestMetricGauge(t *testing.T) { // the the loop above we've created a single metric name with five different labels set ( host0, host1 .. host 4) // let's see if we received all the 5 different labels. - require.Equal(t, 5, len(test.metrics), "Missing metric counts were reported.") + require.Equal(t, 5, len(test.metrics), "Missing metric counts were reported: %+v", test.metrics) // iterate through the metrics and check the each of the metrics reached it's correct count. for k, v := range test.metrics { diff --git a/util/metrics/metrics_test.go b/util/metrics/metrics_test.go index 03369c7a1b..fddb9eda60 100644 --- a/util/metrics/metrics_test.go +++ b/util/metrics/metrics_test.go @@ -25,6 +25,7 @@ import ( "testing" "time" + "github.com/algorand/go-algorand/test/partitiontest" "github.com/algorand/go-deadlock" "github.com/stretchr/testify/require" ) @@ -95,6 +96,8 @@ func (p *MetricTest) testMetricsHandler(w http.ResponseWriter, r *http.Request) } func TestSanitizeTelemetryName(t *testing.T) { + partitiontest.PartitionTest(t) + for _, tc := range []struct{ in, out string }{ {in: "algod_counter_x", out: "algod_counter_x"}, {in: "algod_counter_x{a=b}", out: "algod_counter_x_a_b_"}, @@ -112,3 +115,29 @@ func TestSanitizeTelemetryName(t *testing.T) { }) } } + +func TestSanitizePrometheusName(t *testing.T) { + partitiontest.PartitionTest(t) + + for _, tc := range []struct{ in, out string }{ + {in: "algod_counter_x", out: "algod_counter_x"}, + {in: "algod_counter_x{a=b}", out: "algod_counter_x_a_b_"}, + {in: "this_is1-a-name0", out: "this_is1_a_name0"}, + {in: "myMetricName1:a=yes", out: "myMetricName1_a_yes"}, + {in: "myMetricName1:a=yes,b=no", out: "myMetricName1_a_yes_b_no"}, + {in: "0myMetricName1", out: "_myMetricName1"}, + {in: "myMetricName1{hello=x}", out: "myMetricName1_hello_x_"}, + {in: "myMetricName1.moreNames-n.3", out: "myMetricName1_moreNames_n_3"}, + {in: "-my-metric-name", out: "_my_metric_name"}, + {in: `label-counter:label="a label value"`, out: "label_counter_label__a_label_value_"}, + {in: "go/gc/cycles/total:gc-cycles", out: "go_gc_cycles_total_gc_cycles"}, + {in: "go/gc/heap/allocs:bytes", out: "go_gc_heap_allocs_bytes"}, + {in: "go/gc/heap/allocs:objects", out: "go_gc_heap_allocs_objects"}, + {in: "go/memory/classes/os-stacks:bytes", out: "go_memory_classes_os_stacks_bytes"}, + {in: "go/memory/classes/heap/free:bytes", out: "go_memory_classes_heap_free_bytes"}, + } { + t.Run(tc.in, func(t *testing.T) { + require.Equal(t, tc.out, sanitizePrometheusName(tc.in)) + }) + } +} diff --git a/util/metrics/registryCommon.go b/util/metrics/registryCommon.go index 2eb8d6c532..8a0f53464f 100644 --- a/util/metrics/registryCommon.go +++ b/util/metrics/registryCommon.go @@ -25,7 +25,9 @@ import ( // Metric represent any collectable metric type Metric interface { + // WriteMetric adds metrics in Prometheus exposition format to buf, including parentLabels tags if provided. WriteMetric(buf *strings.Builder, parentLabels string) + // AddMetric adds metrics to a map, used for reporting in telemetry heartbeat messages. AddMetric(values map[string]float64) } @@ -42,3 +44,9 @@ var sanitizeTelemetryCharactersRegexp = regexp.MustCompile("(^[^a-zA-Z_]|[^a-zA- func sanitizeTelemetryName(name string) string { return sanitizeTelemetryCharactersRegexp.ReplaceAllString(name, "_") } + +// sanitizePrometheusName ensures a metric name reported to telemetry doesn't contain any +// non-alphanumeric characters (apart from _) and doesn't start with a number. +func sanitizePrometheusName(name string) string { + return strings.ReplaceAll(sanitizeTelemetryName(name), "-", "_") +} diff --git a/util/metrics/registry_test.go b/util/metrics/registry_test.go index aa48516309..2256993f20 100644 --- a/util/metrics/registry_test.go +++ b/util/metrics/registry_test.go @@ -37,7 +37,7 @@ func TestWriteAdd(t *testing.T) { results := make(map[string]float64) DefaultRegistry().AddMetrics(results) - require.Equal(t, 2, len(results)) + require.Equal(t, 2, len(results), "results", results) require.Contains(t, results, "gauge-name") require.InDelta(t, 12.34, results["gauge-name"], 0.01) require.Contains(t, results, "label-counter_label__a_label_value_") diff --git a/util/metrics/runtime.go b/util/metrics/runtime.go new file mode 100644 index 0000000000..3f89ea761e --- /dev/null +++ b/util/metrics/runtime.go @@ -0,0 +1,137 @@ +// Copyright (C) 2019-2022 Algorand, Inc. +// This file is part of go-algorand +// +// go-algorand 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. +// +// go-algorand 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 go-algorand. If not, see . + +package metrics + +import ( + "runtime/metrics" + "strconv" + "strings" + + "github.com/algorand/go-deadlock" +) + +// defaultRuntimeMetrics contains all the Go runtime metrics, except histograms. +var defaultRuntimeMetrics = []string{ + "/gc/cycles/automatic:gc-cycles", + "/gc/cycles/forced:gc-cycles", + "/gc/cycles/total:gc-cycles", + "/gc/heap/allocs:bytes", + "/gc/heap/allocs:objects", + "/gc/heap/frees:bytes", + "/gc/heap/frees:objects", + "/gc/heap/goal:bytes", + "/gc/heap/objects:objects", + "/gc/heap/tiny/allocs:objects", + "/memory/classes/heap/free:bytes", + "/memory/classes/heap/objects:bytes", + "/memory/classes/heap/released:bytes", + "/memory/classes/heap/stacks:bytes", + "/memory/classes/heap/unused:bytes", + "/memory/classes/metadata/mcache/free:bytes", + "/memory/classes/metadata/mcache/inuse:bytes", + "/memory/classes/metadata/mspan/free:bytes", + "/memory/classes/metadata/mspan/inuse:bytes", + "/memory/classes/metadata/other:bytes", + "/memory/classes/os-stacks:bytes", + "/memory/classes/other:bytes", + "/memory/classes/profiling/buckets:bytes", + "/memory/classes/total:bytes", + "/sched/goroutines:goroutines", +} + +// RuntimeMetrics gathers selected metrics from Go's builtin runtime.metrics package +// and makes them available as Prometheus metrics. +type RuntimeMetrics struct { + descriptions []metrics.Description + samples []metrics.Sample + deadlock.Mutex +} + +// NewRuntimeMetrics creates a RuntimeMetrics object, provided a list of metric names matching +// names in Go's metrics.All(). Otherwise, a default list of runtime metrics will be used. +func NewRuntimeMetrics(enabledMetrics ...string) *RuntimeMetrics { + enabled := make(map[string]bool) + if len(enabledMetrics) == 0 { + enabledMetrics = defaultRuntimeMetrics + } + for _, name := range enabledMetrics { + enabled[name] = true + } + + // create []metrics.Sample and get metric descriptions + rm := &RuntimeMetrics{} + descs := metrics.All() + for _, desc := range descs { + if enabled[desc.Name] { + rm.descriptions = append(rm.descriptions, desc) + rm.samples = append(rm.samples, metrics.Sample{Name: desc.Name}) + } + } + + return rm +} + +// WriteMetric writes runtime metrics to the output stream in prometheus exposition format. +func (rm *RuntimeMetrics) WriteMetric(buf *strings.Builder, parentLabels string) { + rm.Lock() + defer rm.Unlock() + + metrics.Read(rm.samples) + for i, s := range rm.samples { + name := "algod_go" + sanitizePrometheusName(s.Name) + desc := rm.descriptions[i] + + buf.WriteString("# HELP " + name + " " + desc.Description + "\n") + if desc.Cumulative { + buf.WriteString("# TYPE " + name + " counter\n") + } else { + buf.WriteString("# TYPE " + name + " gauge\n") + } + buf.WriteString(name) + if len(parentLabels) > 0 { + buf.WriteString("{" + parentLabels + "}") + } + buf.WriteRune(' ') + switch s.Value.Kind() { + case metrics.KindUint64: + buf.WriteString(strconv.FormatUint(s.Value.Uint64(), 10)) + case metrics.KindFloat64: + buf.WriteString(strconv.FormatFloat(s.Value.Float64(), 'f', -1, 64)) + default: + } + buf.WriteRune('\n') + } +} + +// AddMetric adds runtime metrics to the map used for heartbeat metrics. +func (rm *RuntimeMetrics) AddMetric(m map[string]float64) { + rm.Lock() + defer rm.Unlock() + + metrics.Read(rm.samples) + for _, s := range rm.samples { + name := "go" + sanitizeTelemetryName(s.Name) + + switch s.Value.Kind() { + case metrics.KindUint64: + m[name] = float64(s.Value.Uint64()) + case metrics.KindFloat64: + m[name] = s.Value.Float64() + default: + } + } +} diff --git a/util/metrics/runtime_test.go b/util/metrics/runtime_test.go new file mode 100644 index 0000000000..1032484466 --- /dev/null +++ b/util/metrics/runtime_test.go @@ -0,0 +1,59 @@ +// Copyright (C) 2019-2022 Algorand, Inc. +// This file is part of go-algorand +// +// go-algorand 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. +// +// go-algorand 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 go-algorand. If not, see . + +package metrics + +import ( + "bufio" + "strings" + "testing" + + "github.com/algorand/go-algorand/test/partitiontest" + "github.com/stretchr/testify/require" +) + +func TestRuntimeMetrics(t *testing.T) { + partitiontest.PartitionTest(t) + + rm := NewRuntimeMetrics() + var sb strings.Builder + rm.WriteMetric(&sb, `host="x"`) + scanner := bufio.NewScanner(strings.NewReader(sb.String())) + + // assert default metrics correctly created + cur := 0 + for scanner.Scan() { + curName := "algod_go" + defaultRuntimeMetrics[cur] + curName = strings.ReplaceAll(curName, ":", "_") + curName = strings.ReplaceAll(curName, "-", "_") + curName = strings.ReplaceAll(curName, "/", "_") + require.Regexp(t, `^# HELP `+curName, scanner.Text()) + require.True(t, scanner.Scan()) + require.Regexp(t, `^# TYPE `+curName, scanner.Text()) + require.True(t, scanner.Scan()) + require.Regexp(t, `^`+curName+`{host="x"}`, scanner.Text()) + cur++ + } + require.NoError(t, scanner.Err()) + require.Len(t, defaultRuntimeMetrics, cur) + + m := make(map[string]float64) + rm.AddMetric(m) + for _, name := range defaultRuntimeMetrics { + tname := strings.ReplaceAll(strings.ReplaceAll("go"+name, ":", "_"), "/", "_") + require.Contains(t, m, tname) + } +} diff --git a/util/metrics/segment.go b/util/metrics/segment.go deleted file mode 100644 index 21db004f3a..0000000000 --- a/util/metrics/segment.go +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (C) 2019-2022 Algorand, Inc. -// This file is part of go-algorand -// -// go-algorand 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. -// -// go-algorand 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 go-algorand. If not, see . - -package metrics - -import ( - "sync/atomic" - "time" -) - -// Segment represent a single segment variable. -type Segment struct { - duration *Gauge - totalDuration *Counter - counter *Counter - concurrentInstances *Gauge - concurrentCounter uint32 -} - -// SegmentInstance is generated once a segments starts. -type SegmentInstance struct { - segment *Segment - start time.Time - labels map[string]string -} - -// MakeSegment create a new segment with the provided name and description. -func MakeSegment(metric *MetricName) *Segment { - c := &Segment{ - duration: MakeGauge(MetricName{Name: metric.Name + "_sec", Description: metric.Description + "(duration)"}), - totalDuration: MakeCounter(MetricName{Name: metric.Name + "_sec_total", Description: metric.Description + "(total duration)"}), - counter: MakeCounter(MetricName{Name: metric.Name + "_total", Description: metric.Description + "(total count)"}), - concurrentInstances: MakeGauge(MetricName{Name: metric.Name + "_concurrent", Description: metric.Description + "(concurrent instances)"}), - } - return c -} - -// EnterSegment is called when a segment is entered. -func (segment *Segment) EnterSegment(labels map[string]string) (*SegmentInstance, error) { - segment.counter.Inc(labels) - concurrentCounter := atomic.AddUint32(&segment.concurrentCounter, uint32(1)) - segment.concurrentInstances.Set(float64(concurrentCounter), labels) - return &SegmentInstance{ - segment: segment, - start: time.Now(), - labels: labels, - }, nil -} - -// Register registers the counter with the default/specific registry -func (segment *Segment) Register(reg *Registry) { - segment.duration.Register(reg) - segment.totalDuration.Register(reg) - segment.counter.Register(reg) - segment.concurrentInstances.Register(reg) -} - -// Deregister deregisters the counter with the default/specific registry -func (segment *Segment) Deregister(reg *Registry) { - segment.duration.Deregister(reg) - segment.totalDuration.Deregister(reg) - segment.counter.Deregister(reg) - segment.concurrentInstances.Deregister(reg) -} - -// LeaveSegment is expected to be called via a "defer" statement. -func (segInstance *SegmentInstance) LeaveSegment() error { - if segInstance == nil { - return nil - } - concurrentCounter := atomic.AddUint32(&segInstance.segment.concurrentCounter, ^uint32(0)) - seconds := time.Since(segInstance.start).Seconds() - segInstance.segment.duration.Set(seconds, segInstance.labels) - segInstance.segment.totalDuration.Add(seconds, segInstance.labels) - segInstance.segment.concurrentInstances.Set(float64(concurrentCounter), segInstance.labels) - return nil -} diff --git a/util/metrics/segment_test.go b/util/metrics/segment_test.go deleted file mode 100644 index c5cae321d9..0000000000 --- a/util/metrics/segment_test.go +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright (C) 2019-2022 Algorand, Inc. -// This file is part of go-algorand -// -// go-algorand 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. -// -// go-algorand 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 go-algorand. If not, see . - -package metrics - -import ( - "context" - "fmt" - "strconv" - "strings" - "testing" - "time" - - "github.com/algorand/go-algorand/test/partitiontest" - "github.com/stretchr/testify/require" -) - -type SegmentTest struct { - MetricTest -} - -func TestMetricSegment(t *testing.T) { - partitiontest.PartitionTest(t) - - const initialSleepDuration = 10 * time.Millisecond - const maxSleepDuration = 4 * time.Second - done := false - for sleepDuration := initialSleepDuration; sleepDuration <= maxSleepDuration; sleepDuration *= 2 { - done = testMetricSegmentHelper(t, sleepDuration) - if done { - break - } - } - if !done { - require.Fail(t, "test failed") - } -} - -func testMetricSegmentHelper(t *testing.T, functionTime time.Duration) bool { - - test := &SegmentTest{ - MetricTest: NewMetricTest(), - } - // create a http listener. - port := test.createListener(":0") - - metricService := MakeMetricService(&ServiceConfig{ - NodeExporterListenAddress: fmt.Sprintf("localhost:%d", port), - Labels: map[string]string{ - "host_name": "host_one", - "session_id": "AFX-229"}, - }) - metricService.Start(context.Background()) - - acceptedFunctionThreshold := 1.1 // 10 percent. - segment := MakeSegment(&MetricName{Name: "test_segment_name1", Description: "this is the metric test for segment object"}) - segmentTest := func() { - inst, _ := segment.EnterSegment(map[string]string{"pid": "123"}) - defer inst.LeaveSegment() - time.Sleep(functionTime) - } - segmentTest() - segmentTest() - // wait two reporting cycles to ensure we received all the messages. - time.Sleep(test.sampleRate * 2) - - metricService.Shutdown() - - segment.Deregister(nil) - - test.Lock() - defer test.Unlock() - - // test the metrics values. see if we received all the 4 metrics back correctly. - // we expect the get 4 metrics : test_segment_name1_sec, test_segment_name1_sec_total, test_segment_name1_total and test_segment_name1_concurrent - // ( we don't know in which order they would appear, but the total count should be 4 ) - require.Equal(t, 4, len(test.metrics), "Missing metric counts were reported.") - - for k, v := range test.metrics { - if strings.Contains(k, "test_segment_name1_sec{") { - // should be around 400 milliseconds. - if elapsedTime, err := strconv.ParseFloat(v, 64); err != nil { - t.Fatalf("The metric '%s' has unexpected value of '%s'", k, v) - } else { - if elapsedTime < functionTime.Seconds() || elapsedTime > functionTime.Seconds()*acceptedFunctionThreshold { - return false - } - } - } - if strings.Contains(k, "test_segment_name1_sec_total{") { - // should be around 800 milliseconds. - if elapsedTime, err := strconv.ParseFloat(v, 64); err != nil { - t.Fatalf("The metric '%s' has unexpected value of '%s'", k, v) - } else { - if elapsedTime < 2*functionTime.Seconds() || elapsedTime > 2*functionTime.Seconds()*acceptedFunctionThreshold { - return false - } - } - } - if strings.Contains(k, "test_segment_name1_total{") { - // should be 2, since we had 2 calls. - require.Equal(t, "2", v, "The metric '%s' has unexpected value of '%s'", k, v) - } - } - return true -} diff --git a/util/metrics/tagcounter.go b/util/metrics/tagcounter.go index 53cce7ba69..d110b8d4f0 100644 --- a/util/metrics/tagcounter.go +++ b/util/metrics/tagcounter.go @@ -26,8 +26,12 @@ import ( // NewTagCounter makes a set of metrics under rootName for tagged counting. // "{TAG}" in rootName is replaced by the tag, otherwise "_{TAG}" is appended. -func NewTagCounter(rootName, desc string) *TagCounter { +// Optionally provided declaredTags counters for these names up front (making them easier to discover). +func NewTagCounter(rootName, desc string, declaredTags ...string) *TagCounter { tc := &TagCounter{Name: rootName, Description: desc} + for _, tag := range declaredTags { + tc.Add(tag, 0) + } DefaultRegistry().Register(tc) return tc } @@ -98,32 +102,34 @@ func (tc *TagCounter) WriteMetric(buf *strings.Builder, parentLabels string) { // no values, nothing to say. return } - // TODO: what to do with "parentLabels"? obsolete part of interface? - buf.WriteString("# ") - buf.WriteString(tc.Name) - buf.WriteString(" ") - buf.WriteString(tc.Description) - buf.WriteString("\n") isTemplate := strings.Contains(tc.Name, "{TAG}") tags := tagptr.(map[string]*uint64) for tag, tagcount := range tags { if tagcount == nil { continue } + var name string if isTemplate { - name := strings.ReplaceAll(tc.Name, "{TAG}", tag) - buf.WriteString(name) - buf.WriteRune(' ') - buf.WriteString(strconv.FormatUint(*tagcount, 10)) - buf.WriteRune('\n') + name = strings.ReplaceAll(tc.Name, "{TAG}", tag) } else { - buf.WriteString(tc.Name) - buf.WriteRune('_') - buf.WriteString(tag) - buf.WriteRune(' ') - buf.WriteString(strconv.FormatUint(*tagcount, 10)) - buf.WriteRune('\n') + name = tc.Name + "_" + tag + } + buf.WriteString("# HELP ") + buf.WriteString(name) + buf.WriteRune(' ') + buf.WriteString(strings.ReplaceAll(tc.Description, "{TAG}", tag)) + buf.WriteString("\n# TYPE ") + buf.WriteString(name) + buf.WriteString(" counter\n") + buf.WriteString(name) + if len(parentLabels) > 0 { + buf.WriteRune('{') + buf.WriteString(parentLabels) + buf.WriteRune('}') } + buf.WriteRune(' ') + buf.WriteString(strconv.FormatUint(*tagcount, 10)) + buf.WriteRune('\n') } } diff --git a/util/metrics/tagcounter_test.go b/util/metrics/tagcounter_test.go index b76202c537..feb464a35c 100644 --- a/util/metrics/tagcounter_test.go +++ b/util/metrics/tagcounter_test.go @@ -40,6 +40,7 @@ func TestTagCounter(t *testing.T) { } tc := NewTagCounter("tc", "wat") + DefaultRegistry().Deregister(tc) // check that empty TagCounter cleanly returns no results var sb strings.Builder @@ -80,6 +81,39 @@ func TestTagCounter(t *testing.T) { } } +func TestTagCounterWriteMetric(t *testing.T) { + partitiontest.PartitionTest(t) + + tc := NewTagCounter("count_msgs_{TAG}", "number of {TAG} messages") + DefaultRegistry().Deregister(tc) + + tc.Add("TX", 100) + tc.Add("TX", 1) + tc.Add("RX", 0) + + var sbOut strings.Builder + tc.WriteMetric(&sbOut, `host="myhost"`) + txExpected := `# HELP count_msgs_TX number of TX messages +# TYPE count_msgs_TX counter +count_msgs_TX{host="myhost"} 101 +` + rxExpected := `# HELP count_msgs_RX number of RX messages +# TYPE count_msgs_RX counter +count_msgs_RX{host="myhost"} 0 +` + expfmt := sbOut.String() + require.True(t, expfmt == txExpected+rxExpected || expfmt == rxExpected+txExpected, "bad fmt: %s", expfmt) + + tc2 := NewTagCounter("declared", "number of {TAG}s", "A", "B") + DefaultRegistry().Deregister(tc2) + aExpected := "# HELP declared_A number of As\n# TYPE declared_A counter\ndeclared_A{host=\"h\"} 0\n" + bExpected := "# HELP declared_B number of Bs\n# TYPE declared_B counter\ndeclared_B{host=\"h\"} 0\n" + sbOut = strings.Builder{} + tc2.WriteMetric(&sbOut, `host="h"`) + expfmt = sbOut.String() + require.True(t, expfmt == aExpected+bExpected || expfmt == bExpected+aExpected, "bad fmt: %s", expfmt) +} + func BenchmarkTagCounter(b *testing.B) { b.Logf("b.N = %d", b.N) t := b diff --git a/util/process_common.go b/util/process_common.go index 5685b06a51..b2c1bc7081 100644 --- a/util/process_common.go +++ b/util/process_common.go @@ -14,6 +14,7 @@ // You should have received a copy of the GNU Affero General Public License // along with go-algorand. If not, see . +//go:build !windows // +build !windows package util diff --git a/util/process_windows.go b/util/process_windows.go index b7a5c6b65d..4cad60df7e 100644 --- a/util/process_windows.go +++ b/util/process_windows.go @@ -14,6 +14,7 @@ // You should have received a copy of the GNU Affero General Public License // along with go-algorand. If not, see . +//go:build windows // +build windows package util diff --git a/util/util.go b/util/util.go index c4c7a7385c..a19a5b0690 100644 --- a/util/util.go +++ b/util/util.go @@ -14,6 +14,7 @@ // You should have received a copy of the GNU Affero General Public License // along with go-algorand. If not, see . +//go:build !windows // +build !windows package util