Contract 0x546C79662E028B661dFB4767664d0273184E4dD1 2

Kyber 
 
 
Txn Hash Method
Block
From
To
Value [Txn Fee]
0x21564caf0cb9bcfbac2274b44d92ee1d52019d61005fa2a8d0c72c186de6172cAdd Liquidity ET...363896722022-12-03 21:39:524 mins ago0x22e75347735b9144f0f87b17f9f0d67d3e9b5cce IN  Kyber Swap: Router225 MATIC0.005362979462 30.675395887
0x5e723838bf1b1b16fe7c6c4f8c4a70ce9d5684e02a8ceae56d6a67eb31f9db94Add Liquidity363818462022-12-03 16:50:134 hrs 54 mins ago0xd7ea8366eb70462f2df5ab00f4deac64dd54b59d IN  Kyber Swap: Router0 MATIC0.027629025637 161.629016077
0x4c4b9023a6fb6d32abca240038205543e47319323d5d362730c74da21301f4ecRemove Liquidity...363806732022-12-03 16:05:255 hrs 39 mins ago0x27196fb58d2170644938fbe4d11239bc41cfa374 IN  Kyber Swap: Router0 MATIC0.010119640274 54.252660588
0x37d956b2c9bf3f3e622169a5517b7124957ea469e2a94359d8026f9caf1e3645Remove Liquidity...363790222022-12-03 15:06:316 hrs 38 mins ago0x952d0434ac9f40fe4747546eba5b2609c223885c IN  Kyber Swap: Router0 MATIC0.010805541231 52.724874507
0xba0790db090974f83a13f8235f908bd0935c0ef8259ad47fcb3282524982d30aRemove Liquidity...363770702022-12-03 13:59:167 hrs 45 mins ago0xe014c63c33777b1eedece48f7e5de886e541bc7c IN  Kyber Swap: Router0 MATIC0.009910415006 46.499390072
0x3f823a196a27c4cff616fc3dfbcc081b78119edc58d095d4f3aaf678de1663deAdd Liquidity ET...363710752022-12-03 10:31:4411 hrs 12 mins ago0xf5f046e55506fe63edd22ee49a83a8810a9ba1c2 IN  Kyber Swap: Router36.852978989001022 MATIC0.009269043173 56.905792917
0x99dbb9c2cefeaf7e918de3108d8dd873aec9582c27a7c2e242c28606181072dbRemove Liquidity...363604852022-12-03 4:02:5817 hrs 41 mins ago0xc87baef97a41852e58d540b2c4089bef159c5cee IN  Kyber Swap: Router0 MATIC0.005756094602 30.585799847
0xaf59433c5455c3f3569da99ab97517cb401ca0f040ef7d64659e32ee73651497Remove Liquidity...363589182022-12-03 3:06:5718 hrs 37 mins ago0xccf96f702936c9663ad595f8d00fd7b86783f17d IN  Kyber Swap: Router0 MATIC0.005663220319 30.00000169
0x51d088548ec74b62f8881b6e120e0a2763022916ff279a9dfd770a13f33d8e57Remove Liquidity...363490272022-12-02 21:16:411 day 27 mins ago0x841119517d812e4d173acd6cd63caf8d72283f6b IN  Kyber Swap: Router0 MATIC0.00595573823 34.116423863
0x258b68fa9a89591a309f4f99d492cdd4dc0d1a2dfa61ab5780197955279c77beRemove Liquidity...363405832022-12-02 16:08:091 day 5 hrs ago0x874fcedfbd923bfe104ad50180cefc34faf475d9 IN  Kyber Swap: Router0 MATIC0.01542037473
0xbd5879e6b9c9e7e803c86d45aba6a9b92ff84fad1f77f1ad3897b59fde6d6766Remove Liquidity...363370082022-12-02 13:58:021 day 7 hrs ago0xbe2f0354d970265bfc36d383af77f72736b81b54 IN  Kyber Swap: Router0 MATIC0.026497813999 145.048849912
0x41b9d4f3b64523fbdc6b613d0c6961e7b799f2c6a0d70a9687063e7a70a6c067Remove Liquidity...363364122022-12-02 13:35:261 day 8 hrs ago0x08b7ab9bbc3a07cf7f75b4acec5b536b7e040cfc IN  Kyber Swap: Router0 MATIC0.091727935812 474.627506625
0xe1ee56d973d85198f73f74d5f48c9b5a0c4c33f86dcade72e9345d44799047aeRemove Liquidity...363345852022-12-02 12:30:141 day 9 hrs ago0x28c1e820706d946a7b43f2c9b79427fb0522eb64 IN  Kyber Swap: Router0 MATIC0.01069847636 54.034892121
0x2d122ead7bbdc27d2efeaad475ad0a86c95abc790c7e40a0dae679d6b2bb6558Remove Liquidity...363331702022-12-02 11:39:211 day 10 hrs ago0x43d907a333927c97693d7e66f862595855feee97 IN  Kyber Swap: Router0 MATIC0.031662045343 168.190582485
0xd2382251d13070f12f28041ece19389d56bb7041ccfde41bc8a577ef4e867b5cAdd Liquidity363318232022-12-02 10:50:101 day 10 hrs ago0xd7ea8366eb70462f2df5ab00f4deac64dd54b59d IN  Kyber Swap: Router0 MATIC0.005955081337 33.777921496
0x90f9a820a2ee4851260f48ed223b699ef1a679bf369daf944d06308532add0f2Remove Liquidity...363295672022-12-02 9:25:071 day 12 hrs ago0x90eda907896c684c1581e2ccb38292f3796455b2 IN  Kyber Swap: Router0 MATIC0.011764289577 59.418004652
0x1ee88906962d070fddcef5e5eb80afcbba68fd408a63ff963fe3dca4302be26aAdd Liquidity ET...363165842022-12-02 1:47:131 day 19 hrs ago0xdc7ca55b90433c4e2655ec213a29829dd9f06977 IN  Kyber Swap: Router10.55698580609526 MATIC0.006208636999 36.001907765
0x43ebd47b0b93e7bdd27fb8c58e3db018d5b6032cdc3e7ad25006be0afe163d9cRemove Liquidity...363144332022-12-02 0:33:041 day 21 hrs ago0x9561a9bd4c3fdb0e5d0a4bb032803c0fef4134a4 IN  Kyber Swap: Router0 MATIC0.006467798694 30.069917496
0x3a4778b4e059eb6c42f127ab5c8efc7f01ea4ef854271bc9b38dc6e9769ab694Add Liquidity363060442022-12-01 19:43:562 days 2 hrs ago0x6245df091287ac770ef327f58a526129a56a3f6c IN  Kyber Swap: Router0 MATIC0.006778172794 39.459600026
0xfa077f3820a64f7273030adeede40769a30824c9a3f54e39fee500b40cfb0494Add Liquidity362996962022-12-01 15:58:222 days 5 hrs ago0xe2ad14f95a07652c8113719334c5e244343cd7bd IN  Kyber Swap: Router0 MATIC0.006651723498 39.343480132
0x226a8160da2e5b590ddd6bdfeba76661d62671ba9bfb5ca420088a19e2aaab80Remove Liquidity...362936222022-12-01 12:17:472 days 9 hrs ago0xbaecfeef55dbd8951e205d167df92af834ef912a IN  Kyber Swap: Router0 MATIC0.005647757584 30.004237241
0xc4d8e7f4a95a1bb3a069ee26eac628d14f7e568ba233f77edbe320a7494149f7Remove Liquidity...362900862022-12-01 10:13:082 days 11 hrs ago0xb86e54ae30b95b893ac002da8cf19a5d35108249 IN  Kyber Swap: Router0 MATIC0.006453633732 30.004062135
0xdc0f46a0c263e9f13db32849799e247e7a88ccee3e859b7f6833054e3b8cb7a9Remove Liquidity...362716252022-11-30 23:17:332 days 22 hrs ago0x87058292f212cc4eb6560debae7283d3cf0a5b3f IN  Kyber Swap: Router0 MATIC0.007874866285 36.611618683
0xd906fc7f7a6ad85459219e19bfb9562901c818ffe6262c90c49ee25f0ac2c39bAdd Liquidity362693432022-11-30 21:59:052 days 23 hrs ago0xaaaccbdacb10ca38ac80d13858023fee518a9379 IN  Kyber Swap: Router0 MATIC0.005692595756 30.004457802
0x994282c31987eb03822b8768e472fa1060f3b11ad99cdadd89d506ab12289bc4Remove Liquidity...362669902022-11-30 20:36:513 days 1 hr ago0xc4f20b2cbdd108fd8be8db04ec854098322a6843 IN  Kyber Swap: Router0 MATIC0.006302876352 32.710099448
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0x21564caf0cb9bcfbac2274b44d92ee1d52019d61005fa2a8d0c72c186de6172c363896722022-12-03 21:39:524 mins ago Kyber Swap: Router0x22e75347735b9144f0f87b17f9f0d67d3e9b5cce1 wei
0x21564caf0cb9bcfbac2274b44d92ee1d52019d61005fa2a8d0c72c186de6172c363896722022-12-03 21:39:524 mins ago Kyber Swap: Router Polygon: WMATIC Token224.999999999999999999 MATIC
0x3f823a196a27c4cff616fc3dfbcc081b78119edc58d095d4f3aaf678de1663de363710752022-12-03 10:31:4411 hrs 12 mins ago Kyber Swap: Router Polygon: WMATIC Token36.852978989001022373 MATIC
0x1ee88906962d070fddcef5e5eb80afcbba68fd408a63ff963fe3dca4302be26a363165842022-12-02 1:47:131 day 19 hrs ago Kyber Swap: Router Polygon: WMATIC Token10.556985806095260428 MATIC
0x0db78e27cb74d6a52f4dbbea635a443c82cc897e020c8e5a86429c889a0c8c80361042782022-11-26 20:27:417 days 1 hr ago Kyber Swap: Router0xf7da04c77c5179750121ff0f4896ecaca7c704ce1.199323820838252825 MATIC
0x0db78e27cb74d6a52f4dbbea635a443c82cc897e020c8e5a86429c889a0c8c80361042782022-11-26 20:27:417 days 1 hr ago Polygon: WMATIC Token Kyber Swap: Router1.199323820838252825 MATIC
0x9138ea269cf73082c73bd581b5d551ad1d17a28ad9846e6a284054290e2eaac6360904342022-11-26 12:24:587 days 9 hrs ago Kyber Swap: Router Polygon: WMATIC Token8.924094205530241176 MATIC
0x48b025b4ce62a507a4ab4ac2c56b7cda6aab61722df17ea2ade2ab490b711231360671752022-11-25 22:57:447 days 22 hrs ago Kyber Swap: Router Polygon: WMATIC Token22.37725642327563978 MATIC
0xc4d1b4ed9ebabf7c2a8b204fca58bc7aacebaa348c561f433787b8e655ba442c360586232022-11-25 18:01:068 days 3 hrs ago Kyber Swap: Router0xce908991fa57430b9bf96d954f84208d240735231 wei
0xc4d1b4ed9ebabf7c2a8b204fca58bc7aacebaa348c561f433787b8e655ba442c360586232022-11-25 18:01:068 days 3 hrs ago Kyber Swap: Router Polygon: WMATIC Token27.999999999999999999 MATIC
0x03069c4560a263182ad0e1d0f1e534705ed4d9f3113576798dbee4d6cb815b18360251692022-11-24 22:39:448 days 23 hrs ago Kyber Swap: Router Polygon: WMATIC Token34.223375456576172733 MATIC
0x26c7dbb5c16c6bb68c2018187ed70016c23e298ea1bcc259cceb0905f781406c360175202022-11-24 18:13:169 days 3 hrs ago Kyber Swap: Router Polygon: WMATIC Token693.530259415498887757 MATIC
0x1bbc6168eea0777bd5673cc0f38e81121d8155974e67659e13c066688e4d4f57360060522022-11-24 11:30:209 days 10 hrs ago Kyber Swap: Router0xcc07d4f72a19cbe3df58fab5cfe8f3178165bd561 wei
0x1bbc6168eea0777bd5673cc0f38e81121d8155974e67659e13c066688e4d4f57360060522022-11-24 11:30:209 days 10 hrs ago Kyber Swap: Router Polygon: WMATIC Token0.199999999999999999 MATIC
0xd536eb19c8e72c1c3215be9afc6018daac140e79e3220f01a72bd99ca72c6172358556362022-11-20 19:40:1413 days 2 hrs ago Kyber Swap: Router Polygon: WMATIC Token421.413831741800993654 MATIC
0x0b23a7b8a07a4b77b7b07d0742093a11f641f108b07e6905dcd15455a37542ca358554552022-11-20 19:34:0013 days 2 hrs ago Kyber Swap: Router Polygon: WMATIC Token278.763303217697977558 MATIC
0x8923bc603b16c52cf2bb74d036fec0ac663d4b3e80eb57c7d00099e7d2c5a0d5358347562022-11-20 7:39:0113 days 14 hrs ago Kyber Swap: Router Polygon: WMATIC Token20.872094424371620433 MATIC
0x60e3b705ab1a7cc2f4ad1b2cabcd24eb647af1f79dc9c830ae24a713f95c0b22358341252022-11-20 7:17:1613 days 14 hrs ago Kyber Swap: Router0xa26848f29b71a3fcc545f90a540a612c142e8d1b1.514103173821065092 MATIC
0x60e3b705ab1a7cc2f4ad1b2cabcd24eb647af1f79dc9c830ae24a713f95c0b22358341252022-11-20 7:17:1613 days 14 hrs ago Polygon: WMATIC Token Kyber Swap: Router1.514103173821065092 MATIC
0x1bb8b8cb020f6828aa3639adc73a5d80ef0f1c3f958555a8c61ff68053e5dbf0358144462022-11-19 19:56:1614 days 1 hr ago Kyber Swap: Router Polygon: WMATIC Token25.029379159595622239 MATIC
0x891a6a44c77821b0c6ea104ff518764ee232ac1db746afde4e16658f897ace65357853512022-11-19 3:05:2814 days 18 hrs ago Kyber Swap: Router Polygon: WMATIC Token7.323237437993200742 MATIC
0x8ace128469f5d2a93416f4d4a5178a1d248140e23ee1e3263dee1ba24b5d69db356735002022-11-16 9:35:4717 days 12 hrs ago Kyber Swap: Router0x2aab3ddd93ededc4d4275bef3e4f4d2ca95e00085,025.643146672493607662 MATIC
0x8ace128469f5d2a93416f4d4a5178a1d248140e23ee1e3263dee1ba24b5d69db356735002022-11-16 9:35:4717 days 12 hrs ago Polygon: WMATIC Token Kyber Swap: Router5,025.643146672493607662 MATIC
0xd465cd29b3090ab0edd0551a08df06a9afb05b99749989ea81bfdfbbfa742d95356598702022-11-16 1:33:2417 days 20 hrs ago Kyber Swap: Router Polygon: WMATIC Token5.692194625473789345 MATIC
0x1ed50c4698cdab6a1d9d7b2a934aafabffdcaff16811229c7caf14e25b263895356546602022-11-15 22:34:1017 days 23 hrs ago Kyber Swap: Router0x963a562f7860a000d150c54013f0bc229cb199c69.832988374008885568 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.