Contract 0x546c79662e028b661dfb4767664d0273184e4dd1 3

 
 
Txn Hash
Method
Block
From
To
Value [Txn Fee]
0xa9a32d9cb84c3de06259a7697f24c8425febdefa88bc8c9e71efde1ee798c7edRemove Liquidity...432540992023-05-28 15:35:191 hr 35 mins ago0x7ea82f805e4f5d978a2e106938078dda7090e4d6 IN  Kyber Swap: Router0 MATIC0.032321081671 169.671596031
0xb9f4f0529f0c4491819127c0534da306879853a7479d0e2f4dfbd492a67c693fAdd Liquidity432377902023-05-28 5:48:5611 hrs 21 mins ago0xaa446f886eac38385e354d1fddc813fe3916e7c6 IN  Kyber Swap: Router0 MATIC0.02486796114 142.620960406
0xd8ed76dcd1134c960d817534c93aa5ee71b3a0b1b8d38193897f6598169b9875Add Liquidity432334402023-05-28 3:05:4814 hrs 4 mins ago0x13a887de1ead947607b355d8f00a808b6d28cacd IN  Kyber Swap: Router0 MATIC0.027984780242 140.469625709
0xff80c8407967fd69204846a83f1a0d4f74f25019f4dbf0dc45c8b2d53b848400Remove Liquidity...432289922023-05-28 0:23:2516 hrs 46 mins ago0x12ab8f5ab7ae3d7113d3ae4950237713f8082245 IN  Kyber Swap: Router0 MATIC0.003965817568 139.171026399
0x316deb92ddca92b1b12628ded8ffa8b2625554141a59d3c83ae625c026813e84Remove Liquidity...432206642023-05-27 19:19:2921 hrs 50 mins ago0xc00421579622bb8db65fa368793cc7b458dd785d IN  Kyber Swap: Router0 MATIC0.027052062191 130.313606456
0x035bf900ddb11ab52bb633dbc4fd9237ef6e81afb03461a7ed03e2c8a51d236eRemove Liquidity...432085862023-05-27 11:53:551 day 5 hrs ago cryptohasti.nft  IN  Kyber Swap: Router0 MATIC0.037001800458173.611413028
0x7771df10202c4af5766056a338e95811ed831900ba39d786cf456851d3f4ef26Remove Liquidity...432059802023-05-27 10:20:201 day 6 hrs ago0xf62999efd3ba33340044df1fd4747ea2d9d4be8c IN  Kyber Swap: Router0 MATIC0.030952607032 176.777085635
0xa728436eb7a8605597fc8501588de4b00343ef6ddf557d67c4aeccf676699e71Remove Liquidity...432033832023-05-27 8:44:361 day 8 hrs ago hanzein.x  IN  Kyber Swap: Router0 MATIC0.035565341928 154.477443983
0xaa6baa11e262a2a5cf3a2d9077f2208ef850fa7330935745507e37296ca78d62Remove Liquidity...431996952023-05-27 6:26:061 day 10 hrs ago0x997319bf7b46b1ad1c2acc3d85adb4f46f28b50d IN  Kyber Swap: Router0 MATIC0.02735903684 143.613975772
0xb4035fe3037929c9103a60dcfdf1c41a5cde5978568de48f8370300573415a6dRemove Liquidity...431969302023-05-27 4:41:161 day 12 hrs ago0x62c0e99b6e55680fd234818e4c1f17bba11f85c5 IN  Kyber Swap: Router0 MATIC0.032883860098 146.764290201
0x55b03b9679a73343a20152753f69535586796b3369c6a5953fedbce0e30222cfRemove Liquidity...431949422023-05-27 3:28:191 day 13 hrs ago0xc3ed0469ab4dcda18b8a62a4389bec21959ebe8d IN  Kyber Swap: Router0 MATIC0.028168173096135.721452303
0xecf40ee8919223d090863493b785ad5d5b0e85819844f72b92f158d3dcabeda6Add Liquidity431831162023-05-26 20:14:441 day 20 hrs ago0x77e65d47af2977830c208adef6c718c880460909 IN  Kyber Swap: Router0 MATIC0.027443029352 140.799190148
0xab4d7c4e7584548352403ed0705ae220c77ffffd4c1e8461854ffd36c7cd5f5bAdd Liquidity ET...431653782023-05-26 9:38:502 days 7 hrs ago0x5fc5901cf37641c37c60241dc13e2ef1642de1a4 IN  Kyber Swap: Router31 MATIC0.0335781355 170.202020947
0x00f769d68b1e3e96e52ce470345ec174253968293b6105cdf96264794b69e124Remove Liquidity...431415342023-05-25 19:09:112 days 22 hrs ago0x0dc66f1dcb64d68f77895a44b023988b036b55da IN  Kyber Swap: Router0 MATIC0.029458925449 141.899604293
0x80a0990d631b5c00c71abd262ad377cf962a9dc88d7b1886517384fb30a0a74aRemove Liquidity...431223462023-05-25 7:30:513 days 9 hrs ago0x8801055268d8b038856005b5fb504a9c8c63d9ca IN  Kyber Swap: Router0 MATIC0.035667978355 201.688342779
0x0020e030b5ae819714999a5fcbe0dda2dfa043eb7cab796759ed85d1416a2613Remove Liquidity...431211162023-05-25 6:47:093 days 10 hrs ago0xa069f2204cab4862c861925ad40b113d158a5e2f IN  Kyber Swap: Router0 MATIC0.027178897612 138.64662354
0x0ec6e33db9c9694bb65a1dd460d33134b838c6f114f4869f26f4e094f972b413Add Liquidity Ne...431089422023-05-24 23:27:333 days 17 hrs ago0xf47da0f68c099b0d5db9dbde5fbaf135daa8f486 IN  Kyber Swap: Router0 MATIC0.622263568178 137.727282284
0xfe2085226bd4118b5349e38f6041a77303bb546ecaea7532dc168c63dd314e20Remove Liquidity...431088042023-05-24 23:22:293 days 17 hrs ago0xf47da0f68c099b0d5db9dbde5fbaf135daa8f486 IN  Kyber Swap: Router0 MATIC0.036792333621 145.443214416
0xeabfa285dccfcd8ff9fbc6dc87b9df0a7115ada637405a89bfa15d4e4f521742Remove Liquidity...430966092023-05-24 16:00:524 days 1 hr ago chriskang1104.wallet  IN  Kyber Swap: Router0 MATIC0.043576253573 222.293799795
0x983b3fbab1d401fb1efb37bc26bf88c9bec2873c1f12572fa3eb78bdba82db17Remove Liquidity...430953762023-05-24 15:16:474 days 1 hr ago0xde10caf4598573326eca8679faf42dcec35130aa IN  Kyber Swap: Router0 MATIC0.077734165534 345.623429527
0x2ad12a9a67f725765ed75c5b4a48516ab83d2b1edce88d4c4a65036c1ce3bbd7Remove Liquidity...430941612023-05-24 14:33:444 days 2 hrs ago tonymastermind1.wallet  IN  Kyber Swap: Router0 MATIC0.091778667514 430.649209188
0xcf40b560a0f6f8139c559291abeb28827e5b08c5d0ae83e791c3cd283ec91356Remove Liquidity...430909142023-05-24 12:37:124 days 4 hrs ago0x4be97ec3f1c6a386d5ddf2c0a72e98463bb107ad IN  Kyber Swap: Router0 MATIC0.042359546201 183.997542334
0xfe85e4e985bc578385b0a657ef92e6587a1e3a913e176657a08add76aa5b4f1dRemove Liquidity...430882512023-05-24 10:55:574 days 6 hrs ago0x4f2604aac91114ae3b3d0be485d407d02b24480b IN  Kyber Swap: Router0 MATIC0.032887114339 146.200040629
0xd94289b9b7669e848fa0300c2810249a893727b2348160a34303f68a53dad3d9Remove Liquidity...430824112023-05-24 7:22:214 days 9 hrs ago0x3ec44efca057c5bc4b45b44a8dade90414bc466e IN  Kyber Swap: Router0 MATIC0.032117521856 150.374194025
0x3a2aeab06b57bf0715561ec9855b42867fb38a4073f95ba05a1ff7caabb41802Remove Liquidity...430807552023-05-24 6:22:024 days 10 hrs ago sahathon3.wallet  IN  Kyber Swap: Router0 MATIC0.029401331922 149.993785859
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0xab4d7c4e7584548352403ed0705ae220c77ffffd4c1e8461854ffd36c7cd5f5b431653782023-05-26 9:38:502 days 7 hrs ago Kyber Swap: Router0x5fc5901cf37641c37c60241dc13e2ef1642de1a41 wei
0xab4d7c4e7584548352403ed0705ae220c77ffffd4c1e8461854ffd36c7cd5f5b431653782023-05-26 9:38:502 days 7 hrs ago Kyber Swap: Router Polygon: WMATIC Token30.999999999999999999 MATIC
0xb4d2f8bd3c9b7e08d6d5e90e516dffb1288409d4ed33ff8af0feeea5efb7c3e1430685472023-05-23 22:59:494 days 18 hrs ago Kyber Swap: Router0x9e7478dc7b34abde92979d07f4cf38ab0482735d1 wei
0xb4d2f8bd3c9b7e08d6d5e90e516dffb1288409d4ed33ff8af0feeea5efb7c3e1430685472023-05-23 22:59:494 days 18 hrs ago Kyber Swap: Router Polygon: WMATIC Token99.999999999999999999 MATIC
0x05e54d0d6721601a25ea0d24ba3e3a47ad06471bc47af2dbbc4e61139383629d430629142023-05-23 19:37:084 days 21 hrs ago Kyber Swap: Router Polygon: WMATIC Token0.2 MATIC
0x5aae0792f8f17f1e53a1cf1800b61be7bd669d951d3befd24e777fc5c814b9e1430088252023-05-22 9:31:506 days 7 hrs ago Kyber Swap: Router0x3ec44efca057c5bc4b45b44a8dade90414bc466e1,799.999999999999999998 MATIC
0x5aae0792f8f17f1e53a1cf1800b61be7bd669d951d3befd24e777fc5c814b9e1430088252023-05-22 9:31:506 days 7 hrs ago Polygon: WMATIC Token Kyber Swap: Router1,799.999999999999999998 MATIC
0xe775178d3d51dfc71e366b373d6a64615a1a676660ece85c7a6b6c1b5253b0f8430073562023-05-22 8:34:446 days 8 hrs ago Kyber Swap: Router0x3ec44efca057c5bc4b45b44a8dade90414bc466e1 wei
0xe775178d3d51dfc71e366b373d6a64615a1a676660ece85c7a6b6c1b5253b0f8430073562023-05-22 8:34:446 days 8 hrs ago Kyber Swap: Router Polygon: WMATIC Token1,799.999999999999999999 MATIC
0xa7266f6d277e11b21dd2326523b88acceda60d30a3b5ea38cd09abb42974d70f428792722023-05-19 3:14:309 days 13 hrs ago Kyber Swap: Router0x500ee8bff66269cf8e4ba7a0978d764857af54629.546171643922223362 MATIC
0xa7266f6d277e11b21dd2326523b88acceda60d30a3b5ea38cd09abb42974d70f428792722023-05-19 3:14:309 days 13 hrs ago Polygon: WMATIC Token Kyber Swap: Router9.546171643922223362 MATIC
0x125eec9a38752838e2e7d0507b3c184ac21d2f6ced6e3789eee37846236801d7428791852023-05-19 3:11:269 days 13 hrs ago Kyber Swap: Router0x500ee8bff66269cf8e4ba7a0978d764857af546295.354123027596925709 MATIC
0x125eec9a38752838e2e7d0507b3c184ac21d2f6ced6e3789eee37846236801d7428791852023-05-19 3:11:269 days 13 hrs ago Polygon: WMATIC Token Kyber Swap: Router95.354123027596925709 MATIC
0xc6d9cba7f318b0ea25ec7bfecfa9cebf5c927acb9e08914afc2ca615cbf8451f427869162023-05-16 19:41:4611 days 21 hrs ago Kyber Swap: Router Polygon: WMATIC Token5.766064022982139336 MATIC
0x6add10f6d5aef7425faffedab486dcedd43337a8aa16673d3331bfd682b51e27427867922023-05-16 19:37:2211 days 21 hrs ago Kyber Swap: Router0x9e7478dc7b34abde92979d07f4cf38ab0482735d1 wei
0x6add10f6d5aef7425faffedab486dcedd43337a8aa16673d3331bfd682b51e27427867922023-05-16 19:37:2211 days 21 hrs ago Kyber Swap: Router Polygon: WMATIC Token144.999999999999999999 MATIC
0x3daeb4028e111f1ffb315f4e9fe2748714b257a5582715f27477ff1ab699b831427383782023-05-15 14:47:0013 days 2 hrs ago Kyber Swap: Router0x5fc5901cf37641c37c60241dc13e2ef1642de1a41 wei
0x3daeb4028e111f1ffb315f4e9fe2748714b257a5582715f27477ff1ab699b831427383782023-05-15 14:47:0013 days 2 hrs ago Kyber Swap: Router Polygon: WMATIC Token564.999999999999999999 MATIC
0x2560b8b9b53c67f32d389360259bea219f430d01f50f76da9aefa992e393ea5a427343552023-05-15 12:23:4413 days 4 hrs ago Kyber Swap: Router0xb70f10337dbd6e0f7ede08c7817931c7da06828d993.519709864142544087 MATIC
0x2560b8b9b53c67f32d389360259bea219f430d01f50f76da9aefa992e393ea5a427343552023-05-15 12:23:4413 days 4 hrs ago Polygon: WMATIC Token Kyber Swap: Router993.519709864142544087 MATIC
0x3c2dfaa2992e3b8abfab539b298f2df05e9e785f5acb8c6a5ecbf0550e682272427194852023-05-15 3:32:4013 days 13 hrs ago Kyber Swap: Router Polygon: WMATIC Token6.342999058462703447 MATIC
0xc27d52fe175f5a41da7c25f373fc99c78ba844bfdde8f68cd423e9214217c6c6426613892023-05-13 16:58:1415 days 12 mins ago Kyber Swap: Router Polygon: WMATIC Token498.328945295851223898 MATIC
0x7755f1f9af12d235c6f69985542d3bf51bd39d43af15e0de35f25d705b506aa9426612982023-05-13 16:54:3415 days 15 mins ago Kyber Swap: Router Polygon: WMATIC Token3,156.434313346844751056 MATIC
0x1c9815ef1e2c9bc25dbfbbc317bc14fc3c1f851cd46cfe879a15ec088eab4eef426599262023-05-13 16:05:0515 days 1 hr ago Kyber Swap: Router Polygon: WMATIC Token1,845.176530371812880956 MATIC
0xc7de19f3206ecab9957cbc516a87408e363aa36aa4c98a63a9240edadfe84cd4426594802023-05-13 15:48:4515 days 1 hr ago Kyber Swap: Router Polygon: WMATIC Token2,020.395960635499502116 MATIC
[ Download CSV Export 
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
DMMRouter02

Compiler Version
v0.6.12+commit.27d51765

Optimization Enabled:
Yes with 999999 runs

Other Settings:
default evmVersion, MIT license

Contract Source Code (Solidity)

/**
 *Submitted for verification at polygonscan.com on 2021-06-21
*/

/**
 *Submitted for verification at polygonscan.com on 2021-06-15
*/

/**
 *Submitted for verification at Etherscan.io on 2021-04-27
*/

/**
 *Submitted for verification at Etherscan.io on 2021-04-27
*/

// SPDX-License-Identifier: BUSL-1.1
// File: @uniswap/lib/contracts/libraries/TransferHelper.sol

pragma solidity >=0.6.0;

// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false
library TransferHelper {
    function safeApprove(address token, address to, uint value) internal {
        // bytes4(keccak256(bytes('approve(address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: APPROVE_FAILED');
    }

    function safeTransfer(address token, address to, uint value) internal {
        // bytes4(keccak256(bytes('transfer(address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FAILED');
    }

    function safeTransferFrom(address token, address from, address to, uint value) internal {
        // bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
        require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FROM_FAILED');
    }

    function safeTransferETH(address to, uint value) internal {
        (bool success,) = to.call{value:value}(new bytes(0));
        require(success, 'TransferHelper: ETH_TRANSFER_FAILED');
    }
}

// File: @openzeppelin/contracts/math/SafeMath.sol

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        uint256 c = a + b;
        if (c < a) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the substraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b > a) return (false, 0);
        return (true, a - b);
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) return (true, 0);
        uint256 c = a * b;
        if (c / a != b) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a / b);
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a % b);
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");
        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, "SafeMath: subtraction overflow");
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) return 0;
        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");
        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: division by zero");
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: modulo by zero");
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        return a - b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryDiv}.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        return a % b;
    }
}

// File: @openzeppelin/contracts/token/ERC20/IERC20.sol

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

// File: @openzeppelin/contracts/utils/Address.sol

pragma solidity >=0.6.2 <0.8.0;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        // solhint-disable-next-line no-inline-assembly
        assembly { size := extcodesize(account) }
        return size > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (bool success, ) = recipient.call{ value: amount }("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain`call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
      return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.call{ value: value }(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.staticcall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

// File: @openzeppelin/contracts/token/ERC20/SafeERC20.sol

pragma solidity >=0.6.0 <0.8.0;




/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using SafeMath for uint256;
    using Address for address;

    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        // solhint-disable-next-line max-line-length
        require((value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).add(value);
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) { // Return data is optional
            // solhint-disable-next-line max-line-length
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

// File: contracts/interfaces/IDMMFactory.sol
pragma solidity 0.6.12;


interface IDMMFactory {
    function createPool(
        IERC20 tokenA,
        IERC20 tokenB,
        uint32 ampBps
    ) external returns (address pool);

    function setFeeConfiguration(address feeTo, uint16 governmentFeeBps) external;

    function setFeeToSetter(address) external;

    function getFeeConfiguration() external view returns (address feeTo, uint16 governmentFeeBps);

    function feeToSetter() external view returns (address);

    function allPools(uint256) external view returns (address pool);

    function allPoolsLength() external view returns (uint256);

    function getUnamplifiedPool(IERC20 token0, IERC20 token1) external view returns (address);

    function getPools(IERC20 token0, IERC20 token1)
        external
        view
        returns (address[] memory _tokenPools);

    function isPool(
        IERC20 token0,
        IERC20 token1,
        address pool
    ) external view returns (bool);
}

// File: contracts/interfaces/IWETH.sol
pragma solidity 0.6.12;


interface IWETH is IERC20 {
    function deposit() external payable;

    function withdraw(uint256) external;
}

// File: contracts/interfaces/IDMMExchangeRouter.sol
pragma solidity 0.6.12;


/// @dev an simple interface for integration dApp to swap
interface IDMMExchangeRouter {
    function swapExactTokensForTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata poolsPath,
        IERC20[] calldata path,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);

    function swapTokensForExactTokens(
        uint256 amountOut,
        uint256 amountInMax,
        address[] calldata poolsPath,
        IERC20[] calldata path,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);

    function swapExactETHForTokens(
        uint256 amountOutMin,
        address[] calldata poolsPath,
        IERC20[] calldata path,
        address to,
        uint256 deadline
    ) external payable returns (uint256[] memory amounts);

    function swapTokensForExactETH(
        uint256 amountOut,
        uint256 amountInMax,
        address[] calldata poolsPath,
        IERC20[] calldata path,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);

    function swapExactTokensForETH(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata poolsPath,
        IERC20[] calldata path,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);

    function swapETHForExactTokens(
        uint256 amountOut,
        address[] calldata poolsPath,
        IERC20[] calldata path,
        address to,
        uint256 deadline
    ) external payable returns (uint256[] memory amounts);

    function getAmountsOut(
        uint256 amountIn,
        address[] calldata poolsPath,
        IERC20[] calldata path
    ) external view returns (uint256[] memory amounts);

    function getAmountsIn(
        uint256 amountOut,
        address[] calldata poolsPath,
        IERC20[] calldata path
    ) external view returns (uint256[] memory amounts);
}

// File: contracts/interfaces/IDMMLiquidityRouter.sol
pragma solidity 0.6.12;


/// @dev an simple interface for integration dApp to contribute liquidity
interface IDMMLiquidityRouter {
    /**
     * @param tokenA address of token in the pool
     * @param tokenB address of token in the pool
     * @param pool the address of the pool
     * @param amountADesired the amount of tokenA users want to add to the pool
     * @param amountBDesired the amount of tokenB users want to add to the pool
     * @param amountAMin bounds to the extents to which amountB/amountA can go up
     * @param amountBMin bounds to the extents to which amountB/amountA can go down
     * @param vReserveRatioBounds bounds to the extents to which vReserveB/vReserveA can go (precision: 2 ** 112)
     * @param to Recipient of the liquidity tokens.
     * @param deadline Unix timestamp after which the transaction will revert.
     */
    function addLiquidity(
        IERC20 tokenA,
        IERC20 tokenB,
        address pool,
        uint256 amountADesired,
        uint256 amountBDesired,
        uint256 amountAMin,
        uint256 amountBMin,
        uint256[2] calldata vReserveRatioBounds,
        address to,
        uint256 deadline
    )
        external
        returns (
            uint256 amountA,
            uint256 amountB,
            uint256 liquidity
        );

    function addLiquidityNewPool(
        IERC20 tokenA,
        IERC20 tokenB,
        uint32 ampBps,
        uint256 amountADesired,
        uint256 amountBDesired,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline
    )
        external
        returns (
            uint256 amountA,
            uint256 amountB,
            uint256 liquidity
        );

    function addLiquidityNewPoolETH(
        IERC20 token,
        uint32 ampBps,
        uint256 amountTokenDesired,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    )
        external
        payable
        returns (
            uint256 amountToken,
            uint256 amountETH,
            uint256 liquidity
        );

    /**
     * @param token address of token in the pool
     * @param pool the address of the pool
     * @param amountTokenDesired the amount of token users want to add to the pool
     * @dev   msg.value equals to amountEthDesired
     * @param amountTokenMin bounds to the extents to which WETH/token can go up
     * @param amountETHMin bounds to the extents to which WETH/token can go down
     * @param vReserveRatioBounds bounds to the extents to which vReserveB/vReserveA can go (precision: 2 ** 112)
     * @param to Recipient of the liquidity tokens.
     * @param deadline Unix timestamp after which the transaction will revert.
     */
    function addLiquidityETH(
        IERC20 token,
        address pool,
        uint256 amountTokenDesired,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        uint256[2] calldata vReserveRatioBounds,
        address to,
        uint256 deadline
    )
        external
        payable
        returns (
            uint256 amountToken,
            uint256 amountETH,
            uint256 liquidity
        );

    /**
     * @param tokenA address of token in the pool
     * @param tokenB address of token in the pool
     * @param pool the address of the pool
     * @param liquidity the amount of lp token users want to burn
     * @param amountAMin the minimum token retuned after burning
     * @param amountBMin the minimum token retuned after burning
     * @param to Recipient of the returned tokens.
     * @param deadline Unix timestamp after which the transaction will revert.
     */
    function removeLiquidity(
        IERC20 tokenA,
        IERC20 tokenB,
        address pool,
        uint256 liquidity,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountA, uint256 amountB);

    /**
     * @param tokenA address of token in the pool
     * @param tokenB address of token in the pool
     * @param pool the address of the pool
     * @param liquidity the amount of lp token users want to burn
     * @param amountAMin the minimum token retuned after burning
     * @param amountBMin the minimum token retuned after burning
     * @param to Recipient of the returned tokens.
     * @param deadline Unix timestamp after which the transaction will revert.
     * @param approveMax whether users permit the router spending max lp token or not.
     * @param r s v Signature of user to permit the router spending lp token
     */
    function removeLiquidityWithPermit(
        IERC20 tokenA,
        IERC20 tokenB,
        address pool,
        uint256 liquidity,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (uint256 amountA, uint256 amountB);

    /**
     * @param token address of token in the pool
     * @param pool the address of the pool
     * @param liquidity the amount of lp token users want to burn
     * @param amountTokenMin the minimum token retuned after burning
     * @param amountETHMin the minimum eth in wei retuned after burning
     * @param to Recipient of the returned tokens.
     * @param deadline Unix timestamp after which the transaction will revert
     */
    function removeLiquidityETH(
        IERC20 token,
        address pool,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountToken, uint256 amountETH);

    /**
     * @param token address of token in the pool
     * @param pool the address of the pool
     * @param liquidity the amount of lp token users want to burn
     * @param amountTokenMin the minimum token retuned after burning
     * @param amountETHMin the minimum eth in wei retuned after burning
     * @param to Recipient of the returned tokens.
     * @param deadline Unix timestamp after which the transaction will revert
     * @param approveMax whether users permit the router spending max lp token
     * @param r s v signatures of user to permit the router spending lp token.
     */
    function removeLiquidityETHWithPermit(
        IERC20 token,
        address pool,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (uint256 amountToken, uint256 amountETH);

    /**
     * @param amountA amount of 1 side token added to the pool
     * @param reserveA current reserve of the pool
     * @param reserveB current reserve of the pool
     * @return amountB amount of the other token added to the pool
     */
    function quote(
        uint256 amountA,
        uint256 reserveA,
        uint256 reserveB
    ) external pure returns (uint256 amountB);
}

// File: contracts/interfaces/IDMMRouter01.sol
pragma solidity 0.6.12;





/// @dev full interface for router
interface IDMMRouter01 is IDMMExchangeRouter, IDMMLiquidityRouter {
    function factory() external pure returns (address);

    function weth() external pure returns (IWETH);
}

// File: contracts/interfaces/IDMMRouter02.sol
pragma solidity 0.6.12;


interface IDMMRouter02 is IDMMRouter01 {
    function removeLiquidityETHSupportingFeeOnTransferTokens(
        IERC20 token,
        address pool,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountETH);

    function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
        IERC20 token,
        address pool,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (uint256 amountETH);

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata poolsPath,
        IERC20[] calldata path,
        address to,
        uint256 deadline
    ) external;

    function swapExactETHForTokensSupportingFeeOnTransferTokens(
        uint256 amountOutMin,
        address[] calldata poolsPath,
        IERC20[] calldata path,
        address to,
        uint256 deadline
    ) external payable;

    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata poolsPath,
        IERC20[] calldata path,
        address to,
        uint256 deadline
    ) external;
}

// File: contracts/interfaces/IERC20Permit.sol

pragma solidity 0.6.12;


interface IERC20Permit is IERC20 {
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;
}

// File: contracts/interfaces/IDMMPool.sol

pragma solidity 0.6.12;



interface IDMMPool {
    function mint(address to) external returns (uint256 liquidity);

    function burn(address to) external returns (uint256 amount0, uint256 amount1);

    function swap(
        uint256 amount0Out,
        uint256 amount1Out,
        address to,
        bytes calldata data
    ) external;

    function sync() external;

    function getReserves() external view returns (uint112 reserve0, uint112 reserve1);

    function getTradeInfo()
        external
        view
        returns (
            uint112 _vReserve0,
            uint112 _vReserve1,
            uint112 reserve0,
            uint112 reserve1,
            uint256 feeInPrecision
        );

    function token0() external view returns (IERC20);

    function token1() external view returns (IERC20);

    function ampBps() external view returns (uint32);

    function factory() external view returns (IDMMFactory);

    function kLast() external view returns (uint256);
}

// File: contracts/libraries/DMMLibrary.sol

pragma solidity 0.6.12;




library DMMLibrary {
    using SafeMath for uint256;

    uint256 public constant PRECISION = 1e18;

    // returns sorted token addresses, used to handle return values from pools sorted in this order
    function sortTokens(IERC20 tokenA, IERC20 tokenB)
        internal
        pure
        returns (IERC20 token0, IERC20 token1)
    {
        require(tokenA != tokenB, "DMMLibrary: IDENTICAL_ADDRESSES");
        (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
        require(address(token0) != address(0), "DMMLibrary: ZERO_ADDRESS");
    }

    /// @dev fetch the reserves and fee for a pool, used for trading purposes
    function getTradeInfo(
        address pool,
        IERC20 tokenA,
        IERC20 tokenB
    )
        internal
        view
        returns (
            uint256 reserveA,
            uint256 reserveB,
            uint256 vReserveA,
            uint256 vReserveB,
            uint256 feeInPrecision
        )
    {
        (IERC20 token0, ) = sortTokens(tokenA, tokenB);
        uint256 reserve0;
        uint256 reserve1;
        uint256 vReserve0;
        uint256 vReserve1;
        (reserve0, reserve1, vReserve0, vReserve1, feeInPrecision) = IDMMPool(pool).getTradeInfo();
        (reserveA, reserveB, vReserveA, vReserveB) = tokenA == token0
            ? (reserve0, reserve1, vReserve0, vReserve1)
            : (reserve1, reserve0, vReserve1, vReserve0);
    }

    /// @dev fetches the reserves for a pool, used for liquidity adding
    function getReserves(
        address pool,
        IERC20 tokenA,
        IERC20 tokenB
    ) internal view returns (uint256 reserveA, uint256 reserveB) {
        (IERC20 token0, ) = sortTokens(tokenA, tokenB);
        (uint256 reserve0, uint256 reserve1) = IDMMPool(pool).getReserves();
        (reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
    }

    // given some amount of an asset and pool reserves, returns an equivalent amount of the other asset
    function quote(
        uint256 amountA,
        uint256 reserveA,
        uint256 reserveB
    ) internal pure returns (uint256 amountB) {
        require(amountA > 0, "DMMLibrary: INSUFFICIENT_AMOUNT");
        require(reserveA > 0 && reserveB > 0, "DMMLibrary: INSUFFICIENT_LIQUIDITY");
        amountB = amountA.mul(reserveB) / reserveA;
    }

    // given an input amount of an asset and pool reserves, returns the maximum output amount of the other asset
    function getAmountOut(
        uint256 amountIn,
        uint256 reserveIn,
        uint256 reserveOut,
        uint256 vReserveIn,
        uint256 vReserveOut,
        uint256 feeInPrecision
    ) internal pure returns (uint256 amountOut) {
        require(amountIn > 0, "DMMLibrary: INSUFFICIENT_INPUT_AMOUNT");
        require(reserveIn > 0 && reserveOut > 0, "DMMLibrary: INSUFFICIENT_LIQUIDITY");
        uint256 amountInWithFee = amountIn.mul(PRECISION.sub(feeInPrecision)).div(PRECISION);
        uint256 numerator = amountInWithFee.mul(vReserveOut);
        uint256 denominator = vReserveIn.add(amountInWithFee);
        amountOut = numerator.div(denominator);
        require(reserveOut > amountOut, "DMMLibrary: INSUFFICIENT_LIQUIDITY");
    }

    // given an output amount of an asset and pool reserves, returns a required input amount of the other asset
    function getAmountIn(
        uint256 amountOut,
        uint256 reserveIn,
        uint256 reserveOut,
        uint256 vReserveIn,
        uint256 vReserveOut,
        uint256 feeInPrecision
    ) internal pure returns (uint256 amountIn) {
        require(amountOut > 0, "DMMLibrary: INSUFFICIENT_OUTPUT_AMOUNT");
        require(reserveIn > 0 && reserveOut > amountOut, "DMMLibrary: INSUFFICIENT_LIQUIDITY");
        uint256 numerator = vReserveIn.mul(amountOut);
        uint256 denominator = vReserveOut.sub(amountOut);
        amountIn = numerator.div(denominator).add(1);
        // amountIn = floor(amountIN *PRECISION / (PRECISION - feeInPrecision));
        numerator = amountIn.mul(PRECISION);
        denominator = PRECISION.sub(feeInPrecision);
        amountIn = numerator.add(denominator - 1).div(denominator);
    }

    // performs chained getAmountOut calculations on any number of pools
    function getAmountsOut(
        uint256 amountIn,
        address[] memory poolsPath,
        IERC20[] memory path
    ) internal view returns (uint256[] memory amounts) {
        amounts = new uint256[](path.length);
        amounts[0] = amountIn;
        for (uint256 i; i < path.length - 1; i++) {
            (
                uint256 reserveIn,
                uint256 reserveOut,
                uint256 vReserveIn,
                uint256 vReserveOut,
                uint256 feeInPrecision
            ) = getTradeInfo(poolsPath[i], path[i], path[i + 1]);
            amounts[i + 1] = getAmountOut(
                amounts[i],
                reserveIn,
                reserveOut,
                vReserveIn,
                vReserveOut,
                feeInPrecision
            );
        }
    }

    // performs chained getAmountIn calculations on any number of pools
    function getAmountsIn(
        uint256 amountOut,
        address[] memory poolsPath,
        IERC20[] memory path
    ) internal view returns (uint256[] memory amounts) {
        amounts = new uint256[](path.length);
        amounts[amounts.length - 1] = amountOut;
        for (uint256 i = path.length - 1; i > 0; i--) {
            (
                uint256 reserveIn,
                uint256 reserveOut,
                uint256 vReserveIn,
                uint256 vReserveOut,
                uint256 feeInPrecision
            ) = getTradeInfo(poolsPath[i - 1], path[i - 1], path[i]);
            amounts[i - 1] = getAmountIn(
                amounts[i],
                reserveIn,
                reserveOut,
                vReserveIn,
                vReserveOut,
                feeInPrecision
            );
        }
    }
}

// File: contracts/periphery/DMMRouter02.sol
pragma solidity 0.6.12;










contract DMMRouter02 is IDMMRouter02 {
    using SafeERC20 for IERC20;
    using SafeERC20 for IWETH;
    using SafeMath for uint256;

    uint256 internal constant BPS = 10000;
    uint256 internal constant MIN_VRESERVE_RATIO = 0;
    uint256 internal constant MAX_VRESERVE_RATIO = 2**256 - 1;
    uint256 internal constant Q112 = 2**112;

    address public immutable override factory;
    IWETH public immutable override weth;

    modifier ensure(uint256 deadline) {
        require(deadline >= block.timestamp, "DMMRouter: EXPIRED");
        _;
    }

    constructor(address _factory, IWETH _weth) public {
        factory = _factory;
        weth = _weth;
    }

    receive() external payable {
        assert(msg.sender == address(weth)); // only accept ETH via fallback from the WETH contract
    }

    // **** ADD LIQUIDITY ****
    function _addLiquidity(
        IERC20 tokenA,
        IERC20 tokenB,
        address pool,
        uint256 amountADesired,
        uint256 amountBDesired,
        uint256 amountAMin,
        uint256 amountBMin,
        uint256[2] memory vReserveRatioBounds
    ) internal virtual view returns (uint256 amountA, uint256 amountB) {
        (uint256 reserveA, uint256 reserveB, uint256 vReserveA, uint256 vReserveB, ) = DMMLibrary
            .getTradeInfo(pool, tokenA, tokenB);
        if (reserveA == 0 && reserveB == 0) {
            (amountA, amountB) = (amountADesired, amountBDesired);
        } else {
            uint256 amountBOptimal = DMMLibrary.quote(amountADesired, reserveA, reserveB);
            if (amountBOptimal <= amountBDesired) {
                require(amountBOptimal >= amountBMin, "DMMRouter: INSUFFICIENT_B_AMOUNT");
                (amountA, amountB) = (amountADesired, amountBOptimal);
            } else {
                uint256 amountAOptimal = DMMLibrary.quote(amountBDesired, reserveB, reserveA);
                assert(amountAOptimal <= amountADesired);
                require(amountAOptimal >= amountAMin, "DMMRouter: INSUFFICIENT_A_AMOUNT");
                (amountA, amountB) = (amountAOptimal, amountBDesired);
            }
            uint256 currentRate = (vReserveB * Q112) / vReserveA;
            require(
                currentRate >= vReserveRatioBounds[0] && currentRate <= vReserveRatioBounds[1],
                "DMMRouter: OUT_OF_BOUNDS_VRESERVE"
            );
        }
    }

    function addLiquidity(
        IERC20 tokenA,
        IERC20 tokenB,
        address pool,
        uint256 amountADesired,
        uint256 amountBDesired,
        uint256 amountAMin,
        uint256 amountBMin,
        uint256[2] memory vReserveRatioBounds,
        address to,
        uint256 deadline
    )
        public
        virtual
        override
        ensure(deadline)
        returns (
            uint256 amountA,
            uint256 amountB,
            uint256 liquidity
        )
    {
        verifyPoolAddress(tokenA, tokenB, pool);
        (amountA, amountB) = _addLiquidity(
            tokenA,
            tokenB,
            pool,
            amountADesired,
            amountBDesired,
            amountAMin,
            amountBMin,
            vReserveRatioBounds
        );
        // using tokenA.safeTransferFrom will get "Stack too deep"
        SafeERC20.safeTransferFrom(tokenA, msg.sender, pool, amountA);
        SafeERC20.safeTransferFrom(tokenB, msg.sender, pool, amountB);
        liquidity = IDMMPool(pool).mint(to);
    }

    function addLiquidityETH(
        IERC20 token,
        address pool,
        uint256 amountTokenDesired,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        uint256[2] memory vReserveRatioBounds,
        address to,
        uint256 deadline
    )
        public
        override
        payable
        ensure(deadline)
        returns (
            uint256 amountToken,
            uint256 amountETH,
            uint256 liquidity
        )
    {
        verifyPoolAddress(token, weth, pool);
        (amountToken, amountETH) = _addLiquidity(
            token,
            weth,
            pool,
            amountTokenDesired,
            msg.value,
            amountTokenMin,
            amountETHMin,
            vReserveRatioBounds
        );
        token.safeTransferFrom(msg.sender, pool, amountToken);
        weth.deposit{value: amountETH}();
        weth.safeTransfer(pool, amountETH);
        liquidity = IDMMPool(pool).mint(to);
        // refund dust eth, if any
        if (msg.value > amountETH) {
            TransferHelper.safeTransferETH(msg.sender, msg.value - amountETH);
        }
    }

    function addLiquidityNewPool(
        IERC20 tokenA,
        IERC20 tokenB,
        uint32 ampBps,
        uint256 amountADesired,
        uint256 amountBDesired,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline
    )
        external
        override
        returns (
            uint256 amountA,
            uint256 amountB,
            uint256 liquidity
        )
    {
        address pool;
        if (ampBps == BPS) {
            pool = IDMMFactory(factory).getUnamplifiedPool(tokenA, tokenB);
        }
        if (pool == address(0)) {
            pool = IDMMFactory(factory).createPool(tokenA, tokenB, ampBps);
        }
        // if we add liquidity to an existing pool, this is an unamplifed pool
        // so there is no need for bounds of virtual reserve ratio
        uint256[2] memory vReserveRatioBounds = [MIN_VRESERVE_RATIO, MAX_VRESERVE_RATIO];
        (amountA, amountB, liquidity) = addLiquidity(
            tokenA,
            tokenB,
            pool,
            amountADesired,
            amountBDesired,
            amountAMin,
            amountBMin,
            vReserveRatioBounds,
            to,
            deadline
        );
    }

    function addLiquidityNewPoolETH(
        IERC20 token,
        uint32 ampBps,
        uint256 amountTokenDesired,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    )
        external
        override
        payable
        returns (
            uint256 amountToken,
            uint256 amountETH,
            uint256 liquidity
        )
    {
        address pool;
        if (ampBps == BPS) {
            pool = IDMMFactory(factory).getUnamplifiedPool(token, weth);
        }
        if (pool == address(0)) {
            pool = IDMMFactory(factory).createPool(token, weth, ampBps);
        }
        // if we add liquidity to an existing pool, this is an unamplifed pool
        // so there is no need for bounds of virtual reserve ratio
        uint256[2] memory vReserveRatioBounds = [MIN_VRESERVE_RATIO, MAX_VRESERVE_RATIO];
        (amountToken, amountETH, liquidity) = addLiquidityETH(
            token,
            pool,
            amountTokenDesired,
            amountTokenMin,
            amountETHMin,
            vReserveRatioBounds,
            to,
            deadline
        );
    }

    // **** REMOVE LIQUIDITY ****
    function removeLiquidity(
        IERC20 tokenA,
        IERC20 tokenB,
        address pool,
        uint256 liquidity,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline
    ) public override ensure(deadline) returns (uint256 amountA, uint256 amountB) {
        verifyPoolAddress(tokenA, tokenB, pool);
        IERC20(pool).safeTransferFrom(msg.sender, pool, liquidity); // send liquidity to pool
        (uint256 amount0, uint256 amount1) = IDMMPool(pool).burn(to);
        (IERC20 token0, ) = DMMLibrary.sortTokens(tokenA, tokenB);
        (amountA, amountB) = tokenA == token0 ? (amount0, amount1) : (amount1, amount0);
        require(amountA >= amountAMin, "DMMRouter: INSUFFICIENT_A_AMOUNT");
        require(amountB >= amountBMin, "DMMRouter: INSUFFICIENT_B_AMOUNT");
    }

    function removeLiquidityETH(
        IERC20 token,
        address pool,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    ) public override ensure(deadline) returns (uint256 amountToken, uint256 amountETH) {
        (amountToken, amountETH) = removeLiquidity(
            token,
            weth,
            pool,
            liquidity,
            amountTokenMin,
            amountETHMin,
            address(this),
            deadline
        );
        token.safeTransfer(to, amountToken);
        IWETH(weth).withdraw(amountETH);
        TransferHelper.safeTransferETH(to, amountETH);
    }

    function removeLiquidityWithPermit(
        IERC20 tokenA,
        IERC20 tokenB,
        address pool,
        uint256 liquidity,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external virtual override returns (uint256 amountA, uint256 amountB) {
        uint256 value = approveMax ? uint256(-1) : liquidity;
        IERC20Permit(pool).permit(msg.sender, address(this), value, deadline, v, r, s);
        (amountA, amountB) = removeLiquidity(
            tokenA,
            tokenB,
            pool,
            liquidity,
            amountAMin,
            amountBMin,
            to,
            deadline
        );
    }

    function removeLiquidityETHWithPermit(
        IERC20 token,
        address pool,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external override returns (uint256 amountToken, uint256 amountETH) {
        uint256 value = approveMax ? uint256(-1) : liquidity;
        IERC20Permit(pool).permit(msg.sender, address(this), value, deadline, v, r, s);
        (amountToken, amountETH) = removeLiquidityETH(
            token,
            pool,
            liquidity,
            amountTokenMin,
            amountETHMin,
            to,
            deadline
        );
    }

    // **** REMOVE LIQUIDITY (supporting fee-on-transfer tokens) ****

    function removeLiquidityETHSupportingFeeOnTransferTokens(
        IERC20 token,
        address pool,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    ) public override ensure(deadline) returns (uint256 amountETH) {
        (, amountETH) = removeLiquidity(
            token,
            weth,
            pool,
            liquidity,
            amountTokenMin,
            amountETHMin,
            address(this),
            deadline
        );
        token.safeTransfer(to, IERC20(token).balanceOf(address(this)));
        IWETH(weth).withdraw(amountETH);
        TransferHelper.safeTransferETH(to, amountETH);
    }

    function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
        IERC20 token,
        address pool,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external override returns (uint256 amountETH) {
        uint256 value = approveMax ? uint256(-1) : liquidity;
        IERC20Permit(pool).permit(msg.sender, address(this), value, deadline, v, r, s);
        amountETH = removeLiquidityETHSupportingFeeOnTransferTokens(
            token,
            pool,
            liquidity,
            amountTokenMin,
            amountETHMin,
            to,
            deadline
        );
    }

    // **** SWAP ****
    // requires the initial amount to have already been sent to the first pool
    function _swap(
        uint256[] memory amounts,
        address[] memory poolsPath,
        IERC20[] memory path,
        address _to
    ) private {
        for (uint256 i; i < path.length - 1; i++) {
            (IERC20 input, IERC20 output) = (path[i], path[i + 1]);
            (IERC20 token0, ) = DMMLibrary.sortTokens(input, output);
            uint256 amountOut = amounts[i + 1];
            (uint256 amount0Out, uint256 amount1Out) = input == token0
                ? (uint256(0), amountOut)
                : (amountOut, uint256(0));
            address to = i < path.length - 2 ? poolsPath[i + 1] : _to;
            IDMMPool(poolsPath[i]).swap(amount0Out, amount1Out, to, new bytes(0));
        }
    }

    function swapExactTokensForTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] memory poolsPath,
        IERC20[] memory path,
        address to,
        uint256 deadline
    ) public virtual override ensure(deadline) returns (uint256[] memory amounts) {
        verifyPoolsPathSwap(poolsPath, path);
        amounts = DMMLibrary.getAmountsOut(amountIn, poolsPath, path);
        require(
            amounts[amounts.length - 1] >= amountOutMin,
            "DMMRouter: INSUFFICIENT_OUTPUT_AMOUNT"
        );
        IERC20(path[0]).safeTransferFrom(msg.sender, poolsPath[0], amounts[0]);
        _swap(amounts, poolsPath, path, to);
    }

    function swapTokensForExactTokens(
        uint256 amountOut,
        uint256 amountInMax,
        address[] memory poolsPath,
        IERC20[] memory path,
        address to,
        uint256 deadline
    ) public override ensure(deadline) returns (uint256[] memory amounts) {
        verifyPoolsPathSwap(poolsPath, path);
        amounts = DMMLibrary.getAmountsIn(amountOut, poolsPath, path);
        require(amounts[0] <= amountInMax, "DMMRouter: EXCESSIVE_INPUT_AMOUNT");
        path[0].safeTransferFrom(msg.sender, poolsPath[0], amounts[0]);
        _swap(amounts, poolsPath, path, to);
    }

    function swapExactETHForTokens(
        uint256 amountOutMin,
        address[] calldata poolsPath,
        IERC20[] calldata path,
        address to,
        uint256 deadline
    ) external override payable ensure(deadline) returns (uint256[] memory amounts) {
        require(path[0] == weth, "DMMRouter: INVALID_PATH");
        verifyPoolsPathSwap(poolsPath, path);
        amounts = DMMLibrary.getAmountsOut(msg.value, poolsPath, path);
        require(
            amounts[amounts.length - 1] >= amountOutMin,
            "DMMRouter: INSUFFICIENT_OUTPUT_AMOUNT"
        );
        IWETH(weth).deposit{value: amounts[0]}();
        weth.safeTransfer(poolsPath[0], amounts[0]);
        _swap(amounts, poolsPath, path, to);
    }

    function swapTokensForExactETH(
        uint256 amountOut,
        uint256 amountInMax,
        address[] calldata poolsPath,
        IERC20[] calldata path,
        address to,
        uint256 deadline
    ) external override ensure(deadline) returns (uint256[] memory amounts) {
        require(path[path.length - 1] == weth, "DMMRouter: INVALID_PATH");
        verifyPoolsPathSwap(poolsPath, path);
        amounts = DMMLibrary.getAmountsIn(amountOut, poolsPath, path);
        require(amounts[0] <= amountInMax, "DMMRouter: EXCESSIVE_INPUT_AMOUNT");
        path[0].safeTransferFrom(msg.sender, poolsPath[0], amounts[0]);
        _swap(amounts, poolsPath, path, address(this));
        IWETH(weth).withdraw(amounts[amounts.length - 1]);
        TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]);
    }

    function swapExactTokensForETH(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata poolsPath,
        IERC20[] calldata path,
        address to,
        uint256 deadline
    ) external override ensure(deadline) returns (uint256[] memory amounts) {
        require(path[path.length - 1] == weth, "DMMRouter: INVALID_PATH");
        verifyPoolsPathSwap(poolsPath, path);
        amounts = DMMLibrary.getAmountsOut(amountIn, poolsPath, path);
        require(
            amounts[amounts.length - 1] >= amountOutMin,
            "DMMRouter: INSUFFICIENT_OUTPUT_AMOUNT"
        );
        path[0].safeTransferFrom(msg.sender, poolsPath[0], amounts[0]);
        _swap(amounts, poolsPath, path, address(this));
        IWETH(weth).withdraw(amounts[amounts.length - 1]);
        TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]);
    }

    function swapETHForExactTokens(
        uint256 amountOut,
        address[] calldata poolsPath,
        IERC20[] calldata path,
        address to,
        uint256 deadline
    ) external override payable ensure(deadline) returns (uint256[] memory amounts) {
        require(path[0] == weth, "DMMRouter: INVALID_PATH");
        verifyPoolsPathSwap(poolsPath, path);
        amounts = DMMLibrary.getAmountsIn(amountOut, poolsPath, path);
        require(amounts[0] <= msg.value, "DMMRouter: EXCESSIVE_INPUT_AMOUNT");
        IWETH(weth).deposit{value: amounts[0]}();
        weth.safeTransfer(poolsPath[0], amounts[0]);
        _swap(amounts, poolsPath, path, to);
        // refund dust eth, if any
        if (msg.value > amounts[0]) {
            TransferHelper.safeTransferETH(msg.sender, msg.value - amounts[0]);
        }
    }

    // **** SWAP (supporting fee-on-transfer tokens) ****
    // requires the initial amount to have already been sent to the first pool
    function _swapSupportingFeeOnTransferTokens(
        address[] memory poolsPath,
        IERC20[] memory path,
        address _to
    ) internal {
        verifyPoolsPathSwap(poolsPath, path);
        for (uint256 i; i < path.length - 1; i++) {
            (IERC20 input, IERC20 output) = (path[i], path[i + 1]);
            (IERC20 token0, ) = DMMLibrary.sortTokens(input, output);
            IDMMPool pool = IDMMPool(poolsPath[i]);
            uint256 amountOutput;
            {
                // scope to avoid stack too deep errors
                (
                    uint256 reserveIn,
                    uint256 reserveOut,
                    uint256 vReserveIn,
                    uint256 vReserveOut,
                    uint256 feeInPrecision
                ) = DMMLibrary.getTradeInfo(poolsPath[i], input, output);
                uint256 amountInput = IERC20(input).balanceOf(address(pool)).sub(reserveIn);
                amountOutput = DMMLibrary.getAmountOut(
                    amountInput,
                    reserveIn,
                    reserveOut,
                    vReserveIn,
                    vReserveOut,
                    feeInPrecision
                );
            }
            (uint256 amount0Out, uint256 amount1Out) = input == token0
                ? (uint256(0), amountOutput)
                : (amountOutput, uint256(0));
            address to = i < path.length - 2 ? poolsPath[i + 1] : _to;
            pool.swap(amount0Out, amount1Out, to, new bytes(0));
        }
    }

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] memory poolsPath,
        IERC20[] memory path,
        address to,
        uint256 deadline
    ) public override ensure(deadline) {
        path[0].safeTransferFrom(msg.sender, poolsPath[0], amountIn);
        uint256 balanceBefore = path[path.length - 1].balanceOf(to);
        _swapSupportingFeeOnTransferTokens(poolsPath, path, to);
        uint256 balanceAfter = path[path.length - 1].balanceOf(to);
        require(
            balanceAfter >= balanceBefore.add(amountOutMin),
            "DMMRouter: INSUFFICIENT_OUTPUT_AMOUNT"
        );
    }

    function swapExactETHForTokensSupportingFeeOnTransferTokens(
        uint256 amountOutMin,
        address[] calldata poolsPath,
        IERC20[] calldata path,
        address to,
        uint256 deadline
    ) external override payable ensure(deadline) {
        require(path[0] == weth, "DMMRouter: INVALID_PATH");
        uint256 amountIn = msg.value;
        IWETH(weth).deposit{value: amountIn}();
        weth.safeTransfer(poolsPath[0], amountIn);
        uint256 balanceBefore = IERC20(path[path.length - 1]).balanceOf(to);
        _swapSupportingFeeOnTransferTokens(poolsPath, path, to);
        require(
            path[path.length - 1].balanceOf(to).sub(balanceBefore) >= amountOutMin,
            "DMMRouter: INSUFFICIENT_OUTPUT_AMOUNT"
        );
    }

    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata poolsPath,
        IERC20[] calldata path,
        address to,
        uint256 deadline
    ) external override ensure(deadline) {
        require(path[path.length - 1] == weth, "DMMRouter: INVALID_PATH");
        path[0].safeTransferFrom(msg.sender, poolsPath[0], amountIn);
        _swapSupportingFeeOnTransferTokens(poolsPath, path, address(this));
        uint256 amountOut = IWETH(weth).balanceOf(address(this));
        require(amountOut >= amountOutMin, "DMMRouter: INSUFFICIENT_OUTPUT_AMOUNT");
        IWETH(weth).withdraw(amountOut);
        TransferHelper.safeTransferETH(to, amountOut);
    }

    // **** LIBRARY FUNCTIONS ****

    /// @dev get the amount of tokenB for adding liquidity with given amount of token A and the amount of tokens in the pool
    function quote(
        uint256 amountA,
        uint256 reserveA,
        uint256 reserveB
    ) external override pure returns (uint256 amountB) {
        return DMMLibrary.quote(amountA, reserveA, reserveB);
    }

    function getAmountsOut(
        uint256 amountIn,
        address[] calldata poolsPath,
        IERC20[] calldata path
    ) external override view returns (uint256[] memory amounts) {
        verifyPoolsPathSwap(poolsPath, path);
        return DMMLibrary.getAmountsOut(amountIn, poolsPath, path);
    }

    function getAmountsIn(
        uint256 amountOut,
        address[] calldata poolsPath,
        IERC20[] calldata path
    ) external override view returns (uint256[] memory amounts) {
        verifyPoolsPathSwap(poolsPath, path);
        return DMMLibrary.getAmountsIn(amountOut, poolsPath, path);
    }

    function verifyPoolsPathSwap(address[] memory poolsPath, IERC20[] memory path) internal view {
        require(path.length >= 2, "DMMRouter: INVALID_PATH");
        require(poolsPath.length == path.length - 1, "DMMRouter: INVALID_POOLS_PATH");
        for (uint256 i = 0; i < poolsPath.length; i++) {
            verifyPoolAddress(path[i], path[i + 1], poolsPath[i]);
        }
    }

    function verifyPoolAddress(
        IERC20 tokenA,
        IERC20 tokenB,
        address pool
    ) internal view {
        require(IDMMFactory(factory).isPool(tokenA, tokenB, pool), "DMMRouter: INVALID_POOL");
    }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_factory","type":"address"},{"internalType":"contract IWETH","name":"_weth","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"contract IERC20","name":"tokenA","type":"address"},{"internalType":"contract IERC20","name":"tokenB","type":"address"},{"internalType":"address","name":"pool","type":"address"},{"internalType":"uint256","name":"amountADesired","type":"uint256"},{"internalType":"uint256","name":"amountBDesired","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"uint256[2]","name":"vReserveRatioBounds","type":"uint256[2]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"address","name":"pool","type":"address"},{"internalType":"uint256","name":"amountTokenDesired","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"uint256[2]","name":"vReserveRatioBounds","type":"uint256[2]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidityETH","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"tokenA","type":"address"},{"internalType":"contract IERC20","name":"tokenB","type":"address"},{"internalType":"uint32","name":"ampBps","type":"uint32"},{"internalType":"uint256","name":"amountADesired","type":"uint256"},{"internalType":"uint256","name":"amountBDesired","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidityNewPool","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint32","name":"ampBps","type":"uint32"},{"internalType":"uint256","name":"amountTokenDesired","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidityNewPoolETH","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"address[]","name":"poolsPath","type":"address[]"},{"internalType":"contract IERC20[]","name":"path","type":"address[]"}],"name":"getAmountsIn","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address[]","name":"poolsPath","type":"address[]"},{"internalType":"contract IERC20[]","name":"path","type":"address[]"}],"name":"getAmountsOut","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"reserveA","type":"uint256"},{"internalType":"uint256","name":"reserveB","type":"uint256"}],"name":"quote","outputs":[{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"tokenA","type":"address"},{"internalType":"contract IERC20","name":"tokenB","type":"address"},{"internalType":"address","name":"pool","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"address","name":"pool","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityETH","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"address","name":"pool","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityETHSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"address","name":"pool","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityETHWithPermit","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"address","name":"pool","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityETHWithPermitSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"tokenA","type":"address"},{"internalType":"contract IERC20","name":"tokenB","type":"address"},{"internalType":"address","name":"pool","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityWithPermit","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"address[]","name":"poolsPath","type":"address[]"},{"internalType":"contract IERC20[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapETHForExactTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"poolsPath","type":"address[]"},{"internalType":"contract IERC20[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactETHForTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"poolsPath","type":"address[]"},{"internalType":"contract IERC20[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactETHForTokensSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"poolsPath","type":"address[]"},{"internalType":"contract IERC20[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForETH","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"poolsPath","type":"address[]"},{"internalType":"contract IERC20[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForETHSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"poolsPath","type":"address[]"},{"internalType":"contract IERC20[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"poolsPath","type":"address[]"},{"internalType":"contract IERC20[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForTokensSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address[]","name":"poolsPath","type":"address[]"},{"internalType":"contract IERC20[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapTokensForExactETH","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address[]","name":"poolsPath","type":"address[]"},{"internalType":"contract IERC20[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapTokensForExactTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"contract IWETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

60c06040523480156200001157600080fd5b506040516200611038038062006110833981810160405260408110156200003757600080fd5b5080516020909101516001600160601b0319606092831b8116608052911b1660a05260805160601c60a05160601c615ff762000119600039806101ac528061189952806119815280611a305280611d965280611f755280612083528061211852806122d352806125cf52806126f2528061280152806129b152806130b752806132e752806133be52806134f75280613549528061378152806137ac52806137ff52806138975280613ee25280613fce52806140d55280614302525080611492528061158152806126b552806127c452806135eb52806144535250615ff76000f3fe60806040526004361061018f5760003560e01c8063a8312b1d116100d6578063ceb757d51161007f578063e8898b5f11610059578063e8898b5f146110cc578063ebb5d2e914611227578063fc5b8bce14611291576101d5565b8063ceb757d514610e60578063d72c144714610fbb578063e1f4a7841461105b576101d5565b8063af55e31f116100b0578063af55e31f14610cfc578063b56b681d14610de1578063c45a015514610e4b576101d5565b8063a8312b1d14610a95578063ad615dec14610b6b578063ae8290b714610ba1576101d5565b80634c17fd7c1161013857806389c275941161011257806389c275941461083d5780639e269b6814610934578063a4aabb0814610a0a576101d5565b80634c17fd7c146105ea5780636dce49ae146106955780637d41a422146107dc576101d5565b80632daaa818116101695780632daaa818146103d05780633e741fca146104b55780633fc8cef3146105ac576101d5565b80630e2f024c146101da5780631c5d0a6b146102775780632434193414610313576101d5565b366101d5573373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146101d357fe5b005b600080fd5b3480156101e657600080fd5b5061026560048036036101608110156101fe57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602081013582169160408201359160608101359160808201359160a08101359091169060c08101359060e081013515159060ff6101008201351690610120810135906101400135611376565b60408051918252519081900360200190f35b34801561028357600080fd5b506102f5600480360361012081101561029b57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602081013582169163ffffffff6040830135169160608101359160808201359160a08101359160c08201359160e081013590911690610100013561147a565b60408051938452602084019290925282820152519081900360600190f35b34801561031f57600080fd5b506102f5600480360361016081101561033757600080fd5b60408051808201825273ffffffffffffffffffffffffffffffffffffffff84358116946020810135821694848201359092169360608201359360808301359360a08401359360c0810135939181019290916101208301919060e084019060029083908390808284376000920191909152509194505073ffffffffffffffffffffffffffffffffffffffff823516925050602001356116cf565b6101d3600480360360a08110156103e657600080fd5b8135919081019060408101602082013564010000000081111561040857600080fd5b82018360208201111561041a57600080fd5b8035906020019184602083028401116401000000008311171561043c57600080fd5b91939092909160208101903564010000000081111561045a57600080fd5b82018360208201111561046c57600080fd5b8035906020019184602083028401116401000000008311171561048e57600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135611827565b3480156104c157600080fd5b506101d3600480360360c08110156104d857600080fd5b8135916020810135918101906060810160408201356401000000008111156104ff57600080fd5b82018360208201111561051157600080fd5b8035906020019184602083028401116401000000008311171561053357600080fd5b91939092909160208101903564010000000081111561055157600080fd5b82018360208201111561056357600080fd5b8035906020019184602083028401116401000000008311171561058557600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135611d0f565b3480156105b857600080fd5b506105c1612116565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b3480156105f657600080fd5b5061067c600480360361018081101561060e57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135821691604082013581169160608101359160808201359160a08101359160c0820135169060e08101359061010081013515159060ff610120820135169061014081013590610160013561213a565b6040805192835260208301919091528051918290030190f35b3480156106a157600080fd5b5061078c600480360360c08110156106b857600080fd5b8135916020810135918101906060810160408201356401000000008111156106df57600080fd5b8201836020820111156106f157600080fd5b8035906020019184602083028401116401000000008311171561071357600080fd5b91939092909160208101903564010000000081111561073157600080fd5b82018360208201111561074357600080fd5b8035906020019184602083028401116401000000008311171561076557600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff813516906020013561224a565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156107c85781810151838201526020016107b0565b505050509050019250505060405180910390f35b6102f5600480360360e08110156107f257600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813581169163ffffffff6020820135169160408201359160608101359160808201359160a08101359091169060c0013561269d565b34801561084957600080fd5b5061078c600480360360c081101561086057600080fd5b81359160208101359181019060608101604082013564010000000081111561088757600080fd5b82018360208201111561089957600080fd5b803590602001918460208302840111640100000000831117156108bb57600080fd5b9193909290916020810190356401000000008111156108d957600080fd5b8201836020820111156108eb57600080fd5b8035906020019184602083028401116401000000008311171561090d57600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135612928565b34801561094057600080fd5b5061078c6004803603606081101561095757600080fd5b8135919081019060408101602082013564010000000081111561097957600080fd5b82018360208201111561098b57600080fd5b803590602001918460208302840111640100000000831117156109ad57600080fd5b9193909290916020810190356401000000008111156109cb57600080fd5b8201836020820111156109dd57600080fd5b803590602001918460208302840111640100000000831117156109ff57600080fd5b509092509050612be8565b348015610a1657600080fd5b5061067c6004803603610160811015610a2e57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602081013582169160408201359160608101359160808201359160a08101359091169060c08101359060e081013515159060ff6101008201351690610120810135906101400135612ccf565b348015610aa157600080fd5b5061078c60048036036060811015610ab857600080fd5b81359190810190604081016020820135640100000000811115610ada57600080fd5b820183602082011115610aec57600080fd5b80359060200191846020830284011164010000000083111715610b0e57600080fd5b919390929091602081019035640100000000811115610b2c57600080fd5b820183602082011115610b3e57600080fd5b80359060200191846020830284011164010000000083111715610b6057600080fd5b509092509050612dd9565b348015610b7757600080fd5b5061026560048036036060811015610b8e57600080fd5b5080359060208101359060400135612eb6565b348015610bad57600080fd5b5061078c600480360360c0811015610bc457600080fd5b813591602081013591810190606081016040820135640100000000811115610beb57600080fd5b820183602082011115610bfd57600080fd5b80359060200191846020830284011164010000000083111715610c1f57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050640100000000811115610c6f57600080fd5b820183602082011115610c8157600080fd5b80359060200191846020830284011164010000000083111715610ca357600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505073ffffffffffffffffffffffffffffffffffffffff8335169350505060200135612ecd565b61078c600480360360a0811015610d1257600080fd5b81359190810190604081016020820135640100000000811115610d3457600080fd5b820183602082011115610d4657600080fd5b80359060200191846020830284011164010000000083111715610d6857600080fd5b919390929091602081019035640100000000811115610d8657600080fd5b820183602082011115610d9857600080fd5b80359060200191846020830284011164010000000083111715610dba57600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135613043565b348015610ded57600080fd5b5061067c600480360360e0811015610e0457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602081013582169160408201359160608101359160808201359160a08101359091169060c0013561347e565b348015610e5757600080fd5b506105c16135e9565b348015610e6c57600080fd5b5061078c600480360360c0811015610e8357600080fd5b813591602081013591810190606081016040820135640100000000811115610eaa57600080fd5b820183602082011115610ebc57600080fd5b80359060200191846020830284011164010000000083111715610ede57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050640100000000811115610f2e57600080fd5b820183602082011115610f4057600080fd5b80359060200191846020830284011164010000000083111715610f6257600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505073ffffffffffffffffffffffffffffffffffffffff833516935050506020013561360d565b6102f56004803603610120811015610fd257600080fd5b60408051808201825273ffffffffffffffffffffffffffffffffffffffff84358116946020810135909116938382013593606083013593608084013593928301929160e08301919060a084019060029083908390808284376000920191909152509194505073ffffffffffffffffffffffffffffffffffffffff82351692505060200135613706565b34801561106757600080fd5b5061067c600480360361010081101561107f57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020810135821691604082013581169160608101359160808201359160a08101359160c0820135169060e0013561397c565b3480156110d857600080fd5b506101d3600480360360c08110156110ef57600080fd5b81359160208101359181019060608101604082013564010000000081111561111657600080fd5b82018360208201111561112857600080fd5b8035906020019184602083028401116401000000008311171561114a57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929594936020810193503591505064010000000081111561119a57600080fd5b8201836020820111156111ac57600080fd5b803590602001918460208302840111640100000000831117156111ce57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505073ffffffffffffffffffffffffffffffffffffffff8335169350505060200135613bff565b34801561123357600080fd5b50610265600480360360e081101561124a57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602081013582169160408201359160608101359160808201359160a08101359091169060c00135613e6a565b61078c600480360360a08110156112a757600080fd5b813591908101906040810160208201356401000000008111156112c957600080fd5b8201836020820111156112db57600080fd5b803590602001918460208302840111640100000000831117156112fd57600080fd5b91939092909160208101903564010000000081111561131b57600080fd5b82018360208201111561132d57600080fd5b8035906020019184602083028401116401000000008311171561134f57600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff8135169060200135614061565b60008085611384578a6113a6565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b604080517fd505accf00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101839052606481018a905260ff8816608482015260a4810187905260c48101869052905191925073ffffffffffffffffffffffffffffffffffffffff8e169163d505accf9160e48082019260009290919082900301818387803b15801561144257600080fd5b505af1158015611456573d6000803e3d6000fd5b505050506114698d8d8d8d8d8d8d613e6a565b9d9c50505050505050505050505050565b6000806000806127108b63ffffffff161415611564577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16633d82497e8e8e6040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1681526020019250505060206040518083038186803b15801561153557600080fd5b505afa158015611549573d6000803e3d6000fd5b505050506040513d602081101561155f57600080fd5b505190505b73ffffffffffffffffffffffffffffffffffffffff8116611663577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16638fd648408e8e8e6040518463ffffffff1660e01b8152600401808473ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018263ffffffff1681526020019350505050602060405180830381600087803b15801561163457600080fd5b505af1158015611648573d6000803e3d6000fd5b505050506040513d602081101561165e57600080fd5b505190505b61166b615e3b565b5060408051808201909152600081527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60208201526116b28e8e848e8e8e8e888f8f6116cf565b809550819650829750505050505099509950999650505050505050565b6000806000834281101561174457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f444d4d526f757465723a20455850495245440000000000000000000000000000604482015290519081900360640190fd5b61174f8e8e8e614451565b61175f8e8e8e8e8e8e8e8e6145b0565b90945092506117708e338e876147a7565b61177c8d338e866147a7565b8b73ffffffffffffffffffffffffffffffffffffffff16636a627842876040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b1580156117e557600080fd5b505af11580156117f9573d6000803e3d6000fd5b505050506040513d602081101561180f57600080fd5b5051939e929d50929b50909950505050505050505050565b804281101561189757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f444d4d526f757465723a20455850495245440000000000000000000000000000604482015290519081900360640190fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16858560008181106118db57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461197a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f444d4d526f757465723a20494e56414c49445f50415448000000000000000000604482015290519081900360640190fd5b60003490507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156119e757600080fd5b505af11580156119fb573d6000803e3d6000fd5b5050505050611a7488886000818110611a1057fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff16827f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166148429092919063ffffffff16565b600086867fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818110611aa457fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611b2757600080fd5b505afa158015611b3b573d6000803e3d6000fd5b505050506040513d6020811015611b5157600080fd5b50516040805160208b810282810182019093528b8252929350611bc49290918c918c91829185019084908082843760009201919091525050604080516020808d0282810182019093528c82529093508c92508b9182918501908490808284376000920191909152508a92506148cf915050565b89611cac8289897fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818110611bf757fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231896040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611c7a57600080fd5b505afa158015611c8e573d6000803e3d6000fd5b505050506040513d6020811015611ca457600080fd5b505190614b93565b1015611d03576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526025815260200180615ee46025913960400191505060405180910390fd5b50505050505050505050565b8042811015611d7f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f444d4d526f757465723a20455850495245440000000000000000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001685857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818110611de457fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611e8357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f444d4d526f757465723a20494e56414c49445f50415448000000000000000000604482015290519081900360640190fd5b611f023388886000818110611e9457fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff168b88886000818110611ebf57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166147a7909392919063ffffffff16565b611f7187878080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808b0282810182019093528a82529093508a9250899182918501908490808284376000920191909152503092506148cf915050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611ffa57600080fd5b505afa15801561200e573d6000803e3d6000fd5b505050506040513d602081101561202457600080fd5b5051905088811015612081576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526025815260200180615ee46025913960400191505060405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156120f457600080fd5b505af1158015612108573d6000803e3d6000fd5b50505050611d038482614c0f565b7f000000000000000000000000000000000000000000000000000000000000000081565b60008060008661214a578b61216c565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b604080517fd505accf00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101839052606481018b905260ff8916608482015260a4810188905260c48101879052905191925073ffffffffffffffffffffffffffffffffffffffff8f169163d505accf9160e48082019260009290919082900301818387803b15801561220857600080fd5b505af115801561221c573d6000803e3d6000fd5b505050506122308f8f8f8f8f8f8f8f61397c565b8093508194505050509c509c9a5050505050505050505050565b606081428110156122bc57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f444d4d526f757465723a20455850495245440000000000000000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001686867fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff810181811061232157fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146123c057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f444d4d526f757465723a20494e56414c49445f50415448000000000000000000604482015290519081900360640190fd5b61242d88888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808c0282810182019093528b82529093508b92508a918291850190849080828437600092019190915250614d4792505050565b61249b8a89898080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808d0282810182019093528c82529093508c92508b918291850190849080828437600092019190915250614e8692505050565b915088826001845103815181106124ae57fe5b6020026020010151101561250d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526025815260200180615ee46025913960400191505060405180910390fd5b61255d338989600081811061251e57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff168460008151811061254857fe5b602002602001015189896000818110611ebf57fe5b6125cd8289898080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808d0282810182019093528c82529093508c92508b918291850190849080828437600092019190915250309250614fa3915050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d8360018551038151811061261957fe5b60200260200101516040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561265757600080fd5b505af115801561266b573d6000803e3d6000fd5b50505050612690848360018551038151811061268357fe5b6020026020010151614c0f565b5098975050505050505050565b6000806000806127108a63ffffffff1614156127a7577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16633d82497e8c7f00000000000000000000000000000000000000000000000000000000000000006040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1681526020019250505060206040518083038186803b15801561277857600080fd5b505afa15801561278c573d6000803e3d6000fd5b505050506040513d60208110156127a257600080fd5b505190505b73ffffffffffffffffffffffffffffffffffffffff81166128c6577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16638fd648408c7f00000000000000000000000000000000000000000000000000000000000000008d6040518463ffffffff1660e01b8152600401808473ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018263ffffffff1681526020019350505050602060405180830381600087803b15801561289757600080fd5b505af11580156128ab573d6000803e3d6000fd5b505050506040513d60208110156128c157600080fd5b505190505b6128ce615e3b565b5060408051808201909152600081527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60208201526129138c838c8c8c868d8d613706565b919e909d50909b509950505050505050505050565b6060814281101561299a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f444d4d526f757465723a20455850495245440000000000000000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001686867fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81018181106129ff57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614612a9e57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f444d4d526f757465723a20494e56414c49445f50415448000000000000000000604482015290519081900360640190fd5b612b0b88888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808c0282810182019093528b82529093508b92508a918291850190849080828437600092019190915250614d4792505050565b612b798a89898080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808d0282810182019093528c82529093508c92508b9182918501908490808284376000920191909152506151ec92505050565b91508882600081518110612b8957fe5b6020026020010151111561250d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526021815260200180615e5a6021913960400191505060405180910390fd5b6060612c5785858080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808902828101820190935288825290935088925087918291850190849080828437600092019190915250614d4792505050565b612cc58686868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808a028281018201909352898252909350899250889182918501908490808284376000920191909152506151ec92505050565b9695505050505050565b600080600086612cdf578b612d01565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b604080517fd505accf00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101839052606481018b905260ff8916608482015260a4810188905260c48101879052905191925073ffffffffffffffffffffffffffffffffffffffff8f169163d505accf9160e48082019260009290919082900301818387803b158015612d9d57600080fd5b505af1158015612db1573d6000803e3d6000fd5b50505050612dc48e8e8e8e8e8e8e61347e565b909f909e509c50505050505050505050505050565b6060612e4885858080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808902828101820190935288825290935088925087918291850190849080828437600092019190915250614d4792505050565b612cc58686868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808a02828101820190935289825290935089925088918291850190849080828437600092019190915250614e8692505050565b6000612ec3848484615334565b90505b9392505050565b60608142811015612f3f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f444d4d526f757465723a20455850495245440000000000000000000000000000604482015290519081900360640190fd5b612f498686614d47565b612f548887876151ec565b91508682600081518110612f6457fe5b60200260200101511115612fc3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526021815260200180615e5a6021913960400191505060405180910390fd5b61302c3387600081518110612fd457fe5b602002602001015184600081518110612fe957fe5b602002602001015188600081518110612ffe57fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff166147a7909392919063ffffffff16565b61303882878787614fa3565b509695505050505050565b606081428110156130b557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f444d4d526f757465723a20455850495245440000000000000000000000000000604482015290519081900360640190fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16868660008181106130f957fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461319857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f444d4d526f757465723a20494e56414c49445f50415448000000000000000000604482015290519081900360640190fd5b61320588888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808c0282810182019093528b82529093508b92508a918291850190849080828437600092019190915250614d4792505050565b6132733489898080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808d0282810182019093528c82529093508c92508b918291850190849080828437600092019190915250614e8692505050565b9150888260018451038151811061328657fe5b602002602001015110156132e5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526025815260200180615ee46025913960400191505060405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db08360008151811061332e57fe5b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b15801561336157600080fd5b505af1158015613375573d6000803e3d6000fd5b50505050506134028888600081811061338a57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff16836000815181106133b457fe5b60200260200101517f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166148429092919063ffffffff16565b6134728289898080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808d0282810182019093528c82529093508c92508b9182918501908490808284376000920191909152508a9250614fa3915050565b50979650505050505050565b60008082428110156134f157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f444d4d526f757465723a20455850495245440000000000000000000000000000604482015290519081900360640190fd5b6135218a7f00000000000000000000000000000000000000000000000000000000000000008b8b8b8b308b61397c565b909350915061354773ffffffffffffffffffffffffffffffffffffffff8b168685614842565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d836040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156135ba57600080fd5b505af11580156135ce573d6000803e3d6000fd5b505050506135dc8583614c0f565b5097509795505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b6060814281101561367f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f444d4d526f757465723a20455850495245440000000000000000000000000000604482015290519081900360640190fd5b6136898686614d47565b613694888787614e86565b915086826001845103815181106136a757fe5b60200260200101511015612fc3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526025815260200180615ee46025913960400191505060405180910390fd5b6000806000834281101561377b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f444d4d526f757465723a20455850495245440000000000000000000000000000604482015290519081900360640190fd5b6137a68c7f00000000000000000000000000000000000000000000000000000000000000008d614451565b6137d68c7f00000000000000000000000000000000000000000000000000000000000000008d8d348e8e8e6145b0565b90945092506137fd73ffffffffffffffffffffffffffffffffffffffff8d16338d876147a7565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0846040518263ffffffff1660e01b81526004016000604051808303818588803b15801561386557600080fd5b505af1158015613879573d6000803e3d6000fd5b506138c293505073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001691508d905085614842565b8a73ffffffffffffffffffffffffffffffffffffffff16636a627842876040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b15801561392b57600080fd5b505af115801561393f573d6000803e3d6000fd5b505050506040513d602081101561395557600080fd5b505191503483101561396d5761396d33843403614c0f565b50985098509895505050505050565b60008082428110156139ef57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f444d4d526f757465723a20455850495245440000000000000000000000000000604482015290519081900360640190fd5b6139fa8b8b8b614451565b613a1c73ffffffffffffffffffffffffffffffffffffffff8a16338b8b6147a7565b6000808a73ffffffffffffffffffffffffffffffffffffffff166389afcb44886040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1681526020019150506040805180830381600087803b158015613a8757600080fd5b505af1158015613a9b573d6000803e3d6000fd5b505050506040513d6040811015613ab157600080fd5b50805160209091015190925090506000613acb8e8e615424565b5090508073ffffffffffffffffffffffffffffffffffffffff168e73ffffffffffffffffffffffffffffffffffffffff1614613b08578183613b0b565b82825b909650945089861015613b7f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f444d4d526f757465723a20494e53554646494349454e545f415f414d4f554e54604482015290519081900360640190fd5b88851015613bee57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f444d4d526f757465723a20494e53554646494349454e545f425f414d4f554e54604482015290519081900360640190fd5b505050509850989650505050505050565b8042811015613c6f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f444d4d526f757465723a20455850495245440000000000000000000000000000604482015290519081900360640190fd5b613c963386600081518110613c8057fe5b60200260200101518987600081518110612ffe57fe5b600084600186510381518110613ca857fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff166370a08231856040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015613d1657600080fd5b505afa158015613d2a573d6000803e3d6000fd5b505050506040513d6020811015613d4057600080fd5b50519050613d4f8686866148cf565b600085600187510381518110613d6157fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff166370a08231866040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015613dcf57600080fd5b505afa158015613de3573d6000803e3d6000fd5b505050506040513d6020811015613df957600080fd5b50519050613e07828961558d565b811015613e5f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526025815260200180615ee46025913960400191505060405180910390fd5b505050505050505050565b60008142811015613edc57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f444d4d526f757465723a20455850495245440000000000000000000000000000604482015290519081900360640190fd5b613f0c897f00000000000000000000000000000000000000000000000000000000000000008a8a8a8a308a61397c565b604080517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529051919450613fcc9250869173ffffffffffffffffffffffffffffffffffffffff8d16916370a08231916024808301926020929190829003018186803b158015613f8257600080fd5b505afa158015613f96573d6000803e3d6000fd5b505050506040513d6020811015613fac57600080fd5b505173ffffffffffffffffffffffffffffffffffffffff8c169190614842565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d836040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561403f57600080fd5b505af1158015614053573d6000803e3d6000fd5b505050506134728483614c0f565b606081428110156140d357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f444d4d526f757465723a20455850495245440000000000000000000000000000604482015290519081900360640190fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168686600081811061411757fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146141b657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f444d4d526f757465723a20494e56414c49445f50415448000000000000000000604482015290519081900360640190fd5b61422388888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808c0282810182019093528b82529093508b92508a918291850190849080828437600092019190915250614d4792505050565b6142918989898080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808d0282810182019093528c82529093508c92508b9182918501908490808284376000920191909152506151ec92505050565b915034826000815181106142a157fe5b60200260200101511115614300576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526021815260200180615e5a6021913960400191505060405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db08360008151811061434957fe5b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b15801561437c57600080fd5b505af1158015614390573d6000803e3d6000fd5b50505050506143a58888600081811061338a57fe5b6144158289898080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808d0282810182019093528c82529093508c92508b9182918501908490808284376000920191909152508a9250614fa3915050565b8160008151811061442257fe5b602002602001015134111561347257613472338360008151811061444257fe5b60200260200101513403614c0f565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663eb787f618484846040518463ffffffff1660e01b8152600401808473ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff168152602001935050505060206040518083038186803b15801561451457600080fd5b505afa158015614528573d6000803e3d6000fd5b505050506040513d602081101561453e57600080fd5b50516145ab57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f444d4d526f757465723a20494e56414c49445f504f4f4c000000000000000000604482015290519081900360640190fd5b505050565b6000806000806000806145c48c8f8f615601565b5093509350935093508360001480156145db575082155b156145eb578a9550899450613bee565b60006145f88c8686615334565b90508a811161467b578881101561467057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f444d4d526f757465723a20494e53554646494349454e545f425f414d4f554e54604482015290519081900360640190fd5b8b9650945084614709565b60006146888c8688615334565b90508c81111561469457fe5b8a81101561470357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f444d4d526f757465723a20494e53554646494349454e545f415f414d4f554e54604482015290519081900360640190fd5b96508a95505b6000836e01000000000000000000000000000084028161472557fe5b8a519190049150811080159061473f575060208901518111155b614794576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526021815260200180615fa16021913960400191505060405180910390fd5b5050505050509850989650505050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff80861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017905261483c908590615715565b50505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526145ab908490615715565b6148d98383614d47565b60005b600183510381101561483c576000808483815181106148f757fe5b602002602001015185846001018151811061490e57fe5b60200260200101519150915060006149268383615424565b509050600087858151811061493757fe5b602002602001015190506000806000806000806149688e8c8151811061495957fe5b60200260200101518b8b615601565b9450945094509450945060006149df868c73ffffffffffffffffffffffffffffffffffffffff166370a082318b6040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611c7a57600080fd5b90506149ef8187878787876157ed565b96505050505050506000808473ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1614614a3557826000614a39565b6000835b91509150600060028b51038910614a505789614a68565b8b8960010181518110614a5f57fe5b60200260200101515b60408051600080825260208201928390527f022c0d9f000000000000000000000000000000000000000000000000000000008352602482018781526044830187905273ffffffffffffffffffffffffffffffffffffffff8086166064850152608060848501908152845160a48601819052969750908b169563022c0d9f958a958a958a9591949193919260c486019290918190849084905b83811015614b18578181015183820152602001614b00565b50505050905090810190601f168015614b455780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b158015614b6757600080fd5b505af1158015614b7b573d6000803e3d6000fd5b50506001909a0199506148dc98505050505050505050565b600082821115614c0457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b508082035b92915050565b6040805160008082526020820190925273ffffffffffffffffffffffffffffffffffffffff84169083906040518082805190602001908083835b60208310614c8657805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101614c49565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114614ce8576040519150601f19603f3d011682016040523d82523d6000602084013e614ced565b606091505b50509050806145ab576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180615f2f6023913960400191505060405180910390fd5b600281511015614db857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f444d4d526f757465723a20494e56414c49445f50415448000000000000000000604482015290519081900360640190fd5b6001815103825114614e2b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f444d4d526f757465723a20494e56414c49445f504f4f4c535f50415448000000604482015290519081900360640190fd5b60005b82518110156145ab57614e7e828281518110614e4657fe5b6020026020010151838360010181518110614e5d57fe5b6020026020010151858481518110614e7157fe5b6020026020010151614451565b600101614e2e565b6060815167ffffffffffffffff81118015614ea057600080fd5b50604051908082528060200260200182016040528015614eca578160200160208202803683370190505b5090508381600081518110614edb57fe5b60200260200101818152505060005b6001835103811015614f9b576000806000806000614f45898781518110614f0d57fe5b6020026020010151898881518110614f2157fe5b60200260200101518a8960010181518110614f3857fe5b6020026020010151615601565b94509450945094509450614f70878781518110614f5e57fe5b602002602001015186868686866157ed565b878760010181518110614f7f57fe5b6020908102919091010152505060019093019250614eea915050565b509392505050565b60005b60018351038110156151e557600080848381518110614fc157fe5b6020026020010151858460010181518110614fd857fe5b6020026020010151915091506000614ff08383615424565b509050600088856001018151811061500457fe5b602002602001015190506000808373ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff161461504c57826000615050565b6000835b91509150600060028a51038810615067578861507f565b8a886001018151811061507657fe5b60200260200101515b90508a888151811061508d57fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1663022c0d9f848484600067ffffffffffffffff811180156150cb57600080fd5b506040519080825280601f01601f1916602001820160405280156150f6576020820181803683370190505b506040518563ffffffff1660e01b8152600401808581526020018481526020018373ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b8381101561516b578181015183820152602001615153565b50505050905090810190601f1680156151985780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b1580156151ba57600080fd5b505af11580156151ce573d6000803e3d6000fd5b505060019099019850614fa6975050505050505050565b5050505050565b6060815167ffffffffffffffff8111801561520657600080fd5b50604051908082528060200260200182016040528015615230578160200160208202803683370190505b509050838160018351038151811061524457fe5b602090810291909101015281517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff015b8015614f9b5760008060008060006152bf89600188038151811061529457fe5b60200260200101518960018903815181106152ab57fe5b60200260200101518a8981518110614f3857fe5b945094509450945094506152ea8787815181106152d857fe5b60200260200101518686868686615963565b8760018803815181106152f957fe5b602090810291909101015250507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9093019250615274915050565b60008084116153a457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f444d4d4c6962726172793a20494e53554646494349454e545f414d4f554e5400604482015290519081900360640190fd5b6000831180156153b45750600082115b615409576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526022815260200180615e7b6022913960400191505060405180910390fd5b826154148584615ab9565b8161541b57fe5b04949350505050565b6000808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614156154c257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f444d4d4c6962726172793a204944454e544943414c5f41444452455353455300604482015290519081900360640190fd5b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16106154fc5782846154ff565b83835b909250905073ffffffffffffffffffffffffffffffffffffffff821661558657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f444d4d4c6962726172793a205a45524f5f414444524553530000000000000000604482015290519081900360640190fd5b9250929050565b600082820183811015612ec657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6000806000806000806156148888615424565b5090506000806000808c73ffffffffffffffffffffffffffffffffffffffff1663d66940276040518163ffffffff1660e01b815260040160a06040518083038186803b15801561566357600080fd5b505afa158015615677573d6000803e3d6000fd5b505050506040513d60a081101561568d57600080fd5b50805160208201516040830151606084015160809094015199506dffffffffffffffffffffffffffff928316975090821695508116935016905073ffffffffffffffffffffffffffffffffffffffff8c8116908616146156f057828482846156f5565b838383835b809a50819b50829c50839d50505050505050505050939792965093509350565b6060615777826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16615b2c9092919063ffffffff16565b8051909150156145ab5780806020019051602081101561579657600080fd5b50516145ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602a815260200180615f77602a913960400191505060405180910390fd5b6000808711615847576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526025815260200180615f526025913960400191505060405180910390fd5b6000861180156158575750600085115b6158ac576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526022815260200180615e7b6022913960400191505060405180910390fd5b60006158d4670de0b6b3a76400006158ce6158c78287614b93565b8b90615ab9565b90615b3b565b905060006158e28286615ab9565b905060006158f0878461558d565b90506158fc8282615b3b565b9350838811615956576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526022815260200180615e7b6022913960400191505060405180910390fd5b5050509695505050505050565b60008087116159bd576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526026815260200180615f096026913960400191505060405180910390fd5b6000861180156159cc57508685115b615a21576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526022815260200180615e7b6022913960400191505060405180910390fd5b6000615a2d8589615ab9565b90506000615a3b858a614b93565b9050615a526001615a4c8484615b3b565b9061558d565b9250615a6683670de0b6b3a7640000615ab9565b9150615a7a670de0b6b3a764000085614b93565b9050615aac816158ce847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff830161558d565b9998505050505050505050565b600082615ac857506000614c09565b82820282848281615ad557fe5b0414612ec6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526021815260200180615ec36021913960400191505060405180910390fd5b6060612ec38484600085615bbc565b6000808211615bab57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b818381615bb457fe5b049392505050565b606082471015615c17576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526026815260200180615e9d6026913960400191505060405180910390fd5b615c2085615d77565b615c8b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b600060608673ffffffffffffffffffffffffffffffffffffffff1685876040518082805190602001908083835b60208310615cf557805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101615cb8565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114615d57576040519150601f19603f3d011682016040523d82523d6000602084013e615d5c565b606091505b5091509150615d6c828286615d7d565b979650505050505050565b3b151590565b60608315615d8c575081612ec6565b825115615d9c5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b83811015615e00578181015183820152602001615de8565b50505050905090810190601f168015615e2d5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b6040518060400160405280600290602082028036833750919291505056fe444d4d526f757465723a204558434553534956455f494e5055545f414d4f554e54444d4d4c6962726172793a20494e53554646494349454e545f4c4951554944495459416464726573733a20696e73756666696369656e742062616c616e636520666f722063616c6c536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77444d4d526f757465723a20494e53554646494349454e545f4f55545055545f414d4f554e54444d4d4c6962726172793a20494e53554646494349454e545f4f55545055545f414d4f554e545472616e7366657248656c7065723a204554485f5452414e534645525f4641494c4544444d4d4c6962726172793a20494e53554646494349454e545f494e5055545f414d4f554e545361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564444d4d526f757465723a204f55545f4f465f424f554e44535f5652455345525645a2646970667358221220f37c2f506ca49cb898a2a392882b1ebba5f9cbce2ee4a30ae1d8f78dac365d2a64736f6c634300060c00330000000000000000000000005f1fe642060b5b9658c15721ea22e982643c095c0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf1270

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000005f1fe642060b5b9658c15721ea22e982643c095c0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf1270

-----Decoded View---------------
Arg [0] : _factory (address): 0x5f1fe642060b5b9658c15721ea22e982643c095c
Arg [1] : _weth (address): 0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000005f1fe642060b5b9658c15721ea22e982643c095c
Arg [1] : 0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf1270


Deployed ByteCode Sourcemap

44126:23155:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;44868:10;:27;44890:4;44868:27;;44861:35;;;;44126:23155;;;;;55327:790;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;55327:790:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;48849:1262;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;48849:1262:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;46566:1098;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;46566:1098:0;;-1:-1:-1;;46566:1098:0;;;;;-1:-1:-1;;46566:1098:0;;;;:::i;64064:783::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;64064:783:0;-1:-1:-1;64064:783:0;;;;;;;;;:::i;64855:763::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;64855:763:0;-1:-1:-1;64855:763:0;;;;;;;;;:::i;44529:36::-;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;52937:793;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;52937:793:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;59880:894;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;59880:894:0;-1:-1:-1;59880:894:0;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;50119:1202;;;;;;;;;;;;;;;;-1:-1:-1;50119:1202:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;59037:835::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;59037:835:0;-1:-1:-1;59037:835:0;;;;;;;;;:::i;66339:311::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;66339:311:0;;-1:-1:-1;66339:311:0;-1:-1:-1;66339:311:0;:::i;53738:768::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;53738:768:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;66020:311::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;66020:311:0;;-1:-1:-1;66020:311:0;-1:-1:-1;66020:311:0;:::i;65790:222::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;65790:222:0;;;;;;;;;;;;:::i;57661:611::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;57661:611:0;;;;;;;;-1:-1:-1;57661:611:0;;-1:-1:-1;;57661:611:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;57661:611:0;;-1:-1:-1;;57661:611:0;;;;;-1:-1:-1;;;57661:611:0;;;;:::i;58280:749::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;58280:749:0;-1:-1:-1;58280:749:0;;;;;;;;;:::i;52221:708::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;52221:708:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;44481:41::-;;;;;;;;;;;;;:::i;56967:686::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;56967:686:0;;;;;;;;-1:-1:-1;56967:686:0;;-1:-1:-1;;56967:686:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;56967:686:0;;-1:-1:-1;;56967:686:0;;;;;-1:-1:-1;;;56967:686:0;;;;:::i;47672:1169::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;47672:1169:0;;-1:-1:-1;;47672:1169:0;;;;;-1:-1:-1;;47672:1169:0;;;;:::i;51364:849::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;51364:849:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;63350:706::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;63350:706:0;;;;;;;;-1:-1:-1;63350:706:0;;-1:-1:-1;;63350:706:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;63350:706:0;;-1:-1:-1;;63350:706:0;;;;;-1:-1:-1;;;63350:706:0;;;;:::i;54587:732::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;54587:732:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;60782:851::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;60782:851:0;-1:-1:-1;60782:851:0;;;;;;;;;:::i;55327:790::-;55698:17;55728:13;55744:10;:36;;55771:9;55744:36;;;55765:2;55744:36;55791:78;;;;;;55817:10;55791:78;;;;55837:4;55791:78;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;55728:52;;-1:-1:-1;55791:25:0;;;;;;:78;;;;;-1:-1:-1;;55791:78:0;;;;;;;;-1:-1:-1;55791:25:0;:78;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;55892:217;55954:5;55974:4;55993:9;56017:14;56046:12;56073:2;56090:8;55892:47;:217::i;:::-;55880:229;55327:790;-1:-1:-1;;;;;;;;;;;;;55327:790:0:o;48849:1262::-;49197:15;49227;49257:17;49302:12;44302:5;49329:6;:13;;;49325:108;;;49378:7;49366:39;;;49406:6;49414;49366:55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;49366:55:0;;-1:-1:-1;49325:108:0;49447:18;;;49443:113;;49501:7;49489:31;;;49521:6;49529;49537;49489:55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;49489:55:0;;-1:-1:-1;49443:113:0;49714:37;;:::i;:::-;-1:-1:-1;49714:80:0;;;;;;;;;-1:-1:-1;49714:80:0;;44416:10;49714:80;;;;49837:266;49864:6;49885;49906:4;49925:14;49954;49983:10;50008;49714:80;50067:2;50084:8;49837:12;:266::i;:::-;49805:298;;;;;;;;;;;;48849:1262;;;;;;;;;;;;;;;:::o;46566:1098::-;46995:15;47025;47055:17;46953:8;44639:15;44627:8;:27;;44619:58;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;47100:39:::1;47118:6;47126;47134:4;47100:17;:39::i;:::-;47171:227;47199:6;47220;47241:4;47260:14;47289;47318:10;47343;47368:19;47171:13;:227::i;:::-;47150:248:::0;;-1:-1:-1;47150:248:0;-1:-1:-1;47477:61:0::1;47504:6:::0;47512:10:::1;47524:4:::0;47150:248;47477:26:::1;:61::i;:::-;47549;47576:6;47584:10;47596:4;47602:7;47549:26;:61::i;:::-;47642:4;47633:19;;;47653:2;47633:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;47633:23:0;46566:1098;;;;-1:-1:-1;47633:23:0;;-1:-1:-1;46566:1098:0;;-1:-1:-1;;;;;;;;;;46566:1098:0:o;64064:783::-;64315:8;44639:15;44627:8;:27;;44619:58;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;64355:4:::1;64344:15;;:4;;64349:1;64344:7;;;;;;;;;;;;;;;:15;;;64336:51;;;::::0;;::::1;::::0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;64398:16;64417:9;64398:28;;64443:4;64437:19;;;64464:8;64437:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;64486:41;64504:9;;64514:1;64504:12;;;;;;;;;;;;;;;64518:8;64486:4;:17;;;;:41;;;;;:::i;:::-;64538:21;64569:4:::0;;64574:15;;;64569:21;;::::1;;;;;;;;;;;;;64562:39;;;64602:2;64562:43;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;64562:43:0;64616:55:::1;::::0;;64562:43:::1;64616:55:::0;;::::1;::::0;;;;;;;;;;;64562:43;;-1:-1:-1;64616:55:0::1;::::0;;;64651:9;;;;;;64616:55;::::1;::::0;64651:9;;64616:55;64651:9;64616:55;::::1;;::::0;::::1;::::0;;;;-1:-1:-1;;64616:55:0::1;::::0;;::::1;::::0;;::::1;::::0;;;;;;;;;;;;;-1:-1:-1;64662:4:0;;-1:-1:-1;64662:4:0;;;;64616:55;::::1;::::0;64662:4;;64616:55;64662:4;64616:55;::::1;;::::0;::::1;::::0;;;;-1:-1:-1;64668:2:0;;-1:-1:-1;64616:34:0::1;::::0;-1:-1:-1;;64616:55:0:i:1;:::-;64762:12:::0;64704:54:::1;64744:13:::0;64704:4;;64709:15;;;64704:21;;::::1;;;;;;;;;;;;;:31;;;64736:2;64704:35;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;64704:35:0;;:39:::1;:54::i;:::-;:70;;64682:157;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;44688:1;;64064:783:::0;;;;;;;;:::o;64855:763::-;65125:8;44639:15;44627:8;:27;;44619:58;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;65154:29:::1;65179:4;65154:29;:4:::0;;65159:15;;;65154:21;;::::1;;;;;;;;;;;;;:29;;;65146:65;;;::::0;;::::1;::::0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;65222:60;65247:10;65259:9;;65269:1;65259:12;;;;;;;;;;;;;;;65273:8;65222:4;;65227:1;65222:7;;;;;;;;;;;;;;;:24;;;;:60;;;;;;:::i;:::-;65293:66;65328:9;;65293:66;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;;;;-1:-1:-1;;65293:66:0::1;::::0;;::::1;::::0;;::::1;::::0;;;;;;;;;;;;;-1:-1:-1;65339:4:0;;-1:-1:-1;65339:4:0;;;;65293:66;::::1;::::0;65339:4;;65293:66;65339:4;65293:66;::::1;;::::0;::::1;::::0;;;;-1:-1:-1;65353:4:0::1;::::0;-1:-1:-1;65293:34:0::1;::::0;-1:-1:-1;;65293:66:0:i:1;:::-;65370:17;65396:4;65390:21;;;65420:4;65390:36;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;65390:36:0;;-1:-1:-1;65445:25:0;;::::1;;65437:75;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;65529:4;65523:20;;;65544:9;65523:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;65565:45;65596:2;65600:9;65565:30;:45::i;44529:36::-:0;;;:::o;52937:793::-;53303:15;53320;53348:13;53364:10;:36;;53391:9;53364:36;;;53385:2;53364:36;53411:78;;;;;;53437:10;53411:78;;;;53457:4;53411:78;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;53348:52;;-1:-1:-1;53411:25:0;;;;;;:78;;;;;-1:-1:-1;;53411:78:0;;;;;;;;-1:-1:-1;53411:25:0;:78;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;53521:201;53551:6;53572;53593:4;53612:9;53636:10;53661;53686:2;53703:8;53521:15;:201::i;:::-;53500:222;;;;;;;;52937:793;;;;;;;;;;;;;;;;:::o;59880:894::-;60140:24;60121:8;44639:15;44627:8;:27;;44619:58;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;60185:29:::1;60210:4;60185:29;:4:::0;;60190:15;;;60185:21;;::::1;;;;;;;;;;;;;:29;;;60177:65;;;::::0;;::::1;::::0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;60253:36;60273:9;;60253:36;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;;;;-1:-1:-1;;60253:36:0::1;::::0;;::::1;::::0;;::::1;::::0;;;;;;;;;;;;;-1:-1:-1;60284:4:0;;-1:-1:-1;60284:4:0;;;;60253:36;::::1;::::0;60284:4;;60253:36;60284:4;60253:36;::::1;;::::0;::::1;::::0;;;;-1:-1:-1;60253:19:0::1;::::0;-1:-1:-1;;;60253:36:0:i:1;:::-;60310:51;60335:8;60345:9;;60310:51;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;;;;-1:-1:-1;;60310:51:0::1;::::0;;::::1;::::0;;::::1;::::0;;;;;;;;;;;;;-1:-1:-1;60356:4:0;;-1:-1:-1;60356:4:0;;;;60310:51;::::1;::::0;60356:4;;60310:51;60356:4;60310:51;::::1;;::::0;::::1;::::0;;;;-1:-1:-1;60310:24:0::1;::::0;-1:-1:-1;;;60310:51:0:i:1;:::-;60300:61;;60425:12;60394:7;60419:1;60402:7;:14;:18;60394:27;;;;;;;;;;;;;;:43;;60372:130;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;60513:62;60538:10;60550:9;;60560:1;60550:12;;;;;;;;;;;;;;;60564:7;60572:1;60564:10;;;;;;;;;;;;;;60513:4;;60518:1;60513:7;;;;;;:62;60586:46;60592:7;60601:9;;60586:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;;;;-1:-1:-1;;60586:46:0::1;::::0;;::::1;::::0;;::::1;::::0;;;;;;;;;;;;;-1:-1:-1;60612:4:0;;-1:-1:-1;60612:4:0;;;;60586:46;::::1;::::0;60612:4;;60586:46;60612:4;60586:46;::::1;;::::0;::::1;::::0;;;;-1:-1:-1;60626:4:0::1;::::0;-1:-1:-1;60586:5:0::1;::::0;-1:-1:-1;;60586:46:0:i:1;:::-;60649:4;60643:20;;;60664:7;60689:1;60672:7;:14;:18;60664:27;;;;;;;;;;;;;;60643:49;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;60703:63;60734:2;60738:7;60763:1;60746:7;:14;:18;60738:27;;;;;;;;;;;;;;60703:30;:63::i;:::-;59880:894:::0;;;;;;;;;;;:::o;50119:1202::-;50439:19;50473:17;50505;50550:12;44302:5;50577:6;:13;;;50573:105;;;50626:7;50614:39;;;50654:5;50661:4;50614:52;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;50614:52:0;;-1:-1:-1;50573:105:0;50692:18;;;50688:110;;50746:7;50734:31;;;50766:5;50773:4;50779:6;50734:52;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;50734:52:0;;-1:-1:-1;50688:110:0;50956:37;;:::i;:::-;-1:-1:-1;50956:80:0;;;;;;;;;-1:-1:-1;50956:80:0;;44416:10;50956:80;;;;51085:228;51115:5;51135:4;51154:18;51187:14;51216:12;50956:80;51277:2;51294:8;51085:15;:228::i;:::-;51047:266;;;;-1:-1:-1;51047:266:0;;-1:-1:-1;50119:1202:0;-1:-1:-1;;;;;;;;;;50119:1202:0:o;59037:835::-;59297:24;59278:8;44639:15;44627:8;:27;;44619:58;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;59342:29:::1;59367:4;59342:29;:4:::0;;59347:15;;;59342:21;;::::1;;;;;;;;;;;;;:29;;;59334:65;;;::::0;;::::1;::::0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;59410:36;59430:9;;59410:36;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;;;;-1:-1:-1;;59410:36:0::1;::::0;;::::1;::::0;;::::1;::::0;;;;;;;;;;;;;-1:-1:-1;59441:4:0;;-1:-1:-1;59441:4:0;;;;59410:36;::::1;::::0;59441:4;;59410:36;59441:4;59410:36;::::1;;::::0;::::1;::::0;;;;-1:-1:-1;59410:19:0::1;::::0;-1:-1:-1;;;59410:36:0:i:1;:::-;59467:51;59491:9;59502;;59467:51;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;;;;-1:-1:-1;;59467:51:0::1;::::0;;::::1;::::0;;::::1;::::0;;;;;;;;;;;;;-1:-1:-1;59513:4:0;;-1:-1:-1;59513:4:0;;;;59467:51;::::1;::::0;59513:4;;59467:51;59513:4;59467:51;::::1;;::::0;::::1;::::0;;;;-1:-1:-1;59467:23:0::1;::::0;-1:-1:-1;;;59467:51:0:i:1;:::-;59457:61;;59551:11;59537:7;59545:1;59537:10;;;;;;;;;;;;;;:25;;59529:71;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;66339:311:::0;66500:24;66537:36;66557:9;;66537:36;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;66537:36:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;66568:4:0;;-1:-1:-1;66568:4:0;;;;66537:36;;;66568:4;;66537:36;66568:4;66537:36;;;;;;;;;-1:-1:-1;66537:19:0;;-1:-1:-1;;;66537:36:0:i;:::-;66591:51;66615:9;66626;;66591:51;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;66591:51:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;66637:4:0;;-1:-1:-1;66637:4:0;;;;66591:51;;;66637:4;;66591:51;66637:4;66591:51;;;;;;;;;-1:-1:-1;66591:23:0;;-1:-1:-1;;;66591:51:0:i;:::-;66584:58;66339:311;-1:-1:-1;;;;;;66339:311:0:o;53738:768::-;54080:19;54101:17;54131:13;54147:10;:36;;54174:9;54147:36;;;54168:2;54147:36;54194:78;;;;;;54220:10;54194:78;;;;54240:4;54194:78;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;54131:52;;-1:-1:-1;54194:25:0;;;;;;:78;;;;;-1:-1:-1;;54194:78:0;;;;;;;;-1:-1:-1;54194:25:0;:78;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;54310:188;54343:5;54363:4;54382:9;54406:14;54435:12;54462:2;54479:8;54310:18;:188::i;:::-;54283:215;;;;-1:-1:-1;53738:768:0;-1:-1:-1;;;;;;;;;;;;;53738:768:0:o;66020:311::-;66181:24;66218:36;66238:9;;66218:36;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;66218:36:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;66249:4:0;;-1:-1:-1;66249:4:0;;;;66218:36;;;66249:4;;66218:36;66249:4;66218:36;;;;;;;;;-1:-1:-1;66218:19:0;;-1:-1:-1;;;66218:36:0:i;:::-;66272:51;66297:8;66307:9;;66272:51;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;66272:51:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;66318:4:0;;-1:-1:-1;66318:4:0;;;;66272:51;;;66318:4;;66272:51;66318:4;66272:51;;;;;;;;;-1:-1:-1;66272:24:0;;-1:-1:-1;;;66272:51:0:i;65790:222::-;65924:15;65959:45;65976:7;65985:8;65995;65959:16;:45::i;:::-;65952:52;;65790:222;;;;;;:::o;57661:611::-;57918:24;57899:8;44639:15;44627:8;:27;;44619:58;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;57955:36:::1;57975:9;57986:4;57955:19;:36::i;:::-;58012:51;58036:9;58047;58058:4;58012:23;:51::i;:::-;58002:61;;58096:11;58082:7;58090:1;58082:10;;;;;;;;;;;;;;:25;;58074:71;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;58156:62;58181:10;58193:9;58203:1;58193:12;;;;;;;;;;;;;;58207:7;58215:1;58207:10;;;;;;;;;;;;;;58156:4;58161:1;58156:7;;;;;;;;;;;;;;:24;;;;:62;;;;;;:::i;:::-;58229:35;58235:7;58244:9;58255:4;58261:2;58229:5;:35::i;:::-;57661:611:::0;;;;;;;;;:::o;58280:749::-;58521:24;58502:8;44639:15;44627:8;:27;;44619:58;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;58577:4:::1;58566:15;;:4;;58571:1;58566:7;;;;;;;;;;;;;;;:15;;;58558:51;;;::::0;;::::1;::::0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;58620:36;58640:9;;58620:36;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;;;;-1:-1:-1;;58620:36:0::1;::::0;;::::1;::::0;;::::1;::::0;;;;;;;;;;;;;-1:-1:-1;58651:4:0;;-1:-1:-1;58651:4:0;;;;58620:36;::::1;::::0;58651:4;;58620:36;58651:4;58620:36;::::1;;::::0;::::1;::::0;;;;-1:-1:-1;58620:19:0::1;::::0;-1:-1:-1;;;58620:36:0:i:1;:::-;58677:52;58702:9;58713;;58677:52;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;;;;-1:-1:-1;;58677:52:0::1;::::0;;::::1;::::0;;::::1;::::0;;;;;;;;;;;;;-1:-1:-1;58724:4:0;;-1:-1:-1;58724:4:0;;;;58677:52;::::1;::::0;58724:4;;58677:52;58724:4;58677:52;::::1;;::::0;::::1;::::0;;;;-1:-1:-1;58677:24:0::1;::::0;-1:-1:-1;;;58677:52:0:i:1;:::-;58667:62;;58793:12;58762:7;58787:1;58770:7;:14;:18;58762:27;;;;;;;;;;;;;;:43;;58740:130;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;58887:4;58881:19;;;58908:7;58916:1;58908:10;;;;;;;;;;;;;;58881:40;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;58932:43;58950:9;;58960:1;58950:12;;;;;;;;;;;;;;;58964:7;58972:1;58964:10;;;;;;;;;;;;;;58932:4;:17;;;;:43;;;;;:::i;:::-;58986:35;58992:7;59001:9;;58986:35;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;;;;-1:-1:-1;;58986:35:0::1;::::0;;::::1;::::0;;::::1;::::0;;;;;;;;;;;;;-1:-1:-1;59012:4:0;;-1:-1:-1;59012:4:0;;;;58986:35;::::1;::::0;59012:4;;58986:35;59012:4;58986:35;::::1;;::::0;::::1;::::0;;;;-1:-1:-1;59018:2:0;;-1:-1:-1;58986:5:0::1;::::0;-1:-1:-1;;58986:35:0:i:1;:::-;58280:749:::0;;;;;;;;;;:::o;52221:708::-;52484:19;52505:17;52465:8;44639:15;44627:8;:27;;44619:58;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;52562:215:::1;52592:5;52612:4;52631;52650:9;52674:14;52703:12;52738:4;52758:8;52562:15;:215::i;:::-;52535:242:::0;;-1:-1:-1;52535:242:0;-1:-1:-1;52788:35:0::1;:18;::::0;::::1;52807:2:::0;52535:242;52788:18:::1;:35::i;:::-;52840:4;52834:20;;;52855:9;52834:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;52876:45;52907:2;52911:9;52876:30;:45::i;:::-;52221:708:::0;;;;;;;;;;;:::o;44481:41::-;;;:::o;56967:686::-;57232:24;57213:8;44639:15;44627:8;:27;;44619:58;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;57269:36:::1;57289:9;57300:4;57269:19;:36::i;:::-;57326:51;57351:8;57361:9;57372:4;57326:24;:51::i;:::-;57316:61;;57441:12;57410:7;57435:1;57418:7;:14;:18;57410:27;;;;;;;;;;;;;;:43;;57388:130;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;47672:1169:::0;48056:19;48090:17;48122;48014:8;44639:15;44627:8;:27;;44619:58;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;48167:36:::1;48185:5;48192:4;48198;48167:17;:36::i;:::-;48241:229;48269:5;48289:4;48308;48327:18;48360:9;48384:14;48413:12;48440:19;48241:13;:229::i;:::-;48214:256:::0;;-1:-1:-1;48214:256:0;-1:-1:-1;48481:53:0::1;:22;::::0;::::1;48504:10;48516:4:::0;48214:256;48481:22:::1;:53::i;:::-;48545:4;:12;;;48565:9;48545:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;48588:34:0::1;::::0;-1:-1:-1;;48588:17:0::1;:4;:17;::::0;-1:-1:-1;48606:4:0;;-1:-1:-1;48612:9:0;48588:17:::1;:34::i;:::-;48654:4;48645:19;;;48665:2;48645:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;48645:23:0;;-1:-1:-1;48719:9:0::1;:21:::0;-1:-1:-1;48715:119:0::1;;;48757:65;48788:10;48812:9;48800;:21;48757:30;:65::i;:::-;47672:1169:::0;;;;;;;;;;;;;:::o;51364:849::-;51643:15;51660;51624:8;44639:15;44627:8;:27;;44619:58;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;51688:39:::1;51706:6;51714;51722:4;51688:17;:39::i;:::-;51738:58;:29;::::0;::::1;51768:10;51780:4:::0;51786:9;51738:29:::1;:58::i;:::-;51834:15;51851::::0;51879:4:::1;51870:19;;;51890:2;51870:23;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;51870:23:0;;::::1;::::0;;::::1;::::0;;;-1:-1:-1;51870:23:0;-1:-1:-1;51905:13:0::1;51924:37;51946:6:::0;51954;51924:21:::1;:37::i;:::-;51904:57;;;52003:6;51993:16;;:6;:16;;;:58;;52034:7;52043;51993:58;;;52013:7;52022;51993:58;51972:79:::0;;-1:-1:-1;51972:79:0;-1:-1:-1;52070:21:0;;::::1;;52062:66;;;::::0;;::::1;::::0;;::::1;;::::0;::::1;::::0;;;;;;;::::1;::::0;;;;;;;;;;;;;::::1;;52158:10;52147:7;:21;;52139:66;;;::::0;;::::1;::::0;;::::1;;::::0;::::1;::::0;;;;;;;::::1;::::0;;;;;;;;;;;;;::::1;;44688:1;;;51364:849:::0;;;;;;;;;;;;:::o;63350:706::-;63617:8;44639:15;44627:8;:27;;44619:58;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;63638:60:::1;63663:10;63675:9;63685:1;63675:12;;;;;;;;;;;;;;63689:8;63638:4;63643:1;63638:7;;;;;;;:60;63709:21;63733:4;63752:1;63738:4;:11;:15;63733:21;;;;;;;;;;;;;;:31;;;63765:2;63733:35;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;63733:35:0;;-1:-1:-1;63779:55:0::1;63814:9:::0;63825:4;63831:2;63779:34:::1;:55::i;:::-;63845:20;63868:4;63887:1;63873:4;:11;:15;63868:21;;;;;;;;;;;;;;:31;;;63900:2;63868:35;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;63868:35:0;;-1:-1:-1;63952:31:0::1;:13:::0;63970:12;63952:17:::1;:31::i;:::-;63936:12;:47;;63914:134;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;44688:1;;63350:706:::0;;;;;;;:::o;54587:732::-;54879:17;54860:8;44639:15;44627:8;:27;;44619:58;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;54925:215:::1;54955:5;54975:4;54994;55013:9;55037:14;55066:12;55101:4;55121:8;54925:15;:215::i;:::-;55174:38;::::0;;;;;55206:4:::1;55174:38;::::0;::::1;::::0;;;54909:231;;-1:-1:-1;55151:62:0::1;::::0;-1:-1:-1;55170:2:0;;55174:23:::1;::::0;::::1;::::0;::::1;::::0;:38;;;;;::::1;::::0;;;;;;;;:23;:38;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;55174:38:0;55151:18:::1;::::0;::::1;::::0;:62;:18:::1;:62::i;:::-;55230:4;55224:20;;;55245:9;55224:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;55266:45;55297:2;55301:9;55266:30;:45::i;60782:851::-:0;61020:24;61001:8;44639:15;44627:8;:27;;44619:58;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;61076:4:::1;61065:15;;:4;;61070:1;61065:7;;;;;;;;;;;;;;;:15;;;61057:51;;;::::0;;::::1;::::0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;61119:36;61139:9;;61119:36;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;;;;-1:-1:-1;;61119:36:0::1;::::0;;::::1;::::0;;::::1;::::0;;;;;;;;;;;;;-1:-1:-1;61150:4:0;;-1:-1:-1;61150:4:0;;;;61119:36;::::1;::::0;61150:4;;61119:36;61150:4;61119:36;::::1;;::::0;::::1;::::0;;;;-1:-1:-1;61119:19:0::1;::::0;-1:-1:-1;;;61119:36:0:i:1;:::-;61176:51;61200:9;61211;;61176:51;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;;;;-1:-1:-1;;61176:51:0::1;::::0;;::::1;::::0;;::::1;::::0;;;;;;;;;;;;;-1:-1:-1;61222:4:0;;-1:-1:-1;61222:4:0;;;;61176:51;::::1;::::0;61222:4;;61176:51;61222:4;61176:51;::::1;;::::0;::::1;::::0;;;;-1:-1:-1;61176:23:0::1;::::0;-1:-1:-1;;;61176:51:0:i:1;:::-;61166:61;;61260:9;61246:7;61254:1;61246:10;;;;;;;;;;;;;;:23;;61238:69;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;61324:4;61318:19;;;61345:7;61353:1;61345:10;;;;;;;;;;;;;;61318:40;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;61369:43;61387:9;;61397:1;61387:12;;;;;;61369:43;61423:35;61429:7;61438:9;;61423:35;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;;;;-1:-1:-1;;61423:35:0::1;::::0;;::::1;::::0;;::::1;::::0;;;;;;;;;;;;;-1:-1:-1;61449:4:0;;-1:-1:-1;61449:4:0;;;;61423:35;::::1;::::0;61449:4;;61423:35;61449:4;61423:35;::::1;;::::0;::::1;::::0;;;;-1:-1:-1;61455:2:0;;-1:-1:-1;61423:5:0::1;::::0;-1:-1:-1;;61423:35:0:i:1;:::-;61521:7;61529:1;61521:10;;;;;;;;;;;;;;61509:9;:22;61505:121;;;61548:66;61579:10;61603:7;61611:1;61603:10;;;;;;;;;;;;;;61591:9;:22;61548:30;:66::i;67055:223::-:0;67205:7;67193:27;;;67221:6;67229;67237:4;67193:49;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;67193:49:0;67185:85;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;67055:223;;;:::o;44999:1559::-;45303:15;45320;45349:16;45367;45385:17;45404;45427:59;45465:4;45471:6;45479;45427:37;:59::i;:::-;45348:138;;;;;;;;;45501:8;45513:1;45501:13;:30;;;;-1:-1:-1;45518:13:0;;45501:30;45497:1054;;;45570:14;;-1:-1:-1;45586:14:0;;-1:-1:-1;45497:1054:0;;;45634:22;45659:52;45676:14;45692:8;45702;45659:16;:52::i;:::-;45634:77;;45748:14;45730;:32;45726:559;;45809:10;45791:14;:28;;45783:73;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;45897:14;;-1:-1:-1;45913:14:0;-1:-1:-1;45913:14:0;45726:559;;;45969:22;45994:52;46011:14;46027:8;46037;45994:16;:52::i;:::-;45969:77;;46090:14;46072;:32;;46065:40;;;;46150:10;46132:14;:28;;46124:73;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;46238:14;-1:-1:-1;46254:14:0;;-1:-1:-1;45726:559:0;46299:19;46342:9;44466:6;46322:9;:16;46321:30;;;;;46407:22;;46321:30;;;;-1:-1:-1;46392:37:0;;;;;:78;;-1:-1:-1;46448:22:0;;;;46433:37;;;46392:78;46366:173;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;45497:1054;;44999:1559;;;;;;;;;;;;;;;:::o;20978:205::-;21106:68;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;21129:27;21106:68;;;21079:96;;21099:5;;21079:19;:96::i;:::-;20978:205;;;;:::o;20793:177::-;20903:58;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;20926:23;20903:58;;;20876:86;;20896:5;;20876:19;:86::i;61780:1562::-;61941:36;61961:9;61972:4;61941:19;:36::i;:::-;61993:9;61988:1347;62022:1;62008:4;:11;:15;62004:1;:19;61988:1347;;;62046:12;62060:13;62078:4;62083:1;62078:7;;;;;;;;;;;;;;62087:4;62092:1;62096;62092:5;62087:11;;;;;;;;;;;;;;62045:54;;;;62115:13;62134:36;62156:5;62163:6;62134:21;:36::i;:::-;62114:56;;;62185:13;62210:9;62220:1;62210:12;;;;;;;;;;;;;;62185:38;;62238:20;62372:17;62412:18;62453;62494:19;62536:22;62580:52;62604:9;62614:1;62604:12;;;;;;;;;;;;;;62618:5;62625:6;62580:23;:52::i;:::-;62349:283;;;;;;;;;;62651:19;62673:53;62716:9;62680:5;62673:23;;;62705:4;62673:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:53;62651:75;;62760:245;62806:11;62840:9;62872:10;62905;62938:11;62972:14;62760:23;:245::i;:::-;62745:260;;61988:1347;;;;;;63036:18;63056;63087:6;63078:15;;:5;:15;;;:107;;63160:12;63182:1;63078:107;;;63122:1;63126:12;63078:107;63035:150;;;;63200:10;63231:1;63217:4;:11;:15;63213:1;:19;:44;;63254:3;63213:44;;;63235:9;63245:1;63249;63245:5;63235:16;;;;;;;;;;;;;;63213:44;63310:12;;;63320:1;63310:12;;;;;;;;;;63272:51;;;;;;;;;;;;;;;:9;:51;;;;;;;;;;;;;;;;;;;;;;63200:57;;-1:-1:-1;63272:9:0;;;;;;63282:10;;63294;;63200:57;;63310:12;;63272:51;;;;;;;;63310:12;;63272:51;;;;63310:12;;63272:51;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;62025:3:0;;;;;-1:-1:-1;61988:1347:0;;-1:-1:-1;;;;;;;;;61988:1347:0;5090:158;5148:7;5181:1;5176;:6;;5168:49;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;5235:5:0;;;5090:158;;;;;:::o;1633:195::-;1741:12;;;1703;1741;;;;;;;;;1720:7;;;;1734:5;;1720:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1702:52;;;1773:7;1765:55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;66658:389;66785:1;66770:4;:11;:16;;66762:52;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;66867:1;66853:4;:11;:15;66833:9;:16;:35;66825:77;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;66918:9;66913:127;66937:9;:16;66933:1;:20;66913:127;;;66975:53;66993:4;66998:1;66993:7;;;;;;;;;;;;;;67002:4;67007:1;67011;67007:5;67002:11;;;;;;;;;;;;;;67015:9;67025:1;67015:12;;;;;;;;;;;;;;66975:17;:53::i;:::-;66955:3;;66913:127;;42258:832;42406:24;42467:4;:11;42453:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;42453:26:0;;42443:36;;42503:8;42490:7;42498:1;42490:10;;;;;;;;;;;;;:21;;;;;42527:9;42522:561;42556:1;42542:4;:11;:15;42538:1;:19;42522:561;;;42598:17;42634:18;42671;42708:19;42746:22;42786:48;42799:9;42809:1;42799:12;;;;;;;;;;;;;;42813:4;42818:1;42813:7;;;;;;;;;;;;;;42822:4;42827:1;42831;42827:5;42822:11;;;;;;;;;;;;;;42786:12;:48::i;:::-;42579:255;;;;;;;;;;42866:205;42897:7;42905:1;42897:10;;;;;;;;;;;;;;42926:9;42954:10;42983;43012:11;43042:14;42866:12;:205::i;:::-;42849:7;42857:1;42861;42857:5;42849:14;;;;;;;;;;;;;;;;;:222;-1:-1:-1;;42559:3:0;;;;;-1:-1:-1;42522:561:0;;-1:-1:-1;;42522:561:0;;;42258:832;;;;;:::o;56228:731::-;56399:9;56394:558;56428:1;56414:4;:11;:15;56410:1;:19;56394:558;;;56452:12;56466:13;56484:4;56489:1;56484:7;;;;;;;;;;;;;;56493:4;56498:1;56502;56498:5;56493:11;;;;;;;;;;;;;;56451:54;;;;56521:13;56540:36;56562:5;56569:6;56540:21;:36::i;:::-;56520:56;;;56591:17;56611:7;56619:1;56623;56619:5;56611:14;;;;;;;;;;;;;;56591:34;;56641:18;56661;56692:6;56683:15;;:5;:15;;;:101;;56762:9;56781:1;56683:101;;;56727:1;56731:9;56683:101;56640:144;;;;56799:10;56830:1;56816:4;:11;:15;56812:1;:19;:44;;56853:3;56812:44;;;56834:9;56844:1;56848;56844:5;56834:16;;;;;;;;;;;;;;56812:44;56799:57;;56880:9;56890:1;56880:12;;;;;;;;;;;;;;56871:27;;;56899:10;56911;56923:2;56937:1;56927:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;56927:12:0;;56871:69;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;56431:3:0;;;;;-1:-1:-1;56394:558:0;;-1:-1:-1;;;;;;;;56394:558:0;;;56228:731;;;;:::o;43171:857::-;43319:24;43380:4;:11;43366:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;43366:26:0;;43356:36;;43433:9;43403:7;43428:1;43411:7;:14;:18;43403:27;;;;;;;;;;;;;;;;;:39;43470:11;;:15;;43453:568;43487:5;;43453:568;;43533:17;43569:18;43606;43643:19;43681:22;43721:52;43734:9;43748:1;43744;:5;43734:16;;;;;;;;;;;;;;43752:4;43761:1;43757;:5;43752:11;;;;;;;;;;;;;;43765:4;43770:1;43765:7;;;;;;;43721:52;43514:259;;;;;;;;;;43805:204;43835:7;43843:1;43835:10;;;;;;;;;;;;;;43864:9;43892:10;43921;43950:11;43980:14;43805:11;:204::i;:::-;43788:7;43800:1;43796;:5;43788:14;;;;;;;;;;;;;;;;;:221;-1:-1:-1;;43494:3:0;;;;;-1:-1:-1;43453:568:0;;-1:-1:-1;;43453:568:0;39963:355;40088:15;40134:1;40124:7;:11;40116:55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;40201:1;40190:8;:12;:28;;;;;40217:1;40206:8;:12;40190:28;40182:75;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;40302:8;40278:21;:7;40290:8;40278:11;:21::i;:::-;:32;;;;;;;39963:355;-1:-1:-1;;;;39963:355:0:o;38118:374::-;38218:13;38233;38282:6;38272:16;;:6;:16;;;;38264:60;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;38363:6;38354:15;;:6;:15;;;:53;;38392:6;38400;38354:53;;;38373:6;38381;38354:53;38335:72;;-1:-1:-1;38335:72:0;-1:-1:-1;38426:29:0;;;38418:66;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;38118:374;;;;;:::o;4628:179::-;4686:7;4718:5;;;4742:6;;;;4734:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;38579:793;38743:16;38774;38805:17;38837;38869:22;38920:13;38939:26;38950:6;38958;38939:10;:26::i;:::-;38919:46;;;38976:16;39003;39030:17;39058;39156:4;39147:27;;;:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;39147:29:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;39086:90:0;;;;;-1:-1:-1;39086:90:0;;;;-1:-1:-1;39086:90:0;;;-1:-1:-1;39086:90:0;;-1:-1:-1;39232:16:0;;;;;;;;:132;;39323:8;39333;39343:9;39354;39232:132;;;39265:8;39275;39285:9;39296;39232:132;39187:177;;;;;;;;;;;;;;;;38579:793;;;;;;;;;;;;;;:::o;23098:761::-;23522:23;23548:69;23576:4;23548:69;;;;;;;;;;;;;;;;;23556:5;23548:27;;;;:69;;;;;:::i;:::-;23632:17;;23522:95;;-1:-1:-1;23632:21:0;23628:224;;23774:10;23763:30;;;;;;;;;;;;;;;-1:-1:-1;23763:30:0;23755:85;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;40440:768;40668:17;40717:1;40706:8;:12;40698:62;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;40791:1;40779:9;:13;:31;;;;;40809:1;40796:10;:14;40779:31;40771:78;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;40860:23;40886:58;38004:4;40886:43;40899:29;38004:4;40913:14;40899:13;:29::i;:::-;40886:8;;:12;:43::i;:::-;:47;;:58::i;:::-;40860:84;-1:-1:-1;40955:17:0;40975:32;40860:84;40995:11;40975:19;:32::i;:::-;40955:52;-1:-1:-1;41018:19:0;41040:31;:10;41055:15;41040:14;:31::i;:::-;41018:53;-1:-1:-1;41094:26:0;:9;41018:53;41094:13;:26::i;:::-;41082:38;;41152:9;41139:10;:22;41131:69;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;40440:768;;;;;;;;;;;:::o;41329:847::-;41557:16;41606:1;41594:9;:13;41586:64;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;41681:1;41669:9;:13;:39;;;;;41699:9;41686:10;:22;41669:39;41661:86;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;41758:17;41778:25;:10;41793:9;41778:14;:25::i;:::-;41758:45;-1:-1:-1;41814:19:0;41836:26;:11;41852:9;41836:15;:26::i;:::-;41814:48;-1:-1:-1;41884:33:0;41915:1;41884:26;:9;41814:48;41884:13;:26::i;:::-;:30;;:33::i;:::-;41873:44;-1:-1:-1;42022:23:0;41873:44;38004:4;42022:12;:23::i;:::-;42010:35;-1:-1:-1;42070:29:0;38004:4;42084:14;42070:13;:29::i;:::-;42056:43;-1:-1:-1;42121:47:0;42056:43;42121:30;:9;42135:15;;;42121:13;:30::i;:47::-;42110:58;41329:847;-1:-1:-1;;;;;;;;;41329:847:0:o;5507:220::-;5565:7;5589:6;5585:20;;-1:-1:-1;5604:1:0;5597:8;;5585:20;5628:5;;;5632:1;5628;:5;:1;5652:5;;;;;:10;5644:56;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;15790:195;15893:12;15925:52;15947:6;15955:4;15961:1;15964:12;15925:21;:52::i;6205:153::-;6263:7;6295:1;6291;:5;6283:44;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6349:1;6345;:5;;;;;;;6205:153;-1:-1:-1;;;6205:153:0:o;16842:530::-;16969:12;17027:5;17002:21;:30;;16994:81;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;17094:18;17105:6;17094:10;:18::i;:::-;17086:60;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;17220:12;17234:23;17261:6;:11;;17281:5;17289:4;17261:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;17219:75;;;;17312:52;17330:7;17339:10;17351:12;17312:17;:52::i;:::-;17305:59;16842:530;-1:-1:-1;;;;;;;16842:530:0:o;12872:422::-;13239:20;13278:8;;;12872:422::o;19382:742::-;19497:12;19526:7;19522:595;;;-1:-1:-1;19557:10:0;19550:17;;19522:595;19671:17;;:21;19667:439;;19934:10;19928:17;19995:15;19982:10;19978:2;19974:19;19967:44;19882:148;20077:12;20070:20;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;:::o

Swarm Source

ipfs://f37c2f506ca49cb898a2a392882b1ebba5f9cbce2ee4a30ae1d8f78dac365d2a
Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.