diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -604,6 +604,7 @@
 	node/transaction.cpp
 	node/ui_interface.cpp
 	noui.cpp
+	policy/blockparking.cpp
 	policy/fees.cpp
 	policy/packages.cpp
 	policy/settings.cpp
diff --git a/src/minerfund.cpp b/src/minerfund.cpp
--- a/src/minerfund.cpp
+++ b/src/minerfund.cpp
@@ -52,9 +52,8 @@
 GetMinerFundWhitelist(const Consensus::Params &params,
                       const CBlockIndex *pindexPrev) {
     if (IsWellingtonEnabled(params, pindexPrev)) {
-        // FIXME When Wellington activates, return the whitelist used by policy
-        // checks.
-        return GetMinerFundWhitelist(params, pindexPrev, true);
+        // Return the whitelist used by policy checks.
+        return GetMinerFundWhitelist(params, pindexPrev, false);
     }
 
     // Wellington has not activated, so use the whitelist that consensus checks
@@ -73,9 +72,7 @@
         return {};
     }
 
-    if (isConsensus) {
-        // FIXME Add check for Wellington activation once the policy is fully
-        // implemented.
+    if (isConsensus && !IsWellingtonEnabled(params, pindexPrev)) {
         return {GetMinerFundDestination(!IsGluonEnabled(params, pindexPrev))};
     }
 
diff --git a/src/policy/blockparking.h b/src/policy/blockparking.h
new file mode 100644
--- /dev/null
+++ b/src/policy/blockparking.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2023 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_POLICY_BLOCKPARKING_H
+#define BITCOIN_POLICY_BLOCKPARKING_H
+
+#include <consensus/amount.h>
+#include <primitives/block.h>
+
+#include <memory>
+#include <vector>
+
+class CBlockIndex;
+
+namespace Consensus {
+struct Params;
+}
+
+struct ParkingPolicy {
+    virtual ~ParkingPolicy() {}
+
+    virtual bool operator()() { return false; }
+};
+
+struct MinerFundPolicy : ParkingPolicy {
+    const CBlock &m_block;
+    const Amount &m_blockReward;
+    const Consensus::Params &m_consensusParams;
+    const CBlockIndex *m_pindex;
+
+    MinerFundPolicy(const Consensus::Params &consensusParams,
+                    const CBlockIndex *pindex, const CBlock &block,
+                    const Amount &blockReward)
+        : m_block(block), m_blockReward(blockReward),
+          m_consensusParams(consensusParams), m_pindex(pindex) {}
+
+    bool operator()() override;
+};
+
+std::vector<std::shared_ptr<ParkingPolicy>>
+GetParkingPoliciesForBlock(const Consensus::Params &params,
+                           const CBlockIndex *pindex, const CBlock &block,
+                           const Amount &blockReward);
+
+#endif // BITCOIN_POLICY_BLOCKPARKING_H
diff --git a/src/policy/blockparking.cpp b/src/policy/blockparking.cpp
new file mode 100644
--- /dev/null
+++ b/src/policy/blockparking.cpp
@@ -0,0 +1,27 @@
+// Copyright (c) 2023 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <policy/blockparking.h>
+
+#include <blockindex.h>
+#include <minerfund.h>
+
+std::vector<std::shared_ptr<ParkingPolicy>>
+GetParkingPoliciesForBlock(const Consensus::Params &params,
+                           const CBlockIndex *pindex, const CBlock &block,
+                           const Amount &blockReward) {
+    if (!pindex->pprev) {
+        return {};
+    }
+
+    return {
+        std::make_shared<MinerFundPolicy>(params, pindex, block, blockReward)};
+}
+
+bool MinerFundPolicy::operator()() {
+    assert(m_pindex->pprev);
+    assert(m_block.vtx.size());
+    return !CheckMinerFund(m_consensusParams, m_pindex->pprev,
+                           m_block.vtx[0]->vout, m_blockReward, false);
+}
diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt
--- a/src/test/CMakeLists.txt
+++ b/src/test/CMakeLists.txt
@@ -186,6 +186,7 @@
 		netbase_tests.cpp
 		op_reversebytes_tests.cpp
 		pmt_tests.cpp
+		policy_blockparking_tests.cpp
 		policy_fee_tests.cpp
 		policyestimator_tests.cpp
 		prevector_tests.cpp
diff --git a/src/test/minerfund_tests.cpp b/src/test/minerfund_tests.cpp
--- a/src/test/minerfund_tests.cpp
+++ b/src/test/minerfund_tests.cpp
@@ -85,11 +85,10 @@
     BOOST_CHECK(!IsWellingtonEnabled(consensusParams, &blocks.back()));
     CheckWhitelists(expectedMinerFund, {});
 
+    // Wellington is activated. The whitelist moves from consensus to policy.
     SetMTP(blocks, activation);
     BOOST_CHECK(IsWellingtonEnabled(consensusParams, &blocks.back()));
-    // FIXME Once policy is fully implemented, consensus whitelist should be
-    // empty (deactivated).
-    CheckWhitelists(expectedMinerFund, expectedMinerFund);
+    CheckWhitelists({}, expectedMinerFund);
 }
 
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/policy_blockparking_tests.cpp b/src/test/policy_blockparking_tests.cpp
new file mode 100644
--- /dev/null
+++ b/src/test/policy_blockparking_tests.cpp
@@ -0,0 +1,193 @@
+// Copyright (c) 2023 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <policy/blockparking.h>
+
+#include <blockindex.h>
+#include <chainparams.h>
+#include <consensus/activation.h>
+#include <key_io.h>
+#include <minerfund.h>
+#include <validation.h>
+
+#include <test/util/blockindex.h>
+#include <test/util/setup_common.h>
+
+#include <boost/test/unit_test.hpp>
+
+BOOST_FIXTURE_TEST_SUITE(policy_blockparking_tests, BasicTestingSetup)
+
+static CBlock GetBlockWithMinerFund(const CChainParams &chainparams, int height,
+                                    const Amount &minerFundAmount) {
+    CBlock block;
+    CMutableTransaction coinbaseTx;
+
+    coinbaseTx.vout.resize(1);
+    coinbaseTx.vout[0].nValue = minerFundAmount;
+    const auto minerFund = DecodeDestination(
+        "ecash:prfhcnyqnl5cgrnmlfmms675w93ld7mvvqd0y8lz07", chainparams);
+    coinbaseTx.vout[0].scriptPubKey = GetScriptForDestination(minerFund);
+    block.vtx.push_back(MakeTransactionRef(std::move(coinbaseTx)));
+
+    return block;
+}
+
+static CBlock GetBlock(const CChainParams &chainparams, int height) {
+    CBlock block;
+    CMutableTransaction coinbaseTx;
+
+    coinbaseTx.vout.resize(1);
+    coinbaseTx.vout[0].scriptPubKey = CScript() << OP_TRUE;
+    block.vtx.push_back(MakeTransactionRef(std::move(coinbaseTx)));
+
+    return block;
+}
+
+BOOST_AUTO_TEST_CASE(get_policies) {
+    const CChainParams &chainparams = Params();
+    const Consensus::Params &consensusParams = chainparams.GetConsensus();
+
+    std::array<CBlockIndex, 12> blocks;
+    for (size_t i = 1; i < blocks.size(); ++i) {
+        blocks[i].pprev = &blocks[i - 1];
+        blocks[i].nHeight = consensusParams.gluonHeight + i;
+    }
+    CBlockIndex &blockIndex = blocks.back();
+
+    const Amount blockReward =
+        GetBlockSubsidy(blockIndex.nHeight, consensusParams);
+    CBlock block = GetBlockWithMinerFund(chainparams, blockIndex.nHeight,
+                                         GetMinerFundAmount(blockReward));
+
+    const auto activation = gArgs.GetIntArg(
+        "-wellingtonactivationtime", consensusParams.wellingtonActivationTime);
+
+    // Before Wellington activates
+    SetMTP(blocks, activation - 1);
+    BOOST_CHECK(!IsWellingtonEnabled(consensusParams, &blockIndex));
+    {
+        auto policies = GetParkingPoliciesForBlock(consensusParams, &blockIndex,
+                                                   block, blockReward);
+        BOOST_CHECK_EQUAL(policies.size(), 1);
+    }
+
+    // Wellington is activated but new rules won't be enforced until next block
+    SetMTP(blocks, activation);
+    BOOST_CHECK(IsWellingtonEnabled(consensusParams, &blockIndex));
+    {
+        auto policies = GetParkingPoliciesForBlock(consensusParams, &blockIndex,
+                                                   block, blockReward);
+        BOOST_CHECK_EQUAL(policies.size(), 1);
+    }
+
+    // Wellington rules are now enforced
+    SetMTP(blocks, activation + 1);
+    BOOST_CHECK(IsWellingtonEnabled(consensusParams, blockIndex.pprev));
+    {
+        auto policies = GetParkingPoliciesForBlock(consensusParams, &blockIndex,
+                                                   block, blockReward);
+        BOOST_CHECK_EQUAL(policies.size(), 1);
+    }
+}
+
+BOOST_AUTO_TEST_CASE(policy_minerfund) {
+    const CChainParams &chainparams = Params();
+    const Consensus::Params &consensusParams = chainparams.GetConsensus();
+
+    std::array<CBlockIndex, 12> blocks;
+    for (size_t i = 1; i < blocks.size(); ++i) {
+        blocks[i].pprev = &blocks[i - 1];
+        blocks[i].nHeight = consensusParams.gluonHeight + i;
+    }
+    CBlockIndex &blockIndex = blocks.back();
+
+    const Amount blockReward =
+        GetBlockSubsidy(blockIndex.nHeight, consensusParams);
+    const Amount minerFund = GetMinerFundAmount(blockReward);
+
+    const auto activation = gArgs.GetIntArg(
+        "-wellingtonactivationtime", consensusParams.wellingtonActivationTime);
+
+    // Before Wellington activates
+    SetMTP(blocks, activation - 1);
+    BOOST_CHECK(!IsWellingtonEnabled(consensusParams, &blockIndex));
+
+    {
+        // Block without miner fund
+        CBlock block = GetBlock(chainparams, blockIndex.nHeight);
+        MinerFundPolicy shouldPark(consensusParams, &blockIndex, block,
+                                   blockReward);
+        BOOST_CHECK(!shouldPark());
+    }
+    {
+        // Block with miner fund of various amounts
+        for (const Amount &amount :
+             {minerFund - 1 * SATOSHI, minerFund, minerFund + 1 * SATOSHI}) {
+            CBlock block =
+                GetBlockWithMinerFund(chainparams, blockIndex.nHeight, amount);
+            MinerFundPolicy shouldPark(consensusParams, &blockIndex, block,
+                                       blockReward);
+            BOOST_CHECK(!shouldPark());
+        }
+    }
+
+    // Wellington is activated but new rules won't be enforced until next block
+    SetMTP(blocks, activation);
+    BOOST_CHECK(IsWellingtonEnabled(consensusParams, &blockIndex));
+
+    {
+        // Block without miner fund
+        CBlock block = GetBlock(chainparams, blockIndex.nHeight);
+        MinerFundPolicy shouldPark(consensusParams, &blockIndex, block,
+                                   blockReward);
+        BOOST_CHECK(!shouldPark());
+    }
+    {
+        // Block with miner fund of various amounts
+        for (const Amount &amount :
+             {minerFund - 1 * SATOSHI, minerFund, minerFund + 1 * SATOSHI}) {
+            CBlock block =
+                GetBlockWithMinerFund(chainparams, blockIndex.nHeight, amount);
+            MinerFundPolicy shouldPark(consensusParams, &blockIndex, block,
+                                       blockReward);
+            BOOST_CHECK(!shouldPark());
+        }
+    }
+
+    // Wellington rules are now enforced
+    SetMTP(blocks, activation + 1);
+    BOOST_CHECK(IsWellingtonEnabled(consensusParams, blockIndex.pprev));
+
+    {
+        // Block without miner fund
+        CBlock block = GetBlock(chainparams, blockIndex.nHeight);
+        MinerFundPolicy shouldPark(consensusParams, &blockIndex, block,
+                                   blockReward);
+        BOOST_CHECK(shouldPark());
+    }
+    {
+        // Block with not enough miner fund
+        for (const Amount &amount :
+             {1 * SATOSHI, minerFund / 2, minerFund - 1 * SATOSHI}) {
+            CBlock block =
+                GetBlockWithMinerFund(chainparams, blockIndex.nHeight, amount);
+            MinerFundPolicy shouldPark(consensusParams, &blockIndex, block,
+                                       blockReward);
+            BOOST_CHECK(shouldPark());
+        }
+    }
+    {
+        // Block with sufficient miner fund
+        for (const Amount &amount :
+             {minerFund, minerFund + 1 * SATOSHI, blockReward}) {
+            CBlock block =
+                GetBlockWithMinerFund(chainparams, blockIndex.nHeight, amount);
+            MinerFundPolicy shouldPark(consensusParams, &blockIndex, block,
+                                       blockReward);
+            BOOST_CHECK(!shouldPark());
+        }
+    }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/validation.h b/src/validation.h
--- a/src/validation.h
+++ b/src/validation.h
@@ -15,6 +15,7 @@
 #include <attributes.h>
 #include <blockfileinfo.h>
 #include <blockindexcomparators.h>
+#include <bloom.h>
 #include <chain.h>
 #include <consensus/amount.h>
 #include <consensus/consensus.h>
@@ -683,6 +684,15 @@
     const CBlockIndex *m_avalancheFinalizedBlockIndex
         GUARDED_BY(cs_avalancheFinalizedBlockIndex) = nullptr;
 
+    /**
+     * Filter to prevent parking a block due to block policies more than once.
+     * After first application of block policies, Avalanche voting will
+     * determine the final acceptance state. Rare false positives will be
+     * reconciled by the network and should not have any negative impact.
+     */
+    CRollingBloomFilter m_filterParkingPoliciesApplied =
+        CRollingBloomFilter{1000, 0.000001};
+
     CBlockIndex const *m_best_fork_tip = nullptr;
     CBlockIndex const *m_best_fork_base = nullptr;
 
@@ -849,7 +859,8 @@
         EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
     bool ConnectBlock(const CBlock &block, BlockValidationState &state,
                       CBlockIndex *pindex, CCoinsViewCache &view,
-                      BlockValidationOptions options, bool fJustCheck = false)
+                      BlockValidationOptions options,
+                      Amount *blockFees = nullptr, bool fJustCheck = false)
         EXCLUSIVE_LOCKS_REQUIRED(cs_main);
 
     // Apply the effects of a block disconnection on the UTXO set.
@@ -970,7 +981,7 @@
                     CBlockIndex *pindexNew,
                     const std::shared_ptr<const CBlock> &pblock,
                     ConnectTrace &connectTrace,
-                    DisconnectedBlockTransactions &disconnectpool)
+                    DisconnectedBlockTransactions &disconnectpool, bool &parked)
         EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_mempool->cs);
     void InvalidBlockFound(CBlockIndex *pindex,
                            const BlockValidationState &state)
diff --git a/src/validation.cpp b/src/validation.cpp
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -30,6 +30,7 @@
 #include <node/coinstats.h>
 #include <node/ui_interface.h>
 #include <node/utxo_snapshot.h>
+#include <policy/blockparking.h>
 #include <policy/mempool.h>
 #include <policy/policy.h>
 #include <policy/settings.h>
@@ -1767,7 +1768,7 @@
 bool CChainState::ConnectBlock(const CBlock &block, BlockValidationState &state,
                                CBlockIndex *pindex, CCoinsViewCache &view,
                                BlockValidationOptions options,
-                               bool fJustCheck) {
+                               Amount *blockFees, bool fJustCheck) {
     AssertLockHeld(cs_main);
     assert(pindex);
 
@@ -2145,6 +2146,10 @@
                              "bad-cb-amount");
     }
 
+    if (blockFees) {
+        *blockFees = nFees;
+    }
+
     if (!CheckMinerFund(consensusParams, pindex->pprev, block.vtx[0]->vout,
                         blockReward, true)) {
         return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS,
@@ -2599,7 +2604,8 @@
                              CBlockIndex *pindexNew,
                              const std::shared_ptr<const CBlock> &pblock,
                              ConnectTrace &connectTrace,
-                             DisconnectedBlockTransactions &disconnectpool) {
+                             DisconnectedBlockTransactions &disconnectpool,
+                             bool &parked) {
     AssertLockHeld(cs_main);
     if (m_mempool) {
         AssertLockHeld(m_mempool->cs);
@@ -2630,9 +2636,10 @@
     LogPrint(BCLog::BENCH, "  - Load block from disk: %.2fms [%.2fs]\n",
              (nTime2 - nTime1) * MILLI, nTimeReadFromDisk * MICRO);
     {
+        Amount blockFees{Amount::zero()};
         CCoinsViewCache view(&CoinsTip());
         bool rv = ConnectBlock(blockConnecting, state, pindexNew, view,
-                               BlockValidationOptions(config));
+                               BlockValidationOptions(config), &blockFees);
         GetMainSignals().BlockChecked(blockConnecting, state);
         if (!rv) {
             if (state.IsInvalid()) {
@@ -2644,6 +2651,36 @@
                          state.ToString());
         }
 
+        // We check block parking policies before flushing changes to the UTXO
+        // set. This allows us to avoid rewinding everything immediately after.
+        //
+        // Only check block parking presets the first time the block is
+        // connected. Avalanche voting can override the parking decision made
+        // by these presets.
+        const BlockHash blockhash = pindexNew->GetBlockHash();
+        if (!IsInitialBlockDownload() &&
+            !m_filterParkingPoliciesApplied.contains(blockhash)) {
+            m_filterParkingPoliciesApplied.insert(blockhash);
+
+            // The block is valid by consensus rules so now we check if the
+            // block passes all block preset rules. If not, then park the
+            // block.
+            const Amount blockReward =
+                blockFees +
+                GetBlockSubsidy(pindexNew->nHeight, consensusParams);
+            const auto parkingPolicies = GetParkingPoliciesForBlock(
+                consensusParams, pindexNew, blockConnecting, blockReward);
+            if (std::any_of(parkingPolicies.begin(), parkingPolicies.end(),
+                            [&](const auto policy) { return (*policy)(); })) {
+                LogPrintf("Park block %s because it violated a block policy\n",
+                          blockhash.ToString());
+                pindexNew->nStatus = pindexNew->nStatus.withParked();
+                m_blockman.m_dirty_blockindex.insert(pindexNew);
+                parked = true;
+                return false;
+            }
+        }
+
         nTime3 = GetTimeMicros();
         nTimeConnectTotal += nTime3 - nTime2;
         assert(nBlocksTotal > 0);
@@ -2959,11 +2996,12 @@
 
         // Connect new blocks.
         for (CBlockIndex *pindexConnect : reverse_iterate(vpindexToConnect)) {
+            bool parked{false};
             if (!ConnectTip(config, state, pindexConnect,
                             pindexConnect == pindexMostWork
                                 ? pblock
                                 : std::shared_ptr<const CBlock>(),
-                            connectTrace, disconnectpool)) {
+                            connectTrace, disconnectpool, parked)) {
                 if (state.IsInvalid()) {
                     // The block violates a consensus rule.
                     if (state.GetResult() !=
@@ -2976,6 +3014,13 @@
                     break;
                 }
 
+                if (parked) {
+                    // The block was parked due to a policy violation.
+                    fInvalidFound = true;
+                    fContinue = false;
+                    break;
+                }
+
                 // A system error occurred (disk space, database error, ...).
                 // Make the mempool consistent with the current tip, just in
                 // case any observers try to use it before shutdown.
@@ -4407,7 +4452,7 @@
     }
 
     if (!chainstate.ConnectBlock(block, state, &indexDummy, viewNew,
-                                 validationOptions, true)) {
+                                 validationOptions, nullptr, true)) {
         return false;
     }
 
diff --git a/test/functional/abc_feature_minerfund.py b/test/functional/abc_feature_minerfund.py
--- a/test/functional/abc_feature_minerfund.py
+++ b/test/functional/abc_feature_minerfund.py
@@ -13,6 +13,7 @@
 from test_framework.txtools import pad_tx
 from test_framework.util import assert_equal, assert_greater_than_or_equal
 
+WELLINGTON_ACTIVATION_TIME = 2100000600
 MINER_FUND_RATIO = 8
 MINER_FUND_ADDR = 'ecregtest:prfhcnyqnl5cgrnmlfmms675w93ld7mvvq9jcw0zsn'
 MINER_FUND_ADDR_AXION = 'ecregtest:pqnqv9lt7e5vjyp0w88zf2af0l92l8rxdgz0wv9ltl'
@@ -21,26 +22,29 @@
 class MinerFundTest(BitcoinTestFramework):
     def set_test_params(self):
         self.setup_clean_chain = True
-        self.num_nodes = 1
+        self.num_nodes = 2
         self.extra_args = [[
             '-enableminerfund',
+            '-wellingtonactivationtime={}'.format(WELLINGTON_ACTIVATION_TIME),
+        ], [
+            '-wellingtonactivationtime={}'.format(WELLINGTON_ACTIVATION_TIME),
         ]]
 
     def run_test(self):
         node = self.nodes[0]
 
         self.log.info('Create some history')
-        self.generate(node, 50, sync_fun=self.no_op)
+        self.generate(node, 10)
 
-        def get_best_coinbase():
-            return node.getblock(node.getbestblockhash(), 2)['tx'][0]
+        def get_best_coinbase(n):
+            return n.getblock(n.getbestblockhash(), 2)['tx'][0]
 
-        coinbase = get_best_coinbase()
+        coinbase = get_best_coinbase(node)
         assert_greater_than_or_equal(len(coinbase['vout']), 2)
         block_reward = sum([vout['value'] for vout in coinbase['vout']])
 
         def check_miner_fund_output(expected_address):
-            coinbase = get_best_coinbase()
+            coinbase = get_best_coinbase(node)
             assert_equal(len(coinbase['vout']), 2)
             assert_equal(
                 coinbase['vout'][1]['scriptPubKey']['addresses'][0],
@@ -113,6 +117,44 @@
         node.submitblock(ToHex(good_block))
         assert_equal(node.getbestblockhash(), good_block.hash)
 
+        # Move MTP forward to wellington activation. Next block will enforce
+        # new rules.
+        address = node.get_deterministic_priv_key().address
+        for n in self.nodes:
+            n.setmocktime(WELLINGTON_ACTIVATION_TIME)
+        self.generatetoaddress(node, nblocks=6, address=address)
+        assert_equal(
+            node.getblockchaininfo()['mediantime'],
+            WELLINGTON_ACTIVATION_TIME)
+
+        # First block that does not have miner fund as a consensus requirement.
+        # node0 still mines a block with a coinbase output to the miner fund.
+        first_block_has_miner_fund = self.generatetoaddress(
+            node, nblocks=1, address=address)[0]
+        check_miner_fund_output(MINER_FUND_ADDR)
+
+        # Invalidate it
+        for n in self.nodes:
+            n.invalidateblock(first_block_has_miner_fund)
+
+        # node1 mines a block without a coinbase output to the miner fund.
+        first_block_no_miner_fund = self.generatetoaddress(
+            self.nodes[1],
+            nblocks=1,
+            address=address,
+            sync_fun=self.no_op)[0]
+        coinbase = get_best_coinbase(self.nodes[1])
+        assert_equal(len(coinbase['vout']), 1)
+
+        # node0 parks the block since the miner fund is enforced by policy.
+        def parked_block(blockhash):
+            for tip in node.getchaintips():
+                if tip["hash"] == blockhash:
+                    assert tip["status"] != "active"
+                    return tip["status"] == "parked"
+            return False
+        self.wait_until(lambda: parked_block(first_block_no_miner_fund))
+
 
 if __name__ == '__main__':
     MinerFundTest().main()