Contract 0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a8

Contract Overview

Balance:
0 BNB
Txn Hash Method
Block
From
To
Value [Txn Fee]
0x03908e2ca7d29be28668a35aaf7143f0e6e9e98729397e81f759909fe5787250Enter Markets124319552021-09-17 2:03:102 days 13 hrs ago0xe706fbb75880e6eb7b07402fda6d6b32d0c81dde IN  0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB0.00073708
0x1c88f25bc3e73e23f9a000fa55a307675bf509519daa8ac83a0836124133eb4aEnter Markets124318022021-09-17 1:55:062 days 13 hrs ago0xe706fbb75880e6eb7b07402fda6d6b32d0c81dde IN  0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB0.00073708
0x3e70e8675724d2f0fc8a57730f6d09d753e87a645a7ca9294603084ca0b6ef0fEnter Markets124204902021-09-16 15:59:262 days 23 hrs ago0x7329b0944b33c4b09d4ac004fa15b51ce6f502ea IN  0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB0.00073708
0x1b60f597fc01a419b2838e05d9e352d073ec4e15d0a7f669af0626c53c889a36Enter Markets124203782021-09-16 15:53:502 days 23 hrs ago0x7329b0944b33c4b09d4ac004fa15b51ce6f502ea IN  0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB0.00088708
0x4c5cb837664ee1411ee241dc2dfdb74a761f10acf84d104dbf96e7c6181e92d7Enter Markets124170672021-09-16 13:08:173 days 2 hrs ago0xf5f9e169fafb2d58bc7c869a7ff958eb5ff75058 IN  0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB0.00073696
0x7e6e3b9a77bb5b12dea7fce584a871b8b1d3e7d677ae79d1fb1f0be1bc43fd45Enter Markets124170582021-09-16 13:07:503 days 2 hrs ago0xf5f9e169fafb2d58bc7c869a7ff958eb5ff75058 IN  0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB0.00073708
0xeb1e86ac2b1fb61e2d121ed0fbc4c64fa31546f7897939134726fc81e9b7dfb4Enter Markets124169012021-09-16 12:59:593 days 2 hrs ago0xf5f9e169fafb2d58bc7c869a7ff958eb5ff75058 IN  0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB0.00073684
0xfc4a2f7ddf2de0c631d2f221781b2bf3f03bbde9011396b4463a419e1de4250eEnter Markets124168942021-09-16 12:59:383 days 2 hrs ago0xf5f9e169fafb2d58bc7c869a7ff958eb5ff75058 IN  0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB0.00073708
0x8feba44890f75d1e8022a9f7267cc4c2185b5b03d00cf545e62312499a76801cEnter Markets124168882021-09-16 12:59:203 days 2 hrs ago0xf5f9e169fafb2d58bc7c869a7ff958eb5ff75058 IN  0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB0.00088708
0x1f27725fd16e9676b06a1f77647435fc96a85d2a3597a3fa960a1be51720edffEnter Markets123869422021-09-15 12:01:254 days 3 hrs ago0xef1969fa4a72844d9f7c06e4aa4841aea99f3333 IN  0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB0.00073708
0x02f3c99e4673e7b33cb301b633d2e1cb44e3dfea4c42464a2ea86a28e9ae8d8eEnter Markets123869052021-09-15 11:59:344 days 3 hrs ago0xef1969fa4a72844d9f7c06e4aa4841aea99f3333 IN  0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB0.00088708
0xea4feaecc3af53a60d8331b1ed7740cfcc605e92b58e5b325c9bb49ef82dbb43Exit Market123565832021-09-14 10:25:525 days 4 hrs ago0xfc21dbda49e638fdfe630f82bb6dbe78c0fe75da IN  0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB0.00418265
0x245d396fe5ae790ac958db8eaad46b93bd817a69f62641610771aacd00b85622Enter Markets123511702021-09-14 5:52:265 days 9 hrs ago0x8e71804da1a92221ce059d7d1542ab3955a3fd8a IN  0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB0.00073708
0x6a94b6840f84a02c1e676667b2cbecdc7bc4b1fa3578bb7e8d307e284a6d6ebfEnter Markets123511532021-09-14 5:51:355 days 9 hrs ago0x8e71804da1a92221ce059d7d1542ab3955a3fd8a IN  0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB0.00073696
0xd26c9a31b214554330572537f4153c3c7677281358e6ba9e377a5dd755e329d5Enter Markets123511492021-09-14 5:51:235 days 9 hrs ago0x8e71804da1a92221ce059d7d1542ab3955a3fd8a IN  0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB0.00073708
0x4bd70e15276a5b6ebc1356c9a10ad1b8b3293544b9599ef0a255d052d6d98e71Enter Markets122729762021-09-11 12:01:108 days 3 hrs ago0xad61be2c9b796a8c14712b5ca163d10cf3344dd1 IN  0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB0.00088708
0x0c174c2dbc42e9310add1e2ab66a589e361fdc16792176500b978feb6f682e20Enter Markets120469722021-09-03 14:16:2116 days 1 hr ago0x86b7ac18b9b27e05d9a25e591c197fa085fcb597 IN  0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB0.00073708
0xdd2b03055824e8094aad91cf1ef2d89687e40fb228727cbe5ba5d5ad3247e772Enter Markets120468422021-09-03 14:09:5116 days 1 hr ago0x86b7ac18b9b27e05d9a25e591c197fa085fcb597 IN  0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB0.00088708
0xc36d34920b4c06a05988a27937be42180f5b68c91db5c4d22be3826866891becEnter Markets120330612021-09-03 2:40:4116 days 12 hrs ago0xb0adb635ef42868c6d99877d90d7aa8a8a965755 IN  0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB0.00073684
0xcdead0c255fdc205540d141bc51f4742ff1cca92d42975cf412cc580d54b2766Enter Markets120195062021-09-02 15:22:5416 days 23 hrs ago0xfc21dbda49e638fdfe630f82bb6dbe78c0fe75da IN  0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB0.00073708
0xf0cf2f39289a73e8d1b780ce7b2ca0634abda0c674108c7010174a0275e4c33bEnter Markets120088912021-09-02 6:32:0917 days 8 hrs ago0xf5fab316d1a1c39f2745930aacb16b423b6e46ab IN  0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB0.00073708
0xa43c7df245b159006510246553a26699809661d92006033b912bbedeb4ca5b8fEnter Markets120088852021-09-02 6:31:5117 days 8 hrs ago0xf5fab316d1a1c39f2745930aacb16b423b6e46ab IN  0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB0.00073696
0x2d5722baaeaff0d0b0a12b45c4c510733263ab854c9e239b3c8b0325eaca2008Enter Markets120088742021-09-02 6:31:1817 days 8 hrs ago0xf5fab316d1a1c39f2745930aacb16b423b6e46ab IN  0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB0.00073684
0xb7bccd072cfc9615659ba999f0474a457a2f643c95a03e026cb954bab0ef1586Enter Markets120088662021-09-02 6:30:5417 days 8 hrs ago0xf5fab316d1a1c39f2745930aacb16b423b6e46ab IN  0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB0.00073708
0xa7cd55a448d2a8165c1868f28a25f1fde96a31d18e7cff31d2b4c2d6254dab3fEnter Markets119929002021-09-01 17:12:3617 days 22 hrs ago0x11ce7f91084e8435d34da2e24b8d3b23a3cabd4b IN  0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB0.00073708
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0x3b5140402694329b8b481c8a1ff271a2d358a4b75346d0b8c3f4bd4318060faa124941582021-09-19 6:41:468 hrs 35 mins ago 0x007f699b00fefb9d3572397f9afdbfda4447bc3b 0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB
0x3b5140402694329b8b481c8a1ff271a2d358a4b75346d0b8c3f4bd4318060faa124941582021-09-19 6:41:468 hrs 35 mins ago 0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a8 0x007f699b00fefb9d3572397f9afdbfda4447bc3b0 BNB
0x3b5140402694329b8b481c8a1ff271a2d358a4b75346d0b8c3f4bd4318060faa124941582021-09-19 6:41:468 hrs 35 mins ago 0x007f699b00fefb9d3572397f9afdbfda4447bc3b 0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB
0xb0c5a91794865b4710c58e6a456e8097a0de70c61256d2b494892f34e5cd23cc124941512021-09-19 6:41:258 hrs 35 mins ago 0x0ba072fbdd03305117d893eaac5a0c852c200001 0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB
0xb0c5a91794865b4710c58e6a456e8097a0de70c61256d2b494892f34e5cd23cc124941512021-09-19 6:41:258 hrs 35 mins ago 0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a8 0x0ba072fbdd03305117d893eaac5a0c852c2000010 BNB
0xb0c5a91794865b4710c58e6a456e8097a0de70c61256d2b494892f34e5cd23cc124941512021-09-19 6:41:258 hrs 35 mins ago 0x0ba072fbdd03305117d893eaac5a0c852c200001 0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB
0xcd4dcc4ac14bbafd2ca16d490d83d3e611c1fdc4b59771fa9be6e0b72f2127f4124941442021-09-19 6:41:048 hrs 35 mins ago 0x8ac5b7564f688971f8b690fe6ee0a0d54a245589 0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB
0xcd4dcc4ac14bbafd2ca16d490d83d3e611c1fdc4b59771fa9be6e0b72f2127f4124941442021-09-19 6:41:048 hrs 35 mins ago 0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a8 0x8ac5b7564f688971f8b690fe6ee0a0d54a2455890 BNB
0xcd4dcc4ac14bbafd2ca16d490d83d3e611c1fdc4b59771fa9be6e0b72f2127f4124941442021-09-19 6:41:048 hrs 35 mins ago 0x8ac5b7564f688971f8b690fe6ee0a0d54a245589 0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB
0x5c5cdebf7dae7c1c0410a91367272a4ebe483d7e2f9f730fcc0b55f162502d17124941382021-09-19 6:40:468 hrs 36 mins ago 0xcb8f3788ba780e0e7c3abecc2b015fae72c3fa8d 0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB
0x5c5cdebf7dae7c1c0410a91367272a4ebe483d7e2f9f730fcc0b55f162502d17124941382021-09-19 6:40:468 hrs 36 mins ago 0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a8 0xcb8f3788ba780e0e7c3abecc2b015fae72c3fa8d0 BNB
0x5c5cdebf7dae7c1c0410a91367272a4ebe483d7e2f9f730fcc0b55f162502d17124941382021-09-19 6:40:468 hrs 36 mins ago 0xcb8f3788ba780e0e7c3abecc2b015fae72c3fa8d 0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB
0xd30910640872fad3ef785cbd033c672f5c194ab3e1b368dea988d65d190a76a5124941282021-09-19 6:40:168 hrs 36 mins ago 0x5a55fe4f7187fb2a4cc30a70dc2e1a387a36e95b 0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB
0xd30910640872fad3ef785cbd033c672f5c194ab3e1b368dea988d65d190a76a5124941282021-09-19 6:40:168 hrs 36 mins ago 0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a8 0x5a55fe4f7187fb2a4cc30a70dc2e1a387a36e95b0 BNB
0xd30910640872fad3ef785cbd033c672f5c194ab3e1b368dea988d65d190a76a5124941282021-09-19 6:40:168 hrs 36 mins ago 0x5a55fe4f7187fb2a4cc30a70dc2e1a387a36e95b 0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB
0x1bab9955f3c42b8c19cd2849ae8625ef7581b0f2064f36ac5d68e5b2720778cd124676972021-09-18 7:52:081 day 7 hrs ago 0x007f699b00fefb9d3572397f9afdbfda4447bc3b 0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB
0x1bab9955f3c42b8c19cd2849ae8625ef7581b0f2064f36ac5d68e5b2720778cd124676972021-09-18 7:52:081 day 7 hrs ago 0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a8 0x007f699b00fefb9d3572397f9afdbfda4447bc3b0 BNB
0x1bab9955f3c42b8c19cd2849ae8625ef7581b0f2064f36ac5d68e5b2720778cd124676972021-09-18 7:52:081 day 7 hrs ago 0x007f699b00fefb9d3572397f9afdbfda4447bc3b 0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB
0xf3e0c3b959feba42cd6b2999dacba42743ee262e2c1eebcd97b853d42574e80c124676722021-09-18 7:50:531 day 7 hrs ago 0xcb8f3788ba780e0e7c3abecc2b015fae72c3fa8d 0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB
0xf3e0c3b959feba42cd6b2999dacba42743ee262e2c1eebcd97b853d42574e80c124676722021-09-18 7:50:531 day 7 hrs ago 0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a8 0xcb8f3788ba780e0e7c3abecc2b015fae72c3fa8d0 BNB
0xf3e0c3b959feba42cd6b2999dacba42743ee262e2c1eebcd97b853d42574e80c124676722021-09-18 7:50:531 day 7 hrs ago 0xcb8f3788ba780e0e7c3abecc2b015fae72c3fa8d 0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB
0x34646decda90e94ccb85e340bca2794ad334ca6ffad0833b635ee829121cc70b124676542021-09-18 7:49:591 day 7 hrs ago 0x5a55fe4f7187fb2a4cc30a70dc2e1a387a36e95b 0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB
0x34646decda90e94ccb85e340bca2794ad334ca6ffad0833b635ee829121cc70b124676542021-09-18 7:49:591 day 7 hrs ago 0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a8 0x5a55fe4f7187fb2a4cc30a70dc2e1a387a36e95b0 BNB
0x34646decda90e94ccb85e340bca2794ad334ca6ffad0833b635ee829121cc70b124676542021-09-18 7:49:591 day 7 hrs ago 0x5a55fe4f7187fb2a4cc30a70dc2e1a387a36e95b 0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB
0x635123af389901060f4da12a35b71faa9c5d3525ce254acca24a728ad7a0b8ad124676252021-09-18 7:48:321 day 7 hrs ago 0xf5c46d2193961bd041b54d7adf5c5ac67268e374 0x3b07f80703b9abd9f7d82ab082a4a29d64a3b5a80 BNB
[ Download CSV Export 
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Comptroller

Compiler Version
v0.5.16+commit.9c3226ce

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, None license

Contract Source Code (Solidity)

/**
 *Submitted for verification at BscScan.com on 2021-06-08
*/

// File: contracts/ComptrollerInterface.sol

pragma solidity ^0.5.16;

contract ComptrollerInterfaceG1 {
    /// @notice Indicator that this is a Comptroller contract (for inspection)
    bool public constant isComptroller = true;

    /*** Assets You Are In ***/

    function enterMarkets(address[] calldata bTokens) external returns (uint[] memory);
    function exitMarket(address bToken) external returns (uint);

    /*** Policy Hooks ***/

    function mintAllowed(address bToken, address minter, uint mintAmount) external returns (uint);
    function mintVerify(address bToken, address minter, uint mintAmount, uint mintTokens) external;

    function redeemAllowed(address bToken, address redeemer, uint redeemTokens) external returns (uint);
    function redeemVerify(address bToken, address redeemer, uint redeemAmount, uint redeemTokens) external;

    function borrowAllowed(address bToken, address borrower, uint borrowAmount) external returns (uint);
    function borrowVerify(address bToken, address borrower, uint borrowAmount) external;

    function repayBorrowAllowed(
        address bToken,
        address payer,
        address borrower,
        uint repayAmount) external returns (uint);
    function repayBorrowVerify(
        address bToken,
        address payer,
        address borrower,
        uint repayAmount,
        uint borrowerIndex) external;

    function liquidateBorrowAllowed(
        address bTokenBorrowed,
        address bTokenCollateral,
        address liquidator,
        address borrower,
        uint repayAmount) external returns (uint);
    function liquidateBorrowVerify(
        address bTokenBorrowed,
        address bTokenCollateral,
        address liquidator,
        address borrower,
        uint repayAmount,
        uint seizeTokens) external;

    function seizeAllowed(
        address bTokenCollateral,
        address bTokenBorrowed,
        address liquidator,
        address borrower,
        uint seizeTokens) external returns (uint);
    function seizeVerify(
        address bTokenCollateral,
        address bTokenBorrowed,
        address liquidator,
        address borrower,
        uint seizeTokens) external;

    function transferAllowed(address bToken, address src, address dst, uint transferTokens) external returns (uint);
    function transferVerify(address bToken, address src, address dst, uint transferTokens) external;

    /*** Liquidity/Liquidation Calculations ***/

    function liquidateCalculateSeizeTokens(
        address bTokenBorrowed,
        address bTokenCollateral,
        uint repayAmount) external view returns (uint, uint);
    function setMintedBAIOf(address owner, uint amount) external returns (uint);
}

contract ComptrollerInterfaceG2 is ComptrollerInterfaceG1 {
    function liquidateBAICalculateSeizeTokens(
        address bTokenCollateral,
        uint repayAmount) external view returns (uint, uint);
}

contract ComptrollerInterface is ComptrollerInterfaceG2 {
}

interface IBAIVault {
    function updatePendingRewards() external;
}

interface IComptroller {
    /*** Treasury Data ***/
    function treasuryAddress() external view returns (address);
    function treasuryPercent() external view returns (uint);
}

// File: contracts/InterestRateModel.sol

pragma solidity ^0.5.16;

/**
  * @title Bidao's InterestRateModel Interface
  * @author Bidao
  */
contract InterestRateModel {
    /// @notice Indicator that this is an InterestRateModel contract (for inspection)
    bool public constant isInterestRateModel = true;

    /**
      * @notice Calculates the current borrow interest rate per block
      * @param cash The total amount of cash the market has
      * @param borrows The total amount of borrows the market has outstanding
      * @param reserves The total amnount of reserves the market has
      * @return The borrow rate per block (as a percentage, and scaled by 1e18)
      */
    function getBorrowRate(uint cash, uint borrows, uint reserves) external view returns (uint);

    /**
      * @notice Calculates the current supply interest rate per block
      * @param cash The total amount of cash the market has
      * @param borrows The total amount of borrows the market has outstanding
      * @param reserves The total amnount of reserves the market has
      * @param reserveFactorMantissa The current reserve factor the market has
      * @return The supply rate per block (as a percentage, and scaled by 1e18)
      */
    function getSupplyRate(uint cash, uint borrows, uint reserves, uint reserveFactorMantissa) external view returns (uint);

}

// File: contracts/BTokenInterfaces.sol

pragma solidity ^0.5.16;



contract BTokenStorage {
    /**
     * @dev Guard variable for re-entrancy checks
     */
    bool internal _notEntered;

    /**
     * @notice EIP-20 token name for this token
     */
    string public name;

    /**
     * @notice EIP-20 token symbol for this token
     */
    string public symbol;

    /**
     * @notice EIP-20 token decimals for this token
     */
    uint8 public decimals;

    /**
     * @notice Maximum borrow rate that can ever be applied (.0005% / block)
     */

    uint internal constant borrowRateMaxMantissa = 0.0005e16;

    /**
     * @notice Maximum fraction of interest that can be set aside for reserves
     */
    uint internal constant reserveFactorMaxMantissa = 1e18;

    /**
     * @notice Administrator for this contract
     */
    address payable public admin;

    /**
     * @notice Pending administrator for this contract
     */
    address payable public pendingAdmin;

    /**
     * @notice Contract which oversees inter-bToken operations
     */
    ComptrollerInterface public comptroller;

    /**
     * @notice Model which tells what the current interest rate should be
     */
    InterestRateModel public interestRateModel;

    /**
     * @notice Initial exchange rate used when minting the first BTokens (used when totalSupply = 0)
     */
    uint internal initialExchangeRateMantissa;

    /**
     * @notice Fraction of interest currently set aside for reserves
     */
    uint public reserveFactorMantissa;

    /**
     * @notice Block number that interest was last accrued at
     */
    uint public accrualBlockNumber;

    /**
     * @notice Accumulator of the total earned interest rate since the opening of the market
     */
    uint public borrowIndex;

    /**
     * @notice Total amount of outstanding borrows of the underlying in this market
     */
    uint public totalBorrows;

    /**
     * @notice Total amount of reserves of the underlying held in this market
     */
    uint public totalReserves;

    /**
     * @notice Total number of tokens in circulation
     */
    uint public totalSupply;

    /**
     * @notice Official record of token balances for each account
     */
    mapping (address => uint) internal accountTokens;

    /**
     * @notice Approved token transfer amounts on behalf of others
     */
    mapping (address => mapping (address => uint)) internal transferAllowances;

    /**
     * @notice Container for borrow balance information
     * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action
     * @member interestIndex Global borrowIndex as of the most recent balance-changing action
     */
    struct BorrowSnapshot {
        uint principal;
        uint interestIndex;
    }

    /**
     * @notice Mapping of account addresses to outstanding borrow balances
     */
    mapping(address => BorrowSnapshot) internal accountBorrows;
}

contract BTokenInterface is BTokenStorage {
    /**
     * @notice Indicator that this is a BToken contract (for inspection)
     */
    bool public constant isBToken = true;


    /*** Market Events ***/

    /**
     * @notice Event emitted when interest is accrued
     */
    event AccrueInterest(uint cashPrior, uint interestAccumulated, uint borrowIndex, uint totalBorrows);

    /**
     * @notice Event emitted when tokens are minted
     */
    event Mint(address minter, uint mintAmount, uint mintTokens);

    /**
     * @notice Event emitted when tokens are redeemed
     */
    event Redeem(address redeemer, uint redeemAmount, uint redeemTokens);

    /**
     * @notice Event emitted when tokens are redeemed and fee are transferred
     */
    event RedeemFee(address redeemer, uint feeAmount, uint redeemTokens);

    /**
     * @notice Event emitted when underlying is borrowed
     */
    event Borrow(address borrower, uint borrowAmount, uint accountBorrows, uint totalBorrows);

    /**
     * @notice Event emitted when a borrow is repaid
     */
    event RepayBorrow(address payer, address borrower, uint repayAmount, uint accountBorrows, uint totalBorrows);

    /**
     * @notice Event emitted when a borrow is liquidated
     */
    event LiquidateBorrow(address liquidator, address borrower, uint repayAmount, address bTokenCollateral, uint seizeTokens);


    /*** Admin Events ***/

    /**
     * @notice Event emitted when pendingAdmin is changed
     */
    event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin);

    /**
     * @notice Event emitted when pendingAdmin is accepted, which means admin is updated
     */
    event NewAdmin(address oldAdmin, address newAdmin);

    /**
     * @notice Event emitted when comptroller is changed
     */
    event NewComptroller(ComptrollerInterface oldComptroller, ComptrollerInterface newComptroller);

    /**
     * @notice Event emitted when interestRateModel is changed
     */
    event NewMarketInterestRateModel(InterestRateModel oldInterestRateModel, InterestRateModel newInterestRateModel);

    /**
     * @notice Event emitted when the reserve factor is changed
     */
    event NewReserveFactor(uint oldReserveFactorMantissa, uint newReserveFactorMantissa);

    /**
     * @notice Event emitted when the reserves are added
     */
    event ReservesAdded(address benefactor, uint addAmount, uint newTotalReserves);

    /**
     * @notice Event emitted when the reserves are reduced
     */
    event ReservesReduced(address admin, uint reduceAmount, uint newTotalReserves);

    /**
     * @notice EIP20 Transfer event
     */
    event Transfer(address indexed from, address indexed to, uint amount);

    /**
     * @notice EIP20 Approval event
     */
    event Approval(address indexed owner, address indexed spender, uint amount);

    /**
     * @notice Failure event
     */
    event Failure(uint error, uint info, uint detail);


    /*** User Interface ***/

    function transfer(address dst, uint amount) external returns (bool);
    function transferFrom(address src, address dst, uint amount) external returns (bool);
    function approve(address spender, uint amount) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint);
    function balanceOf(address owner) external view returns (uint);
    function balanceOfUnderlying(address owner) external returns (uint);
    function getAccountSnapshot(address account) external view returns (uint, uint, uint, uint);
    function borrowRatePerBlock() external view returns (uint);
    function supplyRatePerBlock() external view returns (uint);
    function totalBorrowsCurrent() external returns (uint);
    function borrowBalanceCurrent(address account) external returns (uint);
    function borrowBalanceStored(address account) public view returns (uint);
    function exchangeRateCurrent() public returns (uint);
    function exchangeRateStored() public view returns (uint);
    function getCash() external view returns (uint);
    function accrueInterest() public returns (uint);
    function seize(address liquidator, address borrower, uint seizeTokens) external returns (uint);


    /*** Admin Functions ***/

    function _setPendingAdmin(address payable newPendingAdmin) external returns (uint);
    function _acceptAdmin() external returns (uint);
    function _setComptroller(ComptrollerInterface newComptroller) public returns (uint);
    function _setReserveFactor(uint newReserveFactorMantissa) external returns (uint);
    function _reduceReserves(uint reduceAmount) external returns (uint);
    function _setInterestRateModel(InterestRateModel newInterestRateModel) public returns (uint);
}

contract BBep20Storage {
    /**
     * @notice Underlying asset for this BToken
     */
    address public underlying;
}

contract BBep20Interface is BBep20Storage {

    /*** User Interface ***/

    function mint(uint mintAmount) external returns (uint);
    function redeem(uint redeemTokens) external returns (uint);
    function redeemUnderlying(uint redeemAmount) external returns (uint);
    function borrow(uint borrowAmount) external returns (uint);
    function repayBorrow(uint repayAmount) external returns (uint);
    function repayBorrowBehalf(address borrower, uint repayAmount) external returns (uint);
    function liquidateBorrow(address borrower, uint repayAmount, BTokenInterface bTokenCollateral) external returns (uint);


    /*** Admin Functions ***/

    function _addReserves(uint addAmount) external returns (uint);
}

contract VDelegationStorage {
    /**
     * @notice Implementation address for this contract
     */
    address public implementation;
}

contract VDelegatorInterface is VDelegationStorage {
    /**
     * @notice Emitted when implementation is changed
     */
    event NewImplementation(address oldImplementation, address newImplementation);

    /**
     * @notice Called by the admin to update the implementation of the delegator
     * @param implementation_ The address of the new implementation for delegation
     * @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation
     * @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation
     */
    function _setImplementation(address implementation_, bool allowResign, bytes memory becomeImplementationData) public;
}

contract VDelegateInterface is VDelegationStorage {
    /**
     * @notice Called by the delegator on a delegate to initialize it for duty
     * @dev Should revert if any issues arise which make it unfit for delegation
     * @param data The encoded bytes data for any initialization
     */
    function _becomeImplementation(bytes memory data) public;

    /**
     * @notice Called by the delegator on a delegate to forfeit its responsibility
     */
    function _resignImplementation() public;
}

// File: contracts/ErrorReporter.sol

pragma solidity ^0.5.16;

contract ComptrollerErrorReporter {
    enum Error {
        NO_ERROR,
        UNAUTHORIZED,
        COMPTROLLER_MISMATCH,
        INSUFFICIENT_SHORTFALL,
        INSUFFICIENT_LIQUIDITY,
        INVALID_CLOSE_FACTOR,
        INVALID_COLLATERAL_FACTOR,
        INVALID_LIQUIDATION_INCENTIVE,
        MARKET_NOT_ENTERED, // no longer possible
        MARKET_NOT_LISTED,
        MARKET_ALREADY_LISTED,
        MATH_ERROR,
        NONZERO_BORROW_BALANCE,
        PRICE_ERROR,
        REJECTION,
        SNAPSHOT_ERROR,
        TOO_MANY_ASSETS,
        TOO_MUCH_REPAY,
        INSUFFICIENT_BALANCE_FOR_BAI
    }

    enum FailureInfo {
        ACCEPT_ADMIN_PENDING_ADMIN_CHECK,
        ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK,
        EXIT_MARKET_BALANCE_OWED,
        EXIT_MARKET_REJECTION,
        SET_CLOSE_FACTOR_OWNER_CHECK,
        SET_CLOSE_FACTOR_VALIDATION,
        SET_COLLATERAL_FACTOR_OWNER_CHECK,
        SET_COLLATERAL_FACTOR_NO_EXISTS,
        SET_COLLATERAL_FACTOR_VALIDATION,
        SET_COLLATERAL_FACTOR_WITHOUT_PRICE,
        SET_IMPLEMENTATION_OWNER_CHECK,
        SET_LIQUIDATION_INCENTIVE_OWNER_CHECK,
        SET_LIQUIDATION_INCENTIVE_VALIDATION,
        SET_MAX_ASSETS_OWNER_CHECK,
        SET_PENDING_ADMIN_OWNER_CHECK,
        SET_PENDING_IMPLEMENTATION_OWNER_CHECK,
        SET_PRICE_ORACLE_OWNER_CHECK,
        SUPPORT_MARKET_EXISTS,
        SUPPORT_MARKET_OWNER_CHECK,
        SET_PAUSE_GUARDIAN_OWNER_CHECK,
        SET_BAI_MINT_RATE_CHECK,
        SET_BAICONTROLLER_OWNER_CHECK,
        SET_MINTED_BAI_REJECTION,
        SET_TREASURY_OWNER_CHECK
    }

    /**
      * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary
      * contract-specific code that enables us to report opaque error codes from upgradeable contracts.
      **/
    event Failure(uint error, uint info, uint detail);

    /**
      * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator
      */
    function fail(Error err, FailureInfo info) internal returns (uint) {
        emit Failure(uint(err), uint(info), 0);

        return uint(err);
    }

    /**
      * @dev use this when reporting an opaque error from an upgradeable collaborator contract
      */
    function failOpaque(Error err, FailureInfo info, uint opaqueError) internal returns (uint) {
        emit Failure(uint(err), uint(info), opaqueError);

        return uint(err);
    }
}

contract TokenErrorReporter {
    enum Error {
        NO_ERROR,
        UNAUTHORIZED,
        BAD_INPUT,
        COMPTROLLER_REJECTION,
        COMPTROLLER_CALCULATION_ERROR,
        INTEREST_RATE_MODEL_ERROR,
        INVALID_ACCOUNT_PAIR,
        INVALID_CLOSE_AMOUNT_REQUESTED,
        INVALID_COLLATERAL_FACTOR,
        MATH_ERROR,
        MARKET_NOT_FRESH,
        MARKET_NOT_LISTED,
        TOKEN_INSUFFICIENT_ALLOWANCE,
        TOKEN_INSUFFICIENT_BALANCE,
        TOKEN_INSUFFICIENT_CASH,
        TOKEN_TRANSFER_IN_FAILED,
        TOKEN_TRANSFER_OUT_FAILED,
        TOKEN_PRICE_ERROR
    }

    /*
     * Note: FailureInfo (but not Error) is kept in alphabetical order
     *       This is because FailureInfo grows significantly faster, and
     *       the order of Error has some meaning, while the order of FailureInfo
     *       is entirely arbitrary.
     */
    enum FailureInfo {
        ACCEPT_ADMIN_PENDING_ADMIN_CHECK,
        ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED,
        ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED,
        ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED,
        ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED,
        ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED,
        ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED,
        BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED,
        BORROW_ACCRUE_INTEREST_FAILED,
        BORROW_CASH_NOT_ABAILABLE,
        BORROW_FRESHNESS_CHECK,
        BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED,
        BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED,
        BORROW_MARKET_NOT_LISTED,
        BORROW_COMPTROLLER_REJECTION,
        LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED,
        LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED,
        LIQUIDATE_COLLATERAL_FRESHNESS_CHECK,
        LIQUIDATE_COMPTROLLER_REJECTION,
        LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED,
        LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX,
        LIQUIDATE_CLOSE_AMOUNT_IS_ZERO,
        LIQUIDATE_FRESHNESS_CHECK,
        LIQUIDATE_LIQUIDATOR_IS_BORROWER,
        LIQUIDATE_REPAY_BORROW_FRESH_FAILED,
        LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED,
        LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED,
        LIQUIDATE_SEIZE_COMPTROLLER_REJECTION,
        LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER,
        LIQUIDATE_SEIZE_TOO_MUCH,
        MINT_ACCRUE_INTEREST_FAILED,
        MINT_COMPTROLLER_REJECTION,
        MINT_EXCHANGE_CALCULATION_FAILED,
        MINT_EXCHANGE_RATE_READ_FAILED,
        MINT_FRESHNESS_CHECK,
        MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED,
        MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED,
        MINT_TRANSFER_IN_FAILED,
        MINT_TRANSFER_IN_NOT_POSSIBLE,
        REDEEM_ACCRUE_INTEREST_FAILED,
        REDEEM_COMPTROLLER_REJECTION,
        REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED,
        REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED,
        REDEEM_EXCHANGE_RATE_READ_FAILED,
        REDEEM_FRESHNESS_CHECK,
        REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED,
        REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED,
        REDEEM_TRANSFER_OUT_NOT_POSSIBLE,
        REDUCE_RESERVES_ACCRUE_INTEREST_FAILED,
        REDUCE_RESERVES_ADMIN_CHECK,
        REDUCE_RESERVES_CASH_NOT_ABAILABLE,
        REDUCE_RESERVES_FRESH_CHECK,
        REDUCE_RESERVES_VALIDATION,
        REPAY_BEHALF_ACCRUE_INTEREST_FAILED,
        REPAY_BORROW_ACCRUE_INTEREST_FAILED,
        REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED,
        REPAY_BORROW_COMPTROLLER_REJECTION,
        REPAY_BORROW_FRESHNESS_CHECK,
        REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED,
        REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED,
        REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE,
        SET_COLLATERAL_FACTOR_OWNER_CHECK,
        SET_COLLATERAL_FACTOR_VALIDATION,
        SET_COMPTROLLER_OWNER_CHECK,
        SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED,
        SET_INTEREST_RATE_MODEL_FRESH_CHECK,
        SET_INTEREST_RATE_MODEL_OWNER_CHECK,
        SET_MAX_ASSETS_OWNER_CHECK,
        SET_ORACLE_MARKET_NOT_LISTED,
        SET_PENDING_ADMIN_OWNER_CHECK,
        SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED,
        SET_RESERVE_FACTOR_ADMIN_CHECK,
        SET_RESERVE_FACTOR_FRESH_CHECK,
        SET_RESERVE_FACTOR_BOUNDS_CHECK,
        TRANSFER_COMPTROLLER_REJECTION,
        TRANSFER_NOT_ALLOWED,
        TRANSFER_NOT_ENOUGH,
        TRANSFER_TOO_MUCH,
        ADD_RESERVES_ACCRUE_INTEREST_FAILED,
        ADD_RESERVES_FRESH_CHECK,
        ADD_RESERVES_TRANSFER_IN_NOT_POSSIBLE,
        TOKEN_GET_UNDERLYING_PRICE_ERROR,
        REPAY_BAI_COMPTROLLER_REJECTION,
        REPAY_BAI_FRESHNESS_CHECK,
        BAI_MINT_EXCHANGE_CALCULATION_FAILED,
        SFT_MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED,
        REDEEM_FEE_CALCULATION_FAILED
    }

    /**
      * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary
      * contract-specific code that enables us to report opaque error codes from upgradeable contracts.
      **/
    event Failure(uint error, uint info, uint detail);

    /**
      * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator
      */
    function fail(Error err, FailureInfo info) internal returns (uint) {
        emit Failure(uint(err), uint(info), 0);

        return uint(err);
    }

    /**
      * @dev use this when reporting an opaque error from an upgradeable collaborator contract
      */
    function failOpaque(Error err, FailureInfo info, uint opaqueError) internal returns (uint) {
        emit Failure(uint(err), uint(info), opaqueError);

        return uint(err);
    }
}

contract BAIControllerErrorReporter {
    enum Error {
        NO_ERROR,
        UNAUTHORIZED,
        REJECTION,
        SNAPSHOT_ERROR,
        PRICE_ERROR,
        MATH_ERROR,
        INSUFFICIENT_BALANCE_FOR_BAI
    }

    enum FailureInfo {
        SET_PENDING_ADMIN_OWNER_CHECK,
        SET_PENDING_IMPLEMENTATION_OWNER_CHECK,
        SET_COMPTROLLER_OWNER_CHECK,
        ACCEPT_ADMIN_PENDING_ADMIN_CHECK,
        ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK,
        BAI_MINT_REJECTION,
        BAI_BURN_REJECTION,
        BAI_LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED,
        BAI_LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED,
        BAI_LIQUIDATE_COLLATERAL_FRESHNESS_CHECK,
        BAI_LIQUIDATE_COMPTROLLER_REJECTION,
        BAI_LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED,
        BAI_LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX,
        BAI_LIQUIDATE_CLOSE_AMOUNT_IS_ZERO,
        BAI_LIQUIDATE_FRESHNESS_CHECK,
        BAI_LIQUIDATE_LIQUIDATOR_IS_BORROWER,
        BAI_LIQUIDATE_REPAY_BORROW_FRESH_FAILED,
        BAI_LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED,
        BAI_LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED,
        BAI_LIQUIDATE_SEIZE_COMPTROLLER_REJECTION,
        BAI_LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER,
        BAI_LIQUIDATE_SEIZE_TOO_MUCH,
        MINT_FEE_CALCULATION_FAILED,
        SET_TREASURY_OWNER_CHECK
    }

    /**
      * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary
      * contract-specific code that enables us to report opaque error codes from upgradeable contracts.
      **/
    event Failure(uint error, uint info, uint detail);

    /**
      * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator
      */
    function fail(Error err, FailureInfo info) internal returns (uint) {
        emit Failure(uint(err), uint(info), 0);

        return uint(err);
    }

    /**
      * @dev use this when reporting an opaque error from an upgradeable collaborator contract
      */
    function failOpaque(Error err, FailureInfo info, uint opaqueError) internal returns (uint) {
        emit Failure(uint(err), uint(info), opaqueError);

        return uint(err);
    }
}

// File: contracts/CarefulMath.sol

pragma solidity ^0.5.16;

/**
  * @title Careful Math
  * @author Bidao
  * @notice Derived from OpenZeppelin's SafeMath library
  *         https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol
  */
contract CarefulMath {

    /**
     * @dev Possible error codes that we can return
     */
    enum MathError {
        NO_ERROR,
        DIVISION_BY_ZERO,
        INTEGER_OVERFLOW,
        INTEGER_UNDERFLOW
    }

    /**
    * @dev Multiplies two numbers, returns an error on overflow.
    */
    function mulUInt(uint a, uint b) internal pure returns (MathError, uint) {
        if (a == 0) {
            return (MathError.NO_ERROR, 0);
        }

        uint c = a * b;

        if (c / a != b) {
            return (MathError.INTEGER_OVERFLOW, 0);
        } else {
            return (MathError.NO_ERROR, c);
        }
    }

    /**
    * @dev Integer division of two numbers, truncating the quotient.
    */
    function divUInt(uint a, uint b) internal pure returns (MathError, uint) {
        if (b == 0) {
            return (MathError.DIVISION_BY_ZERO, 0);
        }

        return (MathError.NO_ERROR, a / b);
    }

    /**
    * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend).
    */
    function subUInt(uint a, uint b) internal pure returns (MathError, uint) {
        if (b <= a) {
            return (MathError.NO_ERROR, a - b);
        } else {
            return (MathError.INTEGER_UNDERFLOW, 0);
        }
    }

    /**
    * @dev Adds two numbers, returns an error on overflow.
    */
    function addUInt(uint a, uint b) internal pure returns (MathError, uint) {
        uint c = a + b;

        if (c >= a) {
            return (MathError.NO_ERROR, c);
        } else {
            return (MathError.INTEGER_OVERFLOW, 0);
        }
    }

    /**
    * @dev add a and b and then subtract c
    */
    function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) {
        (MathError err0, uint sum) = addUInt(a, b);

        if (err0 != MathError.NO_ERROR) {
            return (err0, 0);
        }

        return subUInt(sum, c);
    }
}

// File: contracts/ExponentialNoError.sol

pragma solidity ^0.5.16;

/**
 * @title Exponential module for storing fixed-precision decimals
 * @author Compound
 * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places.
 *         Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is:
 *         `Exp({mantissa: 5100000000000000000})`.
 */
contract ExponentialNoError {
    uint constant expScale = 1e18;
    uint constant doubleScale = 1e36;
    uint constant halfExpScale = expScale/2;
    uint constant mantissaOne = expScale;

    struct Exp {
        uint mantissa;
    }

    struct Double {
        uint mantissa;
    }

    /**
     * @dev Truncates the given exp to a whole number value.
     *      For example, truncate(Exp{mantissa: 15 * expScale}) = 15
     */
    function truncate(Exp memory exp) pure internal returns (uint) {
        // Note: We are not using careful math here as we're performing a division that cannot fail
        return exp.mantissa / expScale;
    }

    /**
     * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer.
     */
    function mul_ScalarTruncate(Exp memory a, uint scalar) pure internal returns (uint) {
        Exp memory product = mul_(a, scalar);
        return truncate(product);
    }

    /**
     * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer.
     */
    function mul_ScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (uint) {
        Exp memory product = mul_(a, scalar);
        return add_(truncate(product), addend);
    }

    /**
     * @dev Checks if first Exp is less than second Exp.
     */
    function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) {
        return left.mantissa < right.mantissa;
    }

    /**
     * @dev Checks if left Exp <= right Exp.
     */
    function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) {
        return left.mantissa <= right.mantissa;
    }

    /**
     * @dev Checks if left Exp > right Exp.
     */
    function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) {
        return left.mantissa > right.mantissa;
    }

    /**
     * @dev returns true if Exp is exactly zero
     */
    function isZeroExp(Exp memory value) pure internal returns (bool) {
        return value.mantissa == 0;
    }

    function safe224(uint n, string memory errorMessage) pure internal returns (uint224) {
        require(n < 2**224, errorMessage);
        return uint224(n);
    }

    function safe32(uint n, string memory errorMessage) pure internal returns (uint32) {
        require(n < 2**32, errorMessage);
        return uint32(n);
    }

    function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {
        return Exp({mantissa: add_(a.mantissa, b.mantissa)});
    }

    function add_(Double memory a, Double memory b) pure internal returns (Double memory) {
        return Double({mantissa: add_(a.mantissa, b.mantissa)});
    }

    function add_(uint a, uint b) pure internal returns (uint) {
        return add_(a, b, "addition overflow");
    }

    function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {
        uint c = a + b;
        require(c >= a, errorMessage);
        return c;
    }

    function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {
        return Exp({mantissa: sub_(a.mantissa, b.mantissa)});
    }

    function sub_(Double memory a, Double memory b) pure internal returns (Double memory) {
        return Double({mantissa: sub_(a.mantissa, b.mantissa)});
    }

    function sub_(uint a, uint b) pure internal returns (uint) {
        return sub_(a, b, "subtraction underflow");
    }

    function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {
        require(b <= a, errorMessage);
        return a - b;
    }

    function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {
        return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale});
    }

    function mul_(Exp memory a, uint b) pure internal returns (Exp memory) {
        return Exp({mantissa: mul_(a.mantissa, b)});
    }

    function mul_(uint a, Exp memory b) pure internal returns (uint) {
        return mul_(a, b.mantissa) / expScale;
    }

    function mul_(Double memory a, Double memory b) pure internal returns (Double memory) {
        return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale});
    }

    function mul_(Double memory a, uint b) pure internal returns (Double memory) {
        return Double({mantissa: mul_(a.mantissa, b)});
    }

    function mul_(uint a, Double memory b) pure internal returns (uint) {
        return mul_(a, b.mantissa) / doubleScale;
    }

    function mul_(uint a, uint b) pure internal returns (uint) {
        return mul_(a, b, "multiplication overflow");
    }

    function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {
        if (a == 0 || b == 0) {
            return 0;
        }
        uint c = a * b;
        require(c / a == b, errorMessage);
        return c;
    }

    function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) {
        return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)});
    }

    function div_(Exp memory a, uint b) pure internal returns (Exp memory) {
        return Exp({mantissa: div_(a.mantissa, b)});
    }

    function div_(uint a, Exp memory b) pure internal returns (uint) {
        return div_(mul_(a, expScale), b.mantissa);
    }

    function div_(Double memory a, Double memory b) pure internal returns (Double memory) {
        return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)});
    }

    function div_(Double memory a, uint b) pure internal returns (Double memory) {
        return Double({mantissa: div_(a.mantissa, b)});
    }

    function div_(uint a, Double memory b) pure internal returns (uint) {
        return div_(mul_(a, doubleScale), b.mantissa);
    }

    function div_(uint a, uint b) pure internal returns (uint) {
        return div_(a, b, "divide by zero");
    }

    function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) {
        require(b > 0, errorMessage);
        return a / b;
    }

    function fraction(uint a, uint b) pure internal returns (Double memory) {
        return Double({mantissa: div_(mul_(a, doubleScale), b)});
    }
}

// File: contracts/Exponential.sol

pragma solidity ^0.5.16;



/**
 * @title Exponential module for storing fixed-precision decimals
 * @author Bidao
 * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places.
 *         Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is:
 *         `Exp({mantissa: 5100000000000000000})`.
 */
contract Exponential is CarefulMath, ExponentialNoError {
    /**
     * @dev Creates an exponential from numerator and denominator values.
     *      Note: Returns an error if (`num` * 10e18) > MAX_INT,
     *            or if `denom` is zero.
     */
    function getExp(uint num, uint denom) internal pure returns (MathError, Exp memory) {
        (MathError err0, uint scaledNumerator) = mulUInt(num, expScale);
        if (err0 != MathError.NO_ERROR) {
            return (err0, Exp({mantissa: 0}));
        }

        (MathError err1, uint rational) = divUInt(scaledNumerator, denom);
        if (err1 != MathError.NO_ERROR) {
            return (err1, Exp({mantissa: 0}));
        }

        return (MathError.NO_ERROR, Exp({mantissa: rational}));
    }

    /**
     * @dev Adds two exponentials, returning a new exponential.
     */
    function addExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) {
        (MathError error, uint result) = addUInt(a.mantissa, b.mantissa);

        return (error, Exp({mantissa: result}));
    }

    /**
     * @dev Subtracts two exponentials, returning a new exponential.
     */
    function subExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) {
        (MathError error, uint result) = subUInt(a.mantissa, b.mantissa);

        return (error, Exp({mantissa: result}));
    }

    /**
     * @dev Multiply an Exp by a scalar, returning a new Exp.
     */
    function mulScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) {
        (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar);
        if (err0 != MathError.NO_ERROR) {
            return (err0, Exp({mantissa: 0}));
        }

        return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa}));
    }

    /**
     * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer.
     */
    function mulScalarTruncate(Exp memory a, uint scalar) internal pure returns (MathError, uint) {
        (MathError err, Exp memory product) = mulScalar(a, scalar);
        if (err != MathError.NO_ERROR) {
            return (err, 0);
        }

        return (MathError.NO_ERROR, truncate(product));
    }

    /**
     * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer.
     */
    function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) internal pure returns (MathError, uint) {
        (MathError err, Exp memory product) = mulScalar(a, scalar);
        if (err != MathError.NO_ERROR) {
            return (err, 0);
        }

        return addUInt(truncate(product), addend);
    }

    /**
     * @dev Divide an Exp by a scalar, returning a new Exp.
     */
    function divScalar(Exp memory a, uint scalar) internal pure returns (MathError, Exp memory) {
        (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar);
        if (err0 != MathError.NO_ERROR) {
            return (err0, Exp({mantissa: 0}));
        }

        return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa}));
    }

    /**
     * @dev Divide a scalar by an Exp, returning a new Exp.
     */
    function divScalarByExp(uint scalar, Exp memory divisor) internal pure returns (MathError, Exp memory) {
        /*
          We are doing this as:
          getExp(mulUInt(expScale, scalar), divisor.mantissa)

          How it works:
          Exp = a / b;
          Scalar = s;
          `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale`
        */
        (MathError err0, uint numerator) = mulUInt(expScale, scalar);
        if (err0 != MathError.NO_ERROR) {
            return (err0, Exp({mantissa: 0}));
        }
        return getExp(numerator, divisor.mantissa);
    }

    /**
     * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer.
     */
    function divScalarByExpTruncate(uint scalar, Exp memory divisor) internal pure returns (MathError, uint) {
        (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor);
        if (err != MathError.NO_ERROR) {
            return (err, 0);
        }

        return (MathError.NO_ERROR, truncate(fraction));
    }

    /**
     * @dev Multiplies two exponentials, returning a new exponential.
     */
    function mulExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) {

        (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa);
        if (err0 != MathError.NO_ERROR) {
            return (err0, Exp({mantissa: 0}));
        }

        // We add half the scale before dividing so that we get rounding instead of truncation.
        //  See "Listing 6" and text above it at https://accu.org/index.php/journals/1717
        // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18.
        (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct);
        if (err1 != MathError.NO_ERROR) {
            return (err1, Exp({mantissa: 0}));
        }

        (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale);
        // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero.
        assert(err2 == MathError.NO_ERROR);

        return (MathError.NO_ERROR, Exp({mantissa: product}));
    }

    /**
     * @dev Multiplies two exponentials given their mantissas, returning a new exponential.
     */
    function mulExp(uint a, uint b) internal pure returns (MathError, Exp memory) {
        return mulExp(Exp({mantissa: a}), Exp({mantissa: b}));
    }

    /**
     * @dev Multiplies three exponentials, returning a new exponential.
     */
    function mulExp3(Exp memory a, Exp memory b, Exp memory c) internal pure returns (MathError, Exp memory) {
        (MathError err, Exp memory ab) = mulExp(a, b);
        if (err != MathError.NO_ERROR) {
            return (err, ab);
        }
        return mulExp(ab, c);
    }

    /**
     * @dev Divides two exponentials, returning a new exponential.
     *     (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b,
     *  which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa)
     */
    function divExp(Exp memory a, Exp memory b) internal pure returns (MathError, Exp memory) {
        return getExp(a.mantissa, b.mantissa);
    }
}

// File: contracts/EIP20Interface.sol

pragma solidity ^0.5.16;

/**
 * @title BEP 20 Token Standard Interface
 *  https://eips.ethereum.org/EIPS/eip-20
 */
interface EIP20Interface {
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function decimals() external view returns (uint8);

    /**
      * @notice Get the total number of tokens in circulation
      * @return The supply of tokens
      */
    function totalSupply() external view returns (uint256);

    /**
     * @notice Gets the balance of the specified address
     * @param owner The address from which the balance will be retrieved
     * @return The balance
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
      * @notice Transfer `amount` tokens from `msg.sender` to `dst`
      * @param dst The address of the destination account
      * @param amount The number of tokens to transfer
      * @return Whether or not the transfer succeeded
      */
    function transfer(address dst, uint256 amount) external returns (bool success);

    /**
      * @notice Transfer `amount` tokens from `src` to `dst`
      * @param src The address of the source account
      * @param dst The address of the destination account
      * @param amount The number of tokens to transfer
      * @return Whether or not the transfer succeeded
      */
    function transferFrom(address src, address dst, uint256 amount) external returns (bool success);

    /**
      * @notice Approve `spender` to transfer up to `amount` from `src`
      * @dev This will overwrite the approval amount for `spender`
      * @param spender The address of the account which may transfer tokens
      * @param amount The number of tokens that are approved (-1 means infinite)
      * @return Whether or not the approval succeeded
      */
    function approve(address spender, uint256 amount) external returns (bool success);

    /**
      * @notice Get the current allowance from `owner` for `spender`
      * @param owner The address of the account which owns the tokens to be spent
      * @param spender The address of the account which may transfer tokens
      * @return The number of tokens allowed to be spent (-1 means infinite)
      */
    function allowance(address owner, address spender) external view returns (uint256 remaining);

    event Transfer(address indexed from, address indexed to, uint256 amount);
    event Approval(address indexed owner, address indexed spender, uint256 amount);
}

// File: contracts/EIP20NonStandardInterface.sol

pragma solidity ^0.5.16;

/**
 * @title EIP20NonStandardInterface
 * @dev Version of BEP20 with no return values for `transfer` and `transferFrom`
 *  See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca
 */
interface EIP20NonStandardInterface {

    /**
     * @notice Get the total number of tokens in circulation
     * @return The supply of tokens
     */
    function totalSupply() external view returns (uint256);

    /**
     * @notice Gets the balance of the specified address
     * @param owner The address from which the balance will be retrieved
     * @return The balance
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    ///
    /// !!!!!!!!!!!!!!
    /// !!! NOTICE !!! `transfer` does not return a value, in violation of the BEP-20 specification
    /// !!!!!!!!!!!!!!
    ///

    /**
      * @notice Transfer `amount` tokens from `msg.sender` to `dst`
      * @param dst The address of the destination account
      * @param amount The number of tokens to transfer
      */
    function transfer(address dst, uint256 amount) external;

    ///
    /// !!!!!!!!!!!!!!
    /// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the BEP-20 specification
    /// !!!!!!!!!!!!!!
    ///

    /**
      * @notice Transfer `amount` tokens from `src` to `dst`
      * @param src The address of the source account
      * @param dst The address of the destination account
      * @param amount The number of tokens to transfer
      */
    function transferFrom(address src, address dst, uint256 amount) external;

    /**
      * @notice Approve `spender` to transfer up to `amount` from `src`
      * @dev This will overwrite the approval amount for `spender`
      * @param spender The address of the account which may transfer tokens
      * @param amount The number of tokens that are approved
      * @return Whether or not the approval succeeded
      */
    function approve(address spender, uint256 amount) external returns (bool success);

    /**
      * @notice Get the current allowance from `owner` for `spender`
      * @param owner The address of the account which owns the tokens to be spent
      * @param spender The address of the account which may transfer tokens
      * @return The number of tokens allowed to be spent
      */
    function allowance(address owner, address spender) external view returns (uint256 remaining);

    event Transfer(address indexed from, address indexed to, uint256 amount);
    event Approval(address indexed owner, address indexed spender, uint256 amount);
}

// File: contracts/BToken.sol

pragma solidity ^0.5.16;








/**
 * @title Bidao's BToken Contract
 * @notice Abstract base for BTokens
 * @author Bidao
 */
contract BToken is BTokenInterface, Exponential, TokenErrorReporter {
    /**
     * @notice Initialize the money market
     * @param comptroller_ The address of the Comptroller
     * @param interestRateModel_ The address of the interest rate model
     * @param initialExchangeRateMantissa_ The initial exchange rate, scaled by 1e18
     * @param name_ EIP-20 name of this token
     * @param symbol_ EIP-20 symbol of this token
     * @param decimals_ EIP-20 decimal precision of this token
     */
    function initialize(ComptrollerInterface comptroller_,
                        InterestRateModel interestRateModel_,
                        uint initialExchangeRateMantissa_,
                        string memory name_,
                        string memory symbol_,
                        uint8 decimals_) public {
        require(msg.sender == admin, "only admin may initialize the market");
        require(accrualBlockNumber == 0 && borrowIndex == 0, "market may only be initialized once");

        // Set initial exchange rate
        initialExchangeRateMantissa = initialExchangeRateMantissa_;
        require(initialExchangeRateMantissa > 0, "initial exchange rate must be greater than zero.");

        // Set the comptroller
        uint err = _setComptroller(comptroller_);
        require(err == uint(Error.NO_ERROR), "setting comptroller failed");

        // Initialize block number and borrow index (block number mocks depend on comptroller being set)
        accrualBlockNumber = getBlockNumber();
        borrowIndex = mantissaOne;

        // Set the interest rate model (depends on block number / borrow index)
        err = _setInterestRateModelFresh(interestRateModel_);
        require(err == uint(Error.NO_ERROR), "setting interest rate model failed");

        name = name_;
        symbol = symbol_;
        decimals = decimals_;

        // The counter starts true to prevent changing it from zero to non-zero (i.e. smaller cost/refund)
        _notEntered = true;
    }

    /**
     * @notice Transfer `tokens` tokens from `src` to `dst` by `spender`
     * @dev Called by both `transfer` and `transferFrom` internally
     * @param spender The address of the account performing the transfer
     * @param src The address of the source account
     * @param dst The address of the destination account
     * @param tokens The number of tokens to transfer
     * @return Whether or not the transfer succeeded
     */
    function transferTokens(address spender, address src, address dst, uint tokens) internal returns (uint) {
        /* Fail if transfer not allowed */
        uint allowed = comptroller.transferAllowed(address(this), src, dst, tokens);
        if (allowed != 0) {
            return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.TRANSFER_COMPTROLLER_REJECTION, allowed);
        }

        /* Do not allow self-transfers */
        if (src == dst) {
            return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED);
        }

        /* Get the allowance, infinite for the account owner */
        uint startingAllowance = 0;
        if (spender == src) {
            startingAllowance = uint(-1);
        } else {
            startingAllowance = transferAllowances[src][spender];
        }

        /* Do the calculations, checking for {under,over}flow */
        MathError mathErr;
        uint allowanceNew;
        uint srbTokensNew;
        uint dstTokensNew;

        (mathErr, allowanceNew) = subUInt(startingAllowance, tokens);
        if (mathErr != MathError.NO_ERROR) {
            return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ALLOWED);
        }

        (mathErr, srbTokensNew) = subUInt(accountTokens[src], tokens);
        if (mathErr != MathError.NO_ERROR) {
            return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ENOUGH);
        }

        (mathErr, dstTokensNew) = addUInt(accountTokens[dst], tokens);
        if (mathErr != MathError.NO_ERROR) {
            return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH);
        }

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)

        accountTokens[src] = srbTokensNew;
        accountTokens[dst] = dstTokensNew;

        /* Eat some of the allowance (if necessary) */
        if (startingAllowance != uint(-1)) {
            transferAllowances[src][spender] = allowanceNew;
        }

        /* We emit a Transfer event */
        emit Transfer(src, dst, tokens);

        comptroller.transferVerify(address(this), src, dst, tokens);

        return uint(Error.NO_ERROR);
    }

    /**
     * @notice Transfer `amount` tokens from `msg.sender` to `dst`
     * @param dst The address of the destination account
     * @param amount The number of tokens to transfer
     * @return Whether or not the transfer succeeded
     */
    function transfer(address dst, uint256 amount) external nonReentrant returns (bool) {
        return transferTokens(msg.sender, msg.sender, dst, amount) == uint(Error.NO_ERROR);
    }

    /**
     * @notice Transfer `amount` tokens from `src` to `dst`
     * @param src The address of the source account
     * @param dst The address of the destination account
     * @param amount The number of tokens to transfer
     * @return Whether or not the transfer succeeded
     */
    function transferFrom(address src, address dst, uint256 amount) external nonReentrant returns (bool) {
        return transferTokens(msg.sender, src, dst, amount) == uint(Error.NO_ERROR);
    }

    /**
     * @notice Approve `spender` to transfer up to `amount` from `src`
     * @dev This will overwrite the approval amount for `spender`
     *  and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)
     * @param spender The address of the account which may transfer tokens
     * @param amount The number of tokens that are approved (-1 means infinite)
     * @return Whether or not the approval succeeded
     */
    function approve(address spender, uint256 amount) external returns (bool) {
        address src = msg.sender;
        transferAllowances[src][spender] = amount;
        emit Approval(src, spender, amount);
        return true;
    }

    /**
     * @notice Get the current allowance from `owner` for `spender`
     * @param owner The address of the account which owns the tokens to be spent
     * @param spender The address of the account which may transfer tokens
     * @return The number of tokens allowed to be spent (-1 means infinite)
     */
    function allowance(address owner, address spender) external view returns (uint256) {
        return transferAllowances[owner][spender];
    }

    /**
     * @notice Get the token balance of the `owner`
     * @param owner The address of the account to query
     * @return The number of tokens owned by `owner`
     */
    function balanceOf(address owner) external view returns (uint256) {
        return accountTokens[owner];
    }

    /**
     * @notice Get the underlying balance of the `owner`
     * @dev This also accrues interest in a transaction
     * @param owner The address of the account to query
     * @return The amount of underlying owned by `owner`
     */
    function balanceOfUnderlying(address owner) external returns (uint) {
        Exp memory exchangeRate = Exp({mantissa: exchangeRateCurrent()});
        (MathError mErr, uint balance) = mulScalarTruncate(exchangeRate, accountTokens[owner]);
        require(mErr == MathError.NO_ERROR, "balance could not be calculated");
        return balance;
    }

    /**
     * @notice Get a snapshot of the account's balances, and the cached exchange rate
     * @dev This is used by comptroller to more efficiently perform liquidity checks.
     * @param account Address of the account to snapshot
     * @return (possible error, token balance, borrow balance, exchange rate mantissa)
     */
    function getAccountSnapshot(address account) external view returns (uint, uint, uint, uint) {
        uint bTokenBalance = accountTokens[account];
        uint borrowBalance;
        uint exchangeRateMantissa;

        MathError mErr;

        (mErr, borrowBalance) = borrowBalanceStoredInternal(account);
        if (mErr != MathError.NO_ERROR) {
            return (uint(Error.MATH_ERROR), 0, 0, 0);
        }

        (mErr, exchangeRateMantissa) = exchangeRateStoredInternal();
        if (mErr != MathError.NO_ERROR) {
            return (uint(Error.MATH_ERROR), 0, 0, 0);
        }

        return (uint(Error.NO_ERROR), bTokenBalance, borrowBalance, exchangeRateMantissa);
    }

    /**
     * @dev Function to simply retrieve block number
     *  This exists mainly for inheriting test contracts to stub this result.
     */
    function getBlockNumber() internal view returns (uint) {
        return block.number;
    }

    /**
     * @notice Returns the current per-block borrow interest rate for this bToken
     * @return The borrow interest rate per block, scaled by 1e18
     */
    function borrowRatePerBlock() external view returns (uint) {
        return interestRateModel.getBorrowRate(getCashPrior(), totalBorrows, totalReserves);
    }

    /**
     * @notice Returns the current per-block supply interest rate for this bToken
     * @return The supply interest rate per block, scaled by 1e18
     */
    function supplyRatePerBlock() external view returns (uint) {
        return interestRateModel.getSupplyRate(getCashPrior(), totalBorrows, totalReserves, reserveFactorMantissa);
    }

    /**
     * @notice Returns the current total borrows plus accrued interest
     * @return The total borrows with interest
     */
    function totalBorrowsCurrent() external nonReentrant returns (uint) {
        require(accrueInterest() == uint(Error.NO_ERROR), "accrue interest failed");
        return totalBorrows;
    }

    /**
     * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex
     * @param account The address whose balance should be calculated after updating borrowIndex
     * @return The calculated balance
     */
    function borrowBalanceCurrent(address account) external nonReentrant returns (uint) {
        require(accrueInterest() == uint(Error.NO_ERROR), "accrue interest failed");
        return borrowBalanceStored(account);
    }

    /**
     * @notice Return the borrow balance of account based on stored data
     * @param account The address whose balance should be calculated
     * @return The calculated balance
     */
    function borrowBalanceStored(address account) public view returns (uint) {
        (MathError err, uint result) = borrowBalanceStoredInternal(account);
        require(err == MathError.NO_ERROR, "borrowBalanceStored: borrowBalanceStoredInternal failed");
        return result;
    }

    /**
     * @notice Return the borrow balance of account based on stored data
     * @param account The address whose balance should be calculated
     * @return (error code, the calculated balance or 0 if error code is non-zero)
     */
    function borrowBalanceStoredInternal(address account) internal view returns (MathError, uint) {
        /* Note: we do not assert that the market is up to date */
        MathError mathErr;
        uint principalTimesIndex;
        uint result;

        /* Get borrowBalance and borrowIndex */
        BorrowSnapshot storage borrowSnapshot = accountBorrows[account];

        /* If borrowBalance = 0 then borrowIndex is likely also 0.
         * Rather than failing the calculation with a division by 0, we immediately return 0 in this case.
         */
        if (borrowSnapshot.principal == 0) {
            return (MathError.NO_ERROR, 0);
        }

        /* Calculate new borrow balance using the interest index:
         *  recentBorrowBalance = borrower.borrowBalance * market.borrowIndex / borrower.borrowIndex
         */
        (mathErr, principalTimesIndex) = mulUInt(borrowSnapshot.principal, borrowIndex);
        if (mathErr != MathError.NO_ERROR) {
            return (mathErr, 0);
        }

        (mathErr, result) = divUInt(principalTimesIndex, borrowSnapshot.interestIndex);
        if (mathErr != MathError.NO_ERROR) {
            return (mathErr, 0);
        }

        return (MathError.NO_ERROR, result);
    }

    /**
     * @notice Accrue interest then return the up-to-date exchange rate
     * @return Calculated exchange rate scaled by 1e18
     */
    function exchangeRateCurrent() public nonReentrant returns (uint) {
        require(accrueInterest() == uint(Error.NO_ERROR), "accrue interest failed");
        return exchangeRateStored();
    }

    /**
     * @notice Calculates the exchange rate from the underlying to the BToken
     * @dev This function does not accrue interest before calculating the exchange rate
     * @return Calculated exchange rate scaled by 1e18
     */
    function exchangeRateStored() public view returns (uint) {
        (MathError err, uint result) = exchangeRateStoredInternal();
        require(err == MathError.NO_ERROR, "exchangeRateStored: exchangeRateStoredInternal failed");
        return result;
    }

    /**
     * @notice Calculates the exchange rate from the underlying to the BToken
     * @dev This function does not accrue interest before calculating the exchange rate
     * @return (error code, calculated exchange rate scaled by 1e18)
     */
    function exchangeRateStoredInternal() internal view returns (MathError, uint) {
        uint _totalSupply = totalSupply;
        if (_totalSupply == 0) {
            /*
             * If there are no tokens minted:
             *  exchangeRate = initialExchangeRate
             */
            return (MathError.NO_ERROR, initialExchangeRateMantissa);
        } else {
            /*
             * Otherwise:
             *  exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply
             */
            uint totalCash = getCashPrior();
            uint cashPlusBorrowsMinusReserves;
            Exp memory exchangeRate;
            MathError mathErr;

            (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt(totalCash, totalBorrows, totalReserves);
            if (mathErr != MathError.NO_ERROR) {
                return (mathErr, 0);
            }

            (mathErr, exchangeRate) = getExp(cashPlusBorrowsMinusReserves, _totalSupply);
            if (mathErr != MathError.NO_ERROR) {
                return (mathErr, 0);
            }

            return (MathError.NO_ERROR, exchangeRate.mantissa);
        }
    }

    /**
     * @notice Get cash balance of this bToken in the underlying asset
     * @return The quantity of underlying asset owned by this contract
     */
    function getCash() external view returns (uint) {
        return getCashPrior();
    }

    /**
     * @notice Applies accrued interest to total borrows and reserves
     * @dev This calculates interest accrued from the last checkpointed block
     *   up to the current block and writes new checkpoint to storage.
     */
    function accrueInterest() public returns (uint) {
        /* Remember the initial block number */
        uint currentBlockNumber = getBlockNumber();
        uint accrualBlockNumberPrior = accrualBlockNumber;

        /* Short-circuit accumulating 0 interest */
        if (accrualBlockNumberPrior == currentBlockNumber) {
            return uint(Error.NO_ERROR);
        }

        /* Read the previous values out of storage */
        uint cashPrior = getCashPrior();
        uint borrowsPrior = totalBorrows;
        uint reservesPrior = totalReserves;
        uint borrowIndexPrior = borrowIndex;

        /* Calculate the current borrow interest rate */
        uint borrowRateMantissa = interestRateModel.getBorrowRate(cashPrior, borrowsPrior, reservesPrior);
        require(borrowRateMantissa <= borrowRateMaxMantissa, "borrow rate is absurdly high");

        /* Calculate the number of blocks elapsed since the last accrual */
        (MathError mathErr, uint blockDelta) = subUInt(currentBlockNumber, accrualBlockNumberPrior);
        require(mathErr == MathError.NO_ERROR, "could not calculate block delta");

        /*
         * Calculate the interest accumulated into borrows and reserves and the new index:
         *  simpleInterestFactor = borrowRate * blockDelta
         *  interestAccumulated = simpleInterestFactor * totalBorrows
         *  totalBorrowsNew = interestAccumulated + totalBorrows
         *  totalReservesNew = interestAccumulated * reserveFactor + totalReserves
         *  borrowIndexNew = simpleInterestFactor * borrowIndex + borrowIndex
         */

        Exp memory simpleInterestFactor;
        uint interestAccumulated;
        uint totalBorrowsNew;
        uint totalReservesNew;
        uint borrowIndexNew;

        (mathErr, simpleInterestFactor) = mulScalar(Exp({mantissa: borrowRateMantissa}), blockDelta);
        if (mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, uint(mathErr));
        }

        (mathErr, interestAccumulated) = mulScalarTruncate(simpleInterestFactor, borrowsPrior);
        if (mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, uint(mathErr));
        }

        (mathErr, totalBorrowsNew) = addUInt(interestAccumulated, borrowsPrior);
        if (mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, uint(mathErr));
        }

        (mathErr, totalReservesNew) = mulScalarTruncateAddUInt(Exp({mantissa: reserveFactorMantissa}), interestAccumulated, reservesPrior);
        if (mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, uint(mathErr));
        }

        (mathErr, borrowIndexNew) = mulScalarTruncateAddUInt(simpleInterestFactor, borrowIndexPrior, borrowIndexPrior);
        if (mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, uint(mathErr));
        }

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)

        /* We write the previously calculated values into storage */
        accrualBlockNumber = currentBlockNumber;
        borrowIndex = borrowIndexNew;
        totalBorrows = totalBorrowsNew;
        totalReserves = totalReservesNew;

        /* We emit an AccrueInterest event */
        emit AccrueInterest(cashPrior, interestAccumulated, borrowIndexNew, totalBorrowsNew);

        return uint(Error.NO_ERROR);
    }

    /**
     * @notice Sender supplies assets into the market and receives bTokens in exchange
     * @dev Accrues interest whether or not the operation succeeds, unless reverted
     * @param mintAmount The amount of the underlying asset to supply
     * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount.
     */
    function mintInternal(uint mintAmount) internal nonReentrant returns (uint, uint) {
        uint error = accrueInterest();
        if (error != uint(Error.NO_ERROR)) {
            // accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed
            return (fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED), 0);
        }
        // mintFresh emits the actual Mint event if successful and logs on errors, so we don't need to
        return mintFresh(msg.sender, mintAmount);
    }

    struct MintLocalVars {
        Error err;
        MathError mathErr;
        uint exchangeRateMantissa;
        uint mintTokens;
        uint totalSupplyNew;
        uint accountTokensNew;
        uint actualMintAmount;
    }

    /**
     * @notice User supplies assets into the market and receives bTokens in exchange
     * @dev Assumes interest has already been accrued up to the current block
     * @param minter The address of the account which is supplying the assets
     * @param mintAmount The amount of the underlying asset to supply
     * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount.
     */
    function mintFresh(address minter, uint mintAmount) internal returns (uint, uint) {
        /* Fail if mint not allowed */
        uint allowed = comptroller.mintAllowed(address(this), minter, mintAmount);
        if (allowed != 0) {
            return (failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.MINT_COMPTROLLER_REJECTION, allowed), 0);
        }

        /* Verify market's block number equals current block number */
        if (accrualBlockNumber != getBlockNumber()) {
            return (fail(Error.MARKET_NOT_FRESH, FailureInfo.MINT_FRESHNESS_CHECK), 0);
        }

        MintLocalVars memory vars;

        (vars.mathErr, vars.exchangeRateMantissa) = exchangeRateStoredInternal();
        if (vars.mathErr != MathError.NO_ERROR) {
            return (failOpaque(Error.MATH_ERROR, FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED, uint(vars.mathErr)), 0);
        }

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)

        /*
         *  We call `doTransferIn` for the minter and the mintAmount.
         *  Note: The bToken must handle variations between BEP-20 and BNB underlying.
         *  `doTransferIn` reverts if anything goes wrong, since we can't be sure if
         *  side-effects occurred. The function returns the amount actually transferred,
         *  in case of a fee. On success, the bToken holds an additional `actualMintAmount`
         *  of cash.
         */
        vars.actualMintAmount = doTransferIn(minter, mintAmount);

        /*
         * We get the current exchange rate and calculate the number of bTokens to be minted:
         *  mintTokens = actualMintAmount / exchangeRate
         */

        (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate(vars.actualMintAmount, Exp({mantissa: vars.exchangeRateMantissa}));
        require(vars.mathErr == MathError.NO_ERROR, "MINT_EXCHANGE_CALCULATION_FAILED");

        /*
         * We calculate the new total supply of bTokens and minter token balance, checking for overflow:
         *  totalSupplyNew = totalSupply + mintTokens
         *  accountTokensNew = accountTokens[minter] + mintTokens
         */
        (vars.mathErr, vars.totalSupplyNew) = addUInt(totalSupply, vars.mintTokens);
        require(vars.mathErr == MathError.NO_ERROR, "MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED");

        (vars.mathErr, vars.accountTokensNew) = addUInt(accountTokens[minter], vars.mintTokens);
        require(vars.mathErr == MathError.NO_ERROR, "MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED");

        /* We write previously calculated values into storage */
        totalSupply = vars.totalSupplyNew;
        accountTokens[minter] = vars.accountTokensNew;

        /* We emit a Mint event, and a Transfer event */
        emit Mint(minter, vars.actualMintAmount, vars.mintTokens);
        emit Transfer(address(this), minter, vars.mintTokens);

        /* We call the defense hook */
        comptroller.mintVerify(address(this), minter, vars.actualMintAmount, vars.mintTokens);

        return (uint(Error.NO_ERROR), vars.actualMintAmount);
    }

    /**
     * @notice Sender redeems bTokens in exchange for the underlying asset
     * @dev Accrues interest whether or not the operation succeeds, unless reverted
     * @param redeemTokens The number of bTokens to redeem into underlying
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function redeemInternal(uint redeemTokens) internal nonReentrant returns (uint) {
        uint error = accrueInterest();
        if (error != uint(Error.NO_ERROR)) {
            // accrueInterest emits logs on errors, but we still want to log the fact that an attempted redeem failed
            return fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED);
        }
        // redeemFresh emits redeem-specific logs on errors, so we don't need to
        return redeemFresh(msg.sender, redeemTokens, 0);
    }

    /**
     * @notice Sender redeems bTokens in exchange for a specified amount of underlying asset
     * @dev Accrues interest whether or not the operation succeeds, unless reverted
     * @param redeemAmount The amount of underlying to receive from redeeming bTokens
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function redeemUnderlyingInternal(uint redeemAmount) internal nonReentrant returns (uint) {
        uint error = accrueInterest();
        if (error != uint(Error.NO_ERROR)) {
            // accrueInterest emits logs on errors, but we still want to log the fact that an attempted redeem failed
            return fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED);
        }
        // redeemFresh emits redeem-specific logs on errors, so we don't need to
        return redeemFresh(msg.sender, 0, redeemAmount);
    }

    struct RedeemLocalVars {
        Error err;
        MathError mathErr;
        uint exchangeRateMantissa;
        uint redeemTokens;
        uint redeemAmount;
        uint totalSupplyNew;
        uint accountTokensNew;
    }

    /**
     * @notice User redeems bTokens in exchange for the underlying asset
     * @dev Assumes interest has already been accrued up to the current block
     * @param redeemer The address of the account which is redeeming the tokens
     * @param redeemTokensIn The number of bTokens to redeem into underlying (only one of redeemTokensIn or redeemAmountIn may be non-zero)
     * @param redeemAmountIn The number of underlying tokens to receive from redeeming bTokens (only one of redeemTokensIn or redeemAmountIn may be non-zero)
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function redeemFresh(address payable redeemer, uint redeemTokensIn, uint redeemAmountIn) internal returns (uint) {
        require(redeemTokensIn == 0 || redeemAmountIn == 0, "one of redeemTokensIn or redeemAmountIn must be zero");

        RedeemLocalVars memory vars;

        /* exchangeRate = invoke Exchange Rate Stored() */
        (vars.mathErr, vars.exchangeRateMantissa) = exchangeRateStoredInternal();
        if (vars.mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED, uint(vars.mathErr));
        }

        /* If redeemTokensIn > 0: */
        if (redeemTokensIn > 0) {
            /*
             * We calculate the exchange rate and the amount of underlying to be redeemed:
             *  redeemTokens = redeemTokensIn
             *  redeemAmount = redeemTokensIn x exchangeRateCurrent
             */
            vars.redeemTokens = redeemTokensIn;

            (vars.mathErr, vars.redeemAmount) = mulScalarTruncate(Exp({mantissa: vars.exchangeRateMantissa}), redeemTokensIn);
            if (vars.mathErr != MathError.NO_ERROR) {
                return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, uint(vars.mathErr));
            }
        } else {
            /*
             * We get the current exchange rate and calculate the amount to be redeemed:
             *  redeemTokens = redeemAmountIn / exchangeRate
             *  redeemAmount = redeemAmountIn
             */

            (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate(redeemAmountIn, Exp({mantissa: vars.exchangeRateMantissa}));
            if (vars.mathErr != MathError.NO_ERROR) {
                return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, uint(vars.mathErr));
            }

            vars.redeemAmount = redeemAmountIn;
        }

        /* Fail if redeem not allowed */
        uint allowed = comptroller.redeemAllowed(address(this), redeemer, vars.redeemTokens);
        if (allowed != 0) {
            return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.REDEEM_COMPTROLLER_REJECTION, allowed);
        }

        /* Verify market's block number equals current block number */
        if (accrualBlockNumber != getBlockNumber()) {
            return fail(Error.MARKET_NOT_FRESH, FailureInfo.REDEEM_FRESHNESS_CHECK);
        }

        /*
         * We calculate the new total supply and redeemer balance, checking for underflow:
         *  totalSupplyNew = totalSupply - redeemTokens
         *  accountTokensNew = accountTokens[redeemer] - redeemTokens
         */
        (vars.mathErr, vars.totalSupplyNew) = subUInt(totalSupply, vars.redeemTokens);
        if (vars.mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, uint(vars.mathErr));
        }

        (vars.mathErr, vars.accountTokensNew) = subUInt(accountTokens[redeemer], vars.redeemTokens);
        if (vars.mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, uint(vars.mathErr));
        }

        /* Fail gracefully if protocol has insufficient cash */
        if (getCashPrior() < vars.redeemAmount) {
            return fail(Error.TOKEN_INSUFFICIENT_CASH, FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE);
        }

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)

        /*
         * We invoke doTransferOut for the redeemer and the redeemAmount.
         *  Note: The bToken must handle variations between BEP-20 and BNB underlying.
         *  On success, the bToken has redeemAmount less of cash.
         *  doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred.
         */

        uint feeAmount;
        uint remainedAmount;
        if (IComptroller(address(comptroller)).treasuryPercent() != 0) {
            (vars.mathErr, feeAmount) = mulUInt(vars.redeemAmount, IComptroller(address(comptroller)).treasuryPercent());
            if (vars.mathErr != MathError.NO_ERROR) {
                return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_FEE_CALCULATION_FAILED, uint(vars.mathErr));
            }

            (vars.mathErr, feeAmount) = divUInt(feeAmount, 1e18);
            if (vars.mathErr != MathError.NO_ERROR) {
                return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_FEE_CALCULATION_FAILED, uint(vars.mathErr));
            }

            (vars.mathErr, remainedAmount) = subUInt(vars.redeemAmount, feeAmount);
            if (vars.mathErr != MathError.NO_ERROR) {
                return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_FEE_CALCULATION_FAILED, uint(vars.mathErr));
            }

            doTransferOut(address(uint160(IComptroller(address(comptroller)).treasuryAddress())), feeAmount);

            emit RedeemFee(redeemer, feeAmount, vars.redeemTokens);
        } else {
            remainedAmount = vars.redeemAmount;
        }

        doTransferOut(redeemer, remainedAmount);

        /* We write previously calculated values into storage */
        totalSupply = vars.totalSupplyNew;
        accountTokens[redeemer] = vars.accountTokensNew;

        /* We emit a Transfer event, and a Redeem event */
        emit Transfer(redeemer, address(this), vars.redeemTokens);
        emit Redeem(redeemer, remainedAmount, vars.redeemTokens);

        /* We call the defense hook */
        comptroller.redeemVerify(address(this), redeemer, vars.redeemAmount, vars.redeemTokens);

        return uint(Error.NO_ERROR);
    }

    /**
      * @notice Sender borrows assets from the protocol to their own address
      * @param borrowAmount The amount of the underlying asset to borrow
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function borrowInternal(uint borrowAmount) internal nonReentrant returns (uint) {
        uint error = accrueInterest();
        if (error != uint(Error.NO_ERROR)) {
            // accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed
            return fail(Error(error), FailureInfo.BORROW_ACCRUE_INTEREST_FAILED);
        }
        // borrowFresh emits borrow-specific logs on errors, so we don't need to
        return borrowFresh(msg.sender, borrowAmount);
    }

    struct BorrowLocalVars {
        MathError mathErr;
        uint accountBorrows;
        uint accountBorrowsNew;
        uint totalBorrowsNew;
    }

    /**
      * @notice Users borrow assets from the protocol to their own address
      * @param borrowAmount The amount of the underlying asset to borrow
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function borrowFresh(address payable borrower, uint borrowAmount) internal returns (uint) {
        /* Fail if borrow not allowed */
        uint allowed = comptroller.borrowAllowed(address(this), borrower, borrowAmount);
        if (allowed != 0) {
            return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.BORROW_COMPTROLLER_REJECTION, allowed);
        }

        /* Verify market's block number equals current block number */
        if (accrualBlockNumber != getBlockNumber()) {
            return fail(Error.MARKET_NOT_FRESH, FailureInfo.BORROW_FRESHNESS_CHECK);
        }

        /* Fail gracefully if protocol has insufficient underlying cash */
        if (getCashPrior() < borrowAmount) {
            return fail(Error.TOKEN_INSUFFICIENT_CASH, FailureInfo.BORROW_CASH_NOT_ABAILABLE);
        }

        BorrowLocalVars memory vars;

        /*
         * We calculate the new borrower and total borrow balances, failing on overflow:
         *  accountBorrowsNew = accountBorrows + borrowAmount
         *  totalBorrowsNew = totalBorrows + borrowAmount
         */
        (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(borrower);
        if (vars.mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, uint(vars.mathErr));
        }

        (vars.mathErr, vars.accountBorrowsNew) = addUInt(vars.accountBorrows, borrowAmount);
        if (vars.mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, uint(vars.mathErr));
        }

        (vars.mathErr, vars.totalBorrowsNew) = addUInt(totalBorrows, borrowAmount);
        if (vars.mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, uint(vars.mathErr));
        }

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)

        /*
         * We invoke doTransferOut for the borrower and the borrowAmount.
         *  Note: The bToken must handle variations between BEP-20 and BNB underlying.
         *  On success, the bToken borrowAmount less of cash.
         *  doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred.
         */
        doTransferOut(borrower, borrowAmount);

        /* We write the previously calculated values into storage */
        accountBorrows[borrower].principal = vars.accountBorrowsNew;
        accountBorrows[borrower].interestIndex = borrowIndex;
        totalBorrows = vars.totalBorrowsNew;

        /* We emit a Borrow event */
        emit Borrow(borrower, borrowAmount, vars.accountBorrowsNew, vars.totalBorrowsNew);

        /* We call the defense hook */
        comptroller.borrowVerify(address(this), borrower, borrowAmount);

        return uint(Error.NO_ERROR);
    }

    /**
     * @notice Sender repays their own borrow
     * @param repayAmount The amount to repay
     * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount.
     */
    function repayBorrowInternal(uint repayAmount) internal nonReentrant returns (uint, uint) {
        uint error = accrueInterest();
        if (error != uint(Error.NO_ERROR)) {
            // accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed
            return (fail(Error(error), FailureInfo.REPAY_BORROW_ACCRUE_INTEREST_FAILED), 0);
        }
        // repayBorrowFresh emits repay-borrow-specific logs on errors, so we don't need to
        return repayBorrowFresh(msg.sender, msg.sender, repayAmount);
    }

    /**
     * @notice Sender repays a borrow belonging to borrower
     * @param borrower the account with the debt being payed off
     * @param repayAmount The amount to repay
     * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount.
     */
    function repayBorrowBehalfInternal(address borrower, uint repayAmount) internal nonReentrant returns (uint, uint) {
        uint error = accrueInterest();
        if (error != uint(Error.NO_ERROR)) {
            // accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed
            return (fail(Error(error), FailureInfo.REPAY_BEHALF_ACCRUE_INTEREST_FAILED), 0);
        }
        // repayBorrowFresh emits repay-borrow-specific logs on errors, so we don't need to
        return repayBorrowFresh(msg.sender, borrower, repayAmount);
    }

    struct RepayBorrowLocalVars {
        Error err;
        MathError mathErr;
        uint repayAmount;
        uint borrowerIndex;
        uint accountBorrows;
        uint accountBorrowsNew;
        uint totalBorrowsNew;
        uint actualRepayAmount;
    }

    /**
     * @notice Borrows are repaid by another user (possibly the borrower).
     * @param payer the account paying off the borrow
     * @param borrower the account with the debt being payed off
     * @param repayAmount the amount of undelrying tokens being returned
     * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount.
     */
    function repayBorrowFresh(address payer, address borrower, uint repayAmount) internal returns (uint, uint) {
        /* Fail if repayBorrow not allowed */
        uint allowed = comptroller.repayBorrowAllowed(address(this), payer, borrower, repayAmount);
        if (allowed != 0) {
            return (failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.REPAY_BORROW_COMPTROLLER_REJECTION, allowed), 0);
        }

        /* Verify market's block number equals current block number */
        if (accrualBlockNumber != getBlockNumber()) {
            return (fail(Error.MARKET_NOT_FRESH, FailureInfo.REPAY_BORROW_FRESHNESS_CHECK), 0);
        }

        RepayBorrowLocalVars memory vars;

        /* We remember the original borrowerIndex for verification purposes */
        vars.borrowerIndex = accountBorrows[borrower].interestIndex;

        /* We fetch the amount the borrower owes, with accumulated interest */
        (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(borrower);
        if (vars.mathErr != MathError.NO_ERROR) {
            return (failOpaque(Error.MATH_ERROR, FailureInfo.REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, uint(vars.mathErr)), 0);
        }

        /* If repayAmount == -1, repayAmount = accountBorrows */
        if (repayAmount == uint(-1)) {
            vars.repayAmount = vars.accountBorrows;
        } else {
            vars.repayAmount = repayAmount;
        }

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)

        /*
         * We call doTransferIn for the payer and the repayAmount
         *  Note: The bToken must handle variations between BEP-20 and BNB underlying.
         *  On success, the bToken holds an additional repayAmount of cash.
         *  doTransferIn reverts if anything goes wrong, since we can't be sure if side effects occurred.
         *   it returns the amount actually transferred, in case of a fee.
         */
        vars.actualRepayAmount = doTransferIn(payer, vars.repayAmount);

        /*
         * We calculate the new borrower and total borrow balances, failing on underflow:
         *  accountBorrowsNew = accountBorrows - actualRepayAmount
         *  totalBorrowsNew = totalBorrows - actualRepayAmount
         */
        (vars.mathErr, vars.accountBorrowsNew) = subUInt(vars.accountBorrows, vars.actualRepayAmount);
        require(vars.mathErr == MathError.NO_ERROR, "REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED");

        (vars.mathErr, vars.totalBorrowsNew) = subUInt(totalBorrows, vars.actualRepayAmount);
        require(vars.mathErr == MathError.NO_ERROR, "REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED");

        /* We write the previously calculated values into storage */
        accountBorrows[borrower].principal = vars.accountBorrowsNew;
        accountBorrows[borrower].interestIndex = borrowIndex;
        totalBorrows = vars.totalBorrowsNew;

        /* We emit a RepayBorrow event */
        emit RepayBorrow(payer, borrower, vars.actualRepayAmount, vars.accountBorrowsNew, vars.totalBorrowsNew);

        /* We call the defense hook */
        comptroller.repayBorrowVerify(address(this), payer, borrower, vars.actualRepayAmount, vars.borrowerIndex);

        return (uint(Error.NO_ERROR), vars.actualRepayAmount);
    }

    /**
     * @notice The sender liquidates the borrowers collateral.
     *  The collateral seized is transferred to the liquidator.
     * @param borrower The borrower of this bToken to be liquidated
     * @param bTokenCollateral The market in which to seize collateral from the borrower
     * @param repayAmount The amount of the underlying borrowed asset to repay
     * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount.
     */
    function liquidateBorrowInternal(address borrower, uint repayAmount, BTokenInterface bTokenCollateral) internal nonReentrant returns (uint, uint) {
        uint error = accrueInterest();
        if (error != uint(Error.NO_ERROR)) {
            // accrueInterest emits logs on errors, but we still want to log the fact that an attempted liquidation failed
            return (fail(Error(error), FailureInfo.LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED), 0);
        }

        error = bTokenCollateral.accrueInterest();
        if (error != uint(Error.NO_ERROR)) {
            // accrueInterest emits logs on errors, but we still want to log the fact that an attempted liquidation failed
            return (fail(Error(error), FailureInfo.LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED), 0);
        }

        // liquidateBorrowFresh emits borrow-specific logs on errors, so we don't need to
        return liquidateBorrowFresh(msg.sender, borrower, repayAmount, bTokenCollateral);
    }

    /**
     * @notice The liquidator liquidates the borrowers collateral.
     *  The collateral seized is transferred to the liquidator.
     * @param borrower The borrower of this bToken to be liquidated
     * @param liquidator The address repaying the borrow and seizing collateral
     * @param bTokenCollateral The market in which to seize collateral from the borrower
     * @param repayAmount The amount of the underlying borrowed asset to repay
     * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount.
     */
    function liquidateBorrowFresh(address liquidator, address borrower, uint repayAmount, BTokenInterface bTokenCollateral) internal returns (uint, uint) {
        /* Fail if liquidate not allowed */
        uint allowed = comptroller.liquidateBorrowAllowed(address(this), address(bTokenCollateral), liquidator, borrower, repayAmount);
        if (allowed != 0) {
            return (failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.LIQUIDATE_COMPTROLLER_REJECTION, allowed), 0);
        }

        /* Verify market's block number equals current block number */
        if (accrualBlockNumber != getBlockNumber()) {
            return (fail(Error.MARKET_NOT_FRESH, FailureInfo.LIQUIDATE_FRESHNESS_CHECK), 0);
        }

        /* Verify bTokenCollateral market's block number equals current block number */
        if (bTokenCollateral.accrualBlockNumber() != getBlockNumber()) {
            return (fail(Error.MARKET_NOT_FRESH, FailureInfo.LIQUIDATE_COLLATERAL_FRESHNESS_CHECK), 0);
        }

        /* Fail if borrower = liquidator */
        if (borrower == liquidator) {
            return (fail(Error.INVALID_ACCOUNT_PAIR, FailureInfo.LIQUIDATE_LIQUIDATOR_IS_BORROWER), 0);
        }

        /* Fail if repayAmount = 0 */
        if (repayAmount == 0) {
            return (fail(Error.INVALID_CLOSE_AMOUNT_REQUESTED, FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_ZERO), 0);
        }

        /* Fail if repayAmount = -1 */
        if (repayAmount == uint(-1)) {
            return (fail(Error.INVALID_CLOSE_AMOUNT_REQUESTED, FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX), 0);
        }


        /* Fail if repayBorrow fails */
        (uint repayBorrowError, uint actualRepayAmount) = repayBorrowFresh(liquidator, borrower, repayAmount);
        if (repayBorrowError != uint(Error.NO_ERROR)) {
            return (fail(Error(repayBorrowError), FailureInfo.LIQUIDATE_REPAY_BORROW_FRESH_FAILED), 0);
        }

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)

        /* We calculate the number of collateral tokens that will be seized */
        (uint amountSeizeError, uint seizeTokens) = comptroller.liquidateCalculateSeizeTokens(address(this), address(bTokenCollateral), actualRepayAmount);
        require(amountSeizeError == uint(Error.NO_ERROR), "LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED");

        /* Revert if borrower collateral token balance < seizeTokens */
        require(bTokenCollateral.balanceOf(borrower) >= seizeTokens, "LIQUIDATE_SEIZE_TOO_MUCH");

        // If this is also the collateral, run seizeInternal to avoid re-entrancy, otherwise make an external call
        uint seizeError;
        if (address(bTokenCollateral) == address(this)) {
            seizeError = seizeInternal(address(this), liquidator, borrower, seizeTokens);
        } else {
            seizeError = bTokenCollateral.seize(liquidator, borrower, seizeTokens);
        }

        /* Revert if seize tokens fails (since we cannot be sure of side effects) */
        require(seizeError == uint(Error.NO_ERROR), "token seizure failed");

        /* We emit a LiquidateBorrow event */
        emit LiquidateBorrow(liquidator, borrower, actualRepayAmount, address(bTokenCollateral), seizeTokens);

        /* We call the defense hook */
        comptroller.liquidateBorrowVerify(address(this), address(bTokenCollateral), liquidator, borrower, actualRepayAmount, seizeTokens);

        return (uint(Error.NO_ERROR), actualRepayAmount);
    }

    /**
     * @notice Transfers collateral tokens (this market) to the liquidator.
     * @dev Will fail unless called by another bToken during the process of liquidation.
     *  Its absolutely critical to use msg.sender as the borrowed bToken and not a parameter.
     * @param liquidator The account receiving seized collateral
     * @param borrower The account having collateral seized
     * @param seizeTokens The number of bTokens to seize
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function seize(address liquidator, address borrower, uint seizeTokens) external nonReentrant returns (uint) {
        return seizeInternal(msg.sender, liquidator, borrower, seizeTokens);
    }

    /**
     * @notice Transfers collateral tokens (this market) to the liquidator.
     * @dev Called only during an in-kind liquidation, or by liquidateBorrow during the liquidation of another BToken.
     *  Its absolutely critical to use msg.sender as the seizer bToken and not a parameter.
     * @param seizerToken The contract seizing the collateral (i.e. borrowed bToken)
     * @param liquidator The account receiving seized collateral
     * @param borrower The account having collateral seized
     * @param seizeTokens The number of bTokens to seize
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function seizeInternal(address seizerToken, address liquidator, address borrower, uint seizeTokens) internal returns (uint) {
        /* Fail if seize not allowed */
        uint allowed = comptroller.seizeAllowed(address(this), seizerToken, liquidator, borrower, seizeTokens);
        if (allowed != 0) {
            return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, allowed);
        }

        /* Fail if borrower = liquidator */
        if (borrower == liquidator) {
            return fail(Error.INVALID_ACCOUNT_PAIR, FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER);
        }

        MathError mathErr;
        uint borrowerTokensNew;
        uint liquidatorTokensNew;

        /*
         * We calculate the new borrower and liquidator token balances, failing on underflow/overflow:
         *  borrowerTokensNew = accountTokens[borrower] - seizeTokens
         *  liquidatorTokensNew = accountTokens[liquidator] + seizeTokens
         */
        (mathErr, borrowerTokensNew) = subUInt(accountTokens[borrower], seizeTokens);
        if (mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, uint(mathErr));
        }

        (mathErr, liquidatorTokensNew) = addUInt(accountTokens[liquidator], seizeTokens);
        if (mathErr != MathError.NO_ERROR) {
            return failOpaque(Error.MATH_ERROR, FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, uint(mathErr));
        }

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)

        /* We write the previously calculated values into storage */
        accountTokens[borrower] = borrowerTokensNew;
        accountTokens[liquidator] = liquidatorTokensNew;

        /* Emit a Transfer event */
        emit Transfer(borrower, liquidator, seizeTokens);

        /* We call the defense hook */
        comptroller.seizeVerify(address(this), seizerToken, liquidator, borrower, seizeTokens);

        return uint(Error.NO_ERROR);
    }


    /*** Admin Functions ***/

    /**
      * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.
      * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.
      * @param newPendingAdmin New pending admin.
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function _setPendingAdmin(address payable newPendingAdmin) external returns (uint) {
        // Check caller = admin
        if (msg.sender != admin) {
            return fail(Error.UNAUTHORIZED, FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK);
        }

        // Save current value, if any, for inclusion in log
        address oldPendingAdmin = pendingAdmin;

        // Store pendingAdmin with value newPendingAdmin
        pendingAdmin = newPendingAdmin;

        // Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin)
        emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin);

        return uint(Error.NO_ERROR);
    }

    /**
      * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin
      * @dev Admin function for pending admin to accept role and update admin
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function _acceptAdmin() external returns (uint) {
        // Check caller is pendingAdmin and pendingAdmin ≠ address(0)
        if (msg.sender != pendingAdmin || msg.sender == address(0)) {
            return fail(Error.UNAUTHORIZED, FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK);
        }

        // Save current values for inclusion in log
        address oldAdmin = admin;
        address oldPendingAdmin = pendingAdmin;

        // Store admin with value pendingAdmin
        admin = pendingAdmin;

        // Clear the pending value
        pendingAdmin = address(0);

        emit NewAdmin(oldAdmin, admin);
        emit NewPendingAdmin(oldPendingAdmin, pendingAdmin);

        return uint(Error.NO_ERROR);
    }

    /**
      * @notice Sets a new comptroller for the market
      * @dev Admin function to set a new comptroller
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function _setComptroller(ComptrollerInterface newComptroller) public returns (uint) {
        // Check caller is admin
        if (msg.sender != admin) {
            return fail(Error.UNAUTHORIZED, FailureInfo.SET_COMPTROLLER_OWNER_CHECK);
        }

        ComptrollerInterface oldComptroller = comptroller;
        // Ensure invoke comptroller.isComptroller() returns true
        require(newComptroller.isComptroller(), "marker method returned false");

        // Set market's comptroller to newComptroller
        comptroller = newComptroller;

        // Emit NewComptroller(oldComptroller, newComptroller)
        emit NewComptroller(oldComptroller, newComptroller);

        return uint(Error.NO_ERROR);
    }

    /**
      * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh
      * @dev Admin function to accrue interest and set a new reserve factor
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function _setReserveFactor(uint newReserveFactorMantissa) external nonReentrant returns (uint) {
        uint error = accrueInterest();
        if (error != uint(Error.NO_ERROR)) {
            // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reserve factor change failed.
            return fail(Error(error), FailureInfo.SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED);
        }
        // _setReserveFactorFresh emits reserve-factor-specific logs on errors, so we don't need to.
        return _setReserveFactorFresh(newReserveFactorMantissa);
    }

    /**
      * @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual)
      * @dev Admin function to set a new reserve factor
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function _setReserveFactorFresh(uint newReserveFactorMantissa) internal returns (uint) {
        // Check caller is admin
        if (msg.sender != admin) {
            return fail(Error.UNAUTHORIZED, FailureInfo.SET_RESERVE_FACTOR_ADMIN_CHECK);
        }

        // Verify market's block number equals current block number
        if (accrualBlockNumber != getBlockNumber()) {
            return fail(Error.MARKET_NOT_FRESH, FailureInfo.SET_RESERVE_FACTOR_FRESH_CHECK);
        }

        // Check newReserveFactor ≤ maxReserveFactor
        if (newReserveFactorMantissa > reserveFactorMaxMantissa) {
            return fail(Error.BAD_INPUT, FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK);
        }

        uint oldReserveFactorMantissa = reserveFactorMantissa;
        reserveFactorMantissa = newReserveFactorMantissa;

        emit NewReserveFactor(oldReserveFactorMantissa, newReserveFactorMantissa);

        return uint(Error.NO_ERROR);
    }

    /**
     * @notice Accrues interest and reduces reserves by transferring from msg.sender
     * @param addAmount Amount of addition to reserves
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function _addReservesInternal(uint addAmount) internal nonReentrant returns (uint) {
        uint error = accrueInterest();
        if (error != uint(Error.NO_ERROR)) {
            // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reduce reserves failed.
            return fail(Error(error), FailureInfo.ADD_RESERVES_ACCRUE_INTEREST_FAILED);
        }

        // _addReservesFresh emits reserve-addition-specific logs on errors, so we don't need to.
        (error, ) = _addReservesFresh(addAmount);
        return error;
    }

    /**
     * @notice Add reserves by transferring from caller
     * @dev Requires fresh interest accrual
     * @param addAmount Amount of addition to reserves
     * @return (uint, uint) An error code (0=success, otherwise a failure (see ErrorReporter.sol for details)) and the actual amount added, net token fees
     */
    function _addReservesFresh(uint addAmount) internal returns (uint, uint) {
        // totalReserves + actualAddAmount
        uint totalReservesNew;
        uint actualAddAmount;

        // We fail gracefully unless market's block number equals current block number
        if (accrualBlockNumber != getBlockNumber()) {
            return (fail(Error.MARKET_NOT_FRESH, FailureInfo.ADD_RESERVES_FRESH_CHECK), actualAddAmount);
        }

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)

        /*
         * We call doTransferIn for the caller and the addAmount
         *  Note: The bToken must handle variations between BEP-20 and BNB underlying.
         *  On success, the bToken holds an additional addAmount of cash.
         *  doTransferIn reverts if anything goes wrong, since we can't be sure if side effects occurred.
         *  it returns the amount actually transferred, in case of a fee.
         */

        actualAddAmount = doTransferIn(msg.sender, addAmount);

        totalReservesNew = totalReserves + actualAddAmount;

        /* Revert on overflow */
        require(totalReservesNew >= totalReserves, "add reserves unexpected overflow");

        // Store reserves[n+1] = reserves[n] + actualAddAmount
        totalReserves = totalReservesNew;

        /* Emit NewReserves(admin, actualAddAmount, reserves[n+1]) */
        emit ReservesAdded(msg.sender, actualAddAmount, totalReservesNew);

        /* Return (NO_ERROR, actualAddAmount) */
        return (uint(Error.NO_ERROR), actualAddAmount);
    }


    /**
     * @notice Accrues interest and reduces reserves by transferring to admin
     * @param reduceAmount Amount of reduction to reserves
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function _reduceReserves(uint reduceAmount) external nonReentrant returns (uint) {
        uint error = accrueInterest();
        if (error != uint(Error.NO_ERROR)) {
            // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reduce reserves failed.
            return fail(Error(error), FailureInfo.REDUCE_RESERVES_ACCRUE_INTEREST_FAILED);
        }
        // _reduceReservesFresh emits reserve-reduction-specific logs on errors, so we don't need to.
        return _reduceReservesFresh(reduceAmount);
    }

    /**
     * @notice Reduces reserves by transferring to admin
     * @dev Requires fresh interest accrual
     * @param reduceAmount Amount of reduction to reserves
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function _reduceReservesFresh(uint reduceAmount) internal returns (uint) {
        // totalReserves - reduceAmount
        uint totalReservesNew;

        // Check caller is admin
        if (msg.sender != admin) {
            return fail(Error.UNAUTHORIZED, FailureInfo.REDUCE_RESERVES_ADMIN_CHECK);
        }

        // We fail gracefully unless market's block number equals current block number
        if (accrualBlockNumber != getBlockNumber()) {
            return fail(Error.MARKET_NOT_FRESH, FailureInfo.REDUCE_RESERVES_FRESH_CHECK);
        }

        // Fail gracefully if protocol has insufficient underlying cash
        if (getCashPrior() < reduceAmount) {
            return fail(Error.TOKEN_INSUFFICIENT_CASH, FailureInfo.REDUCE_RESERVES_CASH_NOT_ABAILABLE);
        }

        // Check reduceAmount ≤ reserves[n] (totalReserves)
        if (reduceAmount > totalReserves) {
            return fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION);
        }

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)

        totalReservesNew = totalReserves - reduceAmount;
        // We checked reduceAmount <= totalReserves above, so this should never revert.
        require(totalReservesNew <= totalReserves, "reduce reserves unexpected underflow");

        // Store reserves[n+1] = reserves[n] - reduceAmount
        totalReserves = totalReservesNew;

        // doTransferOut reverts if anything goes wrong, since we can't be sure if side effects occurred.
        doTransferOut(admin, reduceAmount);

        emit ReservesReduced(admin, reduceAmount, totalReservesNew);

        return uint(Error.NO_ERROR);
    }

    /**
     * @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh
     * @dev Admin function to accrue interest and update the interest rate model
     * @param newInterestRateModel the new interest rate model to use
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function _setInterestRateModel(InterestRateModel newInterestRateModel) public returns (uint) {
        uint error = accrueInterest();
        if (error != uint(Error.NO_ERROR)) {
            // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted change of interest rate model failed
            return fail(Error(error), FailureInfo.SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED);
        }
        // _setInterestRateModelFresh emits interest-rate-model-update-specific logs on errors, so we don't need to.
        return _setInterestRateModelFresh(newInterestRateModel);
    }

    /**
     * @notice updates the interest rate model (*requires fresh interest accrual)
     * @dev Admin function to update the interest rate model
     * @param newInterestRateModel the new interest rate model to use
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function _setInterestRateModelFresh(InterestRateModel newInterestRateModel) internal returns (uint) {

        // Used to store old model for use in the event that is emitted on success
        InterestRateModel oldInterestRateModel;

        // Check caller is admin
        if (msg.sender != admin) {
            return fail(Error.UNAUTHORIZED, FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK);
        }

        // We fail gracefully unless market's block number equals current block number
        if (accrualBlockNumber != getBlockNumber()) {
            return fail(Error.MARKET_NOT_FRESH, FailureInfo.SET_INTEREST_RATE_MODEL_FRESH_CHECK);
        }

        // Track the market's current interest rate model
        oldInterestRateModel = interestRateModel;

        // Ensure invoke newInterestRateModel.isInterestRateModel() returns true
        require(newInterestRateModel.isInterestRateModel(), "marker method returned false");

        // Set the interest rate model to newInterestRateModel
        interestRateModel = newInterestRateModel;

        // Emit NewMarketInterestRateModel(oldInterestRateModel, newInterestRateModel)
        emit NewMarketInterestRateModel(oldInterestRateModel, newInterestRateModel);

        return uint(Error.NO_ERROR);
    }

    /*** Safe Token ***/

    /**
     * @notice Gets balance of this contract in terms of the underlying
     * @dev This excludes the value of the current message, if any
     * @return The quantity of underlying owned by this contract
     */
    function getCashPrior() internal view returns (uint);

    /**
     * @dev Performs a transfer in, reverting upon failure. Returns the amount actually transferred to the protocol, in case of a fee.
     *  This may revert due to insufficient balance or insufficient allowance.
     */
    function doTransferIn(address from, uint amount) internal returns (uint);

    /**
     * @dev Performs a transfer out, ideally returning an explanatory error code upon failure tather than reverting.
     *  If caller has not called checked protocol's balance, may revert due to insufficient cash held in the contract.
     *  If caller has checked protocol's balance, and verified it is >= amount, this should not revert in normal conditions.
     */
    function doTransferOut(address payable to, uint amount) internal;


    /*** Reentrancy Guard ***/

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     */
    modifier nonReentrant() {
        require(_notEntered, "re-entered");
        _notEntered = false;
        _;
        _notEntered = true; // get a gas-refund post-Istanbul
    }
}

// File: contracts/PriceOracle.sol

pragma solidity ^0.5.16;


contract PriceOracle {
    /// @notice Indicator that this is a PriceOracle contract (for inspection)
    bool public constant isPriceOracle = true;

    /**
      * @notice Get the underlying price of a bToken asset
      * @param bToken The bToken to get the underlying price of
      * @return The underlying asset price mantissa (scaled by 1e18).
      *  Zero means the price is unavailable.
      */
    function getUnderlyingPrice(BToken bToken) external view returns (uint);
}

// File: contracts/BAIControllerInterface.sol

pragma solidity ^0.5.16;

contract BAIControllerInterface {
    function getBAIAddress() public view returns (address);
    function getMintableBAI(address minter) public view returns (uint, uint);
    function mintBAI(address minter, uint mintBAIAmount) external returns (uint);
    function repayBAI(address repayer, uint repayBAIAmount) external returns (uint);

    function _initializeBidaoBAIState(uint blockNumber) external returns (uint);
    function updateBidaoBAIMintIndex() external returns (uint);
    function calcDistributeBAIMinterBidao(address vaiMinter) external returns(uint, uint, uint, uint);
}

// File: contracts/ComptrollerStorage.sol

pragma solidity ^0.5.16;




contract UnitrollerAdminStorage {
    /**
    * @notice Administrator for this contract
    */
    address public admin;

    /**
    * @notice Pending administrator for this contract
    */
    address public pendingAdmin;

    /**
    * @notice Active brains of Unitroller
    */
    address public comptrollerImplementation;

    /**
    * @notice Pending brains of Unitroller
    */
    address public pendingComptrollerImplementation;
}

contract ComptrollerV1Storage is UnitrollerAdminStorage {

    /**
     * @notice Oracle which gives the price of any given asset
     */
    PriceOracle public oracle;

    /**
     * @notice Multiplier used to calculate the maximum repayAmount when liquidating a borrow
     */
    uint public closeFactorMantissa;

    /**
     * @notice Multiplier representing the discount on collateral that a liquidator receives
     */
    uint public liquidationIncentiveMantissa;

    /**
     * @notice Max number of assets a single account can participate in (borrow or use as collateral)
     */
    uint public maxAssets;

    /**
     * @notice Per-account mapping of "assets you are in", capped by maxAssets
     */
    mapping(address => BToken[]) public accountAssets;

    struct Market {
        /// @notice Whether or not this market is listed
        bool isListed;

        /**
         * @notice Multiplier representing the most one can borrow against their collateral in this market.
         *  For instance, 0.9 to allow borrowing 90% of collateral value.
         *  Must be between 0 and 1, and stored as a mantissa.
         */
        uint collateralFactorMantissa;

        /// @notice Per-market mapping of "accounts in this asset"
        mapping(address => bool) accountMembership;

        /// @notice Whether or not this market receives XBID
        bool isBidao;
    }

    /**
     * @notice Official mapping of bTokens -> Market metadata
     * @dev Used e.g. to determine if a market is supported
     */
    mapping(address => Market) public markets;

    /**
     * @notice The Pause Guardian can pause certain actions as a safety mechanism.
     *  Actions which allow users to remove their own assets cannot be paused.
     *  Liquidation / seizing / transfer can only be paused globally, not by market.
     */
    address public pauseGuardian;
    bool public _mintGuardianPaused;
    bool public _borrowGuardianPaused;
    bool public transferGuardianPaused;
    bool public seizeGuardianPaused;
    mapping(address => bool) public mintGuardianPaused;
    mapping(address => bool) public borrowGuardianPaused;

    struct BidaoMarketState {
        /// @notice The market's last updated bidaoBorrowIndex or bidaoSupplyIndex
        uint224 index;

        /// @notice The block number the index was last updated at
        uint32 block;
    }

    /// @notice A list of all markets
    BToken[] public allMarkets;

    /// @notice The rate at which the flywheel distributes XBID, per block
    uint public bidaoRate;

    /// @notice The portion of bidaoRate that each market currently receives
    mapping(address => uint) public bidaoSpeeds;

    /// @notice The Bidao market supply state for each market
    mapping(address => BidaoMarketState) public bidaoSupplyState;

    /// @notice The Bidao market borrow state for each market
    mapping(address => BidaoMarketState) public bidaoBorrowState;

    /// @notice The Bidao supply index for each market for each supplier as of the last time they accrued XBID
    mapping(address => mapping(address => uint)) public bidaoSupplierIndex;

    /// @notice The Bidao borrow index for each market for each borrower as of the last time they accrued XBID
    mapping(address => mapping(address => uint)) public bidaoBorrowerIndex;

    /// @notice The XBID accrued but not yet transferred to each user
    mapping(address => uint) public bidaoAccrued;

    /// @notice The Address of BAIController
    BAIControllerInterface public baiController;

    /// @notice The minted BAI amount to each user
    mapping(address => uint) public mintedBAIs;

    /// @notice BAI Mint Rate as a percentage
    uint public vaiMintRate;

    /**
     * @notice The Pause Guardian can pause certain actions as a safety mechanism.
     */
    bool public mintBAIGuardianPaused;
    bool public repayBAIGuardianPaused;

    /**
     * @notice Pause/Unpause whole protocol actions
     */
    bool public protocolPaused;

    /// @notice The rate at which the flywheel distributes XBID to BAI Minters, per block
    uint public bidaoBAIRate;
}

contract ComptrollerV2Storage is ComptrollerV1Storage {
    /// @notice The rate at which the flywheel distributes XBID to BAI Vault, per block
    uint public bidaoBAIVaultRate;

    // address of BAI Vault
    address public vaiVaultAddress;

    // start block of release to BAI Vault
    uint256 public releaseStartBlock;

    // minimum release amount to BAI Vault
    uint256 public minReleaseAmount;
}

contract ComptrollerV3Storage is ComptrollerV2Storage {
    /// @notice The borrowCapGuardian can set borrowCaps to any number for any market. Lowering the borrow cap could disable borrowing on the given market.
    address public borrowCapGuardian;

    /// @notice Borrow caps enforced by borrowAllowed for each bToken address. Defaults to zero which corresponds to unlimited borrowing.
    mapping(address => uint) public borrowCaps;
}

contract ComptrollerV4Storage is ComptrollerV3Storage {
    /// @notice Treasury Guardian address
    address public treasuryGuardian;

    /// @notice Treasury address
    address public treasuryAddress;

    /// @notice Fee percent of accrued interest with decimal 18
    uint256 public treasuryPercent;
}

// File: contracts/Unitroller.sol

pragma solidity ^0.5.16;


/**
 * @title ComptrollerCore
 * @dev Storage for the comptroller is at this address, while execution is delegated to the `comptrollerImplementation`.
 * BTokens should reference this contract as their comptroller.
 */
contract Unitroller is UnitrollerAdminStorage, ComptrollerErrorReporter {

    /**
      * @notice Emitted when pendingComptrollerImplementation is changed
      */
    event NewPendingImplementation(address oldPendingImplementation, address newPendingImplementation);

    /**
      * @notice Emitted when pendingComptrollerImplementation is accepted, which means comptroller implementation is updated
      */
    event NewImplementation(address oldImplementation, address newImplementation);

    /**
      * @notice Emitted when pendingAdmin is changed
      */
    event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin);

    /**
      * @notice Emitted when pendingAdmin is accepted, which means admin is updated
      */
    event NewAdmin(address oldAdmin, address newAdmin);

    constructor() public {
        // Set admin to caller
        admin = msg.sender;
    }

    /*** Admin Functions ***/
    function _setPendingImplementation(address newPendingImplementation) public returns (uint) {

        if (msg.sender != admin) {
            return fail(Error.UNAUTHORIZED, FailureInfo.SET_PENDING_IMPLEMENTATION_OWNER_CHECK);
        }

        address oldPendingImplementation = pendingComptrollerImplementation;

        pendingComptrollerImplementation = newPendingImplementation;

        emit NewPendingImplementation(oldPendingImplementation, pendingComptrollerImplementation);

        return uint(Error.NO_ERROR);
    }

    /**
    * @notice Accepts new implementation of comptroller. msg.sender must be pendingImplementation
    * @dev Admin function for new implementation to accept it's role as implementation
    * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
    */
    function _acceptImplementation() public returns (uint) {
        // Check caller is pendingImplementation and pendingImplementation ≠ address(0)
        if (msg.sender != pendingComptrollerImplementation || pendingComptrollerImplementation == address(0)) {
            return fail(Error.UNAUTHORIZED, FailureInfo.ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK);
        }

        // Save current values for inclusion in log
        address oldImplementation = comptrollerImplementation;
        address oldPendingImplementation = pendingComptrollerImplementation;

        comptrollerImplementation = pendingComptrollerImplementation;

        pendingComptrollerImplementation = address(0);

        emit NewImplementation(oldImplementation, comptrollerImplementation);
        emit NewPendingImplementation(oldPendingImplementation, pendingComptrollerImplementation);

        return uint(Error.NO_ERROR);
    }


    /**
      * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.
      * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.
      * @param newPendingAdmin New pending admin.
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function _setPendingAdmin(address newPendingAdmin) public returns (uint) {
        // Check caller = admin
        if (msg.sender != admin) {
            return fail(Error.UNAUTHORIZED, FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK);
        }

        // Save current value, if any, for inclusion in log
        address oldPendingAdmin = pendingAdmin;

        // Store pendingAdmin with value newPendingAdmin
        pendingAdmin = newPendingAdmin;

        // Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin)
        emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin);

        return uint(Error.NO_ERROR);
    }

    /**
      * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin
      * @dev Admin function for pending admin to accept role and update admin
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function _acceptAdmin() public returns (uint) {
        // Check caller is pendingAdmin and pendingAdmin ≠ address(0)
        if (msg.sender != pendingAdmin || msg.sender == address(0)) {
            return fail(Error.UNAUTHORIZED, FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK);
        }

        // Save current values for inclusion in log
        address oldAdmin = admin;
        address oldPendingAdmin = pendingAdmin;

        // Store admin with value pendingAdmin
        admin = pendingAdmin;

        // Clear the pending value
        pendingAdmin = address(0);

        emit NewAdmin(oldAdmin, admin);
        emit NewPendingAdmin(oldPendingAdmin, pendingAdmin);

        return uint(Error.NO_ERROR);
    }

    /**
     * @dev Delegates execution to an implementation contract.
     * It returns to the external caller whatever the implementation returns
     * or forwards reverts.
     */
    function () external payable {
        // delegate all other functions to current implementation
        (bool success, ) = comptrollerImplementation.delegatecall(msg.data);

        assembly {
              let free_mem_ptr := mload(0x40)
              returndatacopy(free_mem_ptr, 0, returndatasize)

              switch success
              case 0 { revert(free_mem_ptr, returndatasize) }
              default { return(free_mem_ptr, returndatasize) }
        }
    }
}

// File: contracts/Governance/XBID.sol

pragma solidity ^0.5.16;

contract Owned {

    address public owner;

    event OwnershipTransferred(address indexed _from, address indexed _to);

    constructor() public {
        owner = msg.sender;
    }

    modifier onlyOwner {
        require(msg.sender == owner, "Should be owner");
        _;
    }

    function transferOwnership(address newOwner) public onlyOwner {
        owner = newOwner;
        emit OwnershipTransferred(owner, newOwner);
    }
}

contract Tokenlock is Owned {
    /// @notice Indicates if token is locked
    uint8 isLocked = 0;

    event Freezed();
    event UnFreezed();

    modifier validLock {
        require(isLocked == 0, "Token is locked");
        _;
    }

    function freeze() public onlyOwner {
        isLocked = 1;

        emit Freezed();
    }

    function unfreeze() public onlyOwner {
        isLocked = 0;

        emit UnFreezed();
    }
}

contract XBID is Tokenlock {
    /// @notice BEP-20 token name for this token
    string public constant name = "Bidao";

    /// @notice BEP-20 token symbol for this token
    string public constant symbol = "XBID";

    /// @notice BEP-20 token decimals for this token
    uint8 public constant decimals = 18;

    /// @notice Total number of tokens in circulation
    uint public constant totalSupply = 30000000e18; // 30 million XBID

    /// @notice Allowance amounts on behalf of others
    mapping (address => mapping (address => uint96)) internal allowances;

    /// @notice Official record of token balances for each account
    mapping (address => uint96) internal balances;

    /// @notice A record of each accounts delegate
    mapping (address => address) public delegates;

    /// @notice A checkpoint for marking number of votes from a given block
    struct Checkpoint {
        uint32 fromBlock;
        uint96 votes;
    }

    /// @notice A record of votes checkpoints for each account, by index
    mapping (address => mapping (uint32 => Checkpoint)) public checkpoints;

    /// @notice The number of checkpoints for each account
    mapping (address => uint32) public numCheckpoints;

    /// @notice The EIP-712 typehash for the contract's domain
    bytes32 public constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)");

    /// @notice The EIP-712 typehash for the delegation struct used by the contract
    bytes32 public constant DELEGATION_TYPEHASH = keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");

    /// @notice A record of states for signing / validating signatures
    mapping (address => uint) public nonces;

    /// @notice An event thats emitted when an account changes its delegate
    event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);

    /// @notice An event thats emitted when a delegate account's vote balance changes
    event DelegateVotesChanged(address indexed delegate, uint previousBalance, uint newBalance);

    /// @notice The standard BEP-20 transfer event
    event Transfer(address indexed from, address indexed to, uint256 amount);

    /// @notice The standard BEP-20 approval event
    event Approval(address indexed owner, address indexed spender, uint256 amount);

    /**
     * @notice Construct a new XBID token
     * @param account The initial account to grant all the tokens
     */
    constructor(address account) public {
        balances[account] = uint96(totalSupply);
        emit Transfer(address(0), account, totalSupply);
    }

    /**
     * @notice Get the number of tokens `spender` is approved to spend on behalf of `account`
     * @param account The address of the account holding the funds
     * @param spender The address of the account spending the funds
     * @return The number of tokens approved
     */
    function allowance(address account, address spender) external view returns (uint) {
        return allowances[account][spender];
    }

    /**
     * @notice Approve `spender` to transfer up to `amount` from `src`
     * @dev This will overwrite the approval amount for `spender`
     * @param spender The address of the account which may transfer tokens
     * @param rawAmount The number of tokens that are approved (2^256-1 means infinite)
     * @return Whether or not the approval succeeded
     */
    function approve(address spender, uint rawAmount) external validLock returns (bool) {
        uint96 amount;
        if (rawAmount == uint(-1)) {
            amount = uint96(-1);
        } else {
            amount = safe96(rawAmount, "XBID::approve: amount exceeds 96 bits");
        }

        allowances[msg.sender][spender] = amount;

        emit Approval(msg.sender, spender, amount);
        return true;
    }

    /**
     * @notice Get the number of tokens held by the `account`
     * @param account The address of the account to get the balance of
     * @return The number of tokens held
     */
    function balanceOf(address account) external view returns (uint) {
        return balances[account];
    }

    /**
     * @notice Transfer `amount` tokens from `msg.sender` to `dst`
     * @param dst The address of the destination account
     * @param rawAmount The number of tokens to transfer
     * @return Whether or not the transfer succeeded
     */
    function transfer(address dst, uint rawAmount) external validLock returns (bool) {
        uint96 amount = safe96(rawAmount, "XBID::transfer: amount exceeds 96 bits");
        _transferTokens(msg.sender, dst, amount);
        return true;
    }

    /**
     * @notice Transfer `amount` tokens from `src` to `dst`
     * @param src The address of the source account
     * @param dst The address of the destination account
     * @param rawAmount The number of tokens to transfer
     * @return Whether or not the transfer succeeded
     */
    function transferFrom(address src, address dst, uint rawAmount) external validLock returns (bool) {
        address spender = msg.sender;
        uint96 spenderAllowance = allowances[src][spender];
        uint96 amount = safe96(rawAmount, "XBID::approve: amount exceeds 96 bits");

        if (spender != src && spenderAllowance != uint96(-1)) {
            uint96 newAllowance = sub96(spenderAllowance, amount, "XBID::transferFrom: transfer amount exceeds spender allowance");
            allowances[src][spender] = newAllowance;

            emit Approval(src, spender, newAllowance);
        }

        _transferTokens(src, dst, amount);
        return true;
    }

    /**
     * @notice Delegate votes from `msg.sender` to `delegatee`
     * @param delegatee The address to delegate votes to
     */
    function delegate(address delegatee) public validLock {
        return _delegate(msg.sender, delegatee);
    }

    /**
     * @notice Delegates votes from signatory to `delegatee`
     * @param delegatee The address to delegate votes to
     * @param nonce The contract state required to match the signature
     * @param expiry The time at which to expire the signature
     * @param v The recovery byte of the signature
     * @param r Half of the ECDSA signature pair
     * @param s Half of the ECDSA signature pair
     */
    function delegateBySig(address delegatee, uint nonce, uint expiry, uint8 v, bytes32 r, bytes32 s) public validLock {
        bytes32 domainSeparator = keccak256(abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name)), getChainId(), address(this)));
        bytes32 structHash = keccak256(abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry));
        bytes32 digest = keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
        address signatory = ecrecover(digest, v, r, s);
        require(signatory != address(0), "XBID::delegateBySig: invalid signature");
        require(nonce == nonces[signatory]++, "XBID::delegateBySig: invalid nonce");
        require(now <= expiry, "XBID::delegateBySig: signature expired");
        return _delegate(signatory, delegatee);
    }

    /**
     * @notice Gets the current votes balance for `account`
     * @param account The address to get votes balance
     * @return The number of current votes for `account`
     */
    function getCurrentVotes(address account) external view returns (uint96) {
        uint32 nCheckpoints = numCheckpoints[account];
        return nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0;
    }

    /**
     * @notice Determine the prior number of votes for an account as of a block number
     * @dev Block number must be a finalized block or else this function will revert to prevent misinformation.
     * @param account The address of the account to check
     * @param blockNumber The block number to get the vote balance at
     * @return The number of votes the account had as of the given block
     */
    function getPriorVotes(address account, uint blockNumber) public view returns (uint96) {
        require(blockNumber < block.number, "XBID::getPriorVotes: not yet determined");

        uint32 nCheckpoints = numCheckpoints[account];
        if (nCheckpoints == 0) {
            return 0;
        }

        // First check most recent balance
        if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) {
            return checkpoints[account][nCheckpoints - 1].votes;
        }

        // Next check implicit zero balance
        if (checkpoints[account][0].fromBlock > blockNumber) {
            return 0;
        }

        uint32 lower = 0;
        uint32 upper = nCheckpoints - 1;
        while (upper > lower) {
            uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow
            Checkpoint memory cp = checkpoints[account][center];
            if (cp.fromBlock == blockNumber) {
                return cp.votes;
            } else if (cp.fromBlock < blockNumber) {
                lower = center;
            } else {
                upper = center - 1;
            }
        }
        return checkpoints[account][lower].votes;
    }

    function _delegate(address delegator, address delegatee) internal {
        address currentDelegate = delegates[delegator];
        uint96 delegatorBalance = balances[delegator];
        delegates[delegator] = delegatee;

        emit DelegateChanged(delegator, currentDelegate, delegatee);

        _moveDelegates(currentDelegate, delegatee, delegatorBalance);
    }

    function _transferTokens(address src, address dst, uint96 amount) internal {
        require(src != address(0), "XBID::_transferTokens: cannot transfer from the zero address");
        require(dst != address(0), "XBID::_transferTokens: cannot transfer to the zero address");

        balances[src] = sub96(balances[src], amount, "XBID::_transferTokens: transfer amount exceeds balance");
        balances[dst] = add96(balances[dst], amount, "XBID::_transferTokens: transfer amount overflows");
        emit Transfer(src, dst, amount);

        _moveDelegates(delegates[src], delegates[dst], amount);
    }

    function _moveDelegates(address srcRep, address dstRep, uint96 amount) internal {
        if (srcRep != dstRep && amount > 0) {
            if (srcRep != address(0)) {
                uint32 srcRepNum = numCheckpoints[srcRep];
                uint96 srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].votes : 0;
                uint96 srcRepNew = sub96(srcRepOld, amount, "XBID::_moveVotes: vote amount underflows");
                _writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew);
            }

            if (dstRep != address(0)) {
                uint32 dstRepNum = numCheckpoints[dstRep];
                uint96 dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].votes : 0;
                uint96 dstRepNew = add96(dstRepOld, amount, "XBID::_moveVotes: vote amount overflows");
                _writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew);
            }
        }
    }

    function _writeCheckpoint(address delegatee, uint32 nCheckpoints, uint96 oldVotes, uint96 newVotes) internal {
      uint32 blockNumber = safe32(block.number, "XBID::_writeCheckpoint: block number exceeds 32 bits");

      if (nCheckpoints > 0 && checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber) {
          checkpoints[delegatee][nCheckpoints - 1].votes = newVotes;
      } else {
          checkpoints[delegatee][nCheckpoints] = Checkpoint(blockNumber, newVotes);
          numCheckpoints[delegatee] = nCheckpoints + 1;
      }

      emit DelegateVotesChanged(delegatee, oldVotes, newVotes);
    }

    function safe32(uint n, string memory errorMessage) internal pure returns (uint32) {
        require(n < 2**32, errorMessage);
        return uint32(n);
    }

    function safe96(uint n, string memory errorMessage) internal pure returns (uint96) {
        require(n < 2**96, errorMessage);
        return uint96(n);
    }

    function add96(uint96 a, uint96 b, string memory errorMessage) internal pure returns (uint96) {
        uint96 c = a + b;
        require(c >= a, errorMessage);
        return c;
    }

    function sub96(uint96 a, uint96 b, string memory errorMessage) internal pure returns (uint96) {
        require(b <= a, errorMessage);
        return a - b;
    }

    function getChainId() internal pure returns (uint) {
        uint256 chainId;
        assembly { chainId := chainid() }
        return chainId;
    }
}

// File: contracts/BAI/lib.sol

// SPDX-License-Identifier: AGPL-3.0-or-later

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity >=0.5.16;

contract LibNote {
    event LogNote(
        bytes4   indexed  sig,
        address  indexed  usr,
        bytes32  indexed  arg1,
        bytes32  indexed  arg2,
        bytes             data
    ) anonymous;

    modifier note {
        _;
        assembly {
            // log an 'anonymous' event with a constant 6 words of calldata
            // and four indexed topics: selector, caller, arg1 and arg2
            let mark := msize()                       // end of memory ensures zero
            mstore(0x40, add(mark, 288))              // update free memory pointer
            mstore(mark, 0x20)                        // bytes type data offset
            mstore(add(mark, 0x20), 224)              // bytes size (padded)
            calldatacopy(add(mark, 0x40), 0, 224)     // bytes payload
            log4(mark, 288,                           // calldata
                 shl(224, shr(224, calldataload(0))), // msg.sig
                 caller(),                            // msg.sender
                 calldataload(4),                     // arg1
                 calldataload(36)                     // arg2
                )
        }
    }
}

// File: contracts/BAI/BAI.sol

// SPDX-License-Identifier: AGPL-3.0-or-later

// Copyright (C) 2017, 2018, 2019 dbrock, rain, mrchico

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

pragma solidity >=0.5.16;


contract BAI is LibNote {
    // --- Auth ---
    mapping (address => uint) public wards;
    function rely(address guy) external note auth { wards[guy] = 1; }
    function deny(address guy) external note auth { wards[guy] = 0; }
    modifier auth {
        require(wards[msg.sender] == 1, "BAI/not-authorized");
        _;
    }

    // --- BEP20 Data ---
    string  public constant name     = "BAI Stablecoin";
    string  public constant symbol   = "BAI";
    string  public constant version  = "1";
    uint8   public constant decimals = 18;
    uint256 public totalSupply;

    mapping (address => uint)                      public balanceOf;
    mapping (address => mapping (address => uint)) public allowance;
    mapping (address => uint)                      public nonces;

    event Approval(address indexed src, address indexed guy, uint wad);
    event Transfer(address indexed src, address indexed dst, uint wad);

    // --- Math ---
    function add(uint x, uint y) internal pure returns (uint z) {
        require((z = x + y) >= x, "BAI math error");
    }
    function sub(uint x, uint y) internal pure returns (uint z) {
        require((z = x - y) <= x, "BAI math error");
    }

    // --- EIP712 niceties ---
    bytes32 public DOMAIN_SEPARATOR;
    // bytes32 public constant PERMIT_TYPEHASH = keccak256("Permit(address holder,address spender,uint256 nonce,uint256 expiry,bool allowed)");
    bytes32 public constant PERMIT_TYPEHASH = 0xea2aa0a1be11a07ed86d755c93467f4f82362b452371d1ba94d1715123511acb;

    constructor(uint256 chainId_) public {
        wards[msg.sender] = 1;
        DOMAIN_SEPARATOR = keccak256(abi.encode(
            keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
            keccak256(bytes(name)),
            keccak256(bytes(version)),
            chainId_,
            address(this)
        ));
    }

    // --- Token ---
    function transfer(address dst, uint wad) external returns (bool) {
        return transferFrom(msg.sender, dst, wad);
    }
    function transferFrom(address src, address dst, uint wad)
        public returns (bool)
    {
        require(balanceOf[src] >= wad, "BAI/insufficient-balance");
        if (src != msg.sender && allowance[src][msg.sender] != uint(-1)) {
            require(allowance[src][msg.sender] >= wad, "BAI/insufficient-allowance");
            allowance[src][msg.sender] = sub(allowance[src][msg.sender], wad);
        }
        balanceOf[src] = sub(balanceOf[src], wad);
        balanceOf[dst] = add(balanceOf[dst], wad);
        emit Transfer(src, dst, wad);
        return true;
    }
    function mint(address usr, uint wad) external auth {
        balanceOf[usr] = add(balanceOf[usr], wad);
        totalSupply = add(totalSupply, wad);
        emit Transfer(address(0), usr, wad);
    }
    function burn(address usr, uint wad) external {
        require(balanceOf[usr] >= wad, "BAI/insufficient-balance");
        if (usr != msg.sender && allowance[usr][msg.sender] != uint(-1)) {
            require(allowance[usr][msg.sender] >= wad, "BAI/insufficient-allowance");
            allowance[usr][msg.sender] = sub(allowance[usr][msg.sender], wad);
        }
        balanceOf[usr] = sub(balanceOf[usr], wad);
        totalSupply = sub(totalSupply, wad);
        emit Transfer(usr, address(0), wad);
    }
    function approve(address usr, uint wad) external returns (bool) {
        allowance[msg.sender][usr] = wad;
        emit Approval(msg.sender, usr, wad);
        return true;
    }

    // --- Alias ---
    function push(address usr, uint wad) external {
        transferFrom(msg.sender, usr, wad);
    }
    function pull(address usr, uint wad) external {
        transferFrom(usr, msg.sender, wad);
    }
    function move(address src, address dst, uint wad) external {
        transferFrom(src, dst, wad);
    }

    // --- Approve by signature ---
    function permit(address holder, address spender, uint256 nonce, uint256 expiry,
                    bool allowed, uint8 v, bytes32 r, bytes32 s) external
    {
        bytes32 digest = keccak256(abi.encodePacked(
                "\x19\x01",
                DOMAIN_SEPARATOR,
                keccak256(abi.encode(PERMIT_TYPEHASH,
                                     holder,
                                     spender,
                                     nonce,
                                     expiry,
                                     allowed))
        ));

        require(holder != address(0), "BAI/invalid-address-0");
        require(holder == ecrecover(digest, v, r, s), "BAI/invalid-permit");
        require(expiry == 0 || now <= expiry, "BAI/permit-expired");
        require(nonce == nonces[holder]++, "BAI/invalid-nonce");
        uint wad = allowed ? uint(-1) : 0;
        allowance[holder][spender] = wad;
        emit Approval(holder, spender, wad);
    }
}

// File: contracts/Comptroller.sol

pragma solidity ^0.5.16;









/**
 * @title Bidao's Comptroller Contract
 * @author Bidao
 */
contract Comptroller is ComptrollerV4Storage, ComptrollerInterfaceG2, ComptrollerErrorReporter, ExponentialNoError {
    /// @notice Emitted when an admin supports a market
    event MarketListed(BToken bToken);

    /// @notice Emitted when an account enters a market
    event MarketEntered(BToken bToken, address account);

    /// @notice Emitted when an account exits a market
    event MarketExited(BToken bToken, address account);

    /// @notice Emitted when close factor is changed by admin
    event NewCloseFactor(uint oldCloseFactorMantissa, uint newCloseFactorMantissa);

    /// @notice Emitted when a collateral factor is changed by admin
    event NewCollateralFactor(BToken bToken, uint oldCollateralFactorMantissa, uint newCollateralFactorMantissa);

    /// @notice Emitted when liquidation incentive is changed by admin
    event NewLiquidationIncentive(uint oldLiquidationIncentiveMantissa, uint newLiquidationIncentiveMantissa);

    /// @notice Emitted when price oracle is changed
    event NewPriceOracle(PriceOracle oldPriceOracle, PriceOracle newPriceOracle);

    /// @notice Emitted when BAI Vault info is changed
    event NewBAIVaultInfo(address vault_, uint releaseStartBlock_, uint releaseInterval_);

    /// @notice Emitted when pause guardian is changed
    event NewPauseGuardian(address oldPauseGuardian, address newPauseGuardian);

    /// @notice Emitted when an action is paused globally
    event ActionPaused(string action, bool pauseState);

    /// @notice Emitted when an action is paused on a market
    event ActionPaused(BToken bToken, string action, bool pauseState);

    /// @notice Emitted when Bidao BAI rate is changed
    event NewBidaoBAIRate(uint oldBidaoBAIRate, uint newBidaoBAIRate);

    /// @notice Emitted when Bidao BAI Vault rate is changed
    event NewBidaoBAIVaultRate(uint oldBidaoBAIVaultRate, uint newBidaoBAIVaultRate);

    /// @notice Emitted when a new Bidao speed is calculated for a market
    event BidaoSpeedUpdated(BToken indexed bToken, uint newSpeed);

    /// @notice Emitted when XBID is distributed to a supplier
    event DistributedSupplierBidao(BToken indexed bToken, address indexed supplier, uint bidaoDelta, uint bidaoSupplyIndex);

    /// @notice Emitted when XBID is distributed to a borrower
    event DistributedBorrowerBidao(BToken indexed bToken, address indexed borrower, uint bidaoDelta, uint bidaoBorrowIndex);

    /// @notice Emitted when XBID is distributed to a BAI minter
    event DistributedBAIMinterBidao(address indexed vaiMinter, uint bidaoDelta, uint bidaoBAIMintIndex);

    /// @notice Emitted when XBID is distributed to BAI Vault
    event DistributedBAIVaultBidao(uint amount);

    /// @notice Emitted when BAIController is changed
    event NewBAIController(BAIControllerInterface oldBAIController, BAIControllerInterface newBAIController);

    /// @notice Emitted when BAI mint rate is changed by admin
    event NewBAIMintRate(uint oldBAIMintRate, uint newBAIMintRate);

    /// @notice Emitted when protocol state is changed by admin
    event ActionProtocolPaused(bool state);

    /// @notice Emitted when borrow cap for a bToken is changed
    event NewBorrowCap(BToken indexed bToken, uint newBorrowCap);

    /// @notice Emitted when borrow cap guardian is changed
    event NewBorrowCapGuardian(address oldBorrowCapGuardian, address newBorrowCapGuardian);

    /// @notice Emitted when treasury guardian is changed
    event NewTreasuryGuardian(address oldTreasuryGuardian, address newTreasuryGuardian);

    /// @notice Emitted when treasury address is changed
    event NewTreasuryAddress(address oldTreasuryAddress, address newTreasuryAddress);

    /// @notice Emitted when treasury percent is changed
    event NewTreasuryPercent(uint oldTreasuryPercent, uint newTreasuryPercent);

    /// @notice The initial Bidao index for a market
    uint224 public constant bidaoInitialIndex = 1e36;

    // closeFactorMantissa must be strictly greater than this value
    uint internal constant closeFactorMinMantissa = 0.05e18; // 0.05

    // closeFactorMantissa must not exceed this value
    uint internal constant closeFactorMaxMantissa = 0.9e18; // 0.9

    // No collateralFactorMantissa may exceed this value
    uint internal constant collateralFactorMaxMantissa = 0.9e18; // 0.9

    constructor() public {
        admin = msg.sender;
    }

    modifier onlyProtocolAllowed {
        require(!protocolPaused, "protocol is paused");
        _;
    }

    modifier onlyAdmin() {
        require(msg.sender == admin, "only admin can");
        _;
    }

    modifier onlyListedMarket(BToken bToken) {
        require(markets[address(bToken)].isListed, "bidao market is not listed");
        _;
    }

    modifier validPauseState(bool state) {
        require(msg.sender == pauseGuardian || msg.sender == admin, "only pause guardian and admin can");
        require(msg.sender == admin || state == true, "only admin can unpause");
        _;
    }

    /*** Assets You Are In ***/

    /**
     * @notice Returns the assets an account has entered
     * @param account The address of the account to pull assets for
     * @return A dynamic list with the assets the account has entered
     */
    function getAssetsIn(address account) external view returns (BToken[] memory) {
        return accountAssets[account];
    }

    /**
     * @notice Returns whether the given account is entered in the given asset
     * @param account The address of the account to check
     * @param bToken The bToken to check
     * @return True if the account is in the asset, otherwise false.
     */
    function checkMembership(address account, BToken bToken) external view returns (bool) {
        return markets[address(bToken)].accountMembership[account];
    }

    /**
     * @notice Add assets to be included in account liquidity calculation
     * @param bTokens The list of addresses of the bToken markets to be enabled
     * @return Success indicator for whether each corresponding market was entered
     */
    function enterMarkets(address[] calldata bTokens) external returns (uint[] memory) {
        uint len = bTokens.length;

        uint[] memory results = new uint[](len);
        for (uint i = 0; i < len; i++) {
            results[i] = uint(addToMarketInternal(BToken(bTokens[i]), msg.sender));
        }

        return results;
    }

    /**
     * @notice Add the market to the borrower's "assets in" for liquidity calculations
     * @param bToken The market to enter
     * @param borrower The address of the account to modify
     * @return Success indicator for whether the market was entered
     */
    function addToMarketInternal(BToken bToken, address borrower) internal returns (Error) {
        Market storage marketToJoin = markets[address(bToken)];

        if (!marketToJoin.isListed) {
            // market is not listed, cannot join
            return Error.MARKET_NOT_LISTED;
        }

        if (marketToJoin.accountMembership[borrower]) {
            // already joined
            return Error.NO_ERROR;
        }

        // survived the gauntlet, add to list
        // NOTE: we store these somewhat redundantly as a significant optimization
        //  this avoids having to iterate through the list for the most common use cases
        //  that is, only when we need to perform liquidity checks
        //  and not whenever we want to check if an account is in a particular market
        marketToJoin.accountMembership[borrower] = true;
        accountAssets[borrower].push(bToken);

        emit MarketEntered(bToken, borrower);

        return Error.NO_ERROR;
    }

    /**
     * @notice Removes asset from sender's account liquidity calculation
     * @dev Sender must not have an outstanding borrow balance in the asset,
     *  or be providing necessary collateral for an outstanding borrow.
     * @param bTokenAddress The address of the asset to be removed
     * @return Whether or not the account successfully exited the market
     */
    function exitMarket(address bTokenAddress) external returns (uint) {
        BToken bToken = BToken(bTokenAddress);
        /* Get sender tokensHeld and amountOwed underlying from the bToken */
        (uint oErr, uint tokensHeld, uint amountOwed, ) = bToken.getAccountSnapshot(msg.sender);
        require(oErr == 0, "getAccountSnapshot failed"); // semi-opaque error code

        /* Fail if the sender has a borrow balance */
        if (amountOwed != 0) {
            return fail(Error.NONZERO_BORROW_BALANCE, FailureInfo.EXIT_MARKET_BALANCE_OWED);
        }

        /* Fail if the sender is not permitted to redeem all of their tokens */
        uint allowed = redeemAllowedInternal(bTokenAddress, msg.sender, tokensHeld);
        if (allowed != 0) {
            return failOpaque(Error.REJECTION, FailureInfo.EXIT_MARKET_REJECTION, allowed);
        }

        Market storage marketToExit = markets[address(bToken)];

        /* Return true if the sender is not already ‘in’ the market */
        if (!marketToExit.accountMembership[msg.sender]) {
            return uint(Error.NO_ERROR);
        }

        /* Set bToken account membership to false */
        delete marketToExit.accountMembership[msg.sender];

        /* Delete bToken from the account’s list of assets */
        // In order to delete bToken, copy last item in list to location of item to be removed, reduce length by 1
        BToken[] storage userAssetList = accountAssets[msg.sender];
        uint len = userAssetList.length;
        uint i;
        for (; i < len; i++) {
            if (userAssetList[i] == bToken) {
                userAssetList[i] = userAssetList[len - 1];
                userAssetList.length--;
                break;
            }
        }

        // We *must* have found the asset in the list or our redundant data structure is broken
        assert(i < len);

        emit MarketExited(bToken, msg.sender);

        return uint(Error.NO_ERROR);
    }

    /*** Policy Hooks ***/

    /**
     * @notice Checks if the account should be allowed to mint tokens in the given market
     * @param bToken The market to verify the mint against
     * @param minter The account which would get the minted tokens
     * @param mintAmount The amount of underlying being supplied to the market in exchange for tokens
     * @return 0 if the mint is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)
     */
    function mintAllowed(address bToken, address minter, uint mintAmount) external onlyProtocolAllowed returns (uint) {
        // Pausing is a very serious situation - we revert to sound the alarms
        require(!mintGuardianPaused[bToken], "mint is paused");

        // Shh - currently unused
        mintAmount;

        if (!markets[bToken].isListed) {
            return uint(Error.MARKET_NOT_LISTED);
        }

        // Keep the flywheel moving
        updateBidaoSupplyIndex(bToken);
        distributeSupplierBidao(bToken, minter);

        return uint(Error.NO_ERROR);
    }

    /**
     * @notice Validates mint and reverts on rejection. May emit logs.
     * @param bToken Asset being minted
     * @param minter The address minting the tokens
     * @param actualMintAmount The amount of the underlying asset being minted
     * @param mintTokens The number of tokens being minted
     */
    function mintVerify(address bToken, address minter, uint actualMintAmount, uint mintTokens) external {
        // Shh - currently unused
        bToken;
        minter;
        actualMintAmount;
        mintTokens;
    }

    /**
     * @notice Checks if the account should be allowed to redeem tokens in the given market
     * @param bToken The market to verify the redeem against
     * @param redeemer The account which would redeem the tokens
     * @param redeemTokens The number of bTokens to exchange for the underlying asset in the market
     * @return 0 if the redeem is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)
     */
    function redeemAllowed(address bToken, address redeemer, uint redeemTokens) external onlyProtocolAllowed returns (uint) {
        uint allowed = redeemAllowedInternal(bToken, redeemer, redeemTokens);
        if (allowed != uint(Error.NO_ERROR)) {
            return allowed;
        }

        // Keep the flywheel moving
        updateBidaoSupplyIndex(bToken);
        distributeSupplierBidao(bToken, redeemer);

        return uint(Error.NO_ERROR);
    }

    function redeemAllowedInternal(address bToken, address redeemer, uint redeemTokens) internal view returns (uint) {
        if (!markets[bToken].isListed) {
            return uint(Error.MARKET_NOT_LISTED);
        }

        /* If the redeemer is not 'in' the market, then we can bypass the liquidity check */
        if (!markets[bToken].accountMembership[redeemer]) {
            return uint(Error.NO_ERROR);
        }

        /* Otherwise, perform a hypothetical liquidity check to guard against shortfall */
        (Error err, , uint shortfall) = getHypotheticalAccountLiquidityInternal(redeemer, BToken(bToken), redeemTokens, 0);
        if (err != Error.NO_ERROR) {
            return uint(err);
        }
        if (shortfall != 0) {
            return uint(Error.INSUFFICIENT_LIQUIDITY);
        }

        return uint(Error.NO_ERROR);
    }

    /**
     * @notice Validates redeem and reverts on rejection. May emit logs.
     * @param bToken Asset being redeemed
     * @param redeemer The address redeeming the tokens
     * @param redeemAmount The amount of the underlying asset being redeemed
     * @param redeemTokens The number of tokens being redeemed
     */
    function redeemVerify(address bToken, address redeemer, uint redeemAmount, uint redeemTokens) external {
        // Shh - currently unused
        bToken;
        redeemer;

        // Require tokens is zero or amount is also zero
        require(redeemTokens != 0 || redeemAmount == 0, "redeemTokens zero");
    }

    /**
     * @notice Checks if the account should be allowed to borrow the underlying asset of the given market
     * @param bToken The market to verify the borrow against
     * @param borrower The account which would borrow the asset
     * @param borrowAmount The amount of underlying the account would borrow
     * @return 0 if the borrow is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)
     */
    function borrowAllowed(address bToken, address borrower, uint borrowAmount) external onlyProtocolAllowed returns (uint) {
        // Pausing is a very serious situation - we revert to sound the alarms
        require(!borrowGuardianPaused[bToken], "borrow is paused");

        if (!markets[bToken].isListed) {
            return uint(Error.MARKET_NOT_LISTED);
        }

        if (!markets[bToken].accountMembership[borrower]) {
            // only bTokens may call borrowAllowed if borrower not in market
            require(msg.sender == bToken, "sender must be bToken");

            // attempt to add borrower to the market
            Error err = addToMarketInternal(BToken(bToken), borrower);
            if (err != Error.NO_ERROR) {
                return uint(err);
            }
        }

        if (oracle.getUnderlyingPrice(BToken(bToken)) == 0) {
            return uint(Error.PRICE_ERROR);
        }

        uint borrowCap = borrowCaps[bToken];
        // Borrow cap of 0 corresponds to unlimited borrowing
        if (borrowCap != 0) {
            uint totalBorrows = BToken(bToken).totalBorrows();
            uint nextTotalBorrows = add_(totalBorrows, borrowAmount);
            require(nextTotalBorrows < borrowCap, "market borrow cap reached");
        }

        (Error err, , uint shortfall) = getHypotheticalAccountLiquidityInternal(borrower, BToken(bToken), 0, borrowAmount);
        if (err != Error.NO_ERROR) {
            return uint(err);
        }
        if (shortfall != 0) {
            return uint(Error.INSUFFICIENT_LIQUIDITY);
        }

        // Keep the flywheel moving
        Exp memory borrowIndex = Exp({mantissa: BToken(bToken).borrowIndex()});
        updateBidaoBorrowIndex(bToken, borrowIndex);
        distributeBorrowerBidao(bToken, borrower, borrowIndex);

        return uint(Error.NO_ERROR);
    }

    /**
     * @notice Validates borrow and reverts on rejection. May emit logs.
     * @param bToken Asset whose underlying is being borrowed
     * @param borrower The address borrowing the underlying
     * @param borrowAmount The amount of the underlying asset requested to borrow
     */
    function borrowVerify(address bToken, address borrower, uint borrowAmount) external {
        // Shh - currently unused
        bToken;
        borrower;
        borrowAmount;

        // Shh - we don't ever want this hook to be marked pure
        if (false) {
            maxAssets = maxAssets;
        }
    }

    /**
     * @notice Checks if the account should be allowed to repay a borrow in the given market
     * @param bToken The market to verify the repay against
     * @param payer The account which would repay the asset
     * @param borrower The account which would repay the asset
     * @param repayAmount The amount of the underlying asset the account would repay
     * @return 0 if the repay is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)
     */
    function repayBorrowAllowed(
        address bToken,
        address payer,
        address borrower,
        uint repayAmount) external onlyProtocolAllowed returns (uint) {
        // Shh - currently unused
        payer;
        borrower;
        repayAmount;

        if (!markets[bToken].isListed) {
            return uint(Error.MARKET_NOT_LISTED);
        }

        // Keep the flywheel moving
        Exp memory borrowIndex = Exp({mantissa: BToken(bToken).borrowIndex()});
        updateBidaoBorrowIndex(bToken, borrowIndex);
        distributeBorrowerBidao(bToken, borrower, borrowIndex);

        return uint(Error.NO_ERROR);
    }

    /**
     * @notice Validates repayBorrow and reverts on rejection. May emit logs.
     * @param bToken Asset being repaid
     * @param payer The address repaying the borrow
     * @param borrower The address of the borrower
     * @param actualRepayAmount The amount of underlying being repaid
     */
    function repayBorrowVerify(
        address bToken,
        address payer,
        address borrower,
        uint actualRepayAmount,
        uint borrowerIndex) external {
        // Shh - currently unused
        bToken;
        payer;
        borrower;
        actualRepayAmount;
        borrowerIndex;

        // Shh - we don't ever want this hook to be marked pure
        if (false) {
            maxAssets = maxAssets;
        }
    }

    /**
     * @notice Checks if the liquidation should be allowed to occur
     * @param bTokenBorrowed Asset which was borrowed by the borrower
     * @param bTokenCollateral Asset which was used as collateral and will be seized
     * @param liquidator The address repaying the borrow and seizing the collateral
     * @param borrower The address of the borrower
     * @param repayAmount The amount of underlying being repaid
     */
    function liquidateBorrowAllowed(
        address bTokenBorrowed,
        address bTokenCollateral,
        address liquidator,
        address borrower,
        uint repayAmount) external onlyProtocolAllowed returns (uint) {
        // Shh - currently unused
        liquidator;

        if (!(markets[bTokenBorrowed].isListed || address(bTokenBorrowed) == address(baiController)) || !markets[bTokenCollateral].isListed) {
            return uint(Error.MARKET_NOT_LISTED);
        }

        /* The borrower must have shortfall in order to be liquidatable */
        (Error err, , uint shortfall) = getHypotheticalAccountLiquidityInternal(borrower, BToken(0), 0, 0);
        if (err != Error.NO_ERROR) {
            return uint(err);
        }
        if (shortfall == 0) {
            return uint(Error.INSUFFICIENT_SHORTFALL);
        }

        /* The liquidator may not repay more than what is allowed by the closeFactor */
        uint borrowBalance;
        if (address(bTokenBorrowed) != address(baiController)) {
            borrowBalance = BToken(bTokenBorrowed).borrowBalanceStored(borrower);
        } else {
            borrowBalance = mintedBAIs[borrower];
        }

        uint maxClose = mul_ScalarTruncate(Exp({mantissa: closeFactorMantissa}), borrowBalance);
        if (repayAmount > maxClose) {
            return uint(Error.TOO_MUCH_REPAY);
        }

        return uint(Error.NO_ERROR);
    }

    /**
     * @notice Validates liquidateBorrow and reverts on rejection. May emit logs.
     * @param bTokenBorrowed Asset which was borrowed by the borrower
     * @param bTokenCollateral Asset which was used as collateral and will be seized
     * @param liquidator The address repaying the borrow and seizing the collateral
     * @param borrower The address of the borrower
     * @param actualRepayAmount The amount of underlying being repaid
     */
    function liquidateBorrowVerify(
        address bTokenBorrowed,
        address bTokenCollateral,
        address liquidator,
        address borrower,
        uint actualRepayAmount,
        uint seizeTokens) external {
        // Shh - currently unused
        bTokenBorrowed;
        bTokenCollateral;
        liquidator;
        borrower;
        actualRepayAmount;
        seizeTokens;

        // Shh - we don't ever want this hook to be marked pure
        if (false) {
            maxAssets = maxAssets;
        }
    }

    /**
     * @notice Checks if the seizing of assets should be allowed to occur
     * @param bTokenCollateral Asset which was used as collateral and will be seized
     * @param bTokenBorrowed Asset which was borrowed by the borrower
     * @param liquidator The address repaying the borrow and seizing the collateral
     * @param borrower The address of the borrower
     * @param seizeTokens The number of collateral tokens to seize
     */
    function seizeAllowed(
        address bTokenCollateral,
        address bTokenBorrowed,
        address liquidator,
        address borrower,
        uint seizeTokens) external onlyProtocolAllowed returns (uint) {
        // Pausing is a very serious situation - we revert to sound the alarms
        require(!seizeGuardianPaused, "seize is paused");

        // Shh - currently unused
        seizeTokens;

        // We've added BAIController as a borrowed token list check for seize
        if (!markets[bTokenCollateral].isListed || !(markets[bTokenBorrowed].isListed || address(bTokenBorrowed) == address(baiController))) {
            return uint(Error.MARKET_NOT_LISTED);
        }

        if (BToken(bTokenCollateral).comptroller() != BToken(bTokenBorrowed).comptroller()) {
            return uint(Error.COMPTROLLER_MISMATCH);
        }

        // Keep the flywheel moving
        updateBidaoSupplyIndex(bTokenCollateral);
        distributeSupplierBidao(bTokenCollateral, borrower);
        distributeSupplierBidao(bTokenCollateral, liquidator);

        return uint(Error.NO_ERROR);
    }

    /**
     * @notice Validates seize and reverts on rejection. May emit logs.
     * @param bTokenCollateral Asset which was used as collateral and will be seized
     * @param bTokenBorrowed Asset which was borrowed by the borrower
     * @param liquidator The address repaying the borrow and seizing the collateral
     * @param borrower The address of the borrower
     * @param seizeTokens The number of collateral tokens to seize
     */
    function seizeVerify(
        address bTokenCollateral,
        address bTokenBorrowed,
        address liquidator,
        address borrower,
        uint seizeTokens) external {
        // Shh - currently unused
        bTokenCollateral;
        bTokenBorrowed;
        liquidator;
        borrower;
        seizeTokens;

        // Shh - we don't ever want this hook to be marked pure
        if (false) {
            maxAssets = maxAssets;
        }
    }

    /**
     * @notice Checks if the account should be allowed to transfer tokens in the given market
     * @param bToken The market to verify the transfer against
     * @param src The account which sources the tokens
     * @param dst The account which receives the tokens
     * @param transferTokens The number of bTokens to transfer
     * @return 0 if the transfer is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)
     */
    function transferAllowed(address bToken, address src, address dst, uint transferTokens) external onlyProtocolAllowed returns (uint) {
        // Pausing is a very serious situation - we revert to sound the alarms
        require(!transferGuardianPaused, "transfer is paused");

        // Currently the only consideration is whether or not
        //  the src is allowed to redeem this many tokens
        uint allowed = redeemAllowedInternal(bToken, src, transferTokens);
        if (allowed != uint(Error.NO_ERROR)) {
            return allowed;
        }

        // Keep the flywheel moving
        updateBidaoSupplyIndex(bToken);
        distributeSupplierBidao(bToken, src);
        distributeSupplierBidao(bToken, dst);

        return uint(Error.NO_ERROR);
    }

    /**
     * @notice Validates transfer and reverts on rejection. May emit logs.
     * @param bToken Asset being transferred
     * @param src The account which sources the tokens
     * @param dst The account which receives the tokens
     * @param transferTokens The number of bTokens to transfer
     */
    function transferVerify(address bToken, address src, address dst, uint transferTokens) external {
        // Shh - currently unused
        bToken;
        src;
        dst;
        transferTokens;

        // Shh - we don't ever want this hook to be marked pure
        if (false) {
            maxAssets = maxAssets;
        }
    }

    /*** Liquidity/Liquidation Calculations ***/

    /**
     * @dev Local vars for avoiding stack-depth limits in calculating account liquidity.
     *  Note that `bTokenBalance` is the number of bTokens the account owns in the market,
     *  whereas `borrowBalance` is the amount of underlying that the account has borrowed.
     */
    struct AccountLiquidityLocalVars {
        uint sumCollateral;
        uint sumBorrowPlusEffects;
        uint bTokenBalance;
        uint borrowBalance;
        uint exchangeRateMantissa;
        uint oraclePriceMantissa;
        Exp collateralFactor;
        Exp exchangeRate;
        Exp oraclePrice;
        Exp tokensToDenom;
    }

    /**
     * @notice Determine the current account liquidity wrt collateral requirements
     * @return (possible error code (semi-opaque),
                account liquidity in excess of collateral requirements,
     *          account shortfall below collateral requirements)
     */
    function getAccountLiquidity(address account) public view returns (uint, uint, uint) {
        (Error err, uint liquidity, uint shortfall) = getHypotheticalAccountLiquidityInternal(account, BToken(0), 0, 0);

        return (uint(err), liquidity, shortfall);
    }

    /**
     * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed
     * @param bTokenModify The market to hypothetically redeem/borrow in
     * @param account The account to determine liquidity for
     * @param redeemTokens The number of tokens to hypothetically redeem
     * @param borrowAmount The amount of underlying to hypothetically borrow
     * @return (possible error code (semi-opaque),
                hypothetical account liquidity in excess of collateral requirements,
     *          hypothetical account shortfall below collateral requirements)
     */
    function getHypotheticalAccountLiquidity(
        address account,
        address bTokenModify,
        uint redeemTokens,
        uint borrowAmount) public view returns (uint, uint, uint) {
        (Error err, uint liquidity, uint shortfall) = getHypotheticalAccountLiquidityInternal(account, BToken(bTokenModify), redeemTokens, borrowAmount);
        return (uint(err), liquidity, shortfall);
    }

    /**
     * @notice Determine what the account liquidity would be if the given amounts were redeemed/borrowed
     * @param bTokenModify The market to hypothetically redeem/borrow in
     * @param account The account to determine liquidity for
     * @param redeemTokens The number of tokens to hypothetically redeem
     * @param borrowAmount The amount of underlying to hypothetically borrow
     * @dev Note that we calculate the exchangeRateStored for each collateral bToken using stored data,
     *  without calculating accumulated interest.
     * @return (possible error code,
                hypothetical account liquidity in excess of collateral requirements,
     *          hypothetical account shortfall below collateral requirements)
     */
    function getHypotheticalAccountLiquidityInternal(
        address account,
        BToken bTokenModify,
        uint redeemTokens,
        uint borrowAmount) internal view returns (Error, uint, uint) {

        AccountLiquidityLocalVars memory vars; // Holds all our calculation results
        uint oErr;

        // For each asset the account is in
        BToken[] memory assets = accountAssets[account];
        for (uint i = 0; i < assets.length; i++) {
            BToken asset = assets[i];

            // Read the balances and exchange rate from the bToken
            (oErr, vars.bTokenBalance, vars.borrowBalance, vars.exchangeRateMantissa) = asset.getAccountSnapshot(account);
            if (oErr != 0) { // semi-opaque error code, we assume NO_ERROR == 0 is invariant between upgrades
                return (Error.SNAPSHOT_ERROR, 0, 0);
            }
            vars.collateralFactor = Exp({mantissa: markets[address(asset)].collateralFactorMantissa});
            vars.exchangeRate = Exp({mantissa: vars.exchangeRateMantissa});

            // Get the normalized price of the asset
            vars.oraclePriceMantissa = oracle.getUnderlyingPrice(asset);
            if (vars.oraclePriceMantissa == 0) {
                return (Error.PRICE_ERROR, 0, 0);
            }
            vars.oraclePrice = Exp({mantissa: vars.oraclePriceMantissa});

            // Pre-compute a conversion factor from tokens -> bnb (normalized price value)
            vars.tokensToDenom = mul_(mul_(vars.collateralFactor, vars.exchangeRate), vars.oraclePrice);

            // sumCollateral += tokensToDenom * bTokenBalance
            vars.sumCollateral = mul_ScalarTruncateAddUInt(vars.tokensToDenom, vars.bTokenBalance, vars.sumCollateral);

            // sumBorrowPlusEffects += oraclePrice * borrowBalance
            vars.sumBorrowPlusEffects = mul_ScalarTruncateAddUInt(vars.oraclePrice, vars.borrowBalance, vars.sumBorrowPlusEffects);

            // Calculate effects of interacting with bTokenModify
            if (asset == bTokenModify) {
                // redeem effect
                // sumBorrowPlusEffects += tokensToDenom * redeemTokens
                vars.sumBorrowPlusEffects = mul_ScalarTruncateAddUInt(vars.tokensToDenom, redeemTokens, vars.sumBorrowPlusEffects);

                // borrow effect
                // sumBorrowPlusEffects += oraclePrice * borrowAmount
                vars.sumBorrowPlusEffects = mul_ScalarTruncateAddUInt(vars.oraclePrice, borrowAmount, vars.sumBorrowPlusEffects);
            }
        }

        vars.sumBorrowPlusEffects = add_(vars.sumBorrowPlusEffects, mintedBAIs[account]);

        // These are safe, as the underflow condition is checked first
        if (vars.sumCollateral > vars.sumBorrowPlusEffects) {
            return (Error.NO_ERROR, vars.sumCollateral - vars.sumBorrowPlusEffects, 0);
        } else {
            return (Error.NO_ERROR, 0, vars.sumBorrowPlusEffects - vars.sumCollateral);
        }
    }

    /**
     * @notice Calculate number of tokens of collateral asset to seize given an underlying amount
     * @dev Used in liquidation (called in bToken.liquidateBorrowFresh)
     * @param bTokenBorrowed The address of the borrowed bToken
     * @param bTokenCollateral The address of the collateral bToken
     * @param actualRepayAmount The amount of bTokenBorrowed underlying to convert into bTokenCollateral tokens
     * @return (errorCode, number of bTokenCollateral tokens to be seized in a liquidation)
     */
    function liquidateCalculateSeizeTokens(address bTokenBorrowed, address bTokenCollateral, uint actualRepayAmount) external view returns (uint, uint) {
        /* Read oracle prices for borrowed and collateral markets */
        uint priceBorrowedMantissa = oracle.getUnderlyingPrice(BToken(bTokenBorrowed));
        uint priceCollateralMantissa = oracle.getUnderlyingPrice(BToken(bTokenCollateral));
        if (priceBorrowedMantissa == 0 || priceCollateralMantissa == 0) {
            return (uint(Error.PRICE_ERROR), 0);
        }

        /*
         * Get the exchange rate and calculate the number of collateral tokens to seize:
         *  seizeAmount = actualRepayAmount * liquidationIncentive * priceBorrowed / priceCollateral
         *  seizeTokens = seizeAmount / exchangeRate
         *   = actualRepayAmount * (liquidationIncentive * priceBorrowed) / (priceCollateral * exchangeRate)
         */
        uint exchangeRateMantissa = BToken(bTokenCollateral).exchangeRateStored(); // Note: reverts on error
        uint seizeTokens;
        Exp memory numerator;
        Exp memory denominator;
        Exp memory ratio;

        numerator = mul_(Exp({mantissa: liquidationIncentiveMantissa}), Exp({mantissa: priceBorrowedMantissa}));
        denominator = mul_(Exp({mantissa: priceCollateralMantissa}), Exp({mantissa: exchangeRateMantissa}));
        ratio = div_(numerator, denominator);

        seizeTokens = mul_ScalarTruncate(ratio, actualRepayAmount);

        return (uint(Error.NO_ERROR), seizeTokens);
    }

    /**
     * @notice Calculate number of tokens of collateral asset to seize given an underlying amount
     * @dev Used in liquidation (called in bToken.liquidateBorrowFresh)
     * @param bTokenCollateral The address of the collateral bToken
     * @param actualRepayAmount The amount of bTokenBorrowed underlying to convert into bTokenCollateral tokens
     * @return (errorCode, number of bTokenCollateral tokens to be seized in a liquidation)
     */
    function liquidateBAICalculateSeizeTokens(address bTokenCollateral, uint actualRepayAmount) external view returns (uint, uint) {
        /* Read oracle prices for borrowed and collateral markets */
        uint priceBorrowedMantissa = 1e18;  // Note: this is BAI
        uint priceCollateralMantissa = oracle.getUnderlyingPrice(BToken(bTokenCollateral));
        if (priceCollateralMantissa == 0) {
            return (uint(Error.PRICE_ERROR), 0);
        }

        /*
         * Get the exchange rate and calculate the number of collateral tokens to seize:
         *  seizeAmount = actualRepayAmount * liquidationIncentive * priceBorrowed / priceCollateral
         *  seizeTokens = seizeAmount / exchangeRate
         *   = actualRepayAmount * (liquidationIncentive * priceBorrowed) / (priceCollateral * exchangeRate)
         */
        uint exchangeRateMantissa = BToken(bTokenCollateral).exchangeRateStored(); // Note: reverts on error
        uint seizeTokens;
        Exp memory numerator;
        Exp memory denominator;
        Exp memory ratio;

        numerator = mul_(Exp({mantissa: liquidationIncentiveMantissa}), Exp({mantissa: priceBorrowedMantissa}));
        denominator = mul_(Exp({mantissa: priceCollateralMantissa}), Exp({mantissa: exchangeRateMantissa}));
        ratio = div_(numerator, denominator);

        seizeTokens = mul_ScalarTruncate(ratio, actualRepayAmount);

        return (uint(Error.NO_ERROR), seizeTokens);
    }

    /*** Admin Functions ***/

    /**
      * @notice Sets a new price oracle for the comptroller
      * @dev Admin function to set a new price oracle
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function _setPriceOracle(PriceOracle newOracle) public returns (uint) {
        // Check caller is admin
        if (msg.sender != admin) {
            return fail(Error.UNAUTHORIZED, FailureInfo.SET_PRICE_ORACLE_OWNER_CHECK);
        }

        // Track the old oracle for the comptroller
        PriceOracle oldOracle = oracle;

        // Set comptroller's oracle to newOracle
        oracle = newOracle;

        // Emit NewPriceOracle(oldOracle, newOracle)
        emit NewPriceOracle(oldOracle, newOracle);

        return uint(Error.NO_ERROR);
    }

    /**
      * @notice Sets the closeFactor used when liquidating borrows
      * @dev Admin function to set closeFactor
      * @param newCloseFactorMantissa New close factor, scaled by 1e18
      * @return uint 0=success, otherwise a failure
      */
    function _setCloseFactor(uint newCloseFactorMantissa) external returns (uint) {
        // Check caller is admin
    	require(msg.sender == admin, "only admin can set close factor");

        uint oldCloseFactorMantissa = closeFactorMantissa;
        closeFactorMantissa = newCloseFactorMantissa;
        emit NewCloseFactor(oldCloseFactorMantissa, newCloseFactorMantissa);

        return uint(Error.NO_ERROR);
    }

    /**
      * @notice Sets the collateralFactor for a market
      * @dev Admin function to set per-market collateralFactor
      * @param bToken The market to set the factor on
      * @param newCollateralFactorMantissa The new collateral factor, scaled by 1e18
      * @return uint 0=success, otherwise a failure. (See ErrorReporter for details)
      */
    function _setCollateralFactor(BToken bToken, uint newCollateralFactorMantissa) external returns (uint) {
        // Check caller is admin
        if (msg.sender != admin) {
            return fail(Error.UNAUTHORIZED, FailureInfo.SET_COLLATERAL_FACTOR_OWNER_CHECK);
        }

        // Verify market is listed
        Market storage market = markets[address(bToken)];
        if (!market.isListed) {
            return fail(Error.MARKET_NOT_LISTED, FailureInfo.SET_COLLATERAL_FACTOR_NO_EXISTS);
        }

        Exp memory newCollateralFactorExp = Exp({mantissa: newCollateralFactorMantissa});

        // Check collateral factor <= 0.9
        Exp memory highLimit = Exp({mantissa: collateralFactorMaxMantissa});
        if (lessThanExp(highLimit, newCollateralFactorExp)) {
            return fail(Error.INVALID_COLLATERAL_FACTOR, FailureInfo.SET_COLLATERAL_FACTOR_VALIDATION);
        }

        // If collateral factor != 0, fail if price == 0
        if (newCollateralFactorMantissa != 0 && oracle.getUnderlyingPrice(bToken) == 0) {
            return fail(Error.PRICE_ERROR, FailureInfo.SET_COLLATERAL_FACTOR_WITHOUT_PRICE);
        }

        // Set market's collateral factor to new collateral factor, remember old value
        uint oldCollateralFactorMantissa = market.collateralFactorMantissa;
        market.collateralFactorMantissa = newCollateralFactorMantissa;

        // Emit event with asset, old collateral factor, and new collateral factor
        emit NewCollateralFactor(bToken, oldCollateralFactorMantissa, newCollateralFactorMantissa);

        return uint(Error.NO_ERROR);
    }

    /**
      * @notice Sets liquidationIncentive
      * @dev Admin function to set liquidationIncentive
      * @param newLiquidationIncentiveMantissa New liquidationIncentive scaled by 1e18
      * @return uint 0=success, otherwise a failure. (See ErrorReporter for details)
      */
    function _setLiquidationIncentive(uint newLiquidationIncentiveMantissa) external returns (uint) {
        // Check caller is admin
        if (msg.sender != admin) {
            return fail(Error.UNAUTHORIZED, FailureInfo.SET_LIQUIDATION_INCENTIVE_OWNER_CHECK);
        }

        // Save current value for use in log
        uint oldLiquidationIncentiveMantissa = liquidationIncentiveMantissa;

        // Set liquidation incentive to new incentive
        liquidationIncentiveMantissa = newLiquidationIncentiveMantissa;

        // Emit event with old incentive, new incentive
        emit NewLiquidationIncentive(oldLiquidationIncentiveMantissa, newLiquidationIncentiveMantissa);

        return uint(Error.NO_ERROR);
    }

    /**
      * @notice Add the market to the markets mapping and set it as listed
      * @dev Admin function to set isListed and add support for the market
      * @param bToken The address of the market (token) to list
      * @return uint 0=success, otherwise a failure. (See enum Error for details)
      */
    function _supportMarket(BToken bToken) external returns (uint) {
        if (msg.sender != admin) {
            return fail(Error.UNAUTHORIZED, FailureInfo.SUPPORT_MARKET_OWNER_CHECK);
        }

        if (markets[address(bToken)].isListed) {
            return fail(Error.MARKET_ALREADY_LISTED, FailureInfo.SUPPORT_MARKET_EXISTS);
        }

        bToken.isBToken(); // Sanity check to make sure its really a BToken

        // Note that isBidao is not in active use anymore
        markets[address(bToken)] = Market({isListed: true, isBidao: false, collateralFactorMantissa: 0});

        _addMarketInternal(bToken);

        emit MarketListed(bToken);

        return uint(Error.NO_ERROR);
    }

    function _addMarketInternal(BToken bToken) internal {
        for (uint i = 0; i < allMarkets.length; i ++) {
            require(allMarkets[i] != bToken, "market already added");
        }
        allMarkets.push(bToken);
    }

    /**
     * @notice Admin function to change the Pause Guardian
     * @param newPauseGuardian The address of the new Pause Guardian
     * @return uint 0=success, otherwise a failure. (See enum Error for details)
     */
    function _setPauseGuardian(address newPauseGuardian) public returns (uint) {
        if (msg.sender != admin) {
            return fail(Error.UNAUTHORIZED, FailureInfo.SET_PAUSE_GUARDIAN_OWNER_CHECK);
        }

        // Save current value for inclusion in log
        address oldPauseGuardian = pauseGuardian;

        // Store pauseGuardian with value newPauseGuardian
        pauseGuardian = newPauseGuardian;

        // Emit NewPauseGuardian(OldPauseGuardian, NewPauseGuardian)
        emit NewPauseGuardian(oldPauseGuardian, newPauseGuardian);

        return uint(Error.NO_ERROR);
    }

    /**
      * @notice Set the given borrow caps for the given bToken markets. Borrowing that brings total borrows to or above borrow cap will revert.
      * @dev Admin or borrowCapGuardian function to set the borrow caps. A borrow cap of 0 corresponds to unlimited borrowing.
      * @param bTokens The addresses of the markets (tokens) to change the borrow caps for
      * @param newBorrowCaps The new borrow cap values in underlying to be set. A value of 0 corresponds to unlimited borrowing.
      */
    function _setMarketBorrowCaps(BToken[] calldata bTokens, uint[] calldata newBorrowCaps) external {
        require(msg.sender == admin || msg.sender == borrowCapGuardian, "only admin or borrow cap guardian can set borrow caps");

        uint numMarkets = bTokens.length;
        uint numBorrowCaps = newBorrowCaps.length;

        require(numMarkets != 0 && numMarkets == numBorrowCaps, "invalid input");

        for(uint i = 0; i < numMarkets; i++) {
            borrowCaps[address(bTokens[i])] = newBorrowCaps[i];
            emit NewBorrowCap(bTokens[i], newBorrowCaps[i]);
        }
    }

    /**
     * @notice Admin function to change the Borrow Cap Guardian
     * @param newBorrowCapGuardian The address of the new Borrow Cap Guardian
     */
    function _setBorrowCapGuardian(address newBorrowCapGuardian) external onlyAdmin {
        // Save current value for inclusion in log
        address oldBorrowCapGuardian = borrowCapGuardian;

        // Store borrowCapGuardian with value newBorrowCapGuardian
        borrowCapGuardian = newBorrowCapGuardian;

        // Emit NewBorrowCapGuardian(OldBorrowCapGuardian, NewBorrowCapGuardian)
        emit NewBorrowCapGuardian(oldBorrowCapGuardian, newBorrowCapGuardian);
    }

    /**
     * @notice Set whole protocol pause/unpause state
     */
    function _setProtocolPaused(bool state) public validPauseState(state) returns(bool) {
        protocolPaused = state;
        emit ActionProtocolPaused(state);
        return state;
    }

    /**
      * @notice Sets a new BAI controller
      * @dev Admin function to set a new BAI controller
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function _setBAIController(BAIControllerInterface baiController_) external returns (uint) {
        // Check caller is admin
        if (msg.sender != admin) {
            return fail(Error.UNAUTHORIZED, FailureInfo.SET_BAICONTROLLER_OWNER_CHECK);
        }

        BAIControllerInterface oldRate = baiController;
        baiController = baiController_;
        emit NewBAIController(oldRate, baiController_);
    }

    function _setBAIMintRate(uint newBAIMintRate) external returns (uint) {
        // Check caller is admin
        if (msg.sender != admin) {
            return fail(Error.UNAUTHORIZED, FailureInfo.SET_BAI_MINT_RATE_CHECK);
        }

        uint oldBAIMintRate = vaiMintRate;
        vaiMintRate = newBAIMintRate;
        emit NewBAIMintRate(oldBAIMintRate, newBAIMintRate);

        return uint(Error.NO_ERROR);
    }

    function _setTreasuryData(address newTreasuryGuardian, address newTreasuryAddress, uint newTreasuryPercent) external returns (uint) {
        // Check caller is admin
        if (!(msg.sender == admin || msg.sender == treasuryGuardian)) {
            return fail(Error.UNAUTHORIZED, FailureInfo.SET_TREASURY_OWNER_CHECK);
        }

        require(newTreasuryPercent < 1e18, "treasury percent cap overflow");

        address oldTreasuryGuardian = treasuryGuardian;
        address oldTreasuryAddress = treasuryAddress;
        uint oldTreasuryPercent = treasuryPercent;

        treasuryGuardian = newTreasuryGuardian;
        treasuryAddress = newTreasuryAddress;
        treasuryPercent = newTreasuryPercent;

        emit NewTreasuryGuardian(oldTreasuryGuardian, newTreasuryGuardian);
        emit NewTreasuryAddress(oldTreasuryAddress, newTreasuryAddress);
        emit NewTreasuryPercent(oldTreasuryPercent, newTreasuryPercent);

        return uint(Error.NO_ERROR);
    }

    function _become(Unitroller unitroller) public {
        require(msg.sender == unitroller.admin(), "only unitroller admin can");
        require(unitroller._acceptImplementation() == 0, "not authorized");
    }

    /**
     * @notice Checks caller is admin, or this contract is becoming the new implementation
     */
    function adminOrInitializing() internal view returns (bool) {
        return msg.sender == admin || msg.sender == comptrollerImplementation;
    }

    /*** Bidao Distribution ***/

    function setBidaoSpeedInternal(BToken bToken, uint bidaoSpeed) internal {
        uint currentBidaoSpeed = bidaoSpeeds[address(bToken)];
        if (currentBidaoSpeed != 0) {
            // note that XBID speed could be set to 0 to halt liquidity rewards for a market
            Exp memory borrowIndex = Exp({mantissa: bToken.borrowIndex()});
            updateBidaoSupplyIndex(address(bToken));
            updateBidaoBorrowIndex(address(bToken), borrowIndex);
        } else if (bidaoSpeed != 0) {
            // Add the XBID market
            Market storage market = markets[address(bToken)];
            require(market.isListed == true, "bidao market is not listed");

            if (bidaoSupplyState[address(bToken)].index == 0 && bidaoSupplyState[address(bToken)].block == 0) {
                bidaoSupplyState[address(bToken)] = BidaoMarketState({
                    index: bidaoInitialIndex,
                    block: safe32(getBlockNumber(), "block number exceeds 32 bits")
                });
            }


        if (bidaoBorrowState[address(bToken)].index == 0 && bidaoBorrowState[address(bToken)].block == 0) {
                bidaoBorrowState[address(bToken)] = BidaoMarketState({
                    index: bidaoInitialIndex,
                    block: safe32(getBlockNumber(), "block number exceeds 32 bits")
                });
            }
        }

        if (currentBidaoSpeed != bidaoSpeed) {
            bidaoSpeeds[address(bToken)] = bidaoSpeed;
            emit BidaoSpeedUpdated(bToken, bidaoSpeed);
        }
    }

    /**
     * @notice Accrue XBID to the market by updating the supply index
     * @param bToken The market whose supply index to update
     */
    function updateBidaoSupplyIndex(address bToken) internal {
        BidaoMarketState storage supplyState = bidaoSupplyState[bToken];
        uint supplySpeed = bidaoSpeeds[bToken];
        uint blockNumber = getBlockNumber();
        uint deltaBlocks = sub_(blockNumber, uint(supplyState.block));
        if (deltaBlocks > 0 && supplySpeed > 0) {
            uint supplyTokens = BToken(bToken).totalSupply();
            uint bidaoAccrued = mul_(deltaBlocks, supplySpeed);
            Double memory ratio = supplyTokens > 0 ? fraction(bidaoAccrued, supplyTokens) : Double({mantissa: 0});
            Double memory index = add_(Double({mantissa: supplyState.index}), ratio);
            bidaoSupplyState[bToken] = BidaoMarketState({
                index: safe224(index.mantissa, "new index overflows"),
                block: safe32(blockNumber, "block number overflows")
            });
        } else if (deltaBlocks > 0) {
            supplyState.block = safe32(blockNumber, "block number overflows");
        }
    }

    /**
     * @notice Accrue XBID to the market by updating the borrow index
     * @param bToken The market whose borrow index to update
     */
    function updateBidaoBorrowIndex(address bToken, Exp memory marketBorrowIndex) internal {
        BidaoMarketState storage borrowState = bidaoBorrowState[bToken];
        uint borrowSpeed = bidaoSpeeds[bToken];
        uint blockNumber = getBlockNumber();
        uint deltaBlocks = sub_(blockNumber, uint(borrowState.block));
        if (deltaBlocks > 0 && borrowSpeed > 0) {
            uint borrowAmount = div_(BToken(bToken).totalBorrows(), marketBorrowIndex);
            uint bidaoAccrued = mul_(deltaBlocks, borrowSpeed);
            Double memory ratio = borrowAmount > 0 ? fraction(bidaoAccrued, borrowAmount) : Double({mantissa: 0});
            Double memory index = add_(Double({mantissa: borrowState.index}), ratio);
            bidaoBorrowState[bToken] = BidaoMarketState({
                index: safe224(index.mantissa, "new index overflows"),
                block: safe32(blockNumber, "block number overflows")
            });
        } else if (deltaBlocks > 0) {
            borrowState.block = safe32(blockNumber, "block number overflows");
        }
    }

    /**
     * @notice Calculate XBID accrued by a supplier and possibly transfer it to them
     * @param bToken The market in which the supplier is interacting
     * @param supplier The address of the supplier to distribute XBID to
     */
    function distributeSupplierBidao(address bToken, address supplier) internal {
        if (address(vaiVaultAddress) != address(0)) {
            releaseToVault();
        }

        BidaoMarketState storage supplyState = bidaoSupplyState[bToken];
        Double memory supplyIndex = Double({mantissa: supplyState.index});
        Double memory supplierIndex = Double({mantissa: bidaoSupplierIndex[bToken][supplier]});
        bidaoSupplierIndex[bToken][supplier] = supplyIndex.mantissa;

        if (supplierIndex.mantissa == 0 && supplyIndex.mantissa > 0) {
            supplierIndex.mantissa = bidaoInitialIndex;
        }

        Double memory deltaIndex = sub_(supplyIndex, supplierIndex);
        uint supplierTokens = BToken(bToken).balanceOf(supplier);
        uint supplierDelta = mul_(supplierTokens, deltaIndex);
        uint supplierAccrued = add_(bidaoAccrued[supplier], supplierDelta);
        bidaoAccrued[supplier] = supplierAccrued;
        emit DistributedSupplierBidao(BToken(bToken), supplier, supplierDelta, supplyIndex.mantissa);
    }

    /**
     * @notice Calculate XBID accrued by a borrower and possibly transfer it to them
     * @dev Borrowers will not begin to accrue until after the first interaction with the protocol.
     * @param bToken The market in which the borrower is interacting
     * @param borrower The address of the borrower to distribute XBID to
     */
    function distributeBorrowerBidao(address bToken, address borrower, Exp memory marketBorrowIndex) internal {
        if (address(vaiVaultAddress) != address(0)) {
            releaseToVault();
        }

        BidaoMarketState storage borrowState = bidaoBorrowState[bToken];
        Double memory borrowIndex = Double({mantissa: borrowState.index});
        Double memory borrowerIndex = Double({mantissa: bidaoBorrowerIndex[bToken][borrower]});
        bidaoBorrowerIndex[bToken][borrower] = borrowIndex.mantissa;

        if (borrowerIndex.mantissa > 0) {
            Double memory deltaIndex = sub_(borrowIndex, borrowerIndex);
            uint borrowerAmount = div_(BToken(bToken).borrowBalanceStored(borrower), marketBorrowIndex);
            uint borrowerDelta = mul_(borrowerAmount, deltaIndex);
            uint borrowerAccrued = add_(bidaoAccrued[borrower], borrowerDelta);
            bidaoAccrued[borrower] = borrowerAccrued;
            emit DistributedBorrowerBidao(BToken(bToken), borrower, borrowerDelta, borrowIndex.mantissa);
        }
    }

    /**
     * @notice Calculate XBID accrued by a BAI minter and possibly transfer it to them
     * @dev BAI minters will not begin to accrue until after the first interaction with the protocol.
     * @param vaiMinter The address of the BAI minter to distribute XBID to
     */
    function distributeBAIMinterBidao(address vaiMinter) public {
        if (address(vaiVaultAddress) != address(0)) {
            releaseToVault();
        }

        if (address(baiController) != address(0)) {
            uint vaiMinterAccrued;
            uint vaiMinterDelta;
            uint vaiMintIndexMantissa;
            uint err;
            (err, vaiMinterAccrued, vaiMinterDelta, vaiMintIndexMantissa) = baiController.calcDistributeBAIMinterBidao(vaiMinter);
            if (err == uint(Error.NO_ERROR)) {
                bidaoAccrued[vaiMinter] = vaiMinterAccrued;
                emit DistributedBAIMinterBidao(vaiMinter, vaiMinterDelta, vaiMintIndexMantissa);
            }
        }
    }

    /**
     * @notice Claim all the xvs accrued by holder in all markets and BAI
     * @param holder The address to claim XBID for
     */
    function claimBidao(address holder) public {
        return claimBidao(holder, allMarkets);
    }

    /**
     * @notice Claim all the xvs accrued by holder in the specified markets
     * @param holder The address to claim XBID for
     * @param bTokens The list of markets to claim XBID in
     */
    function claimBidao(address holder, BToken[] memory bTokens) public {
        address[] memory holders = new address[](1);
        holders[0] = holder;
        claimBidao(holders, bTokens, true, true);
    }

    /**
     * @notice Claim all xvs accrued by the holders
     * @param holders The addresses to claim XBID for
     * @param bTokens The list of markets to claim XBID in
     * @param borrowers Whether or not to claim XBID earned by borrowing
     * @param suppliers Whether or not to claim XBID earned by supplying
     */
    function claimBidao(address[] memory holders, BToken[] memory bTokens, bool borrowers, bool suppliers) public {
        uint j;
        if(address(baiController) != address(0)) {
            baiController.updateBidaoBAIMintIndex();
        }
        for (j = 0; j < holders.length; j++) {
            distributeBAIMinterBidao(holders[j]);
            bidaoAccrued[holders[j]] = grantXBIDInternal(holders[j], bidaoAccrued[holders[j]]);
        }
        for (uint i = 0; i < bTokens.length; i++) {
            BToken bToken = bTokens[i];
            require(markets[address(bToken)].isListed, "not listed market");
            if (borrowers) {
                Exp memory borrowIndex = Exp({mantissa: bToken.borrowIndex()});
                updateBidaoBorrowIndex(address(bToken), borrowIndex);
                for (j = 0; j < holders.length; j++) {
                    distributeBorrowerBidao(address(bToken), holders[j], borrowIndex);
                    bidaoAccrued[holders[j]] = grantXBIDInternal(holders[j], bidaoAccrued[holders[j]]);
                }
            }
            if (suppliers) {
                updateBidaoSupplyIndex(address(bToken));
                for (j = 0; j < holders.length; j++) {
                    distributeSupplierBidao(address(bToken), holders[j]);
                    bidaoAccrued[holders[j]] = grantXBIDInternal(holders[j], bidaoAccrued[holders[j]]);
                }
            }
        }
    }

    /**
     * @notice Transfer XBID to the user
     * @dev Note: If there is not enough XBID, we do not perform the transfer all.
     * @param user The address of the user to transfer XBID to
     * @param amount The amount of XBID to (possibly) transfer
     * @return The amount of XBID which was NOT transferred to the user
     */
    function grantXBIDInternal(address user, uint amount) internal returns (uint) {
        XBID xvs = XBID(getXBIDAddress());
        uint bidaoRemaining = xvs.balanceOf(address(this));
        if (amount > 0 && amount <= bidaoRemaining) {
            xvs.transfer(user, amount);
            return 0;
        }
        return amount;
    }

    /*** Bidao Distribution Admin ***/

    /**
     * @notice Set the amount of XBID distributed per block to BAI Mint
     * @param bidaoBAIRate_ The amount of XBID wei per block to distribute to BAI Mint
     */
    function _setBidaoBAIRate(uint bidaoBAIRate_) public onlyAdmin {
        uint oldBAIRate = bidaoBAIRate;
        bidaoBAIRate = bidaoBAIRate_;
        emit NewBidaoBAIRate(oldBAIRate, bidaoBAIRate_);
    }

    /**
     * @notice Set the amount of XBID distributed per block to BAI Vault
     * @param bidaoBAIVaultRate_ The amount of XBID wei per block to distribute to BAI Vault
     */
    function _setBidaoBAIVaultRate(uint bidaoBAIVaultRate_) public onlyAdmin {
        uint oldBidaoBAIVaultRate = bidaoBAIVaultRate;
        bidaoBAIVaultRate = bidaoBAIVaultRate_;
        emit NewBidaoBAIVaultRate(oldBidaoBAIVaultRate, bidaoBAIVaultRate_);
    }

    /**
     * @notice Set the BAI Vault infos
     * @param vault_ The address of the BAI Vault
     * @param releaseStartBlock_ The start block of release to BAI Vault
     * @param minReleaseAmount_ The minimum release amount to BAI Vault
     */
    function _setBAIVaultInfo(address vault_, uint256 releaseStartBlock_, uint256 minReleaseAmount_) public onlyAdmin {
        vaiVaultAddress = vault_;
        releaseStartBlock = releaseStartBlock_;
        minReleaseAmount = minReleaseAmount_;
        emit NewBAIVaultInfo(vault_, releaseStartBlock_, minReleaseAmount_);
    }

    /**
     * @notice Set XBID speed for a single market
     * @param bToken The market whose XBID speed to update
     * @param bidaoSpeed New XBID speed for market
     */
    function _setBidaoSpeed(BToken bToken, uint bidaoSpeed) public {
        require(adminOrInitializing(), "only admin can set bidao speed");
        setBidaoSpeedInternal(bToken, bidaoSpeed);
    }

    /**
     * @notice Return all of the markets
     * @dev The automatic getter may be used to access an individual market.
     * @return The list of market addresses
     */
    function getAllMarkets() public view returns (BToken[] memory) {
        return allMarkets;
    }

    function getBlockNumber() public view returns (uint) {
        return block.number;
    }

    /**
     * @notice Return the address of the XBID token
     * @return The address of XBID
     */
    function getXBIDAddress() public view returns (address) {
        return 0x4502b7165187427F0e05be956edd892292683a93;
    }

    /*** BAI functions ***/

    /**
     * @notice Set the minted BAI amount of the `owner`
     * @param owner The address of the account to set
     * @param amount The amount of BAI to set to the account
     * @return The number of minted BAI by `owner`
     */
    function setMintedBAIOf(address owner, uint amount) external onlyProtocolAllowed returns (uint) {
        // Pausing is a very serious situation - we revert to sound the alarms
        require(!mintBAIGuardianPaused && !repayBAIGuardianPaused, "BAI is paused");
        // Check caller is baiController
        if (msg.sender != address(baiController)) {
            return fail(Error.REJECTION, FailureInfo.SET_MINTED_BAI_REJECTION);
        }
        mintedBAIs[owner] = amount;

        return uint(Error.NO_ERROR);
    }

    /**
     * @notice Transfer XBID to BAI Vault
     */
    function releaseToVault() public {
        if(releaseStartBlock == 0 || getBlockNumber() < releaseStartBlock) {
            return;
        }

        XBID xvs = XBID(getXBIDAddress());

        uint256 xvsBalance = xvs.balanceOf(address(this));
        if(xvsBalance == 0) {
            return;
        }


        uint256 actualAmount;
        uint256 deltaBlocks = sub_(getBlockNumber(), releaseStartBlock);
        // releaseAmount = bidaoBAIVaultRate * deltaBlocks
        uint256 _releaseAmount = mul_(bidaoBAIVaultRate, deltaBlocks);

        if (_releaseAmount < minReleaseAmount) {
            return;
        }

        if (xvsBalance >= _releaseAmount) {
            actualAmount = _releaseAmount;
        } else {
            actualAmount = xvsBalance;
        }

        releaseStartBlock = getBlockNumber();

        xvs.transfer(vaiVaultAddress, actualAmount);
        emit DistributedBAIVaultBidao(actualAmount);

        IBAIVault(vaiVaultAddress).updatePendingRewards();
    }
}

Contract ABI

[{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"action","type":"string"},{"indexed":false,"internalType":"bool","name":"pauseState","type":"bool"}],"name":"ActionPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract BToken","name":"bToken","type":"address"},{"indexed":false,"internalType":"string","name":"action","type":"string"},{"indexed":false,"internalType":"bool","name":"pauseState","type":"bool"}],"name":"ActionPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"state","type":"bool"}],"name":"ActionProtocolPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract BToken","name":"bToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"newSpeed","type":"uint256"}],"name":"BidaoSpeedUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vaiMinter","type":"address"},{"indexed":false,"internalType":"uint256","name":"bidaoDelta","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bidaoBAIMintIndex","type":"uint256"}],"name":"DistributedBAIMinterBidao","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"DistributedBAIVaultBidao","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract BToken","name":"bToken","type":"address"},{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"bidaoDelta","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bidaoBorrowIndex","type":"uint256"}],"name":"DistributedBorrowerBidao","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract BToken","name":"bToken","type":"address"},{"indexed":true,"internalType":"address","name":"supplier","type":"address"},{"indexed":false,"internalType":"uint256","name":"bidaoDelta","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bidaoSupplyIndex","type":"uint256"}],"name":"DistributedSupplierBidao","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"error","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"info","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"detail","type":"uint256"}],"name":"Failure","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract BToken","name":"bToken","type":"address"},{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"MarketEntered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract BToken","name":"bToken","type":"address"},{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"MarketExited","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract BToken","name":"bToken","type":"address"}],"name":"MarketListed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract BAIControllerInterface","name":"oldBAIController","type":"address"},{"indexed":false,"internalType":"contract BAIControllerInterface","name":"newBAIController","type":"address"}],"name":"NewBAIController","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldBAIMintRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newBAIMintRate","type":"uint256"}],"name":"NewBAIMintRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"vault_","type":"address"},{"indexed":false,"internalType":"uint256","name":"releaseStartBlock_","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"releaseInterval_","type":"uint256"}],"name":"NewBAIVaultInfo","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldBidaoBAIRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newBidaoBAIRate","type":"uint256"}],"name":"NewBidaoBAIRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldBidaoBAIVaultRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newBidaoBAIVaultRate","type":"uint256"}],"name":"NewBidaoBAIVaultRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract BToken","name":"bToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"newBorrowCap","type":"uint256"}],"name":"NewBorrowCap","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldBorrowCapGuardian","type":"address"},{"indexed":false,"internalType":"address","name":"newBorrowCapGuardian","type":"address"}],"name":"NewBorrowCapGuardian","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldCloseFactorMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCloseFactorMantissa","type":"uint256"}],"name":"NewCloseFactor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract BToken","name":"bToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"oldCollateralFactorMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCollateralFactorMantissa","type":"uint256"}],"name":"NewCollateralFactor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldLiquidationIncentiveMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newLiquidationIncentiveMantissa","type":"uint256"}],"name":"NewLiquidationIncentive","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldPauseGuardian","type":"address"},{"indexed":false,"internalType":"address","name":"newPauseGuardian","type":"address"}],"name":"NewPauseGuardian","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract PriceOracle","name":"oldPriceOracle","type":"address"},{"indexed":false,"internalType":"contract PriceOracle","name":"newPriceOracle","type":"address"}],"name":"NewPriceOracle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldTreasuryAddress","type":"address"},{"indexed":false,"internalType":"address","name":"newTreasuryAddress","type":"address"}],"name":"NewTreasuryAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldTreasuryGuardian","type":"address"},{"indexed":false,"internalType":"address","name":"newTreasuryGuardian","type":"address"}],"name":"NewTreasuryGuardian","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldTreasuryPercent","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTreasuryPercent","type":"uint256"}],"name":"NewTreasuryPercent","type":"event"},{"constant":false,"inputs":[{"internalType":"contract Unitroller","name":"unitroller","type":"address"}],"name":"_become","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"_borrowGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_mintGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"contract BAIControllerInterface","name":"baiController_","type":"address"}],"name":"_setBAIController","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"newBAIMintRate","type":"uint256"}],"name":"_setBAIMintRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"vault_","type":"address"},{"internalType":"uint256","name":"releaseStartBlock_","type":"uint256"},{"internalType":"uint256","name":"minReleaseAmount_","type":"uint256"}],"name":"_setBAIVaultInfo","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"bidaoBAIRate_","type":"uint256"}],"name":"_setBidaoBAIRate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"bidaoBAIVaultRate_","type":"uint256"}],"name":"_setBidaoBAIVaultRate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract BToken","name":"bToken","type":"address"},{"internalType":"uint256","name":"bidaoSpeed","type":"uint256"}],"name":"_setBidaoSpeed","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newBorrowCapGuardian","type":"address"}],"name":"_setBorrowCapGuardian","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"newCloseFactorMantissa","type":"uint256"}],"name":"_setCloseFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract BToken","name":"bToken","type":"address"},{"internalType":"uint256","name":"newCollateralFactorMantissa","type":"uint256"}],"name":"_setCollateralFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"newLiquidationIncentiveMantissa","type":"uint256"}],"name":"_setLiquidationIncentive","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract BToken[]","name":"bTokens","type":"address[]"},{"internalType":"uint256[]","name":"newBorrowCaps","type":"uint256[]"}],"name":"_setMarketBorrowCaps","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newPauseGuardian","type":"address"}],"name":"_setPauseGuardian","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract PriceOracle","name":"newOracle","type":"address"}],"name":"_setPriceOracle","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bool","name":"state","type":"bool"}],"name":"_setProtocolPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newTreasuryGuardian","type":"address"},{"internalType":"address","name":"newTreasuryAddress","type":"address"},{"internalType":"uint256","name":"newTreasuryPercent","type":"uint256"}],"name":"_setTreasuryData","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract BToken","name":"bToken","type":"address"}],"name":"_supportMarket","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"accountAssets","outputs":[{"internalType":"contract BToken","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"allMarkets","outputs":[{"internalType":"contract BToken","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"baiController","outputs":[{"internalType":"contract BAIControllerInterface","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"bidaoAccrued","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"bidaoBAIRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"bidaoBAIVaultRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"bidaoBorrowState","outputs":[{"internalType":"uint224","name":"index","type":"uint224"},{"internalType":"uint32","name":"block","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"bidaoBorrowerIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"bidaoInitialIndex","outputs":[{"internalType":"uint224","name":"","type":"uint224"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"bidaoRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"bidaoSpeeds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"bidaoSupplierIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"bidaoSupplyState","outputs":[{"internalType":"uint224","name":"index","type":"uint224"},{"internalType":"uint32","name":"block","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"bToken","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"name":"borrowAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"borrowCapGuardian","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"borrowCaps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"borrowGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"bToken","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"name":"borrowVerify","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"contract BToken","name":"bToken","type":"address"}],"name":"checkMembership","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"holder","type":"address"}],"name":"claimBidao","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"holder","type":"address"},{"internalType":"contract BToken[]","name":"bTokens","type":"address[]"}],"name":"claimBidao","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address[]","name":"holders","type":"address[]"},{"internalType":"contract BToken[]","name":"bTokens","type":"address[]"},{"internalType":"bool","name":"borrowers","type":"bool"},{"internalType":"bool","name":"suppliers","type":"bool"}],"name":"claimBidao","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"closeFactorMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"comptrollerImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"vaiMinter","type":"address"}],"name":"distributeBAIMinterBidao","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address[]","name":"bTokens","type":"address[]"}],"name":"enterMarkets","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"bTokenAddress","type":"address"}],"name":"exitMarket","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getAccountLiquidity","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getAllMarkets","outputs":[{"internalType":"contract BToken[]","name":"","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getAssetsIn","outputs":[{"internalType":"contract BToken[]","name":"","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"bTokenModify","type":"address"},{"internalType":"uint256","name":"redeemTokens","type":"uint256"},{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"name":"getHypotheticalAccountLiquidity","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getXBIDAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isComptroller","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"bTokenCollateral","type":"address"},{"internalType":"uint256","name":"actualRepayAmount","type":"uint256"}],"name":"liquidateBAICalculateSeizeTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"bTokenBorrowed","type":"address"},{"internalType":"address","name":"bTokenCollateral","type":"address"},{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"repayAmount","type":"uint256"}],"name":"liquidateBorrowAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"bTokenBorrowed","type":"address"},{"internalType":"address","name":"bTokenCollateral","type":"address"},{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"actualRepayAmount","type":"uint256"},{"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"liquidateBorrowVerify","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"bTokenBorrowed","type":"address"},{"internalType":"address","name":"bTokenCollateral","type":"address"},{"internalType":"uint256","name":"actualRepayAmount","type":"uint256"}],"name":"liquidateCalculateSeizeTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"liquidationIncentiveMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"markets","outputs":[{"internalType":"bool","name":"isListed","type":"bool"},{"internalType":"uint256","name":"collateralFactorMantissa","type":"uint256"},{"internalType":"bool","name":"isBidao","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"maxAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"minReleaseAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"bToken","type":"address"},{"internalType":"address","name":"minter","type":"address"},{"internalType":"uint256","name":"mintAmount","type":"uint256"}],"name":"mintAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"mintBAIGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"mintGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"bToken","type":"address"},{"internalType":"address","name":"minter","type":"address"},{"internalType":"uint256","name":"actualMintAmount","type":"uint256"},{"internalType":"uint256","name":"mintTokens","type":"uint256"}],"name":"mintVerify","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"mintedBAIs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"oracle","outputs":[{"internalType":"contract PriceOracle","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"pauseGuardian","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"pendingAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"pendingComptrollerImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"protocolPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"bToken","type":"address"},{"internalType":"address","name":"redeemer","type":"address"},{"internalType":"uint256","name":"redeemTokens","type":"uint256"}],"name":"redeemAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"bToken","type":"address"},{"internalType":"address","name":"redeemer","type":"address"},{"internalType":"uint256","name":"redeemAmount","type":"uint256"},{"internalType":"uint256","name":"redeemTokens","type":"uint256"}],"name":"redeemVerify","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"releaseStartBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"releaseToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"repayBAIGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"bToken","type":"address"},{"internalType":"address","name":"payer","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"repayAmount","type":"uint256"}],"name":"repayBorrowAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"bToken","type":"address"},{"internalType":"address","name":"payer","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"actualRepayAmount","type":"uint256"},{"internalType":"uint256","name":"borrowerIndex","type":"uint256"}],"name":"repayBorrowVerify","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"bTokenCollateral","type":"address"},{"internalType":"address","name":"bTokenBorrowed","type":"address"},{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"seizeAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"seizeGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"bTokenCollateral","type":"address"},{"internalType":"address","name":"bTokenBorrowed","type":"address"},{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"seizeVerify","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"setMintedBAIOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"bToken","type":"address"},{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"transferTokens","type":"uint256"}],"name":"transferAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"transferGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"bToken","type":"address"},{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"transferTokens","type":"uint256"}],"name":"transferVerify","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"treasuryAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"treasuryGuardian","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"treasuryPercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"vaiMintRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"vaiVaultAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"}]

608060405234801561001057600080fd5b50600080546001600160a01b03191633179055615dd080620000336000396000f3fe608060405234801561001057600080fd5b50600436106104f85760003560e01c8063719f701b11610299578063c299823811610167578063ddfd287e116100d9578063eabe7d9111610092578063eabe7d9114611318578063ec386c151461134e578063ede4edd014611372578063f0971c3214611398578063f6643c43146113a0578063f851a440146113a8576104f8565b8063ddfd287e146112a6578063de357629146112ae578063e4028eee146112d4578063e6653f3d14611300578063e875544614611308578063e97608b214611310576104f8565b8063d02f73511161012b578063d02f735114611094578063d24febad146110da578063d529802c14611110578063da3d454c1461123c578063dce1544914611272578063dcfbc0c71461129e576104f8565b8063c299823814610fb2578063c488847b14611020578063c59e105814611056578063c5f956af14611084578063cd69fb081461108c576104f8565b806394b2294b1161020b578063b2eafc39116101c4578063b2eafc3914610f12578063bb82aa5e14610f1a578063bb8d8f1114610f22578063bdcdc25814610f48578063bec04f7214610f84578063c0342f7614610f8c576104f8565b806394b2294b14610dad5780639ebd08d514610db5578063a76b3fda14610e66578063abfceffc14610e8c578063ac0b0bb714610f02578063b0772d0b14610f0a576104f8565b80638038ed7c1161025d5780638038ed7c14610cdb5780638748cb1914610ce357806387f7630314610d095780638e8f294b14610d11578063929fe9a114610d595780639305391014610d87576104f8565b8063719f701b14610c4f578063731f0c2b14610c575780637a5feecb14610c7d5780637d172bd514610ccb5780637dc0d1d014610cd3576104f8565b80633d67eb21116103d65780634fd42e17116103485780635f5af1aa116103015780635f5af1aa14610a7d5780635fc7e71e14610aa3578063607ef6c114610ae95780636a56947e14610ba75780636d154ea514610be35780636d35bf9114610c09576104f8565b80634fd42e171461098557806351dff989146109a257806352d84d1e146109de57806355ee1fe1146109fb5780635c77860514610a215780635ec88c7914610a57576104f8565b806342cbb15c1161039a57806342cbb15c1461087357806347ef3b3b1461087b5780634a584432146108c75780634ada90af146108ed5780634e79238f146108f55780634ef4c3e11461094f576104f8565b80633d67eb21146107ba5780633f0c5a7b146107e057806340bc640c1461081257806341c728b91461082f578063425fad581461086b576104f8565b806321af45691161046f5780632a6a6065116104335780632a6a60651461071c578063317b0b771461073b578063391957d714610758578063394555fe1461077e5780633b68032a146107aa5780633c94786f146107b2576104f8565b806321af456914610680578063232431b7146106a457806324008a62146106d057806324a3d6221461070c5780632678224714610714576104f8565b80630db4b4e5116104c15780630db4b4e5146105ae578063118a40b3146105b65780631616fb14146105d35780631afc2169146105fb5780631d504dc6146106185780631ededc911461063e576104f8565b80627e3dd2146104fd578063039a2a1e1461051957806304ef9d581461053357806306c405541461053b5780630a47769a14610580575b600080fd5b6105056113b0565b604080519115158252519081900360200190f35b6105216113b5565b60408051918252519081900360200190f35b6105216113bb565b6105676004803603604081101561055157600080fd5b506001600160a01b0381351690602001356113c1565b6040805192835260208301919091528051918290030190f35b6105216004803603604081101561059657600080fd5b506001600160a01b0381358116916020013516611566565b610521611583565b610521600480360360208110156105cc57600080fd5b5035611589565b6105f9600480360360208110156105e957600080fd5b50356001600160a01b03166115fe565b005b6105f96004803603602081101561061157600080fd5b5035611665565b6105f96004803603602081101561062e57600080fd5b50356001600160a01b03166116fc565b6105f9600480360360a081101561065457600080fd5b506001600160a01b03813581169160208101358216916040820135169060608101359060800135611867565b61068861186e565b604080516001600160a01b039092168252519081900360200190f35b6105f9600480360360408110156106ba57600080fd5b506001600160a01b03813516906020013561187d565b610521600480360360808110156106e657600080fd5b506001600160a01b038135811691602081013582169160408201351690606001356118e4565b610688611a01565b610688611a10565b6105056004803603602081101561073257600080fd5b50351515611a1f565b6105216004803603602081101561075157600080fd5b5035611b3c565b6105f96004803603602081101561076e57600080fd5b50356001600160a01b0316611be6565b6105216004803603604081101561079457600080fd5b506001600160a01b038135169060200135611c99565b610688611d95565b610505611dae565b610521600480360360208110156107d057600080fd5b50356001600160a01b0316611dbe565b6105f9600480360360608110156107f657600080fd5b506001600160a01b038135169060208101359060400135611dd0565b6105f96004803603602081101561082857600080fd5b5035611e8d565b6105f96004803603608081101561084557600080fd5b506001600160a01b03813581169160208101359091169060408101359060600135611f24565b610505611f2a565b610521611f39565b6105f9600480360360c081101561089157600080fd5b506001600160a01b0381358116916020810135821691604082013581169160608101359091169060808101359060a00135611f3d565b610521600480360360208110156108dd57600080fd5b50356001600160a01b0316611f45565b610521611f57565b6109316004803603608081101561090b57600080fd5b506001600160a01b03813581169160208101359091169060408101359060600135611f5d565b60408051938452602084019290925282820152519081900360600190f35b6105216004803603606081101561096557600080fd5b506001600160a01b03813581169160208101359091169060400135611f97565b6105216004803603602081101561099b57600080fd5b5035612096565b6105f9600480360360808110156109b857600080fd5b506001600160a01b038135811691602081013590911690604081013590606001356120ff565b610688600480360360208110156109f457600080fd5b5035612150565b61052160048036036020811015610a1157600080fd5b50356001600160a01b0316612177565b6105f960048036036060811015610a3757600080fd5b506001600160a01b038135811691602081013590911690604001356121fc565b61093160048036036020811015610a6d57600080fd5b50356001600160a01b0316612201565b61052160048036036020811015610a9357600080fd5b50356001600160a01b0316612236565b610521600480360360a0811015610ab957600080fd5b506001600160a01b03813581169160208101358216916040820135811691606081013590911690608001356122bb565b6105f960048036036040811015610aff57600080fd5b810190602081018135600160201b811115610b1957600080fd5b820183602082011115610b2b57600080fd5b803590602001918460208302840111600160201b83111715610b4c57600080fd5b919390929091602081019035600160201b811115610b6957600080fd5b820183602082011115610b7b57600080fd5b803590602001918460208302840111600160201b83111715610b9c57600080fd5b5090925090506124c7565b6105f960048036036080811015610bbd57600080fd5b506001600160a01b03813581169160208101358216916040820135169060600135612657565b61050560048036036020811015610bf957600080fd5b50356001600160a01b031661265c565b6105f9600480360360a0811015610c1f57600080fd5b506001600160a01b0381358116916020810135821691604082013581169160608101359091169060800135611867565b610521612671565b61050560048036036020811015610c6d57600080fd5b50356001600160a01b0316612677565b610ca360048036036020811015610c9357600080fd5b50356001600160a01b031661268c565b604080516001600160e01b03909316835263ffffffff90911660208301528051918290030190f35b6106886126b6565b6106886126c5565b6106886126d4565b61052160048036036020811015610cf957600080fd5b50356001600160a01b03166126e3565b6105056126f5565b610d3760048036036020811015610d2757600080fd5b50356001600160a01b0316612705565b6040805193151584526020840192909252151582820152519081900360600190f35b61050560048036036040811015610d6f57600080fd5b506001600160a01b038135811691602001351661272b565b6105f960048036036020811015610d9d57600080fd5b50356001600160a01b031661275e565b61052161288a565b6105f960048036036040811015610dcb57600080fd5b6001600160a01b038235169190810190604081016020820135600160201b811115610df557600080fd5b820183602082011115610e0757600080fd5b803590602001918460208302840111600160201b83111715610e2857600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550612890945050505050565b61052160048036036020811015610e7c57600080fd5b50356001600160a01b03166128ed565b610eb260048036036020811015610ea257600080fd5b50356001600160a01b0316612a4a565b60408051602080825283518183015283519192839290830191858101910280838360005b83811015610eee578181015183820152602001610ed6565b505050509050019250505060405180910390f35b610505612ac0565b610eb2612ad0565b610688612b32565b610688612b41565b610ca360048036036020811015610f3857600080fd5b50356001600160a01b0316612b50565b61052160048036036080811015610f5e57600080fd5b506001600160a01b03813581169160208101358216916040820135169060600135612b7a565b610521612c5d565b61052160048036036020811015610fa257600080fd5b50356001600160a01b0316612c63565b610eb260048036036020811015610fc857600080fd5b810190602081018135600160201b811115610fe257600080fd5b820183602082011115610ff457600080fd5b803590602001918460208302840111600160201b8311171561101557600080fd5b509092509050612c75565b6105676004803603606081101561103657600080fd5b506001600160a01b03813581169160208101359091169060400135612d0b565b6105216004803603604081101561106c57600080fd5b506001600160a01b0381358116916020013516612f33565b610688612f50565b610521612f5f565b610521600480360360a08110156110aa57600080fd5b506001600160a01b0381358116916020810135821691604082013581169160608101359091169060800135612f65565b610521600480360360608110156110f057600080fd5b506001600160a01b03813581169160208101359091169060400135613184565b6105f96004803603608081101561112657600080fd5b810190602081018135600160201b81111561114057600080fd5b82018360208201111561115257600080fd5b803590602001918460208302840111600160201b8311171561117357600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b8111156111c257600080fd5b8201836020820111156111d457600080fd5b803590602001918460208302840111600160201b831117156111f557600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550505050803515159150602001351515613319565b6105216004803603606081101561125257600080fd5b506001600160a01b038135811691602081013590911690604001356136b8565b6106886004803603604081101561128857600080fd5b506001600160a01b038135169060200135613ab5565b610688613aea565b6105f9613af9565b610521600480360360208110156112c457600080fd5b50356001600160a01b0316613d29565b610521600480360360408110156112ea57600080fd5b506001600160a01b038135169060200135613dad565b610505613f56565b610521613f66565b610505613f6c565b6105216004803603606081101561132e57600080fd5b506001600160a01b03813581169160208101359091169060400135613f7a565b61135661400a565b604080516001600160e01b039092168252519081900360200190f35b6105216004803603602081101561138857600080fd5b50356001600160a01b031661401d565b6105056142d9565b6105216142e2565b6106886142e8565b600181565b600e5481565b60225481565b600480546040805163fc57d4df60e01b81526001600160a01b038681169482019490945290516000938493670de0b6b3a7640000938593929091169163fc57d4df91602480820192602092909190829003018186803b15801561142357600080fd5b505afa158015611437573d6000803e3d6000fd5b505050506040513d602081101561144d57600080fd5b505190508061146657600d93506000925061155f915050565b6000866001600160a01b031663182df0f56040518163ffffffff1660e01b815260040160206040518083038186803b1580156114a157600080fd5b505afa1580156114b5573d6000803e3d6000fd5b505050506040513d60208110156114cb57600080fd5b5051905060006114d9615c86565b6114e1615c86565b6114e9615c86565b611511604051806020016040528060065481525060405180602001604052808a8152506142f7565b92506115396040518060200160405280888152506040518060200160405280888152506142f7565b91506115458383614336565b9050611551818b614372565b600099509750505050505050505b9250929050565b601260209081526000928352604080842090915290825290205481565b601d5481565b600080546001600160a01b031633146115af576115a860016014614391565b90506115f9565b6017805490839055604080518281526020810185905281517f87556fdb7c6cae9258034825895c0ffc1f54010b413046cf0ac6e05479e938cd929181900390910190a160005b9150505b919050565b61166281600d80548060200260200160405190810160405280929190818152602001828054801561165857602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161163a575b5050505050612890565b50565b6000546001600160a01b031633146116b5576040805162461bcd60e51b815260206004820152600e60248201526d37b7363c9030b236b4b71031b0b760911b604482015290519081900360640190fd5b6019805490829055604080518281526020810184905281517fe8aae0da1bca1d322dd772a375b82d9421de568a4d5250bcfa87a3304daa94bc929181900390910190a15050565b806001600160a01b031663f851a4406040518163ffffffff1660e01b815260040160206040518083038186803b15801561173557600080fd5b505afa158015611749573d6000803e3d6000fd5b505050506040513d602081101561175f57600080fd5b50516001600160a01b031633146117bd576040805162461bcd60e51b815260206004820152601960248201527f6f6e6c7920756e6974726f6c6c65722061646d696e2063616e00000000000000604482015290519081900360640190fd5b806001600160a01b031663c1e803346040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156117f857600080fd5b505af115801561180c573d6000803e3d6000fd5b505050506040513d602081101561182257600080fd5b505115611662576040805162461bcd60e51b815260206004820152600e60248201526d1b9bdd08185d5d1a1bdc9a5e995960921b604482015290519081900360640190fd5b5050505050565b601e546001600160a01b031681565b6118856143f7565b6118d6576040805162461bcd60e51b815260206004820152601e60248201527f6f6e6c792061646d696e2063616e2073657420626964616f2073706565640000604482015290519081900360640190fd5b6118e08282614420565b5050565b60185460009062010000900460ff161561193a576040805162461bcd60e51b81526020600482015260126024820152711c1c9bdd1bd8dbdb081a5cc81c185d5cd95960721b604482015290519081900360640190fd5b6001600160a01b03851660009081526009602052604090205460ff16611962575060096119f9565b61196a615c86565b6040518060200160405280876001600160a01b031663aa5af0fd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156119ae57600080fd5b505afa1580156119c2573d6000803e3d6000fd5b505050506040513d60208110156119d857600080fd5b5051905290506119e886826147b2565b6119f3868583614a46565b60009150505b949350505050565b600a546001600160a01b031681565b6001546001600160a01b031681565b600a5460009082906001600160a01b0316331480611a4757506000546001600160a01b031633145b611a825760405162461bcd60e51b8152600401808060200182810382526021815260200180615d466021913960400191505060405180910390fd5b6000546001600160a01b0316331480611a9d57506001811515145b611ae7576040805162461bcd60e51b81526020600482015260166024820152756f6e6c792061646d696e2063616e20756e706175736560501b604482015290519081900360640190fd5b6018805484151562010000810262ff0000199092169190911790915560408051918252517fd7500633dd3ddd74daa7af62f8c8404c7fe4a81da179998db851696bed004b389181900360200190a15090919050565b600080546001600160a01b03163314611b9c576040805162461bcd60e51b815260206004820152601f60248201527f6f6e6c792061646d696e2063616e2073657420636c6f736520666163746f7200604482015290519081900360640190fd5b6005805490839055604080518281526020810185905281517f3b9670cf975d26958e754b57098eaa2ac914d8d2a31b83257997b9f346110fd9929181900390910190a160006115f5565b6000546001600160a01b03163314611c36576040805162461bcd60e51b815260206004820152600e60248201526d37b7363c9030b236b4b71031b0b760911b604482015290519081900360640190fd5b601e80546001600160a01b038381166001600160a01b0319831681179093556040805191909216808252602082019390935281517feda98690e518e9a05f8ec6837663e188211b2da8f4906648b323f2c1d4434e29929181900390910190a15050565b60185460009062010000900460ff1615611cef576040805162461bcd60e51b81526020600482015260126024820152711c1c9bdd1bd8dbdb081a5cc81c185d5cd95960721b604482015290519081900360640190fd5b60185460ff16158015611d0a5750601854610100900460ff16155b611d4b576040805162461bcd60e51b815260206004820152600d60248201526c109052481a5cc81c185d5cd959609a1b604482015290519081900360640190fd5b6015546001600160a01b03163314611d7057611d69600e6016614391565b9050611d8f565b6001600160a01b03831660009081526016602052604081208390555b90505b92915050565b734502b7165187427f0e05be956edd892292683a935b90565b600a54600160a01b900460ff1681565b60166020526000908152604090205481565b6000546001600160a01b03163314611e20576040805162461bcd60e51b815260206004820152600e60248201526d37b7363c9030b236b4b71031b0b760911b604482015290519081900360640190fd5b601b80546001600160a01b0385166001600160a01b03199091168117909155601c839055601d8290556040805191825260208201849052818101839052517f39cd6c72cb8a6bb4b95166b673fdff696f8d0a0e0920ec123d11fbcdbeaa02f49181900360600190a1505050565b6000546001600160a01b03163314611edd576040805162461bcd60e51b815260206004820152600e60248201526d37b7363c9030b236b4b71031b0b760911b604482015290519081900360640190fd5b601a805490829055604080518281526020810184905281517f89ac3eaa3388a79111338e39a808c9da783a1cd0210125b2e29fea8b7bb6f707929181900390910190a15050565b50505050565b60185462010000900460ff1681565b4390565b505050505050565b601f6020526000908152604090205481565b60065481565b600080600080600080611f728a8a8a8a614bf6565b925092509250826012811115611f8457fe5b95509093509150505b9450945094915050565b60185460009062010000900460ff1615611fed576040805162461bcd60e51b81526020600482015260126024820152711c1c9bdd1bd8dbdb081a5cc81c185d5cd95960721b604482015290519081900360640190fd5b6001600160a01b0384166000908152600b602052604090205460ff161561204c576040805162461bcd60e51b815260206004820152600e60248201526d1b5a5b9d081a5cc81c185d5cd95960921b604482015290519081900360640190fd5b6001600160a01b03841660009081526009602052604090205460ff166120765760095b905061208f565b61207f84614f63565b61208984846151ed565b60005b90505b9392505050565b600080546001600160a01b031633146120b5576115a86001600b614391565b6006805490839055604080518281526020810185905281517faeba5a6c40a8ac138134bff1aaa65debf25971188a58804bad717f82f0ec1316929181900390910190a160006115f5565b8015158061210b575081155b611f24576040805162461bcd60e51b815260206004820152601160248201527072656465656d546f6b656e73207a65726f60781b604482015290519081900360640190fd5b600d818154811061215d57fe5b6000918252602090912001546001600160a01b0316905081565b600080546001600160a01b03163314612196576115a860016010614391565b600480546001600160a01b038481166001600160a01b0319831681179093556040805191909216808252602082019390935281517fd52b2b9b7e9ee655fcb95d2e5b9e0c9f69e7ef2b8e9d2d0ea78402d576d22e22929181900390910190a160006115f5565b505050565b600080600080600080612218876000806000614bf6565b92509250925082601281111561222a57fe5b97919650945092505050565b600080546001600160a01b03163314612255576115a860016013614391565b600a80546001600160a01b038481166001600160a01b0319831681179093556040805191909216808252602082019390935281517f0613b6ee6a04f0d09f390e4d9318894b9f6ac7fd83897cd8d18896ba579c401e929181900390910190a160006115f5565b60185460009062010000900460ff1615612311576040805162461bcd60e51b81526020600482015260126024820152711c1c9bdd1bd8dbdb081a5cc81c185d5cd95960721b604482015290519081900360640190fd5b6001600160a01b03861660009081526009602052604090205460ff168061234557506015546001600160a01b038781169116145b158061236a57506001600160a01b03851660009081526009602052604090205460ff16155b156123795760095b90506124be565b60008061238a856000806000614bf6565b919350909150600090508260128111156123a057fe5b146123ba578160128111156123b157fe5b925050506124be565b806123c65760036123b1565b6015546000906001600160a01b038a811691161461246757886001600160a01b03166395dd9193876040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561243457600080fd5b505afa158015612448573d6000803e3d6000fd5b505050506040513d602081101561245e57600080fd5b50519050612482565b506001600160a01b0385166000908152601660205260409020545b600061249e604051806020016040528060055481525083614372565b9050808611156124b55760119450505050506124be565b60009450505050505b95945050505050565b6000546001600160a01b03163314806124ea5750601e546001600160a01b031633145b6125255760405162461bcd60e51b8152600401808060200182810382526035815260200180615d676035913960400191505060405180910390fd5b8281811580159061253557508082145b612576576040805162461bcd60e51b815260206004820152600d60248201526c1a5b9d985b1a59081a5b9c1d5d609a1b604482015290519081900360640190fd5b60005b8281101561264e5784848281811061258d57fe5b90506020020135601f60008989858181106125a457fe5b905060200201356001600160a01b03166001600160a01b03166001600160a01b03168152602001908152602001600020819055508686828181106125e457fe5b905060200201356001600160a01b03166001600160a01b03167f6f1951b2aad10f3fc81b86d91105b413a5b3f847a34bbc5ce1904201b14438f686868481811061262a57fe5b905060200201356040518082815260200191505060405180910390a2600101612579565b50505050505050565b611f24565b600c6020526000908152604090205460ff1681565b601c5481565b600b6020526000908152604090205460ff1681565b6010602052600090815260409020546001600160e01b03811690600160e01b900463ffffffff1682565b601b546001600160a01b031681565b6004546001600160a01b031681565b6015546001600160a01b031681565b600f6020526000908152604090205481565b600a54600160b01b900460ff1681565b60096020526000908152604090208054600182015460039092015460ff91821692911683565b6001600160a01b038082166000908152600960209081526040808320938616835260029093019052205460ff1692915050565b601b546001600160a01b03161561277757612777613af9565b6015546001600160a01b031615611662576015546040805163d34d2ba760e01b81526001600160a01b0384811660048301529151600093849384938493919092169163d34d2ba791602480830192608092919082900301818787803b1580156127df57600080fd5b505af11580156127f3573d6000803e3d6000fd5b505050506040513d608081101561280957600080fd5b50805160208201516040830151606090930151909650919450909250905080611867576001600160a01b038516600081815260146020908152604091829020879055815186815290810185905281517f51756bbc6ae1e2b6db1d1daa808ab8e6f76a09c2f44d06ce4c915f6c3671c9ba929181900390910190a25050505050565b60075481565b6040805160018082528183019092526060916020808301908038833901905050905082816000815181106128c057fe5b60200260200101906001600160a01b031690816001600160a01b0316815250506121fc8183600180613319565b600080546001600160a01b0316331461290c576115a860016012614391565b6001600160a01b03821660009081526009602052604090205460ff1615612939576115a8600a6011614391565b816001600160a01b031663fbb623376040518163ffffffff1660e01b815260040160206040518083038186803b15801561297257600080fd5b505afa158015612986573d6000803e3d6000fd5b505050506040513d602081101561299c57600080fd5b5050604080516060810182526001808252600060208381018281528486018381526001600160a01b03891684526009909252949091209251835490151560ff19918216178455935191830191909155516003909101805491151591909216179055612a06826153e5565b604080516001600160a01b038416815290517fcf583bb0c569eb967f806b11601c4cb93c10310485c67add5f8362c2f212321f9181900360200190a1600092915050565b6001600160a01b038116600090815260086020908152604091829020805483518184028101840190945280845260609392830182828015612ab457602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612a96575b50505050509050919050565b600a54600160b81b900460ff1681565b6060600d805480602002602001604051908101604052809291908181526020018280548015612b2857602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612b0a575b5050505050905090565b6020546001600160a01b031681565b6002546001600160a01b031681565b6011602052600090815260409020546001600160e01b03811690600160e01b900463ffffffff1682565b60185460009062010000900460ff1615612bd0576040805162461bcd60e51b81526020600482015260126024820152711c1c9bdd1bd8dbdb081a5cc81c185d5cd95960721b604482015290519081900360640190fd5b600a54600160b01b900460ff1615612c24576040805162461bcd60e51b81526020600482015260126024820152711d1c985b9cd9995c881a5cc81c185d5cd95960721b604482015290519081900360640190fd5b6000612c318686856154c3565b90508015612c405790506119f9565b612c4986614f63565b612c5386866151ed565b6119f386856151ed565b60175481565b60146020526000908152604090205481565b60408051828152602080840282010190915260609082908290828015612ca5578160200160208202803883390190505b50905060005b82811015612d0257612cd8868683818110612cc257fe5b905060200201356001600160a01b03163361556f565b6012811115612ce357fe5b828281518110612cef57fe5b6020908102919091010152600101612cab565b50949350505050565b600480546040805163fc57d4df60e01b81526001600160a01b038781169482019490945290516000938493849391169163fc57d4df91602480820192602092909190829003018186803b158015612d6157600080fd5b505afa158015612d75573d6000803e3d6000fd5b505050506040513d6020811015612d8b57600080fd5b5051600480546040805163fc57d4df60e01b81526001600160a01b038a8116948201949094529051939450600093929091169163fc57d4df91602480820192602092909190829003018186803b158015612de457600080fd5b505afa158015612df8573d6000803e3d6000fd5b505050506040513d6020811015612e0e57600080fd5b50519050811580612e1d575080155b15612e3257600d935060009250612f2b915050565b6000866001600160a01b031663182df0f56040518163ffffffff1660e01b815260040160206040518083038186803b158015612e6d57600080fd5b505afa158015612e81573d6000803e3d6000fd5b505050506040513d6020811015612e9757600080fd5b505190506000612ea5615c86565b612ead615c86565b612eb5615c86565b612edd604051806020016040528060065481525060405180602001604052808a8152506142f7565b9250612f056040518060200160405280888152506040518060200160405280888152506142f7565b9150612f118383614336565b9050612f1d818b614372565b600099509750505050505050505b935093915050565b601360209081526000928352604080842090915290825290205481565b6021546001600160a01b031681565b601a5481565b60185460009062010000900460ff1615612fbb576040805162461bcd60e51b81526020600482015260126024820152711c1c9bdd1bd8dbdb081a5cc81c185d5cd95960721b604482015290519081900360640190fd5b600a54600160b81b900460ff161561300c576040805162461bcd60e51b815260206004820152600f60248201526e1cd95a5e99481a5cc81c185d5cd959608a1b604482015290519081900360640190fd5b6001600160a01b03861660009081526009602052604090205460ff16158061306557506001600160a01b03851660009081526009602052604090205460ff168061306357506015546001600160a01b038681169116145b155b15613071576009612372565b846001600160a01b0316635fe3b5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156130aa57600080fd5b505afa1580156130be573d6000803e3d6000fd5b505050506040513d60208110156130d457600080fd5b505160408051635fe3b56760e01b815290516001600160a01b0392831692891691635fe3b567916004808301926020929190829003018186803b15801561311a57600080fd5b505afa15801561312e573d6000803e3d6000fd5b505050506040513d602081101561314457600080fd5b50516001600160a01b03161461315b576002612372565b61316486614f63565b61316e86846151ed565b61317886856151ed565b60009695505050505050565b600080546001600160a01b03163314806131a857506020546001600160a01b031633145b6131b85761206f60016017614391565b670de0b6b3a76400008210613214576040805162461bcd60e51b815260206004820152601d60248201527f74726561737572792070657263656e7420636170206f766572666c6f77000000604482015290519081900360640190fd5b6020805460218054602280546001600160a01b038a81166001600160a01b0319808816821789558b8316908616179095559188905560408051958316808752968601949094528351929091169390927f29f06ea15931797ebaed313d81d100963dc22cb213cb4ce2737b5a62b1a8b1e892918290030190a1604080516001600160a01b0380851682528816602082015281517f8de763046d7b8f08b6c3d03543de1d615309417842bb5d2d62f110f65809ddac929181900390910190a1604080518281526020810187905281517f0893f8f4101baaabbeb513f96761e7a36eb837403c82cc651c292a4abdc94ed7929181900390910190a16000979650505050505050565b6015546000906001600160a01b0316156133aa57601560009054906101000a90046001600160a01b03166001600160a01b031663b8a192636040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561337d57600080fd5b505af1158015613391573d6000803e3d6000fd5b505050506040513d60208110156133a757600080fd5b50505b5060005b8451811015613464576133d38582815181106133c657fe5b602002602001015161275e565b6134288582815181106133e257fe5b6020026020010151601460008885815181106133fa57fe5b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002054615660565b6014600087848151811061343857fe5b6020908102919091018101516001600160a01b03168252810191909152604001600020556001016133ae565b60005b8451811015611f3d57600085828151811061347e57fe5b6020908102919091018101516001600160a01b0381166000908152600990925260409091205490915060ff166134ef576040805162461bcd60e51b81526020600482015260116024820152701b9bdd081b1a5cdd1959081b585c9ad95d607a1b604482015290519081900360640190fd5b841561360f576134fd615c86565b6040518060200160405280836001600160a01b031663aa5af0fd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561354157600080fd5b505afa158015613555573d6000803e3d6000fd5b505050506040513d602081101561356b57600080fd5b50519052905061357b82826147b2565b600093505b875184101561360d576135a78289868151811061359957fe5b602002602001015183614a46565b6135ce8885815181106135b657fe5b6020026020010151601460008b88815181106133fa57fe5b601460008a87815181106135de57fe5b6020908102919091018101516001600160a01b0316825281019190915260400160002055600190930192613580565b505b83156136af5761361e81614f63565b600092505b86518310156136af576136498188858151811061363c57fe5b60200260200101516151ed565b61367087848151811061365857fe5b6020026020010151601460008a87815181106133fa57fe5b6014600089868151811061368057fe5b6020908102919091018101516001600160a01b0316825281019190915260400160002055600190920191613623565b50600101613467565b60185460009062010000900460ff161561370e576040805162461bcd60e51b81526020600482015260126024820152711c1c9bdd1bd8dbdb081a5cc81c185d5cd95960721b604482015290519081900360640190fd5b6001600160a01b0384166000908152600c602052604090205460ff161561376f576040805162461bcd60e51b815260206004820152601060248201526f189bdc9c9bddc81a5cc81c185d5cd95960821b604482015290519081900360640190fd5b6001600160a01b03841660009081526009602052604090205460ff1661379657600961206f565b6001600160a01b038085166000908152600960209081526040808320938716835260029093019052205460ff1661385357336001600160a01b0385161461381c576040805162461bcd60e51b815260206004820152601560248201527439b2b73232b91036bab9ba10313290312a37b5b2b760591b604482015290519081900360640190fd5b6000613828858561556f565b9050600081601281111561383857fe5b146138515780601281111561384957fe5b91505061208f565b505b600480546040805163fc57d4df60e01b81526001600160a01b03888116948201949094529051929091169163fc57d4df91602480820192602092909190829003018186803b1580156138a457600080fd5b505afa1580156138b8573d6000803e3d6000fd5b505050506040513d60208110156138ce57600080fd5b50516138db57600d61206f565b6001600160a01b0384166000908152601f602052604090205480156139c8576000856001600160a01b03166347bd37186040518163ffffffff1660e01b815260040160206040518083038186803b15801561393557600080fd5b505afa158015613949573d6000803e3d6000fd5b505050506040513d602081101561395f57600080fd5b50519050600061396f828661579a565b90508281106139c5576040805162461bcd60e51b815260206004820152601960248201527f6d61726b657420626f72726f7720636170207265616368656400000000000000604482015290519081900360640190fd5b50505b6000806139d88688600088614bf6565b919350909150600090508260128111156139ee57fe5b14613a09578160128111156139ff57fe5b935050505061208f565b8015613a165760046139ff565b613a1e615c86565b6040518060200160405280896001600160a01b031663aa5af0fd6040518163ffffffff1660e01b815260040160206040518083038186803b158015613a6257600080fd5b505afa158015613a76573d6000803e3d6000fd5b505050506040513d6020811015613a8c57600080fd5b505190529050613a9c88826147b2565b613aa7888883614a46565b600098975050505050505050565b60086020528160005260406000208181548110613ace57fe5b6000918252602090912001546001600160a01b03169150829050565b6003546001600160a01b031681565b601c541580613b105750601c54613b0e611f39565b105b15613b1a57613d27565b6000613b24611d95565b604080516370a0823160e01b815230600482015290519192506000916001600160a01b038416916370a08231916024808301926020929190829003018186803b158015613b7057600080fd5b505afa158015613b84573d6000803e3d6000fd5b505050506040513d6020811015613b9a57600080fd5b5051905080613baa575050613d27565b600080613bc0613bb8611f39565b601c546157d0565b90506000613bd0601a548361580a565b9050601d54811015613be6575050505050613d27565b808410613bf557809250613bf9565b8392505b613c01611f39565b601c55601b546040805163a9059cbb60e01b81526001600160a01b0392831660048201526024810186905290519187169163a9059cbb916044808201926020929091908290030181600087803b158015613c5a57600080fd5b505af1158015613c6e573d6000803e3d6000fd5b505050506040513d6020811015613c8457600080fd5b50506040805184815290517fbdbef8994172ee78e2e25df1c5d6c2dac1ade9250fc10daf12338fde9a7cba799181900360200190a1601b60009054906101000a90046001600160a01b03166001600160a01b031663faa1809e6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613d0957600080fd5b505af1158015613d1d573d6000803e3d6000fd5b5050505050505050505b565b600080546001600160a01b03163314613d48576115a860016015614391565b601580546001600160a01b038481166001600160a01b0319831681179093556040805191909216808252602082019390935281517fb2807483a31a2826395150a74934b52e5f19de2706264a997a4f846199095504929181900390910190a150919050565b600080546001600160a01b03163314613dcc57611d6960016006614391565b6001600160a01b0383166000908152600960205260409020805460ff16613e0157613df960096007614391565b915050611d8f565b613e09615c86565b506040805160208101909152838152613e20615c86565b506040805160208101909152670c7d713b49da00008152613e41818361584c565b15613e5c57613e5260066008614391565b9350505050611d8f565b8415801590613ee55750600480546040805163fc57d4df60e01b81526001600160a01b038a8116948201949094529051929091169163fc57d4df91602480820192602092909190829003018186803b158015613eb757600080fd5b505afa158015613ecb573d6000803e3d6000fd5b505050506040513d6020811015613ee157600080fd5b5051155b15613ef657613e52600d6009614391565b60018301805490869055604080516001600160a01b03891681526020810183905280820188905290517f70483e6592cd5182d45ac970e05bc62cdcc90e9d8ef2c2dbe686cf383bcd7fc59181900360600190a16000979650505050505050565b600a54600160a81b900460ff1681565b60055481565b601854610100900460ff1681565b60185460009062010000900460ff1615613fd0576040805162461bcd60e51b81526020600482015260126024820152711c1c9bdd1bd8dbdb081a5cc81c185d5cd95960721b604482015290519081900360640190fd5b6000613fdd8585856154c3565b90508015613fec57905061208f565b613ff585614f63565b613fff85856151ed565b600095945050505050565b6ec097ce7bc90715b34b9f100000000081565b6000808290506000806000836001600160a01b031663c37f68e2336040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060806040518083038186803b15801561407e57600080fd5b505afa158015614092573d6000803e3d6000fd5b505050506040513d60808110156140a857600080fd5b508051602082015160409092015190945090925090508215614111576040805162461bcd60e51b815260206004820152601960248201527f6765744163636f756e74536e617073686f74206661696c656400000000000000604482015290519081900360640190fd5b801561412e57614123600c6002614391565b9450505050506115f9565b600061413b8733856154c3565b9050801561415c57614150600e600383615853565b955050505050506115f9565b6001600160a01b0385166000908152600960209081526040808320338452600281019092529091205460ff1661419b57600096505050505050506115f9565b3360009081526002820160209081526040808320805460ff1916905560089091528120805490915b8181101561427c57886001600160a01b03168382815481106141e157fe5b6000918252602090912001546001600160a01b031614156142745782600183038154811061420b57fe5b9060005260206000200160009054906101000a90046001600160a01b031683828154811061423557fe5b600091825260209091200180546001600160a01b0319166001600160a01b0392909216919091179055825461426e846000198301615c99565b5061427c565b6001016141c3565b81811061428557fe5b604080516001600160a01b038b16815233602082015281517fe699a64c18b07ac5b7301aa273f36a2287239eb9501d81950672794afba29a0d929181900390910190a160009b9a5050505050505050505050565b60185460ff1681565b60195481565b6000546001600160a01b031681565b6142ff615c86565b6040518060200160405280670de0b6b3a76400006143258660000151866000015161580a565b8161432c57fe5b0490529392505050565b61433e615c86565b60405180602001604052806143696143628660000151670de0b6b3a764000061580a565b85516158b9565b90529392505050565b600061437c615c86565b61438684846158ec565b90506119f98161590d565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa08360128111156143c057fe5b8360178111156143cc57fe5b604080519283526020830191909152600082820152519081900360600190a1826012811115611d8c57fe5b600080546001600160a01b031633148061441b57506002546001600160a01b031633145b905090565b6001600160a01b0382166000908152600f602052604090205480156144d457614447615c86565b6040518060200160405280856001600160a01b031663aa5af0fd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561448b57600080fd5b505afa15801561449f573d6000803e3d6000fd5b505050506040513d60208110156144b557600080fd5b5051905290506144c484614f63565b6144ce84826147b2565b50614756565b8115614756576001600160a01b0383166000908152600960205260409020805460ff16151560011461454d576040805162461bcd60e51b815260206004820152601a60248201527f626964616f206d61726b6574206973206e6f74206c6973746564000000000000604482015290519081900360640190fd5b6001600160a01b0384166000908152601060205260409020546001600160e01b031615801561459f57506001600160a01b038416600090815260106020526040902054600160e01b900463ffffffff16155b1561466e5760405180604001604052806ec097ce7bc90715b34b9f10000000006001600160e01b031681526020016146136145d8611f39565b6040518060400160405280601c81526020017f626c6f636b206e756d626572206578636565647320333220626974730000000081525061591c565b63ffffffff9081169091526001600160a01b0386166000908152601060209081526040909120835181549490920151909216600160e01b026001600160e01b039182166001600160e01b031990941693909317169190911790555b6001600160a01b0384166000908152601160205260409020546001600160e01b03161580156146c057506001600160a01b038416600090815260116020526040902054600160e01b900463ffffffff16155b156147545760405180604001604052806ec097ce7bc90715b34b9f10000000006001600160e01b031681526020016146f96145d8611f39565b63ffffffff9081169091526001600160a01b0386166000908152601160209081526040909120835181549490920151909216600160e01b026001600160e01b039182166001600160e01b031990941693909317169190911790555b505b8181146121fc576001600160a01b0383166000818152600f6020908152604091829020859055815185815291517ffa14dc84f9ef6b70ad40db65b3ca480e181013d2f1e4840145e64343d98f2dc59281900390910190a2505050565b6001600160a01b0382166000908152601160209081526040808320600f90925282205490916147df611f39565b83549091506000906147ff908390600160e01b900463ffffffff166157d0565b90506000811180156148115750600083115b156149e1576000614886876001600160a01b03166347bd37186040518163ffffffff1660e01b815260040160206040518083038186803b15801561485457600080fd5b505afa158015614868573d6000803e3d6000fd5b505050506040513d602081101561487e57600080fd5b5051876159b6565b90506000614894838661580a565b905061489e615c86565b600083116148bb57604051806020016040528060008152506148c5565b6148c582846159d4565b90506148cf615c86565b604080516020810190915288546001600160e01b031681526148f19083615a09565b905060405180604001604052806149378360000151604051806040016040528060138152602001726e657720696e646578206f766572666c6f777360681b815250615a2e565b6001600160e01b0316815260200161497d8860405180604001604052806016815260200175626c6f636b206e756d626572206f766572666c6f777360501b81525061591c565b63ffffffff9081169091526001600160a01b038c166000908152601160209081526040909120835181549490920151909216600160e01b026001600160e01b039182166001600160e01b0319909416939093171691909117905550611f3d92505050565b8015611f3d57614a1f8260405180604001604052806016815260200175626c6f636b206e756d626572206f766572666c6f777360501b81525061591c565b845463ffffffff91909116600160e01b026001600160e01b03909116178455505050505050565b601b546001600160a01b031615614a5f57614a5f613af9565b6001600160a01b0383166000908152601160205260409020614a7f615c86565b50604080516020810190915281546001600160e01b03168152614aa0615c86565b5060408051602080820183526001600160a01b0380891660009081526013835284812091891680825282845294812080548552865195909152915291909155805115611f3d57614aee615c86565b614af88383615a83565b90506000614b55886001600160a01b03166395dd9193896040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561485457600080fd5b90506000614b638284615aa8565b6001600160a01b03891660009081526014602052604081205491925090614b8a908361579a565b6001600160a01b03808b166000818152601460209081526040918290208590558a5182518881529182015281519495509193928e16927fe5983996a7e7b648983d12b3ff7a5b8383fceae86d03973258690c5aff7c4ba29281900390910190a350505050505050505050565b6000806000614c03615cbd565b6001600160a01b03881660009081526008602090815260408083208054825181850281018501909352808352606093830182828015614c6b57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311614c4d575b50939450600093505050505b8151811015614eef576000828281518110614c8e57fe5b60200260200101519050806001600160a01b031663c37f68e28d6040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060806040518083038186803b158015614cee57600080fd5b505afa158015614d02573d6000803e3d6000fd5b505050506040513d6080811015614d1857600080fd5b508051602082015160408084015160609485015160808b0152938901939093529187019190915293508315614d5d5750600f965060009550859450611f8d9350505050565b60408051602080820183526001600160a01b0380851660008181526009845285902060010154845260c08a01939093528351808301855260808a0151815260e08a015260048054855163fc57d4df60e01b815291820194909452935192169263fc57d4df9260248083019392829003018186803b158015614ddd57600080fd5b505afa158015614df1573d6000803e3d6000fd5b505050506040513d6020811015614e0757600080fd5b505160a08601819052614e2a5750600d965060009550859450611f8d9350505050565b604080516020810190915260a0860151815261010086015260c085015160e0860151614e6491614e59916142f7565b8661010001516142f7565b610120860181905260408601518651614e7e929190615ad7565b855261010085015160608601516020870151614e9b929190615ad7565b60208601526001600160a01b03818116908c161415614ee657614ec88561012001518b8760200151615ad7565b60208601819052610100860151614ee0918b90615ad7565b60208601525b50600101614c77565b50614f238360200151601660008d6001600160a01b03166001600160a01b031681526020019081526020016000205461579a565b6020840181905283511115614f4a5750506020810151905160009450039150829050611f8d565b5050805160209091015160009450849350039050611f8d565b6001600160a01b0381166000908152601060209081526040808320600f9092528220549091614f90611f39565b8354909150600090614fb0908390600160e01b900463ffffffff166157d0565b9050600081118015614fc25750600083115b15615189576000856001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561500257600080fd5b505afa158015615016573d6000803e3d6000fd5b505050506040513d602081101561502c57600080fd5b50519050600061503c838661580a565b9050615046615c86565b60008311615063576040518060200160405280600081525061506d565b61506d82846159d4565b9050615077615c86565b604080516020810190915288546001600160e01b031681526150999083615a09565b905060405180604001604052806150df8360000151604051806040016040528060138152602001726e657720696e646578206f766572666c6f777360681b815250615a2e565b6001600160e01b031681526020016151258860405180604001604052806016815260200175626c6f636b206e756d626572206f766572666c6f777360501b81525061591c565b63ffffffff9081169091526001600160a01b038b166000908152601060209081526040909120835181549490920151909216600160e01b026001600160e01b039182166001600160e01b031990941693909317169190911790555061186792505050565b8015611867576151c78260405180604001604052806016815260200175626c6f636b206e756d626572206f766572666c6f777360501b81525061591c565b845463ffffffff91909116600160e01b026001600160e01b039091161784555050505050565b601b546001600160a01b03161561520657615206613af9565b6001600160a01b0382166000908152601060205260409020615226615c86565b50604080516020810190915281546001600160e01b03168152615247615c86565b5060408051602080820183526001600160a01b038088166000908152601283528481209188168082528284529481208054855286519590915291529190915580511580156152955750815115155b156152ad576ec097ce7bc90715b34b9f100000000081525b6152b5615c86565b6152bf8383615a83565b90506000866001600160a01b03166370a08231876040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561531957600080fd5b505afa15801561532d573d6000803e3d6000fd5b505050506040513d602081101561534357600080fd5b5051905060006153538284615aa8565b6001600160a01b0388166000908152601460205260408120549192509061537a908361579a565b6001600160a01b03808a166000818152601460209081526040918290208590558a5182518881529182015281519495509193928d16927f27b6c7ab802cbf1312e7632f3c8f7d3ef10e054ca65b9890bb0a9034103e80b99281900390910190a3505050505050505050565b60005b600d5481101561547057816001600160a01b0316600d828154811061540957fe5b6000918252602090912001546001600160a01b03161415615468576040805162461bcd60e51b81526020600482015260146024820152731b585c9ad95d08185b1c9958591e48185919195960621b604482015290519081900360640190fd5b6001016153e8565b50600d80546001810182556000919091527fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb50180546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b03831660009081526009602052604081205460ff166154ea57600961206f565b6001600160a01b038085166000908152600960209081526040808320938716835260029093019052205460ff1661552257600061206f565b6000806155328587866000614bf6565b9193509091506000905082601281111561554857fe5b146155625781601281111561555957fe5b9250505061208f565b8015613178576004615559565b6001600160a01b0382166000908152600960205260408120805460ff1661559a576009915050611d8f565b6001600160a01b038316600090815260028201602052604090205460ff16156155c7576000915050611d8f565b6001600160a01b0380841660008181526002840160209081526040808320805460ff19166001908117909155600883528184208054918201815584529282902090920180549489166001600160a01b031990951685179055815193845283019190915280517f3ab23ab0d51cccc0c3085aec51f99228625aa1a922b3a8ca89a26b0f2027a1a59281900390910190a15060009392505050565b60008061566b611d95565b604080516370a0823160e01b815230600482015290519192506000916001600160a01b038416916370a08231916024808301926020929190829003018186803b1580156156b757600080fd5b505afa1580156156cb573d6000803e3d6000fd5b505050506040513d60208110156156e157600080fd5b5051905083158015906156f45750808411155b1561579157816001600160a01b031663a9059cbb86866040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b15801561575957600080fd5b505af115801561576d573d6000803e3d6000fd5b505050506040513d602081101561578357600080fd5b5060009350611d8f92505050565b50919392505050565b6000611d8c8383604051806040016040528060118152602001706164646974696f6e206f766572666c6f7760781b815250615aff565b6000611d8c8383604051806040016040528060158152602001747375627472616374696f6e20756e646572666c6f7760581b815250615b54565b6000611d8c83836040518060400160405280601781526020017f6d756c7469706c69636174696f6e206f766572666c6f77000000000000000000815250615bae565b5190511090565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa084601281111561588257fe5b84601781111561588e57fe5b604080519283526020830191909152818101859052519081900360600190a183601281111561208c57fe5b6000611d8c83836040518060400160405280600e81526020016d646976696465206279207a65726f60901b815250615c24565b6158f4615c86565b604051806020016040528061436985600001518561580a565b51670de0b6b3a7640000900490565b600081600160201b84106159ae5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561597357818101518382015260200161595b565b50505050905090810190601f1680156159a05780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b509192915050565b6000611d8c6159cd84670de0b6b3a764000061580a565b83516158b9565b6159dc615c86565b6040518060200160405280614369615a03866ec097ce7bc90715b34b9f100000000061580a565b856158b9565b615a11615c86565b60405180602001604052806143698560000151856000015161579a565b600081600160e01b84106159ae5760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561597357818101518382015260200161595b565b615a8b615c86565b6040518060200160405280614369856000015185600001516157d0565b60006ec097ce7bc90715b34b9f1000000000615ac884846000015161580a565b81615acf57fe5b049392505050565b6000615ae1615c86565b615aeb85856158ec565b90506124be615af98261590d565b8461579a565b60008383018285821015612d025760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561597357818101518382015260200161595b565b60008184841115615ba65760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561597357818101518382015260200161595b565b505050900390565b6000831580615bbb575082155b15615bc85750600061208f565b83830283858281615bd557fe5b04148390612d025760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561597357818101518382015260200161595b565b60008183615c735760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561597357818101518382015260200161595b565b50828481615c7d57fe5b04949350505050565b6040518060200160405280600081525090565b8154818355818111156121fc576000838152602090206121fc918101908301615d27565b604051806101400160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001615cfb615c86565b8152602001615d08615c86565b8152602001615d15615c86565b8152602001615d22615c86565b905290565b611dab91905b80821115615d415760008155600101615d2d565b509056fe6f6e6c7920706175736520677561726469616e20616e642061646d696e2063616e6f6e6c792061646d696e206f7220626f72726f772063617020677561726469616e2063616e2073657420626f72726f772063617073a265627a7a723158207f766a23999569d0ed5d0820bbc0e57a7af1a009ed7ada7e8aa517d2e4a6674764736f6c63430005100032

Deployed ByteCode Sourcemap

149148:63586:0:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;149148:63586:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;194:41;;;:::i;:::-;;;;;;;;;;;;;;;;;;118776:21;;;:::i;:::-;;;;;;;;;;;;;;;;121554:30;;;:::i;184446:1480::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;184446:1480:0;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;119312:70;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;119312:70:0;;;;;;;;;;:::i;120785:31::-;;;:::i;195353:429::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;195353:429:0;;:::i;205281:99::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;205281:99:0;-1:-1:-1;;;;;205281:99:0;;:::i;:::-;;208540:209;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;208540:209:0;;:::i;196798:213::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;196798:213:0;-1:-1:-1;;;;;196798:213:0;;:::i;167921:458::-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;167921:458:0;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;121042:32::-;;;:::i;:::-;;;;-1:-1:-1;;;;;121042:32:0;;;;;;;;;;;;;;209991:198;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;209991:198:0;;;;;;;;:::i;166938:661::-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;166938:661:0;;;;;;;;;;;;;;;;;;;;;;:::i;118075:28::-;;;:::i;115914:27::-;;;:::i;194513:191::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;194513:191:0;;;;:::i;187031:426::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;187031:426:0;;:::i;193948:484::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;193948:484:0;-1:-1:-1;;;;;193948:484:0;;:::i;211100:534::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;211100:534:0;;;;;;;;:::i;210693:124::-;;;:::i;118110:31::-;;;:::i;119856:42::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;119856:42:0;-1:-1:-1;;;;;119856:42:0;;:::i;209471:331::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;209471:331:0;;;;;;;;;;;;;:::i;208943:264::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;208943:264:0;;:::i;160789:226::-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;160789:226:0;;;;;;;;;;;;;;;;;;;;;;:::i;120242:26::-;;;:::i;210487:91::-;;;:::i;170759:546::-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;170759:546:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;121222:42::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;121222:42:0;-1:-1:-1;;;;;121222:42:0;;:::i;116621:40::-;;;:::i;177662:408::-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;177662:408:0;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;159856:601;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;159856:601:0;;;;;;;;;;;;;;;;;:::i;189771:742::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;189771:742:0;;:::i;163155:321::-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;163155:321:0;;;;;;;;;;;;;;;;;;;;;;:::i;118665:26::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;118665:26:0;;:::i;186191:572::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;186191:572:0;-1:-1:-1;;;;;186191:572:0;;:::i;166122:322::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;166122:322:0;;;;;;;;;;;;;;;;;:::i;176757:268::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;176757:268:0;-1:-1:-1;;;;;176757:268:0;;:::i;192040:610::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;192040:610:0;-1:-1:-1;;;;;192040:610:0;;:::i;168833:1452::-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;168833:1452:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;193172:606::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;193172:606:0;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;193172:606:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;193172:606:0;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;-1:-1;;;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;193172:606:0;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;193172:606:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;193172:606:0;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;-1:-1;;;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;-1:-1;193172:606:0;;-1:-1:-1;193172:606:0;-1:-1:-1;193172:606:0;:::i;175412:345::-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;175412:345:0;;;;;;;;;;;;;;;;;;;;;;:::i;118324:52::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;118324:52:0;-1:-1:-1;;;;;118324:52:0;;:::i;173358:475::-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;173358:475:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;120700:32::-;;;:::i;118267:50::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;118267:50:0;-1:-1:-1;;;;;118267:50:0;;:::i;118999:60::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;118999:60:0;-1:-1:-1;;;;;118999:60:0;;:::i;:::-;;;;-1:-1:-1;;;;;118999:60:0;;;;;;;;;;;;;;;;;;;;;;120617:30;;;:::i;116322:25::-;;;:::i;119752:43::-;;;:::i;118884:::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;118884:43:0;-1:-1:-1;;;;;118884:43:0;;:::i;118188:34::-;;;:::i;117757:41::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;117757:41:0;-1:-1:-1;;;;;117757:41:0;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;154905:163;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;154905:163:0;;;;;;;;;;:::i;204410:718::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;204410:718:0;-1:-1:-1;;;;;204410:718:0;;:::i;116791:21::-;;;:::i;205595:211::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;205595:211:0;;;;;;;;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;205595:211:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;205595:211:0;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;-1:-1;;;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;205595:211:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;205595:211:0;;-1:-1:-1;205595:211:0;;-1:-1:-1;;;;;205595:211:0:i;190840:721::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;190840:721:0;-1:-1:-1;;;;;190840:721:0;;:::i;154502:126::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;154502:126:0;-1:-1:-1;;;;;154502:126:0;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:100:-1;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;154502:126:0;;;;;;;;;;;;;;;;;118229:31;;;:::i;210380:99::-;;;:::i;121376:31::-;;;:::i;116010:40::-;;;:::i;119131:60::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;119131:60:0;-1:-1:-1;;;;;119131:60:0;;:::i;174300:787::-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;174300:787:0;;;;;;;;;;;;;;;;;;;;;;:::i;119954:23::-;;;:::i;119653:44::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;119653:44:0;-1:-1:-1;;;;;119653:44:0;;:::i;155334:344::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;155334:344:0;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;155334:344:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;155334:344:0;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;-1:-1;;;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;-1:-1;155334:344:0;;-1:-1:-1;155334:344:0;-1:-1:-1;155334:344:0;:::i;182419:1554::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;182419:1554:0;;;;;;;;;;;;;;;;;:::i;119503:70::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;119503:70:0;;;;;;;;;;:::i;121450:30::-;;;:::i;120550:29::-;;;:::i;171768:1129::-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;;171768:1129:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;195790:1000::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;195790:1000:0;;;;;;;;;;;;;;;;;:::i;206148:1465::-;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;206148:1465:0;;;;;;;;-1:-1:-1;;;5:28;;2:2;;;46:1;43;36:12;2:2;206148:1465:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;206148:1465:0;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;-1:-1;;;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;206148:1465:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;206148:1465:0;;;;;;;;-1:-1:-1;206148:1465:0;;-1:-1:-1;;;;;5:28;;2:2;;;46:1;43;36:12;2:2;206148:1465:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;206148:1465:0;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;-1:-1;;;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;206148:1465:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;206148:1465:0;;-1:-1:-1;;;;206148:1465:0;;;;;-1:-1:-1;206148:1465:0;;;;;;:::i;163917:1898::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;163917:1898:0;;;;;;;;;;;;;;;;;:::i;116919:49::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;116919:49:0;;;;;;;;:::i;116120:47::-;;;:::i;211703:1028::-;;;:::i;194920:425::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;194920:425:0;-1:-1:-1;;;;;194920:425:0;;:::i;187831:1639::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;187831:1639:0;;;;;;;;:::i;118148:33::-;;;:::i;116469:31::-;;;:::i;120128:34::-;;;:::i;161466:467::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;161466:467:0;;;;;;;;;;;;;;;;;:::i;153103:48::-;;;:::i;:::-;;;;-1:-1:-1;;;;;153103:48:0;;;;;;;;;;;;;;157367:2010;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;157367:2010:0;-1:-1:-1;;;;;157367:2010:0;;:::i;120088:33::-;;;:::i;120368:24::-;;;:::i;115813:20::-;;;:::i;194:41::-;231:4;194:41;:::o;118776:21::-;;;;:::o;121554:30::-;;;;:::o;184446:1480::-;184751:6;;;:51;;;-1:-1:-1;;;184751:51:0;;-1:-1:-1;;;;;184751:51:0;;;;;;;;;;;;184561:4;;;;184683;;184561;;184751:6;;;;;:25;;:51;;;;;;;;;;;;;;;:6;:51;;;5:2:-1;;;;30:1;27;20:12;5:2;184751:51:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;184751:51:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;184751:51:0;;-1:-1:-1;184817:28:0;184813:96;;184875:17;184862:35;-1:-1:-1;184895:1:0;;-1:-1:-1;184862:35:0;;-1:-1:-1;;184862:35:0;184813:96;185302:25;185337:16;-1:-1:-1;;;;;185330:43:0;;:45;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;185330:45:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;185330:45:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;185330:45:0;;-1:-1:-1;185412:16:0;185439:20;;:::i;:::-;185470:22;;:::i;:::-;185503:16;;:::i;:::-;185544:91;185549:45;;;;;;;;185564:28;;185549:45;;;185596:38;;;;;;;;185611:21;185596:38;;;185544:4;:91::i;:::-;185532:103;;185660:85;185665:40;;;;;;;;185680:23;185665:40;;;185707:37;;;;;;;;185722:20;185707:37;;;185660:4;:85::i;:::-;185646:99;;185764:28;185769:9;185780:11;185764:4;:28::i;:::-;185756:36;;185819:44;185838:5;185845:17;185819:18;:44::i;:::-;185889:14;;-1:-1:-1;185805:58:0;-1:-1:-1;;;;;;;;184446:1480:0;;;;;;:::o;119312:70::-;;;;;;;;;;;;;;;;;;;;;;;;:::o;120785:31::-;;;;:::o;195353:429::-;195417:4;195486:5;;-1:-1:-1;;;;;195486:5:0;195472:10;:19;195468:120;;195515:61;195520:18;195540:35;195515:4;:61::i;:::-;195508:68;;;;195468:120;195622:11;;;195644:28;;;;195688:46;;;;;;;;;;;;;;;;;;;;;;;;;195759:14;195754:20;195747:27;;;195353:429;;;;:::o;205281:99::-;205342:30;205353:6;205361:10;205342:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;205342:30:0;;;;;;;;;;;;;;;;;;;;;:10;:30::i;:::-;205281:99;:::o;208540:209::-;153793:5;;-1:-1:-1;;;;;153793:5:0;153779:10;:19;153771:46;;;;;-1:-1:-1;;;153771:46:0;;;;;;;;;;;;-1:-1:-1;;;153771:46:0;;;;;;;;;;;;;;;208632:12;;;208655:28;;;;208699:42;;;;;;;;;;;;;;;;;;;;;;;;;153828:1;208540:209;:::o;196798:213::-;196878:10;-1:-1:-1;;;;;196878:16:0;;:18;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;196878:18:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;196878:18:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;196878:18:0;-1:-1:-1;;;;;196864:32:0;:10;:32;196856:70;;;;;-1:-1:-1;;;196856:70:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;196945:10;-1:-1:-1;;;;;196945:32:0;;:34;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;196945:34:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;196945:34:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;196945:34:0;:39;196937:66;;;;;-1:-1:-1;;;196937:66:0;;;;;;;;;;;;-1:-1:-1;;;196937:66:0;;;;;;;;;;;;;;167921:458;;;;;;:::o;121042:32::-;;;-1:-1:-1;;;;;121042:32:0;;:::o;209991:198::-;210073:21;:19;:21::i;:::-;210065:64;;;;;-1:-1:-1;;;210065:64:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;210140:41;210162:6;210170:10;210140:21;:41::i;:::-;209991:198;;:::o;166938:661::-;153674:14;;167108:4;;153674:14;;;;;153673:15;153665:46;;;;;-1:-1:-1;;;153665:46:0;;;;;;;;;;;;-1:-1:-1;;;153665:46:0;;;;;;;;;;;;;;;-1:-1:-1;;;;;167224:15:0;;;;;;:7;:15;;;;;:24;;;167219:94;;-1:-1:-1;167277:23:0;167265:36;;167219:94;167362:22;;:::i;:::-;167387:45;;;;;;;;167409:6;-1:-1:-1;;;;;167402:26:0;;:28;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;167402:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;167402:28:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;167402:28:0;167387:45;;167362:70;-1:-1:-1;167443:43:0;167466:6;167362:70;167443:22;:43::i;:::-;167497:54;167521:6;167529:8;167539:11;167497:23;:54::i;:::-;167576:14;167564:27;;;153722:1;166938:661;;;;;;:::o;118075:28::-;;;-1:-1:-1;;;;;118075:28:0;;:::o;115914:27::-;;;-1:-1:-1;;;;;115914:27:0;;:::o;194513:191::-;154067:13;;194591:4;;194576:5;;-1:-1:-1;;;;;154067:13:0;154053:10;:27;;:50;;-1:-1:-1;154098:5:0;;-1:-1:-1;;;;;154098:5:0;154084:10;:19;154053:50;154045:96;;;;-1:-1:-1;;;154045:96:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;154174:5;;-1:-1:-1;;;;;154174:5:0;154160:10;:19;;:36;;-1:-1:-1;154192:4:0;154183:13;;;;154160:36;154152:71;;;;;-1:-1:-1;;;154152:71:0;;;;;;;;;;;;-1:-1:-1;;;154152:71:0;;;;;;;;;;;;;;;194608:14;:22;;;;;;;;-1:-1:-1;;194608:22:0;;;;;;;;;;194646:27;;;;;;;;;;;;;;;;-1:-1:-1;194691:5:0;;194513:191;-1:-1:-1;194513:191:0:o;187031:426::-;187103:4;187173:5;;-1:-1:-1;;;;;187173:5:0;187159:10;:19;187151:63;;;;;-1:-1:-1;;;187151:63:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;187257:19;;;187287:44;;;;187347:62;;;;;;;;;;;;;;;;;;;;;;;;;187434:14;187429:20;;193948:484;153793:5;;-1:-1:-1;;;;;153793:5:0;153779:10;:19;153771:46;;;;;-1:-1:-1;;;153771:46:0;;;;;;;;;;;;-1:-1:-1;;;153771:46:0;;;;;;;;;;;;;;;194122:17;;;-1:-1:-1;;;;;194220:40:0;;;-1:-1:-1;;;;;;194220:40:0;;;;;;;194360:64;;;194122:17;;;;194360:64;;;;;;;;;;;;;;;;;;;;;;;153828:1;193948:484;:::o;211100:534::-;153674:14;;211190:4;;153674:14;;;;;153673:15;153665:46;;;;;-1:-1:-1;;;153665:46:0;;;;;;;;;;;;-1:-1:-1;;;153665:46:0;;;;;;;;;;;;;;;211296:21;;;;211295:22;:49;;;;-1:-1:-1;211322:22:0;;;;;;;211321:23;211295:49;211287:75;;;;;-1:-1:-1;;;211287:75:0;;;;;;;;;;;;-1:-1:-1;;;211287:75:0;;;;;;;;;;;;;;;211441:13;;-1:-1:-1;;;;;211441:13:0;211419:10;:36;211415:135;;211479:59;211484:15;211501:36;211479:4;:59::i;:::-;211472:66;;;;211415:135;-1:-1:-1;;;;;211560:17:0;;;;;;:10;:17;;;;;:26;;;211606:20;211599:27;;153722:1;211100:534;;;;:::o;210693:124::-;210767:42;210693:124;;:::o;118110:31::-;;;-1:-1:-1;;;118110:31:0;;;;;:::o;119856:42::-;;;;;;;;;;;;;:::o;209471:331::-;153793:5;;-1:-1:-1;;;;;153793:5:0;153779:10;:19;153771:46;;;;;-1:-1:-1;;;153771:46:0;;;;;;;;;;;;-1:-1:-1;;;153771:46:0;;;;;;;;;;;;;;;209596:15;:24;;-1:-1:-1;;;;;209596:24:0;;-1:-1:-1;;;;;;209596:24:0;;;;;;;;209631:17;:38;;;209680:16;:36;;;209732:62;;;;;;;;;;;;;;;;;;;;;;;;;;;;209471:331;;;:::o;208943:264::-;153793:5;;-1:-1:-1;;;;;153793:5:0;153779:10;:19;153771:46;;;;;-1:-1:-1;;;153771:46:0;;;;;;;;;;;;-1:-1:-1;;;153771:46:0;;;;;;;;;;;;;;;209055:17;;;209083:38;;;;209137:62;;;;;;;;;;;;;;;;;;;;;;;;;153828:1;208943:264;:::o;160789:226::-;;;;;:::o;120242:26::-;;;;;;;;;:::o;210487:91::-;210558:12;210487:91;:::o;170759:546::-;;;;;;;:::o;121222:42::-;;;;;;;;;;;;;:::o;116621:40::-;;;;:::o;177662:408::-;177838:4;177844;177850;177868:9;177879:14;177895;177913:98;177953:7;177969:12;177984;177998;177913:39;:98::i;:::-;177867:144;;;;;;178035:3;178030:9;;;;;;;;178022:40;-1:-1:-1;178041:9:0;;-1:-1:-1;178052:9:0;-1:-1:-1;;177662:408:0;;;;;;;;;:::o;159856:601::-;153674:14;;159964:4;;153674:14;;;;;153673:15;153665:46;;;;;-1:-1:-1;;;153665:46:0;;;;;;;;;;;;-1:-1:-1;;;153665:46:0;;;;;;;;;;;;;;;-1:-1:-1;;;;;160070:26:0;;;;;;:18;:26;;;;;;;;160069:27;160061:54;;;;;-1:-1:-1;;;160061:54:0;;;;;;;;;;;;-1:-1:-1;;;160061:54:0;;;;;;;;;;;;;;;-1:-1:-1;;;;;160191:15:0;;;;;;:7;:15;;;;;:24;;;160186:94;;160244:23;160239:29;160232:36;;;;160186:94;160329:30;160352:6;160329:22;:30::i;:::-;160370:39;160394:6;160402;160370:23;:39::i;:::-;160434:14;160429:20;160422:27;;153722:1;159856:601;;;;;:::o;189771:742::-;189861:4;189930:5;;-1:-1:-1;;;;;189930:5:0;189916:10;:19;189912:134;;189959:75;189964:18;189984:49;189959:4;:75::i;189912:134::-;190143:28;;;190239:62;;;;190376:89;;;;;;;;;;;;;;;;;;;;;;;;;190490:14;190485:20;;163155:321;163408:17;;;;:38;;-1:-1:-1;163429:17:0;;163408:38;163400:68;;;;;-1:-1:-1;;;163400:68:0;;;;;;;;;;;;-1:-1:-1;;;163400:68:0;;;;;;;;;;;;;;118665:26;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;118665:26:0;;-1:-1:-1;118665:26:0;:::o;186191:572::-;186255:4;186324:5;;-1:-1:-1;;;;;186324:5:0;186310:10;:19;186306:125;;186353:66;186358:18;186378:40;186353:4;:66::i;186306:125::-;186520:6;;;-1:-1:-1;;;;;186589:18:0;;;-1:-1:-1;;;;;;186589:18:0;;;;;;;186679:36;;;186520:6;;;;186679:36;;;;;;;;;;;;;;;;;;;;;;;186740:14;186735:20;;166122:322;;;;:::o;176757:268::-;176824:4;176830;176836;176854:9;176865:14;176881;176899:65;176939:7;176955:1;176959;176962;176899:39;:65::i;:::-;176853:111;;;;;;176990:3;176985:9;;;;;;;;176977:40;176996:9;;-1:-1:-1;176996:9:0;-1:-1:-1;176757:268:0;-1:-1:-1;;;176757:268:0:o;192040:610::-;192109:4;192144:5;;-1:-1:-1;;;;;192144:5:0;192130:10;:19;192126:127;;192173:68;192178:18;192198:42;192173:4;:68::i;192126:127::-;192344:13;;;-1:-1:-1;;;;;192430:32:0;;;-1:-1:-1;;;;;;192430:32:0;;;;;;;192550:52;;;192344:13;;;;192550:52;;;;;;;;;;;;;;;;;;;;;;;192627:14;192622:20;;168833:1452;153674:14;;169055:4;;153674:14;;;;;153673:15;153665:46;;;;;-1:-1:-1;;;153665:46:0;;;;;;;;;;;;-1:-1:-1;;;153665:46:0;;;;;;;;;;;;;;;-1:-1:-1;;;;;169136:23:0;;;;;;:7;:23;;;;;:32;;;;:85;;-1:-1:-1;169207:13:0;;-1:-1:-1;;;;;169172:49:0;;;169207:13;;169172:49;169136:85;169134:88;:127;;;-1:-1:-1;;;;;;169227:25:0;;;;;;:7;:25;;;;;:34;;;169226:35;169134:127;169130:196;;;169290:23;169285:29;169278:36;;;;169130:196;169415:9;169428:14;169446:66;169486:8;169503:1;169507;169510;169446:39;:66::i;:::-;169414:98;;-1:-1:-1;169414:98:0;;-1:-1:-1;169534:14:0;;-1:-1:-1;169527:3:0;:21;;;;;;;;;169523:70;;169577:3;169572:9;;;;;;;;169565:16;;;;;;169523:70;169607:14;169603:88;;169650:28;169645:34;;169603:88;169860:13;;169792:18;;-1:-1:-1;;;;;169825:49:0;;;169860:13;;169825:49;169821:219;;169914:14;-1:-1:-1;;;;;169907:42:0;;169950:8;169907:52;;;;;;;;;;;;;-1:-1:-1;;;;;169907:52:0;-1:-1:-1;;;;;169907:52:0;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;169907:52:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;169907:52:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;169907:52:0;;-1:-1:-1;169821:219:0;;;-1:-1:-1;;;;;;170008:20:0;;;;;;:10;:20;;;;;;169821:219;170052:13;170068:71;170087:36;;;;;;;;170102:19;;170087:36;;;170125:13;170068:18;:71::i;:::-;170052:87;;170168:8;170154:11;:22;170150:88;;;170205:20;170193:33;;;;;;;;170150:88;170262:14;170250:27;;;;;;153722:1;168833:1452;;;;;;;:::o;193172:606::-;193302:5;;-1:-1:-1;;;;;193302:5:0;193288:10;:19;;:54;;-1:-1:-1;193325:17:0;;-1:-1:-1;;;;;193325:17:0;193311:10;:31;193288:54;193280:120;;;;-1:-1:-1;;;193280:120:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;193431:7;193477:13;193518:15;;;;;:46;;;193551:13;193537:10;:27;193518:46;193510:72;;;;;-1:-1:-1;;;193510:72:0;;;;;;;;;;;;-1:-1:-1;;;193510:72:0;;;;;;;;;;;;;;;193599:6;193595:176;193615:10;193611:1;:14;193595:176;;;193681:13;;193695:1;193681:16;;;;;;;;;;;;;193647:10;:31;193666:7;;193674:1;193666:10;;;;;;;;;;;;;-1:-1:-1;;;;;193666:10:0;-1:-1:-1;;;;;193647:31:0;-1:-1:-1;;;;;193647:31:0;;;;;;;;;;;;:50;;;;193730:7;;193738:1;193730:10;;;;;;;;;;;;;-1:-1:-1;;;;;193730:10:0;-1:-1:-1;;;;;193717:42:0;;193742:13;;193756:1;193742:16;;;;;;;;;;;;;193717:42;;;;;;;;;;;;;;;;;;193627:3;;193595:176;;;;193172:606;;;;;;:::o;175412:345::-;175691:59;;118324:52;;;;;;;;;;;;;;;:::o;120700:32::-;;;;:::o;118267:50::-;;;;;;;;;;;;;;;:::o;118999:60::-;;;;;;;;;;;;-1:-1:-1;;;;;118999:60:0;;;-1:-1:-1;;;118999:60:0;;;;;:::o;120617:30::-;;;-1:-1:-1;;;;;120617:30:0;;:::o;116322:25::-;;;-1:-1:-1;;;;;116322:25:0;;:::o;119752:43::-;;;-1:-1:-1;;;;;119752:43:0;;:::o;118884:::-;;;;;;;;;;;;;:::o;118188:34::-;;;-1:-1:-1;;;118188:34:0;;;;;:::o;117757:41::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;154905:163::-;-1:-1:-1;;;;;155009:24:0;;;154985:4;155009:24;;;:7;:24;;;;;;;;:51;;;;;:42;;;;:51;;;;;;154905:163;;;;:::o;204410:718::-;204493:15;;-1:-1:-1;;;;;204493:15:0;204485:38;204481:87;;204540:16;:14;:16::i;:::-;204592:13;;-1:-1:-1;;;;;204592:13:0;204584:36;204580:541;;204834:13;;:53;;;-1:-1:-1;;;204834:53:0;;-1:-1:-1;;;;;204834:53:0;;;;;;;;;204637:21;;;;;;;;204834:13;;;;;:42;;:53;;;;;;;;;;;;;;204637:21;204834:13;:53;;;5:2:-1;;;;30:1;27;20:12;5:2;204834:53:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;204834:53:0;;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;204834:53:0;;;;;;;;;;;;;;;;;-1:-1:-1;204834:53:0;;-1:-1:-1;204834:53:0;;-1:-1:-1;204834:53:0;-1:-1:-1;204906:27:0;204902:208;;-1:-1:-1;;;;;204954:23:0;;;;;;:12;:23;;;;;;;;;:42;;;205020:74;;;;;;;;;;;;;;;;;;;;;;;;204580:541;;;;204410:718;:::o;116791:21::-;;;;:::o;205595:211::-;205701:16;;;205715:1;205701:16;;;;;;;;;205674:24;;205701:16;;;;;;105:10:-1;205701:16:0;88:34:-1;136:17;;-1:-1;205701:16:0;205674:43;;205741:6;205728:7;205736:1;205728:10;;;;;;;;;;;;;:19;-1:-1:-1;;;;;205728:19:0;;;-1:-1:-1;;;;;205728:19:0;;;;;205758:40;205769:7;205778;205787:4;205793;205758:10;:40::i;190840:721::-;190897:4;190932:5;;-1:-1:-1;;;;;190932:5:0;190918:10;:19;190914:123;;190961:64;190966:18;190986:38;190961:4;:64::i;190914:123::-;-1:-1:-1;;;;;191053:24:0;;;;;;:7;:24;;;;;:33;;;191049:141;;;191110:68;191115:27;191144:33;191110:4;:68::i;191049:141::-;191202:6;-1:-1:-1;;;;;191202:15:0;;:17;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;191202:17:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;191202:17:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;191367:69:0;;;;;;;;191385:4;191367:69;;;-1:-1:-1;191202:17:0;191367:69;;;;;;;;;;;;-1:-1:-1;;;;;191340:24:0;;;;:7;:24;;;;;;;:96;;;;;;;-1:-1:-1;;191340:96:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;191449:26;191356:6;191449:18;:26::i;:::-;191493:20;;;-1:-1:-1;;;;;191493:20:0;;;;;;;;;;;;;;;191538:14;191526:27;190840:721;-1:-1:-1;;190840:721:0:o;154502:126::-;-1:-1:-1;;;;;154598:22:0;;;;;;:13;:22;;;;;;;;;154591:29;;;;;;;;;;;;;;;;;154563:15;;154591:29;;;154598:22;154591:29;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;154591:29:0;;;;;;;;;;;;;;;;;;;;;;;154502:126;;;:::o;118229:31::-;;;-1:-1:-1;;;118229:31:0;;;;;:::o;210380:99::-;210426:15;210461:10;210454:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;210454:17:0;;;;;;;;;;;;;;;;;;;;;;;210380:99;:::o;121376:31::-;;;-1:-1:-1;;;;;121376:31:0;;:::o;116010:40::-;;;-1:-1:-1;;;;;116010:40:0;;:::o;119131:60::-;;;;;;;;;;;;-1:-1:-1;;;;;119131:60:0;;;-1:-1:-1;;;119131:60:0;;;;;:::o;174300:787::-;153674:14;;174426:4;;153674:14;;;;;153673:15;153665:46;;;;;-1:-1:-1;;;153665:46:0;;;;;;;;;;;;-1:-1:-1;;;153665:46:0;;;;;;;;;;;;;;;174532:22;;-1:-1:-1;;;174532:22:0;;;;174531:23;174523:54;;;;;-1:-1:-1;;;174523:54:0;;;;;;;;;;;;-1:-1:-1;;;174523:54:0;;;;;;;;;;;;;;;174712:12;174727:50;174749:6;174757:3;174762:14;174727:21;:50::i;:::-;174712:65;-1:-1:-1;174792:31:0;;174788:78;;174847:7;-1:-1:-1;174840:14:0;;174788:78;174915:30;174938:6;174915:22;:30::i;:::-;174956:36;174980:6;174988:3;174956:23;:36::i;:::-;175003;175027:6;175035:3;175003:23;:36::i;119954:23::-;;;;:::o;119653:44::-;;;;;;;;;;;;;:::o;155334:344::-;155490:15;;;;;;;;;;;;;;;;155402:13;;155439:7;;155402:13;;155439:7;155490:15;;;;;;;29:2:-1;21:6;17:15;117:4;105:10;97:6;88:34;136:17;;-1:-1;155490:15:0;-1:-1:-1;155466:39:0;-1:-1:-1;155521:6:0;155516:128;155537:3;155533:1;:7;155516:128;;;155580:51;155607:7;;155615:1;155607:10;;;;;;;;;;;;;-1:-1:-1;;;;;155607:10:0;155620;155580:19;:51::i;:::-;155575:57;;;;;;;;155562:7;155570:1;155562:10;;;;;;;;;;;;;;;;;:70;155542:3;;155516:128;;;-1:-1:-1;155663:7:0;155334:344;-1:-1:-1;;;;155334:344:0:o;182419:1554::-;182677:6;;;:49;;;-1:-1:-1;;;182677:49:0;;-1:-1:-1;;;;;182677:49:0;;;;;;;;;;;;182555:4;;;;;;182677:6;;;:25;;:49;;;;;;;;;;;;;;;:6;:49;;;5:2:-1;;;;30:1;27;20:12;5:2;182677:49:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;182677:49:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;182677:49:0;182768:6;;;:51;;;-1:-1:-1;;;182768:51:0;;-1:-1:-1;;;;;182768:51:0;;;;;;;;;;;;182677:49;;-1:-1:-1;182737:28:0;;182768:6;;;;;:25;;:51;;;;;182677:49;;182768:51;;;;;;;;:6;:51;;;5:2:-1;;;;30:1;27;20:12;5:2;182768:51:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;182768:51:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;182768:51:0;;-1:-1:-1;182834:26:0;;;:58;;-1:-1:-1;182864:28:0;;182834:58;182830:126;;;182922:17;182909:35;-1:-1:-1;182942:1:0;;-1:-1:-1;182909:35:0;;-1:-1:-1;;182909:35:0;182830:126;183349:25;183384:16;-1:-1:-1;;;;;183377:43:0;;:45;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;183377:45:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;183377:45:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;183377:45:0;;-1:-1:-1;183459:16:0;183486:20;;:::i;:::-;183517:22;;:::i;:::-;183550:16;;:::i;:::-;183591:91;183596:45;;;;;;;;183611:28;;183596:45;;;183643:38;;;;;;;;183658:21;183643:38;;;183591:4;:91::i;:::-;183579:103;;183707:85;183712:40;;;;;;;;183727:23;183712:40;;;183754:37;;;;;;;;183769:20;183754:37;;;183707:4;:85::i;:::-;183693:99;;183811:28;183816:9;183827:11;183811:4;:28::i;:::-;183803:36;;183866:44;183885:5;183892:17;183866:18;:44::i;:::-;183936:14;;-1:-1:-1;183852:58:0;-1:-1:-1;;;;;;;;182419:1554:0;;;;;;;:::o;119503:70::-;;;;;;;;;;;;;;;;;;;;;;;;:::o;121450:30::-;;;-1:-1:-1;;;;;121450:30:0;;:::o;120550:29::-;;;;:::o;171768:1129::-;153674:14;;171980:4;;153674:14;;;;;153673:15;153665:46;;;;;-1:-1:-1;;;153665:46:0;;;;;;;;;;;;-1:-1:-1;;;153665:46:0;;;;;;;;;;;;;;;172086:19;;-1:-1:-1;;;172086:19:0;;;;172085:20;172077:48;;;;;-1:-1:-1;;;172077:48:0;;;;;;;;;;;;-1:-1:-1;;;172077:48:0;;;;;;;;;;;;;;;-1:-1:-1;;;;;172281:25:0;;;;;;:7;:25;;;;;:34;;;172280:35;;:127;;-1:-1:-1;;;;;;172321:23:0;;;;;;:7;:23;;;;;:32;;;;:85;;-1:-1:-1;172392:13:0;;-1:-1:-1;;;;;172357:49:0;;;172392:13;;172357:49;172321:85;172319:88;172280:127;172276:196;;;172436:23;172431:29;;172276:196;172537:14;-1:-1:-1;;;;;172530:34:0;;:36;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;172530:36:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;172530:36:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;172530:36:0;172488:38;;;-1:-1:-1;;;172488:38:0;;;;-1:-1:-1;;;;;172488:78:0;;;;:36;;;;;:38;;;;;172530:36;;172488:38;;;;;;;:36;:38;;;5:2:-1;;;;30:1;27;20:12;5:2;172488:38:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;172488:38:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;172488:38:0;-1:-1:-1;;;;;172488:78:0;;172484:150;;172595:26;172590:32;;172484:150;172683:40;172706:16;172683:22;:40::i;:::-;172734:51;172758:16;172776:8;172734:23;:51::i;:::-;172796:53;172820:16;172838:10;172796:23;:53::i;:::-;172874:14;172862:27;171768:1129;-1:-1:-1;;;;;;171768:1129:0:o;195790:1000::-;195916:4;195987:5;;-1:-1:-1;;;;;195987:5:0;195973:10;:19;;:53;;-1:-1:-1;196010:16:0;;-1:-1:-1;;;;;196010:16:0;195996:10;:30;195973:53;195967:158;;196051:62;196056:18;196076:36;196051:4;:62::i;195967:158::-;196166:4;196145:18;:25;196137:67;;;;;-1:-1:-1;;;196137:67:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;196247:16;;;196303:15;;;196355;;;-1:-1:-1;;;;;196383:38:0;;;-1:-1:-1;;;;;;196383:38:0;;;;;;;196432:36;;;;;;;;;;196479;;;;196533:61;;;196247:16;;;196533:61;;;;;;;;;;;;196303:15;;;;;196355;;196533:61;;;;;;;;;196610:58;;;-1:-1:-1;;;;;196610:58:0;;;;;;;;;;;;;;;;;;;;;;;;196684;;;;;;;;;;;;;;;;;;;;;;;;;196767:14;196755:27;195790:1000;-1:-1:-1;;;;;;;195790:1000:0:o;206148:1465::-;206297:13;;206269:6;;-1:-1:-1;;;;;206297:13:0;206289:36;206286:107;;206342:13;;;;;;;;;-1:-1:-1;;;;;206342:13:0;-1:-1:-1;;;;;206342:37:0;;:39;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;206342:39:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;206342:39:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;206286:107:0;-1:-1:-1;206412:1:0;206403:197;206419:7;:14;206415:1;:18;206403:197;;;206455:36;206480:7;206488:1;206480:10;;;;;;;;;;;;;;206455:24;:36::i;:::-;206533:55;206551:7;206559:1;206551:10;;;;;;;;;;;;;;206563:12;:24;206576:7;206584:1;206576:10;;;;;;;;;;;;;;-1:-1:-1;;;;;206563:24:0;-1:-1:-1;;;;;206563:24:0;;;;;;;;;;;;;206533:17;:55::i;:::-;206506:12;:24;206519:7;206527:1;206519:10;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;206506:24:0;;;;;;;;;;;-1:-1:-1;206506:24:0;:82;206435:3;;206403:197;;;206615:6;206610:996;206631:7;:14;206627:1;:18;206610:996;;;206667:13;206683:7;206691:1;206683:10;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;206716:24:0;;;;;;:7;:24;;;;;;;:33;206683:10;;-1:-1:-1;206716:33:0;;206708:63;;;;;-1:-1:-1;;;206708:63:0;;;;;;;;;;;;-1:-1:-1;;;206708:63:0;;;;;;;;;;;;;;;206790:9;206786:451;;;206820:22;;:::i;:::-;206845:37;;;;;;;;206860:6;-1:-1:-1;;;;;206860:18:0;;:20;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;206860:20:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;206860:20:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;206860:20:0;206845:37;;206820:62;-1:-1:-1;206901:52:0;206932:6;206820:62;206901:22;:52::i;:::-;206981:1;206977:5;;206972:250;206988:7;:14;206984:1;:18;206972:250;;;207032:65;207064:6;207073:7;207081:1;207073:10;;;;;;;;;;;;;;207085:11;207032:23;:65::i;:::-;207147:55;207165:7;207173:1;207165:10;;;;;;;;;;;;;;207177:12;:24;207190:7;207198:1;207190:10;;;;;;;207147:55;207120:12;:24;207133:7;207141:1;207133:10;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;207120:24:0;;;;;;;;;;;-1:-1:-1;207120:24:0;:82;207004:3;;;;;206972:250;;;206786:451;;207255:9;207251:344;;;207285:39;207316:6;207285:22;:39::i;:::-;207352:1;207348:5;;207343:237;207359:7;:14;207355:1;:18;207343:237;;;207403:52;207435:6;207444:7;207452:1;207444:10;;;;;;;;;;;;;;207403:23;:52::i;:::-;207505:55;207523:7;207531:1;207523:10;;;;;;;;;;;;;;207535:12;:24;207548:7;207556:1;207548:10;;;;;;;207505:55;207478:12;:24;207491:7;207499:1;207491:10;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;207478:24:0;;;;;;;;;;;-1:-1:-1;207478:24:0;:82;207375:3;;;;;207343:237;;;-1:-1:-1;206647:3:0;;206610:996;;163917:1898;153674:14;;164031:4;;153674:14;;;;;153673:15;153665:46;;;;;-1:-1:-1;;;153665:46:0;;;;;;;;;;;;-1:-1:-1;;;153665:46:0;;;;;;;;;;;;;;;-1:-1:-1;;;;;164137:28:0;;;;;;:20;:28;;;;;;;;164136:29;164128:58;;;;;-1:-1:-1;;;164128:58:0;;;;;;;;;;;;-1:-1:-1;;;164128:58:0;;;;;;;;;;;;;;;-1:-1:-1;;;;;164204:15:0;;;;;;:7;:15;;;;;:24;;;164199:94;;164257:23;164252:29;;164199:94;-1:-1:-1;;;;;164310:15:0;;;;;;;:7;:15;;;;;;;;:43;;;;;:33;;;;:43;;;;;;164305:429;;164456:10;-1:-1:-1;;;;;164456:20:0;;;164448:54;;;;;-1:-1:-1;;;164448:54:0;;;;;;;;;;;;-1:-1:-1;;;164448:54:0;;;;;;;;;;;;;;;164573:9;164585:45;164612:6;164621:8;164585:19;:45::i;:::-;164573:57;-1:-1:-1;164656:14:0;164649:3;:21;;;;;;;;;164645:78;;164703:3;164698:9;;;;;;;;164691:16;;;;;164645:78;164305:429;;164750:6;;;:41;;;-1:-1:-1;;;164750:41:0;;-1:-1:-1;;;;;164750:41:0;;;;;;;;;;;;:6;;;;;:25;;:41;;;;;;;;;;;;;;;:6;:41;;;5:2:-1;;;;30:1;27;20:12;5:2;164750:41:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;164750:41:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;164750:41:0;164746:109;;164825:17;164820:23;;164746:109;-1:-1:-1;;;;;164884:18:0;;164867:14;164884:18;;;:10;:18;;;;;;164980:14;;164976:248;;165011:17;165038:6;-1:-1:-1;;;;;165031:27:0;;:29;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;165031:29:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;165031:29:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;165031:29:0;;-1:-1:-1;165075:21:0;165099:32;165031:29;165118:12;165099:4;:32::i;:::-;165075:56;;165173:9;165154:16;:28;165146:66;;;;;-1:-1:-1;;;165146:66:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;164976:248;;;165237:9;165250:14;165268:82;165308:8;165325:6;165334:1;165337:12;165268:39;:82::i;:::-;165236:114;;-1:-1:-1;165236:114:0;;-1:-1:-1;165372:14:0;;-1:-1:-1;165365:3:0;:21;;;;;;;;;165361:70;;165415:3;165410:9;;;;;;;;165403:16;;;;;;;165361:70;165445:14;;165441:88;;165488:28;165483:34;;165441:88;165578:22;;:::i;:::-;165603:45;;;;;;;;165625:6;-1:-1:-1;;;;;165618:26:0;;:28;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;165618:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;165618:28:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;165618:28:0;165603:45;;165578:70;-1:-1:-1;165659:43:0;165682:6;165578:70;165659:22;:43::i;:::-;165713:54;165737:6;165745:8;165755:11;165713:23;:54::i;:::-;165792:14;165780:27;163917:1898;-1:-1:-1;;;;;;;;163917:1898:0:o;116919:49::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;116919:49:0;;-1:-1:-1;116919:49:0;;-1:-1:-1;116919:49:0:o;116120:47::-;;;-1:-1:-1;;;;;116120:47:0;;:::o;211703:1028::-;211750:17;;:22;;:62;;;211795:17;;211776:16;:14;:16::i;:::-;:36;211750:62;211747:100;;;211829:7;;211747:100;211859:8;211875:16;:14;:16::i;:::-;211926:28;;;-1:-1:-1;;;211926:28:0;;211948:4;211926:28;;;;;;211859:33;;-1:-1:-1;211905:18:0;;-1:-1:-1;;;;;211926:13:0;;;;;:28;;;;;;;;;;;;;;:13;:28;;;5:2:-1;;;;30:1;27;20:12;5:2;211926:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;211926:28:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;211926:28:0;;-1:-1:-1;211968:15:0;211965:53;;212000:7;;;;211965:53;212032:20;212063:19;212085:41;212090:16;:14;:16::i;:::-;212108:17;;212085:4;:41::i;:::-;212063:63;;212197:22;212222:36;212227:17;;212246:11;212222:4;:36::i;:::-;212197:61;;212292:16;;212275:14;:33;212271:72;;;212325:7;;;;;;;212271:72;212373:14;212359:10;:28;212355:148;;212419:14;212404:29;;212355:148;;;212481:10;212466:25;;212355:148;212535:16;:14;:16::i;:::-;212515:17;:36;212577:15;;212564:43;;;-1:-1:-1;;;212564:43:0;;-1:-1:-1;;;;;212577:15:0;;;212564:43;;;;;;;;;;;;:12;;;;;;:43;;;;;;;;;;;;;;;212577:15;212564:12;:43;;;5:2:-1;;;;30:1;27;20:12;5:2;212564:43:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;212564:43:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;212623:38:0;;;;;;;;;;;;;212564:43;212623:38;;;212684:15;;;;;;;;;-1:-1:-1;;;;;212684:15:0;-1:-1:-1;;;;;212674:47:0;;:49;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;212674:49:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;212674:49:0;;;;211703:1028;;;;;;:::o;194920:425::-;195004:4;195073:5;;-1:-1:-1;;;;;195073:5:0;195059:10;:19;195055:126;;195102:67;195107:18;195127:41;195102:4;:67::i;195055:126::-;195226:13;;;-1:-1:-1;;;;;195250:30:0;;;-1:-1:-1;;;;;;195250:30:0;;;;;;;195296:41;;;195226:13;;;;195296:41;;;;;;;;;;;;;;;;;;;;;;;194920:425;;;;:::o;187831:1639::-;187928:4;187997:5;;-1:-1:-1;;;;;187997:5:0;187983:10;:19;187979:130;;188026:71;188031:18;188051:45;188026:4;:71::i;187979:130::-;-1:-1:-1;;;;;188181:24:0;;188157:21;188181:24;;;:7;:24;;;;;188221:15;;;;188216:130;;188260:74;188265:23;188290:43;188260:4;:74::i;:::-;188253:81;;;;;188216:130;188358:33;;:::i;:::-;-1:-1:-1;188394:44:0;;;;;;;;;;;;188494:20;;:::i;:::-;-1:-1:-1;188517:44:0;;;;;;;;;153537:6;188517:44;;188576:46;188517:44;188599:22;188576:11;:46::i;:::-;188572:169;;;188646:83;188651:31;188684:44;188646:4;:83::i;:::-;188639:90;;;;;;;188572:169;188815:32;;;;;:74;;-1:-1:-1;188851:6:0;;;:33;;;-1:-1:-1;;;188851:33:0;;-1:-1:-1;;;;;188851:33:0;;;;;;;;;;;;:6;;;;;:25;;:33;;;;;;;;;;;;;;;:6;:33;;;5:2:-1;;;;30:1;27;20:12;5:2;188851:33:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;188851:33:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;188851:33:0;:38;188815:74;188811:186;;;188913:72;188918:17;188937:47;188913:4;:72::i;188811:186::-;189132:31;;;;;189174:61;;;;189337:85;;;-1:-1:-1;;;;;189337:85:0;;;;;;;;;;;;;;;;;;;;;;;;;;;189447:14;189435:27;187831:1639;-1:-1:-1;;;;;;;187831:1639:0:o;118148:33::-;;;-1:-1:-1;;;118148:33:0;;;;;:::o;116469:31::-;;;;:::o;120128:34::-;;;;;;;;;:::o;161466:467::-;153674:14;;161580:4;;153674:14;;;;;153673:15;153665:46;;;;;-1:-1:-1;;;153665:46:0;;;;;;;;;;;;-1:-1:-1;;;153665:46:0;;;;;;;;;;;;;;;161597:12;161612:53;161634:6;161642:8;161652:12;161612:21;:53::i;:::-;161597:68;-1:-1:-1;161680:31:0;;161676:78;;161735:7;-1:-1:-1;161728:14:0;;161676:78;161803:30;161826:6;161803:22;:30::i;:::-;161844:41;161868:6;161876:8;161844:23;:41::i;:::-;161910:14;161898:27;161466:467;-1:-1:-1;;;;;161466:467:0:o;153103:48::-;153147:4;153103:48;:::o;157367:2010::-;157428:4;157445:13;157468;157445:37;;157573:9;157584:15;157601;157622:6;-1:-1:-1;;;;;157622:25:0;;157648:10;157622:37;;;;;;;;;;;;;-1:-1:-1;;;;;157622:37:0;-1:-1:-1;;;;;157622:37:0;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;157622:37:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;157622:37:0;;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;157622:37:0;;;;;;;;;;;;;-1:-1:-1;157622:37:0;;-1:-1:-1;157622:37:0;-1:-1:-1;157678:9:0;;157670:47;;;;;-1:-1:-1;;;157670:47:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;157815:15;;157811:127;;157854:72;157859:28;157889:36;157854:4;:72::i;:::-;157847:79;;;;;;;;157811:127;158031:12;158046:60;158068:13;158083:10;158095;158046:21;:60::i;:::-;158031:75;-1:-1:-1;158121:12:0;;158117:123;;158157:71;158168:15;158185:33;158220:7;158157:10;:71::i;:::-;158150:78;;;;;;;;;158117:123;-1:-1:-1;;;;;158282:24:0;;158252:27;158282:24;;;:7;:24;;;;;;;;158431:10;158400:42;;:30;;;:42;;;;;;;;;158395:103;;158471:14;158459:27;;;;;;;;;;158395:103;158602:10;158571:42;;;;:30;;;:42;;;;;;;;158564:49;;-1:-1:-1;;158564:49:0;;;158840:13;:25;;;;;158887:20;;158840:25;;158935:220;158946:3;158942:1;:7;158935:220;;;158995:6;-1:-1:-1;;;;;158975:26:0;:13;158989:1;158975:16;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;158975:16:0;:26;158971:173;;;159041:13;159061:1;159055:3;:7;159041:22;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;159041:22:0;159022:13;159036:1;159022:16;;;;;;;;;;;;;;;;;:41;;-1:-1:-1;;;;;;159022:41:0;-1:-1:-1;;;;;159022:41:0;;;;;;;;;;159082:22;;;;-1:-1:-1;;159082:22:0;;;:::i;:::-;;159123:5;;158971:173;158951:3;;158935:220;;;159275:3;159271:1;:7;159264:15;;;;159297:32;;;-1:-1:-1;;;;;159297:32:0;;;;159318:10;159297:32;;;;;;;;;;;;;;;;;159354:14;159342:27;157367:2010;-1:-1:-1;;;;;;;;;;;157367:2010:0:o;120088:33::-;;;;;;:::o;120368:24::-;;;;:::o;115813:20::-;;;-1:-1:-1;;;;;115813:20:0;;:::o;32145:159::-;32210:10;;:::i;:::-;32240:56;;;;;;;;28446:4;32255:28;32260:1;:10;;;32272:1;:10;;;32255:4;:28::i;:::-;:39;;;;;;32240:56;;32233:63;32145:159;-1:-1:-1;;;32145:159:0:o;33437:164::-;33502:10;;:::i;:::-;33532:61;;;;;;;;33547:44;33552:26;33557:1;:10;;;28446:4;33552;:26::i;:::-;33580:10;;33547:4;:44::i;:::-;33532:61;;33525:68;33437:164;-1:-1:-1;;;33437:164:0:o;29168:174::-;29246:4;29263:18;;:::i;:::-;29284:15;29289:1;29292:6;29284:4;:15::i;:::-;29263:36;;29317:17;29326:7;29317:8;:17::i;17105:153::-;17166:4;17188:33;17201:3;17196:9;;;;;;;;17212:4;17207:10;;;;;;;;17188:33;;;;;;;;;;;;;17219:1;17188:33;;;;;;;;;;;;;17246:3;17241:9;;;;;;;197129:148;197183:4;197221:5;;-1:-1:-1;;;;;197221:5:0;197207:10;:19;;:62;;-1:-1:-1;197244:25:0;;-1:-1:-1;;;;;197244:25:0;197230:10;:39;197207:62;197200:69;;197129:148;:::o;197321:1583::-;-1:-1:-1;;;;;197429:28:0;;197404:22;197429:28;;;:11;:28;;;;;;197472:22;;197468:1255;;197605:22;;:::i;:::-;197630:37;;;;;;;;197645:6;-1:-1:-1;;;;;197645:18:0;;:20;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;197645:20:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;197645:20:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;197645:20:0;197630:37;;197605:62;-1:-1:-1;197682:39:0;197713:6;197682:22;:39::i;:::-;197736:52;197767:6;197776:11;197736:22;:52::i;:::-;197468:1255;;;;197810:15;;197806:917;;-1:-1:-1;;;;;197902:24:0;;197878:21;197902:24;;;:7;:24;;;;;197949:15;;;;:23;;:15;:23;197941:62;;;;;-1:-1:-1;;;197941:62:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;198024:33:0;;;;;;:16;:33;;;;;:39;-1:-1:-1;;;;;198024:39:0;:44;:92;;;;-1:-1:-1;;;;;;198072:33:0;;;;;;:16;:33;;;;;:39;-1:-1:-1;;;198072:39:0;;;;:44;198024:92;198020:339;;;198173:170;;;;;;;;153147:4;-1:-1:-1;;;;;198173:170:0;;;;;198267:56;198274:16;:14;:16::i;:::-;198267:56;;;;;;;;;;;;;;;;;:6;:56::i;:::-;198173:170;;;;;;;-1:-1:-1;;;;;198137:33:0;;;;;;:16;:33;;;;;;;;:206;;;;;;;;;;;;-1:-1:-1;;;198137:206:0;-1:-1:-1;;;;;198137:206:0;;;-1:-1:-1;;;;;;198137:206:0;;;;;;;;;;;;;;198020:339;-1:-1:-1;;;;;198377:33:0;;;;;;:16;:33;;;;;:39;-1:-1:-1;;;;;198377:39:0;:44;:92;;;;-1:-1:-1;;;;;;198425:33:0;;;;;;:16;:33;;;;;:39;-1:-1:-1;;;198425:39:0;;;;:44;198377:92;198373:339;;;198526:170;;;;;;;;153147:4;-1:-1:-1;;;;;198526:170:0;;;;;198620:56;198627:16;:14;:16::i;198620:56::-;198526:170;;;;;;;-1:-1:-1;;;;;198490:33:0;;;;;;:16;:33;;;;;;;;:206;;;;;;;;;;;;-1:-1:-1;;;198490:206:0;-1:-1:-1;;;;;198490:206:0;;;-1:-1:-1;;;;;;198490:206:0;;;;;;;;;;;;;;198373:339;197806:917;;198760:10;198739:17;:31;198735:162;;-1:-1:-1;;;;;198787:28:0;;;;;;:11;:28;;;;;;;;;:41;;;198848:37;;;;;;;;;;;;;;;;;197321:1583;;;:::o;200258:1092::-;-1:-1:-1;;;;;200395:24:0;;200356:36;200395:24;;;:16;:24;;;;;;;;200449:11;:19;;;;;;200395:24;;200498:16;:14;:16::i;:::-;200567:17;;200479:35;;-1:-1:-1;200525:16:0;;200544:42;;200479:35;;-1:-1:-1;;;200567:17:0;;;;200544:4;:42::i;:::-;200525:61;;200615:1;200601:11;:15;:34;;;;;200634:1;200620:11;:15;200601:34;200597:746;;;200652:17;200672:54;200684:6;-1:-1:-1;;;;;200677:27:0;;:29;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;200677:29:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;200677:29:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;200677:29:0;200708:17;200672:4;:54::i;:::-;200652:74;;200741:17;200761:30;200766:11;200779;200761:4;:30::i;:::-;200741:50;;200806:19;;:::i;:::-;200843:1;200828:12;:16;:79;;200886:21;;;;;;;;200904:1;200886:21;;;200828:79;;;200847:36;200856:12;200870;200847:8;:36::i;:::-;200806:101;;200922:19;;:::i;:::-;200949:37;;;;;;;;;200967:17;;-1:-1:-1;;;;;200967:17:0;200949:37;;200944:50;;200988:5;200944:4;:50::i;:::-;200922:72;;201036:176;;;;;;;;201079:46;201087:5;:14;;;201079:46;;;;;;;;;;;;;-1:-1:-1;;;201079:46:0;;;:7;:46::i;:::-;-1:-1:-1;;;;;201036:176:0;;;;;201151:45;201158:11;201151:45;;;;;;;;;;;;;-1:-1:-1;;;201151:45:0;;;:6;:45::i;:::-;201036:176;;;;;;;-1:-1:-1;;;;;201009:24:0;;;;;;:16;:24;;;;;;;;:203;;;;;;;;;;;;-1:-1:-1;;;201009:203:0;-1:-1:-1;;;;;201009:203:0;;;-1:-1:-1;;;;;;201009:203:0;;;;;;;;;;;;;;-1:-1:-1;200597:746:0;;-1:-1:-1;;;200597:746:0;;201234:15;;201230:113;;201286:45;201293:11;201286:45;;;;;;;;;;;;;-1:-1:-1;;;201286:45:0;;;:6;:45::i;:::-;201266:65;;;;;;;-1:-1:-1;;;201266:65:0;-1:-1:-1;;;;;201266:65:0;;;;;;200258:1092;;;;;;:::o;203039:1077::-;203168:15;;-1:-1:-1;;;;;203168:15:0;203160:38;203156:87;;203215:16;:14;:16::i;:::-;-1:-1:-1;;;;;203294:24:0;;203255:36;203294:24;;;:16;:24;;;;;203329:25;;:::i;:::-;-1:-1:-1;203357:37:0;;;;;;;;;203375:17;;-1:-1:-1;;;;;203375:17:0;203357:37;;203405:27;;:::i;:::-;-1:-1:-1;203435:56:0;;;;;;;;;-1:-1:-1;;;;;203453:26:0;;;-1:-1:-1;203453:26:0;;;:18;:26;;;;;:36;;;;;;;;;;;;;;203435:56;;203541:20;;203502:36;;;;;;:59;;;;203578:22;;:26;203574:535;;203621:24;;:::i;:::-;203648:32;203653:11;203666:13;203648:4;:32::i;:::-;203621:59;;203695:19;203717:69;203729:6;-1:-1:-1;;;;;203722:34:0;;203757:8;203722:44;;;;;;;;;;;;;-1:-1:-1;;;;;203722:44:0;-1:-1:-1;;;;;203722:44:0;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;203717:69:0;203695:91;;203801:18;203822:32;203827:14;203843:10;203822:4;:32::i;:::-;-1:-1:-1;;;;;203897:22:0;;203869:20;203897:22;;;:12;:22;;;;;;203801:53;;-1:-1:-1;203869:20:0;203892:43;;203801:53;203892:4;:43::i;:::-;-1:-1:-1;;;;;203950:22:0;;;;;;;:12;:22;;;;;;;;;:40;;;204076:20;;204010:87;;;;;;;;;;;203869:66;;-1:-1:-1;203950:22:0;;204010:87;;;;;;;;;;;;;;203574:535;;;;203039:1077;;;;;;:::o;178849:3032::-;179034:5;179041:4;179047;179066:37;;:::i;:::-;-1:-1:-1;;;;;179243:22:0;;179151:9;179243:22;;;:13;:22;;;;;;;;179218:47;;;;;;;;;;;;;;;;;:22;;:47;;179243:22;179218:47;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;179218:47:0;;;;;;;;;;;;;;;;-1:-1:-1;179218:47:0;;-1:-1:-1;179281:6:0;;-1:-1:-1;;;;179276:2161:0;179297:6;:13;179293:1;:17;179276:2161;;;179332:12;179347:6;179354:1;179347:9;;;;;;;;;;;;;;179332:24;;179517:5;-1:-1:-1;;;;;179517:24:0;;179542:7;179517:33;;;;;;;;;;;;;-1:-1:-1;;;;;179517:33:0;-1:-1:-1;;;;;179517:33:0;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;179517:33:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;179517:33:0;;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;179517:33:0;;;;;;;;;;;;;;;;;179488:25;;179441:109;179468:18;;;179441:109;;;;179448:18;;;179441:109;;;;179517:33;-1:-1:-1;179569:9:0;;179565:166;;-1:-1:-1;179688:20:0;;-1:-1:-1;179710:1:0;;-1:-1:-1;179710:1:0;;-1:-1:-1;179680:35:0;;-1:-1:-1;;;;179680:35:0;179565:166;179769:65;;;;;;;;;-1:-1:-1;;;;;179784:23:0;;;-1:-1:-1;179784:23:0;;;:7;:23;;;;;:48;;;179769:65;;179745:21;;;:89;;;;179869:42;;;;;;;-1:-1:-1;;;179884:25:0;179869:42;;179849:17;;;:62;180009:6;;;:32;;-1:-1:-1;;;180009:32:0;;;;;;;;;;;:6;;;:25;;:32;;;;;179769:65;180009:32;;;;;:6;:32;;;5:2:-1;;;;30:1;27;20:12;5:2;180009:32:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;180009:32:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;180009:32:0;179982:24;;;:59;;;180056:102;;-1:-1:-1;180118:17:0;;-1:-1:-1;180137:1:0;;-1:-1:-1;180137:1:0;;-1:-1:-1;180110:32:0;;-1:-1:-1;;;;180110:32:0;180056:102;180191:41;;;;;;;;;180206:24;;;;180191:41;;180172:16;;;:60;180372:21;;;;180395:17;;;;180362:70;;180367:46;;:4;:46::i;:::-;180415:4;:16;;;180362:4;:70::i;:::-;180341:18;;;:91;;;180579:18;;;;180599;;180533:85;;180341:91;180579:18;180533:25;:85::i;:::-;180512:106;;180757:16;;;;180775:18;;;;180795:25;;;;180731:90;;180757:16;180775:18;180731:25;:90::i;:::-;180703:25;;;:118;-1:-1:-1;;;;;180909:21:0;;;;;;;180905:521;;;181086:86;181112:4;:18;;;181132:12;181146:4;:25;;;181086;:86::i;:::-;181058:25;;;:114;;;181352:16;;;;181326:84;;181370:12;;181326:25;:84::i;:::-;181298:25;;;:112;180905:521;-1:-1:-1;179312:3:0;;179276:2161;;;;181477:52;181482:4;:25;;;181509:10;:19;181520:7;-1:-1:-1;;;;;181509:19:0;-1:-1:-1;;;;;181509:19:0;;;;;;;;;;;;;181477:4;:52::i;:::-;181449:25;;;:80;;;181618:18;;:46;181614:260;;;-1:-1:-1;;181726:25:0;;;;181705:18;;181689:14;;-1:-1:-1;181705:46:0;;-1:-1:-1;181689:14:0;;-1:-1:-1;181681:74:0;;181614:260;-1:-1:-1;;181843:18:0;;181815:25;;;;;181796:14;;-1:-1:-1;181796:14:0;;-1:-1:-1;181815:46:0;;-1:-1:-1;181788:74:0;;199063:1036;-1:-1:-1;;;;;199170:24:0;;199131:36;199170:24;;;:16;:24;;;;;;;;199224:11;:19;;;;;;199170:24;;199273:16;:14;:16::i;:::-;199342:17;;199254:35;;-1:-1:-1;199300:16:0;;199319:42;;199254:35;;-1:-1:-1;;;199342:17:0;;;;199319:4;:42::i;:::-;199300:61;;199390:1;199376:11;:15;:34;;;;;199409:1;199395:11;:15;199376:34;199372:720;;;199427:17;199454:6;-1:-1:-1;;;;;199447:26:0;;:28;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;199447:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;199447:28:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;199447:28:0;;-1:-1:-1;199490:17:0;199510:30;199515:11;199528;199510:4;:30::i;:::-;199490:50;;199555:19;;:::i;:::-;199592:1;199577:12;:16;:79;;199635:21;;;;;;;;199653:1;199635:21;;;199577:79;;;199596:36;199605:12;199619;199596:8;:36::i;:::-;199555:101;;199671:19;;:::i;:::-;199698:37;;;;;;;;;199716:17;;-1:-1:-1;;;;;199716:17:0;199698:37;;199693:50;;199737:5;199693:4;:50::i;:::-;199671:72;;199785:176;;;;;;;;199828:46;199836:5;:14;;;199828:46;;;;;;;;;;;;;-1:-1:-1;;;199828:46:0;;;:7;:46::i;:::-;-1:-1:-1;;;;;199785:176:0;;;;;199900:45;199907:11;199900:45;;;;;;;;;;;;;-1:-1:-1;;;199900:45:0;;;:6;:45::i;:::-;199785:176;;;;;;;-1:-1:-1;;;;;199758:24:0;;;;;;:16;:24;;;;;;;;:203;;;;;;;;;;;;-1:-1:-1;;;199758:203:0;-1:-1:-1;;;;;199758:203:0;;;-1:-1:-1;;;;;;199758:203:0;;;;;;;;;;;;;;-1:-1:-1;199372:720:0;;-1:-1:-1;;;199372:720:0;;199983:15;;199979:113;;200035:45;200042:11;200035:45;;;;;;;;;;;;;-1:-1:-1;;;200035:45:0;;;:6;:45::i;:::-;200015:65;;;;;;;-1:-1:-1;;;200015:65:0;-1:-1:-1;;;;;200015:65:0;;;;;;199063:1036;;;;;:::o;201606:1076::-;201705:15;;-1:-1:-1;;;;;201705:15:0;201697:38;201693:87;;201752:16;:14;:16::i;:::-;-1:-1:-1;;;;;201831:24:0;;201792:36;201831:24;;;:16;:24;;;;;201866:25;;:::i;:::-;-1:-1:-1;201894:37:0;;;;;;;;;201912:17;;-1:-1:-1;;;;;201912:17:0;201894:37;;201942:27;;:::i;:::-;-1:-1:-1;201972:56:0;;;;;;;;;-1:-1:-1;;;;;201990:26:0;;;-1:-1:-1;201990:26:0;;;:18;:26;;;;;:36;;;;;;;;;;;;;;201972:56;;202078:20;;202039:36;;;;;;:59;;;;202115:22;;:27;:55;;;;-1:-1:-1;202146:20:0;;:24;;202115:55;202111:130;;;153147:4;202187:42;;202111:130;202253:24;;:::i;:::-;202280:32;202285:11;202298:13;202280:4;:32::i;:::-;202253:59;;202323:19;202352:6;-1:-1:-1;;;;;202345:24:0;;202370:8;202345:34;;;;;;;;;;;;;-1:-1:-1;;;;;202345:34:0;-1:-1:-1;;;;;202345:34:0;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;202345:34:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;202345:34:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;202345:34:0;;-1:-1:-1;202390:18:0;202411:32;202345:34;202432:10;202411:4;:32::i;:::-;-1:-1:-1;;;;;202482:22:0;;202454:20;202482:22;;;:12;:22;;;;;;202390:53;;-1:-1:-1;202454:20:0;202477:43;;202390:53;202477:4;:43::i;:::-;-1:-1:-1;;;;;202531:22:0;;;;;;;:12;:22;;;;;;;;;:40;;;202653:20;;202587:87;;;;;;;;;;;202454:66;;-1:-1:-1;202531:22:0;;202587:87;;;;;;;;;;;;;;201606:1076;;;;;;;;;:::o;191569:233::-;191637:6;191632:129;191653:10;:17;191649:21;;191632:129;;;191718:6;-1:-1:-1;;;;;191701:23:0;:10;191712:1;191701:13;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;191701:13:0;:23;;191693:56;;;;;-1:-1:-1;;;191693:56:0;;;;;;;;;;;;-1:-1:-1;;;191693:56:0;;;;;;;;;;;;;;;191672:4;;191632:129;;;-1:-1:-1;191771:10:0;27::-1;;39:1;23:18;;45:23;;-1:-1;191771:23:0;;;;;;;;-1:-1:-1;;;;;;191771:23:0;-1:-1:-1;;;;;191771:23:0;;;;;;;;;;191569:233::o;161941:872::-;-1:-1:-1;;;;;162070:15:0;;162048:4;162070:15;;;:7;:15;;;;;:24;;;162065:94;;162123:23;162118:29;;162065:94;-1:-1:-1;;;;;162270:15:0;;;;;;;:7;:15;;;;;;;;:43;;;;;:33;;;;:43;;;;;;162265:104;;162342:14;162337:20;;162265:104;162474:9;162487:14;162505:82;162545:8;162562:6;162571:12;162585:1;162505:39;:82::i;:::-;162473:114;;-1:-1:-1;162473:114:0;;-1:-1:-1;162609:14:0;;-1:-1:-1;162602:3:0;:21;;;;;;;;;162598:70;;162652:3;162647:9;;;;;;;;162640:16;;;;;;162598:70;162682:14;;162678:88;;162725:28;162720:34;;155964:1010;-1:-1:-1;;;;;156092:24:0;;156044:5;156092:24;;;:7;:24;;;;;156134:21;;;;156129:135;;156229:23;156222:30;;;;;156129:135;-1:-1:-1;;;;;156280:40:0;;;;;;:30;;;:40;;;;;;;;156276:125;;;156375:14;156368:21;;;;;156276:125;-1:-1:-1;;;;;156789:40:0;;;;;;;:30;;;:40;;;;;;;;:47;;-1:-1:-1;;156789:47:0;156832:4;156789:47;;;;;;156847:13;:23;;;;;27:10:-1;;23:18;;;45:23;;156847:36:0;;;;;;;;;;;;;;-1:-1:-1;;;;;;156847:36:0;;;;;;;156901:31;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;156952:14:0;;155964:1010;-1:-1:-1;;;155964:1010:0:o;207966:345::-;208038:4;208055:8;208071:16;:14;:16::i;:::-;208121:28;;;-1:-1:-1;;;208121:28:0;;208143:4;208121:28;;;;;;208055:33;;-1:-1:-1;208099:19:0;;-1:-1:-1;;;;;208121:13:0;;;;;:28;;;;;;;;;;;;;;:13;:28;;;5:2:-1;;;;30:1;27;20:12;5:2;208121:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;208121:28:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;208121:28:0;;-1:-1:-1;208164:10:0;;;;;:38;;;208188:14;208178:6;:24;;208164:38;208160:120;;;208219:3;-1:-1:-1;;;;;208219:12:0;;208232:4;208238:6;208219:26;;;;;;;;;;;;;-1:-1:-1;;;;;208219:26:0;-1:-1:-1;;;;;208219:26:0;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;208219:26:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;208219:26:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;208267:1:0;;-1:-1:-1;208260:8:0;;-1:-1:-1;;;208260:8:0;208160:120;-1:-1:-1;208297:6:0;;207966:345;-1:-1:-1;;;207966:345:0:o;31216:116::-;31269:4;31293:31;31298:1;31301;31293:31;;;;;;;;;;;;;-1:-1:-1;;;31293:31:0;;;:4;:31::i;31851:120::-;31904:4;31928:35;31933:1;31936;31928:35;;;;;;;;;;;;;-1:-1:-1;;;31928:35:0;;;:4;:35::i;33049:122::-;33102:4;33126:37;33131:1;33134;33126:37;;;;;;;;;;;;;;;;;:4;:37::i;29779:141::-;29898:14;29882:13;;:30;;29779:141::o;17381:187::-;17466:4;17488:43;17501:3;17496:9;;;;;;;;17512:4;17507:10;;;;;;;;17488:43;;;;;;;;;;;;;;;;;;;;;;;;;;;;17556:3;17551:9;;;;;;;34361:113;34414:4;34438:28;34443:1;34446;34438:28;;;;;;;;;;;;;-1:-1:-1;;;34438:28:0;;;:4;:28::i;32312:133::-;32371:10;;:::i;:::-;32401:36;;;;;;;;32416:19;32421:1;:10;;;32433:1;32416:4;:19::i;28842:213::-;29024:12;28446:4;29024:23;;;28842:213::o;30723:161::-;30798:6;30836:12;-1:-1:-1;;;30825:9:0;;30817:32;;;;-1:-1:-1;;;30817:32:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;30817:32:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;30874:1:0;;30723:161;-1:-1:-1;;30723:161:0:o;33750:126::-;33809:4;33833:35;33838:17;33843:1;28446:4;33838;:17::i;:::-;33857:10;;33833:4;:35::i;34647:147::-;34704:13;;:::i;:::-;34737:49;;;;;;;;34755:29;34760:20;34765:1;28485:4;34760;:20::i;:::-;34782:1;34755:4;:29::i;31048:160::-;31119:13;;:::i;:::-;31152:48;;;;;;;;31170:28;31175:1;:10;;;31187:1;:10;;;31170:4;:28::i;30550:165::-;30626:7;30666:12;-1:-1:-1;;;30654:10:0;;30646:33;;;;-1:-1:-1;;;30646:33:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;31683:160:0;31754:13;;:::i;:::-;31787:48;;;;;;;;31805:28;31810:1;:10;;;31822:1;:10;;;31805:4;:28::i;32914:127::-;32976:4;28485;33000:19;33005:1;33008;:10;;;33000:4;:19::i;:::-;:33;;;;;;;32914:127;-1:-1:-1;;;32914:127:0:o;29487:208::-;29585:4;29602:18;;:::i;:::-;29623:15;29628:1;29631:6;29623:4;:15::i;:::-;29602:36;;29656:31;29661:17;29670:7;29661:8;:17::i;:::-;29680:6;29656:4;:31::i;31340:179::-;31421:4;31447:5;;;31479:12;31471:6;;;;31463:29;;;;-1:-1:-1;;;31463:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;31979:158:0;32060:4;32093:12;32085:6;;;;32077:29;;;;-1:-1:-1;;;32077:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;32077:29:0;-1:-1:-1;;;32124:5:0;;;31979:158::o;33179:250::-;33260:4;33281:6;;;:16;;-1:-1:-1;33291:6:0;;33281:16;33277:57;;;-1:-1:-1;33321:1:0;33314:8;;33277:57;33353:5;;;33357:1;33353;:5;:1;33377:5;;;;;:10;33389:12;33369:33;;;;;-1:-1:-1;;;33369:33:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;34482:157:0;34563:4;34595:12;34588:5;34580:28;;;;-1:-1:-1;;;34580:28:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;34580:28:0;;34630:1;34626;:5;;;;;;;34482:157;-1:-1:-1;;;;34482:157:0:o;149148:63586::-;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;

Swarm Source

bzzr://7f766a23999569d0ed5d0820bbc0e57a7af1a009ed7ada7e8aa517d2e4a66747
Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading