FTM Price: $0.564123 (-2.84%)
Gas: 8 GWei
 

Sponsored

Transaction Hash
Method
Block
From
To
Value
Swap Exact Token...835583982024-06-23 15:17:403 hrs ago1719155860IN
0xe146178d...0ED948Afb
0 FTM0.014486427
Swap Exact Token...835583402024-06-23 15:16:273 hrs ago1719155787IN
0xe146178d...0ED948Afb
0 FTM0.014729637
Swap Exact Token...835440822024-06-23 10:29:058 hrs ago1719138545IN
0xe146178d...0ED948Afb
0 FTM0.008358334
Add Liquidity835340672024-06-23 7:24:1911 hrs ago1719127459IN
0xe146178d...0ED948Afb
0 FTM0.006360944
Swap Exact Token...835340072024-06-23 7:23:0911 hrs ago1719127389IN
0xe146178d...0ED948Afb
0 FTM0.008332564
Swap Exact Token...835051362024-06-22 22:30:4520 hrs ago1719095445IN
0xe146178d...0ED948Afb
0 FTM0.010447945
Swap Exact Token...834327922024-06-21 23:05:4443 hrs ago1719011144IN
0xe146178d...0ED948Afb
0 FTM0.0361297217
Swap Exact ETH F...834277052024-06-21 21:05:5245 hrs ago1719003952IN
0xe146178d...0ED948Afb
700 FTM0.0482162224.05957071
Swap Exact ETH F...834083152024-06-21 14:37:272 days ago1718980647IN
0xe146178d...0ED948Afb
8 FTM0.0329976116.61880218
Swap Exact Token...833926812024-06-21 9:28:432 days ago1718962123IN
0xe146178d...0ED948Afb
0 FTM0.0250471612.30377928
Swap Exact Token...833894682024-06-21 8:18:402 days ago1718957920IN
0xe146178d...0ED948Afb
0 FTM0.0281897513
Add Liquidity833858092024-06-21 7:13:142 days ago1718953994IN
0xe146178d...0ED948Afb
0 FTM0.0238791115
Swap Exact Token...833856922024-06-21 7:11:112 days ago1718953871IN
0xe146178d...0ED948Afb
0 FTM0.032433115
Swap Exact Token...833716802024-06-21 3:43:112 days ago1718941391IN
0xe146178d...0ED948Afb
0 FTM0.0523958626.53009024
Swap Exact Token...833220622024-06-20 15:58:473 days ago1718899127IN
0xe146178d...0ED948Afb
0 FTM0.118930358.8488853
Swap Exact Token...833074612024-06-20 12:31:553 days ago1718886715IN
0xe146178d...0ED948Afb
0 FTM0.1173241854
Swap Exact Token...832891552024-06-20 7:27:143 days ago1718868434IN
0xe146178d...0ED948Afb
0 FTM0.1959997393
Add Liquidity832851852024-06-20 6:34:363 days ago1718865276IN
0xe146178d...0ED948Afb
0 FTM0.108472368
Swap Exact Token...832851382024-06-20 6:33:463 days ago1718865226IN
0xe146178d...0ED948Afb
0 FTM0.1513537270
Swap Exact Token...832744832024-06-20 4:13:073 days ago1718856787IN
0xe146178d...0ED948Afb
0 FTM0.0694112433
Swap Exact Token...832743672024-06-20 4:11:423 days ago1718856702IN
0xe146178d...0ED948Afb
0 FTM0.0507099423
Swap Exact Token...832607452024-06-20 1:13:083 days ago1718845988IN
0xe146178d...0ED948Afb
0 FTM0.007752832
Swap Exact Token...832606452024-06-20 1:11:463 days ago1718845906IN
0xe146178d...0ED948Afb
0 FTM0.0105223632
Swap Exact Token...832564922024-06-20 0:17:373 days ago1718842657IN
0xe146178d...0ED948Afb
0 FTM0.0688183333
Swap Exact Token...832556732024-06-20 0:07:133 days ago1718842033IN
0xe146178d...0ED948Afb
0 FTM0.0866266841
View all transactions

Latest 25 internal transactions (View All)

Parent Transaction Hash Block From To Value
834277052024-06-21 21:05:5245 hrs ago1719003952
0xe146178d...0ED948Afb
700 FTM
834083152024-06-21 14:37:272 days ago1718980647
0xe146178d...0ED948Afb
8 FTM
833926812024-06-21 9:28:432 days ago1718962123
0xe146178d...0ED948Afb
44.42141009 FTM
833926812024-06-21 9:28:432 days ago1718962123
0xe146178d...0ED948Afb
44.42141009 FTM
832021242024-06-19 10:34:504 days ago1718793290
0xe146178d...0ED948Afb
15.15573745 FTM
832021242024-06-19 10:34:504 days ago1718793290
0xe146178d...0ED948Afb
15.15573745 FTM
831361742024-06-18 10:22:465 days ago1718706166
0xe146178d...0ED948Afb
982.21780517 FTM
831255102024-06-18 6:05:065 days ago1718690706
0xe146178d...0ED948Afb
966 FTM
831253492024-06-18 6:01:085 days ago1718690468
0xe146178d...0ED948Afb
964 FTM
829308042024-06-15 7:16:378 days ago1718435797
0xe146178d...0ED948Afb
47 FTM
828742542024-06-14 10:26:229 days ago1718360782
0xe146178d...0ED948Afb
233.76104745 FTM
828420402024-06-13 22:59:309 days ago1718319570
0xe146178d...0ED948Afb
40 FTM
828165752024-06-13 13:29:3710 days ago1718285377
0xe146178d...0ED948Afb
1,620.19784642 FTM
828165752024-06-13 13:29:3710 days ago1718285377
0xe146178d...0ED948Afb
1,620.19784642 FTM
826258012024-06-10 10:39:4913 days ago1718015989
0xe146178d...0ED948Afb
1.16724232 FTM
826258012024-06-10 10:39:4913 days ago1718015989
0xe146178d...0ED948Afb
1.16724232 FTM
826257782024-06-10 10:39:2013 days ago1718015960
0xe146178d...0ED948Afb
1.16724216 FTM
826257782024-06-10 10:39:2013 days ago1718015960
0xe146178d...0ED948Afb
1.16724216 FTM
825523102024-06-09 6:55:3014 days ago1717916130
0xe146178d...0ED948Afb
95 FTM
824902412024-06-08 8:14:1015 days ago1717834450
0xe146178d...0ED948Afb
40 FTM
824501542024-06-07 16:53:3716 days ago1717779217
0xe146178d...0ED948Afb
431.04947783 FTM
824501542024-06-07 16:53:3716 days ago1717779217
0xe146178d...0ED948Afb
431.04947783 FTM
823227652024-06-05 17:50:5118 days ago1717609851
0xe146178d...0ED948Afb
425.98828774 FTM
823227652024-06-05 17:50:5118 days ago1717609851
0xe146178d...0ED948Afb
425.98828774 FTM
823227432024-06-05 17:50:2518 days ago1717609825
0xe146178d...0ED948Afb
424.71790421 FTM
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
wMLPRouter

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 1 runs

Other Settings:
default evmVersion, MIT license

Contract Source Code (Solidity)

/**
 *Submitted for verification at ftmscan.com on 2024-01-26
*/

// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    enum Rounding {
        Down, // Toward negative infinity
        Up, // Toward infinity
        Zero // Toward zero
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
     * with further edits by Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod0 := mul(x, y)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1, "Math: mulDiv overflow");

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
            // See https://cs.stackexchange.com/q/138556/92363.

            // Does not overflow because the denominator cannot be zero at this stage in the function.
            uint256 twos = denominator & (~denominator + 1);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
            // in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256, rounded down, of a positive value.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
        }
    }
}

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

/**
 * @dev Contract module which provides access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership} and {acceptOwnership}.
 *
 * This module is used through inheritance. It will make available all functions
 * from parent (Ownable).
 */
abstract contract Ownable2Step is Ownable {
    address private _pendingOwner;

    event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Returns the address of the pending owner.
     */
    function pendingOwner() public view virtual returns (address) {
        return _pendingOwner;
    }

    /**
     * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual override onlyOwner {
        _pendingOwner = newOwner;
        emit OwnershipTransferStarted(owner(), newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual override {
        delete _pendingOwner;
        super._transferOwnership(newOwner);
    }

    /**
     * @dev The new owner accepts the ownership transfer.
     */
    function acceptOwnership() public virtual {
        address sender = _msgSender();
        require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner");
        _transferOwnership(sender);
    }
}

interface IERC20 {
    function totalSupply() external view returns (uint256);

    function transfer(address recipient, uint amount) external returns (bool);

    function decimals() external view returns (uint8);

    function symbol() external view returns (string memory);

    function balanceOf(address) external view returns (uint);

    function transferFrom(
        address sender,
        address recipient,
        uint amount
    ) external returns (bool);

    function allowance(
        address owner,
        address spender
    ) external view returns (uint);

    function approve(address spender, uint value) external returns (bool);

    event Transfer(address indexed from, address indexed to, uint value);
    event Approval(address indexed owner, address indexed spender, uint value);
}

interface VaultAPI is IERC20 {
    // NOTE: Vyper produces multiple signatures for a given function with "default" args
    function deposit() external returns (uint256);

    function deposit(uint256 amount) external returns (uint256);

    function deposit(
        uint256 amount,
        address recipient
    ) external returns (uint256);

    // NOTE: Vyper produces multiple signatures for a given function with "default" args
    function withdraw() external returns (uint256);

    function withdraw(uint256 maxShares) external returns (uint256);

    function withdraw(
        uint256 maxShares,
        address recipient
    ) external returns (uint256);

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

interface IBMX is IERC20 {
    function glp() external view returns (address);

    function usdg() external view returns (address);

    function cooldownDuration() external returns (uint256);

    function getAumInUsdg(bool maximise) external view returns (uint256);

    function underlyingToken() external view returns (address);

    function lastAddedAt(address _account) external returns (uint256);

    function getPaymentTokenAmountForExerciseLp(
        uint256,
        uint256
    ) external view returns (uint256, uint256);

    function addLiquidity(
        address _token,
        uint256 _amount,
        uint256 _minUsdg,
        uint256 _minGlp
    ) external returns (uint256);

    function unstakeAndRedeemGlp(
        address _tokenOut,
        uint256 _glpAmount,
        uint256 _minOut,
        address _receiver
    ) external returns (uint256);

    function addLiquidityForAccount(
        address _fundingAccount,
        address _account,
        address _token,
        uint256 _amount,
        uint256 _minUsdg,
        uint256 _minGlp
    ) external returns (uint256);

    function removeLiquidity(
        address _tokenOut,
        uint256 _glpAmount,
        uint256 _minOut,
        address _receiver
    ) external returns (uint256);

    function removeLiquidityForAccount(
        address _account,
        address _tokenOut,
        uint256 _glpAmount,
        uint256 _minOut,
        address _receiver
    ) external returns (uint256);

    function setShortsTrackerAveragePriceWeight(
        uint256 _shortsTrackerAveragePriceWeight
    ) external;

    function setCooldownDuration(uint256 _cooldownDuration) external;

    function exerciseLp(
        uint256 _amount,
        uint256 _maxPaymentAmount,
        address _recipient,
        uint256 _discount,
        uint256 _deadline
    ) external returns (uint256, uint256);

    function claimable(address) external view returns (uint256);

    function pairAmounts(address) external view returns (uint256);

    function depositBalances(address, address) external view returns (uint256);

    function handleRewards(bool, bool, bool) external;

    function withdraw() external;

    function deposit(uint256) external;

    function signalTransfer(address) external;

    function acceptTransfer(address) external;

    function getPairAmount(address, uint256) external view returns (uint256);

    function mintAndStakeGlp(
        address,
        uint256,
        uint256,
        uint256
    ) external returns (uint256);

    function updateCumulativeFundingRate(
        address _collateralToken,
        address _indexToken
    ) external returns (bool);

    function validateIncreasePosition(
        address _account,
        address _collateralToken,
        address _indexToken,
        uint256 _sizeDelta,
        bool _isLong
    ) external view;

    function validateDecreasePosition(
        address _account,
        address _collateralToken,
        address _indexToken,
        uint256 _collateralDelta,
        uint256 _sizeDelta,
        bool _isLong,
        address _receiver
    ) external view;

    function getEntryFundingRate(
        address _collateralToken,
        address _indexToken,
        bool _isLong
    ) external view returns (uint256);

    function getPositionFee(
        address _account,
        address _collateralToken,
        address _indexToken,
        bool _isLong,
        uint256 _sizeDelta
    ) external view returns (uint256);

    function getFundingFee(
        address _account,
        address _collateralToken,
        address _indexToken,
        bool _isLong,
        uint256 _size,
        uint256 _entryFundingRate
    ) external view returns (uint256);

    function getBuyUsdgFeeBasisPoints(
        address _token,
        uint256 _usdgAmount
    ) external view returns (uint256);

    function getSellUsdgFeeBasisPoints(
        address _token,
        uint256 _usdgAmount
    ) external view returns (uint256);

    function getSwapFeeBasisPoints(
        address _tokenIn,
        address _tokenOut,
        uint256 _usdgAmount
    ) external view returns (uint256);

    function isInitialized() external view returns (bool);

    function adjustForDecimals(
        uint256 _amount,
        address _tokenDiv,
        address _tokenMul
    ) external view returns (uint256);

    function PRICE_PRECISION() external view returns (uint256);

    function BASIS_POINTS_DIVISOR() external view returns (uint256);

    function isSwapEnabled() external view returns (bool);

    function isLeverageEnabled() external view returns (bool);

    function setError(uint256 _errorCode, string calldata _error) external;

    function router() external view returns (address);

    function gov() external view returns (address);

    function whitelistedTokenCount() external view returns (uint256);

    function maxLeverage() external view returns (uint256);

    function minProfitTime() external view returns (uint256);

    function hasDynamicFees() external view returns (bool);

    function fundingInterval() external view returns (uint256);

    function totalTokenWeights() external view returns (uint256);

    function getTargetUsdgAmount(
        address _token
    ) external view returns (uint256);

    function inManagerMode() external view returns (bool);

    function inPrivateLiquidationMode() external view returns (bool);

    function maxGasPrice() external view returns (uint256);

    function approvedRouters(
        address _account,
        address _router
    ) external view returns (bool);

    function isLiquidator(address _account) external view returns (bool);

    function isManager(address _account) external view returns (bool);

    function minProfitBasisPoints(
        address _token
    ) external view returns (uint256);

    function tokenBalances(address _token) external view returns (uint256);

    function lastFundingTimes(address _token) external view returns (uint256);

    function setMaxLeverage(uint256 _maxLeverage) external;

    function setInManagerMode(bool _inManagerMode) external;

    function setManager(address _manager, bool _isManager) external;

    function setIsSwapEnabled(bool _isSwapEnabled) external;

    function setIsLeverageEnabled(bool _isLeverageEnabled) external;

    function setMaxGasPrice(uint256 _maxGasPrice) external;

    function setUsdgAmount(address _token, uint256 _amount) external;

    function setBufferAmount(address _token, uint256 _amount) external;

    function setMaxGlobalShortSize(address _token, uint256 _amount) external;

    function setInPrivateLiquidationMode(
        bool _inPrivateLiquidationMode
    ) external;

    function setLiquidator(address _liquidator, bool _isActive) external;

    function setFundingRate(
        uint256 _fundingInterval,
        uint256 _fundingRateFactor,
        uint256 _stableFundingRateFactor
    ) external;

    function setFees(
        uint256 _taxBasisPoints,
        uint256 _stableTaxBasisPoints,
        uint256 _mintBurnFeeBasisPoints,
        uint256 _swapFeeBasisPoints,
        uint256 _stableSwapFeeBasisPoints,
        uint256 _marginFeeBasisPoints,
        uint256 _liquidationFeeUsd,
        uint256 _minProfitTime,
        bool _hasDynamicFees
    ) external;

    function setTokenConfig(
        address _token,
        uint256 _tokenDecimals,
        uint256 _redemptionBps,
        uint256 _minProfitBps,
        uint256 _maxUsdgAmount,
        bool _isStable,
        bool _isShortable
    ) external;

    function setPriceFeed(address _priceFeed) external;

    function withdrawFees(
        address _token,
        address _receiver
    ) external returns (uint256);

    function directPoolDeposit(address _token) external;

    function buyUSDG(
        address _token,
        address _receiver
    ) external returns (uint256);

    function sellUSDG(
        address _token,
        address _receiver
    ) external returns (uint256);

    function swap(
        address _tokenIn,
        address _tokenOut,
        address _receiver
    ) external returns (uint256);

    function increasePosition(
        address _account,
        address _collateralToken,
        address _indexToken,
        uint256 _sizeDelta,
        bool _isLong
    ) external;

    function decreasePosition(
        address _account,
        address _collateralToken,
        address _indexToken,
        uint256 _collateralDelta,
        uint256 _sizeDelta,
        bool _isLong,
        address _receiver
    ) external returns (uint256);

    function validateLiquidation(
        address _account,
        address _collateralToken,
        address _indexToken,
        bool _isLong,
        bool _raise
    ) external view returns (uint256, uint256);

    function liquidatePosition(
        address _account,
        address _collateralToken,
        address _indexToken,
        bool _isLong,
        address _feeReceiver
    ) external;

    function tokenToUsdMin(
        address _token,
        uint256 _tokenAmount
    ) external view returns (uint256);

    function priceFeed() external view returns (address);

    function fundingRateFactor() external view returns (uint256);

    function stableFundingRateFactor() external view returns (uint256);

    function cumulativeFundingRates(
        address _token
    ) external view returns (uint256);

    function getNextFundingRate(address _token) external view returns (uint256);

    function getFeeBasisPoints(
        address _token,
        uint256 _usdgDelta,
        uint256 _feeBasisPoints,
        uint256 _taxBasisPoints,
        bool _increment
    ) external view returns (uint256);

    function liquidationFeeUsd() external view returns (uint256);

    function taxBasisPoints() external view returns (uint256);

    function stableTaxBasisPoints() external view returns (uint256);

    function mintBurnFeeBasisPoints() external view returns (uint256);

    function swapFeeBasisPoints() external view returns (uint256);

    function stableSwapFeeBasisPoints() external view returns (uint256);

    function marginFeeBasisPoints() external view returns (uint256);

    function allWhitelistedTokensLength() external view returns (uint256);

    function allWhitelistedTokens(uint256) external view returns (address);

    function whitelistedTokens(address _token) external view returns (bool);

    function stableTokens(address _token) external view returns (bool);

    function shortableTokens(address _token) external view returns (bool);

    function feeReserves(address _token) external view returns (uint256);

    function globalShortSizes(address _token) external view returns (uint256);

    function globalShortAveragePrices(
        address _token
    ) external view returns (uint256);

    function maxGlobalShortSizes(
        address _token
    ) external view returns (uint256);

    function tokenDecimals(address _token) external view returns (uint256);

    function tokenWeights(address _token) external view returns (uint256);

    function guaranteedUsd(address _token) external view returns (uint256);

    function poolAmounts(address _token) external view returns (uint256);

    function bufferAmounts(address _token) external view returns (uint256);

    function reservedAmounts(address _token) external view returns (uint256);

    function usdgAmounts(address _token) external view returns (uint256);

    function maxUsdgAmounts(address _token) external view returns (uint256);

    function getLivePrice() external view returns (uint256);

    function getRedemptionAmount(
        address _token,
        uint256 _usdgAmount
    ) external view returns (uint256);

    function getMaxPrice(address _token) external view returns (uint256);

    function getMinPrice(address _token) external view returns (uint256);

    function getDelta(
        address _indexToken,
        uint256 _size,
        uint256 _averagePrice,
        bool _isLong,
        uint256 _lastIncreasedTime
    ) external view returns (bool, uint256);

    function getPosition(
        address _account,
        address _collateralToken,
        address _indexToken,
        bool _isLong
    )
        external
        view
        returns (
            uint256,
            uint256,
            uint256,
            uint256,
            uint256,
            uint256,
            bool,
            uint256
        );
}

interface IPair {
    function metadata()
        external
        view
        returns (
            uint dec0,
            uint dec1,
            uint r0,
            uint r1,
            bool st,
            address t0,
            address t1
        );

    function tokens() external returns (address, address);

    function token0() external returns (address);

    function token1() external returns (address);

    function externalBribe() external returns (address);

    function transferFrom(
        address src,
        address dst,
        uint amount
    ) external returns (bool);

    function permit(
        address owner,
        address spender,
        uint value,
        uint deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

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

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

    function mint(address to) external returns (uint liquidity);

    function getReserves()
        external
        view
        returns (uint _reserve0, uint _reserve1, uint _blockTimestampLast);

    function getAmountOut(uint, address) external view returns (uint);

    function setHasGauge(bool value) external;

    function setExternalBribe(address _externalBribe) external;

    function hasGauge() external view returns (bool);

    function stable() external view returns (bool);

    function prices(
        address tokenIn,
        uint amountIn,
        uint points
    ) external view returns (uint[] memory);
}

interface IPairFactory {
    function allPairsLength() external view returns (uint);

    function isPair(address pair) external view returns (bool);

    function isPaused() external view returns (bool);

    function pairCodeHash() external pure returns (bytes32);

    function getFee(address pair) external view returns (uint256);

    function getPair(
        address tokenA,
        address token,
        bool stable
    ) external view returns (address);

    function getInitializable() external view returns (address, address, bool);

    function createPair(
        address tokenA,
        address tokenB,
        bool stable
    ) external returns (address pair);

    function voter() external view returns (address);

    function tank() external view returns (address);
}

interface IBalancer {
    function flashLoan(
        address recipient,
        address[] memory tokens,
        uint256[] memory amounts,
        bytes memory userData
    ) external;
}

interface IRouter {
    struct route {
        address from;
        address to;
        bool stable;
    }

    function pairFor(
        address tokenA,
        address tokenB,
        bool stable
    ) external view returns (address pair);

    function getAmountOut(
        uint amountIn,
        address tokenIn,
        address tokenOut,
        bool stable
    ) external view returns (uint amount);

    function getReserves(
        address tokenA,
        address tokenB,
        bool stable
    ) external view returns (uint, uint);

    function addLiquidity(
        address tokenA,
        address tokenB,
        bool stable,
        uint amountADesired,
        uint amountBDesired,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) external returns (uint, uint, uint);

    function swapExactTokensForTokens(
        uint amountIn,
        uint amountOutMin,
        route[] calldata routes,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);
}

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

    function transfer(address to, uint256 value) external returns (bool);

    function withdraw(uint256) external;
}

interface IShareHelper {
    function sharesToAmount(
        address vault,
        uint shares,
        bool useCeiling
    ) external view returns (uint);

    function amountToShares(
        address vault,
        uint amount,
        bool useCeiling
    ) external view returns (uint);
}

/**
 * @title wMLP Router
 * @notice This contract simplifies conversions between wMLP, MPX, and other assets
 *  using wMLP's underlying tokens as virtual pairs with wMLP.
 */

contract wMLPRouter is Ownable2Step {
    struct Route {
        address from;
        address to;
        bool stable;
    }

    /// @notice Factory address that deployed our Velodrome pool.
    address public constant factory =
        0x472f3C3c9608fe0aE8d702f3f8A2d12c410C881A;

    IWETH public constant wftm =
        IWETH(0x21be370D5312f44cB42ce377BC9b8a0cEF1A4C83);
    uint256 internal constant MINIMUM_LIQUIDITY = 10 ** 3;
    bytes32 internal immutable pairCodeHash;
    uint256 internal immutable PRICE_PRECISION;
    uint256 internal immutable BASIS_POINTS_DIVISOR;

    /// @notice The tokens currently approved for deposit to MLP.
    address[] public mlpTokens;

    // contracts used for wMLP mint/burn
    VaultAPI internal constant wMLP =
        VaultAPI(0xAE4846b148A65782865A4849E940575F77359b2B);

    IBMX internal constant sMLP =
        IBMX(0x6E3e180b1C5742FC445F0bbdaB7Aa7b902560630);

    IBMX internal constant rewardRouter =
        IBMX(0xd6489eAf13f61822356F30618E1D9947fa1Ef46F);

    IBMX internal constant morphexVault =
        IBMX(0x245cD6d33578de9aF75a3C0c636c726b1A8cbdAa);

    IBMX internal constant mlpManager =
        IBMX(0x3A15Bac2D87C89F08147353fc9aE27080631b73d);

    IBMX internal constant vaultUtils =
        IBMX(0x6280873fFDB6A9c8FD601B323F60980061627384);

    IShareHelper internal constant shareValueHelper =
        IShareHelper(0xb643724c5C364d1F1971EDB7BAB059cB9Ab6567d);

    constructor() {
        pairCodeHash = IPairFactory(factory).pairCodeHash();

        // do approvals for wMLP
        sMLP.approve(address(wMLP), type(uint256).max);

        // update our allowances
        updateAllowances();

        PRICE_PRECISION = morphexVault.PRICE_PRECISION();
        BASIS_POINTS_DIVISOR = morphexVault.BASIS_POINTS_DIVISOR();
    }

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

    // only accept FTM via fallback from the WFTM contract
    receive() external payable {
        assert(msg.sender == address(wftm));
    }

    /* ========== NEW/MODIFIED FUNCTIONS ========== */

    /**
     * @notice
     *  Checks for current tokens in MLP, approves them, and updates our stored array.
     * @dev This may only be called by owner.
     */
    function updateAllowances() public onlyOwner {
        // first, set all of our allowances to zero
        for (uint256 i = 0; i < mlpTokens.length; ++i) {
            IERC20 token = IERC20(mlpTokens[i]);
            token.approve(address(mlpManager), 0);
        }

        // clear out our saved array
        delete mlpTokens;

        // add our new tokens
        uint256 tokensCount = morphexVault.whitelistedTokenCount();
        for (uint256 i = 0; i < tokensCount; ++i) {
            IERC20 token = IERC20(morphexVault.allWhitelistedTokens(i));
            token.approve(address(mlpManager), type(uint256).max);
            mlpTokens.push(address(token));
        }
    }

    /**
     * @notice
     *  Performs chained getAmountOut calculations on any number of pairs.
     * @dev This is mainly used when conducting swaps.
     * @param _amountIn The amount of our first token to swap.
     * @param _routes Array of structs that we use for our swap path.
     * @return amounts Amount of each token in the swap path.
     */
    function getAmountsOut(
        uint256 _amountIn,
        Route[] memory _routes
    ) public view returns (uint256[] memory amounts) {
        require(_routes.length >= 1, "Router: INVALID_PATH");
        amounts = new uint256[](_routes.length + 1);
        amounts[0] = _amountIn;
        for (uint256 i = 0; i < _routes.length; i++) {
            // check if we need to convert to or from wMLP
            if (_routes[i].from == address(wMLP)) {
                // check to make sure it's one of the tokens in MLP
                if (_isMLPToken(_routes[i].to)) {
                    amounts[i + 1] = getRedeemAmountWrappedMLP(
                        _routes[i].to,
                        amounts[i],
                        false
                    );
                    continue;
                }
            } else if (_routes[i].to == address(wMLP)) {
                // check to make sure it's one of the tokens in MLP
                if (_isMLPToken(_routes[i].from)) {
                    // make sure to underestimate the amount out here
                    amounts[i + 1] = getMintAmountWrappedMLP(
                        _routes[i].from,
                        amounts[i]
                    );
                    continue;
                }
            }

            // if it's not depositing or withdrawing from wMLP, we can treat it like
            //  normal
            address pair = pairFor(
                _routes[i].from,
                _routes[i].to,
                _routes[i].stable
            );
            if (IPairFactory(factory).isPair(pair)) {
                amounts[i + 1] = IPair(pair).getAmountOut(
                    amounts[i],
                    _routes[i].from
                );
            }
        }
    }

    /**
     * @notice
     *  Swap wMLP or our paired token for FTM.
     * @param _amountIn The amount of our first token to swap.
     * @param _amountOutMin Minimum amount of FTM we must receive.
     * @param _routes Array of structs that we use for our swap path.
     * @param _to Address that will receive the FTM.
     * @param _deadline Deadline for transaction to complete.
     * @return amounts Amount of each token in the swap path.
     */
    function swapExactTokensForETH(
        uint256 _amountIn,
        uint256 _amountOutMin,
        Route[] calldata _routes,
        address _to,
        uint256 _deadline
    ) external ensure(_deadline) returns (uint256[] memory amounts) {
        amounts = getAmountsOut(_amountIn, _routes);
        require(
            amounts[amounts.length - 1] >= _amountOutMin,
            "Router: INSUFFICIENT_OUTPUT_AMOUNT"
        );
        require(
            _routes[_routes.length - 1].to == address(wftm),
            "Router: END_ROUTE_IN_FTM_BOZO"
        );

        // if our first pair is mint/burn of wMLP, transfer to the router
        if (
            _routes[0].from == address(wMLP) || _routes[0].to == address(wMLP)
        ) {
            if (_isMLPToken(_routes[0].from) || _isMLPToken(_routes[0].to)) {
                _safeTransferFrom(
                    _routes[0].from,
                    msg.sender,
                    address(this),
                    amounts[0]
                );
            } else {
                // if it's not wMLP AND an underlying, it's just a normal wMLP swap
                //  (likely w/ MPX)
                _safeTransferFrom(
                    _routes[0].from,
                    msg.sender,
                    pairFor(_routes[0].from, _routes[0].to, _routes[0].stable),
                    amounts[0]
                );
            }
        } else {
            _safeTransferFrom(
                _routes[0].from,
                msg.sender,
                pairFor(_routes[0].from, _routes[0].to, _routes[0].stable),
                amounts[0]
            );
        }

        _swap(amounts, _routes, address(this));

        // WFTM -> FTM
        uint256 amountUnderlying = wftm.balanceOf(address(this));
        wftm.withdraw(amountUnderlying);
        _safeTransferETH(_to, amountUnderlying);
    }

    /**
     * @notice
     *  Swap FTM for tokens, with special handling for wMLP pairs.
     * @param _amountIn The amount of FTM to swap.
     * @param _amountOutMin Minimum amount of our final token we must receive.
     * @param _routes Array of structs that we use for our swap path.
     * @param _to Address that will receive the final token in the swap path.
     * @param _deadline Deadline for transaction to complete.
     * @return amounts Amount of each token in the swap path.
     */
    function swapExactETHForTokens(
        uint256 _amountIn,
        uint256 _amountOutMin,
        Route[] calldata _routes,
        address _to,
        uint256 _deadline
    ) public payable ensure(_deadline) returns (uint256[] memory amounts) {
        amounts = getAmountsOut(_amountIn, _routes);
        require(
            amounts[amounts.length - 1] >= _amountOutMin,
            "Router: INSUFFICIENT_OUTPUT_AMOUNT"
        );

        // deposit to wftm first
        wftm.deposit{value: _amountIn}();
        if (wftm.balanceOf(address(this)) != _amountIn) {
            revert("WFTM not sent");
        }

        if (
            _routes[0].from != address(wftm) || _routes[0].to != address(wMLP)
        ) {
            revert("Route must start WFTM -> wMLP");
        }

        _swap(amounts, _routes, _to);
    }

    /**
     * @notice
     *  Swap tokens for tokens, with special handling for wMLP pairs.
     * @param _amountIn The amount of our first token to swap.
     * @param _amountOutMin Minimum amount of our final token we must receive.
     * @param _routes Array of structs that we use for our swap path.
     * @param _to Address that will receive the final token in the swap path.
     * @param _deadline Deadline for transaction to complete.
     * @return amounts Amount of each token in the swap path.
     */
    function swapExactTokensForTokens(
        uint256 _amountIn,
        uint256 _amountOutMin,
        Route[] calldata _routes,
        address _to,
        uint256 _deadline
    ) external ensure(_deadline) returns (uint256[] memory amounts) {
        amounts = getAmountsOut(_amountIn, _routes);
        require(
            amounts[amounts.length - 1] >= _amountOutMin,
            "Router: INSUFFICIENT_OUTPUT_AMOUNT"
        );

        // if our first pair is mint/burn of wMLP, transfer to the router
        if (
            _routes[0].from == address(wMLP) || _routes[0].to == address(wMLP)
        ) {
            if (_isMLPToken(_routes[0].from) || _isMLPToken(_routes[0].to)) {
                _safeTransferFrom(
                    _routes[0].from,
                    msg.sender,
                    address(this),
                    amounts[0]
                );
            } else {
                // if it's not wMLP AND an underlying, it's just a normal wMLP swap
                //  (likely w/ MPX)
                _safeTransferFrom(
                    _routes[0].from,
                    msg.sender,
                    pairFor(_routes[0].from, _routes[0].to, _routes[0].stable),
                    amounts[0]
                );
            }
        } else {
            _safeTransferFrom(
                _routes[0].from,
                msg.sender,
                pairFor(_routes[0].from, _routes[0].to, _routes[0].stable),
                amounts[0]
            );
        }

        _swap(amounts, _routes, _to);
    }

    // **** SWAP ****
    // requires the initial amount to have already been sent to the first pair
    // or in this case, our underlying or wMLP to have been sent to the router
    function _swap(
        uint256[] memory _amounts,
        Route[] memory _routes,
        address _to
    ) internal virtual {
        for (uint256 i = 0; i < _routes.length; i++) {
            (address token0, ) = sortTokens(_routes[i].from, _routes[i].to);
            uint256 amountOut = _amounts[i + 1];
            (uint256 amount0Out, uint256 amount1Out) = _routes[i].from == token0
                ? (uint256(0), amountOut)
                : (amountOut, uint256(0));

            // only if we're doing a wMLP deposit/withdrawal in the middle of a route
            bool directSend;
            uint256 received;
            address to;

            // check if we need to convert to or from wMLP
            if (_routes[i].from == address(wMLP)) {
                // check to see if it's one of the tokens in MLP
                if (_isMLPToken(_routes[i].to)) {
                    received = _withdrawFromWrappedMLP(_routes[i].to);
                    if (i < (_routes.length - 1)) {
                        // if we're not done, send our underlying to the next pair
                        directSend = true;
                    } else {
                        // if this is the last token, send to our _to address
                        _safeTransfer(_routes[i].to, _to, received);
                        return;
                    }
                }
            } else if (_routes[i].to == address(wMLP)) {
                // check to make sure it's one of the tokens in MLP
                if (_isMLPToken(_routes[i].from)) {
                    received = _depositToWrappedMLP(_routes[i].from);
                    if (i < (_routes.length - 1)) {
                        // if we're not done, directly send our wMLP to the next pair
                        directSend = true;
                    } else {
                        // if this is the last token, send to our _to address
                        _safeTransfer(_routes[i].to, _to, received);
                        return;
                    }
                }
            }

            if (i == _routes.length - 1) {
                // end of the route, send to the receiver
                to = _to;
            } else if (
                (_isMLPToken(_routes[i + 1].from) &&
                    _routes[i + 1].to == address(wMLP)) ||
                (_isMLPToken(_routes[i + 1].to) &&
                    _routes[i + 1].from == address(wMLP))
            ) {
                // if we're about to go underlying -> wMLP or wMLP -> underlying, then
                //  make sure we get our needed token back to the router
                to = address(this);
            } else {
                // normal mid-route swap
                to = pairFor(
                    _routes[i + 1].from,
                    _routes[i + 1].to,
                    _routes[i + 1].stable
                );
            }

            if (directSend) {
                _safeTransfer(_routes[i].to, to, received);
            } else {
                IPair(
                    pairFor(_routes[i].from, _routes[i].to, _routes[i].stable)
                ).swap(amount0Out, amount1Out, to, new bytes(0));
            }
        }
    }

    /**
     * @notice
     *  Add liquidity for wMLP-TOKEN with an underlying token for wMLP.
     * @dev Removed the stable and tokenA params from the standard function
     *  as they're not needed and so stack isn't too deep.
     * @param _underlyingToken The token to zap into wMLP for creating the LP.
     * @param _amountToZapIn Amount of underlying token to deposit to wMLP.
     * @param token The token to pair with wMLP for the LP.
     * @param _amountWrappedMLPDesired The amount of wMLP we would like to deposit to the
     *  LP.
     * @param _amountTokenDesired The amount of other token we would like to deposit to the
     *  LP.
     * @param _amountWrappedMLPMin The minimum amount of wMLP we will accept in the LP.
     * @param _amountTokenMin The minimum amount of other token we will accept in the LP.
     * @param _to Address that will receive the LP token.
     * @return amountWrappedMLP Amount of wMLP actually deposited in the LP.
     * @return amountToken Amount of our other token actually deposited in the LP.
     * @return liquidity Amount of LP token generated.
     */
    function addLiquidity(
        address _underlyingToken,
        uint256 _amountToZapIn,
        address token,
        uint256 _amountWrappedMLPDesired,
        uint256 _amountTokenDesired,
        uint256 _amountWrappedMLPMin,
        uint256 _amountTokenMin,
        address _to
    )
        external
        returns (
            uint256 amountWrappedMLP,
            uint256 amountToken,
            uint256 liquidity
        )
    {
        _safeTransferFrom(
            _underlyingToken,
            msg.sender,
            address(this),
            _amountToZapIn
        );

        // first, deposit the underlying to wMLP, deposit function checks that underlying
        //  is actually in the LP
        _amountWrappedMLPDesired = _depositToWrappedMLP(_underlyingToken);

        (amountWrappedMLP, amountToken) = _addLiquidity(
            address(wMLP),
            token,
            false, // stable LPs with wMLP would be kind dumb
            _amountWrappedMLPDesired,
            _amountTokenDesired,
            _amountWrappedMLPMin,
            _amountTokenMin
        );
        address pair = pairFor(address(wMLP), token, false);

        // wMLP will already be in the router, so transfer for it. transferFrom for other
        //  token.
        _safeTransfer(address(wMLP), pair, amountWrappedMLP);
        _safeTransferFrom(token, msg.sender, pair, amountToken);

        liquidity = IPair(pair).mint(_to);
        uint256 remainingBalance = wMLP.balanceOf(address(this));
        // return any leftover wMLP
        if (remainingBalance > 0) {
            _safeTransfer(address(wMLP), msg.sender, remainingBalance);
        }
    }

    /**
     * @notice
     *  Add liquidity for wMLP-TOKEN with FTM.
     * @param _amountToZapIn Amount of FTM to deposit to wMLP.
     * @param token The token to pair with wMLP for the LP.
     * @param _amountWrappedMLPDesired The amount of wMLP we would like to deposit to the
     *  LP.
     * @param _amountTokenDesired The amount of other token we would like to deposit to the
     *  LP.
     * @param _amountWrappedMLPMin The minimum amount of wMLP we will accept in the LP.
     * @param _amountTokenMin The minimum amount of other token we will accept in the LP.
     * @param _to Address that will receive the LP token.
     * @return amountWrappedMLP Amount of wMLP actually deposited in the LP.
     * @return amountToken Amount of our other token actually deposited in the LP.
     * @return liquidity Amount of LP token generated.
     */
    function addLiquidityETH(
        uint256 _amountToZapIn,
        address token,
        uint256 _amountWrappedMLPDesired,
        uint256 _amountTokenDesired,
        uint256 _amountWrappedMLPMin,
        uint256 _amountTokenMin,
        address _to
    )
        external
        payable
        returns (
            uint256 amountWrappedMLP,
            uint256 amountToken,
            uint256 liquidity
        )
    {
        // deposit to wftm, then everything is the same
        wftm.deposit{value: _amountToZapIn}();
        if (wftm.balanceOf(address(this)) != _amountToZapIn) {
            revert("WFTM not sent");
        }

        // first, deposit the underlying to wMLP, deposit function checks that underlying
        //  is actually in the LP
        _amountWrappedMLPDesired = _depositToWrappedMLP(address(wftm));

        (amountWrappedMLP, amountToken) = _addLiquidity(
            address(wMLP),
            token,
            false, // stable LPs with wMLP would be kind dumb
            _amountWrappedMLPDesired,
            _amountTokenDesired,
            _amountWrappedMLPMin,
            _amountTokenMin
        );
        address pair = pairFor(address(wMLP), token, false);

        // wMLP will already be in the router, so transfer for it. transferFrom for other
        //  token.
        _safeTransfer(address(wMLP), pair, amountWrappedMLP);
        _safeTransferFrom(token, msg.sender, pair, amountToken);
        liquidity = IPair(pair).mint(_to);

        // return any leftover wMLP
        uint256 remainingBalance = wMLP.balanceOf(address(this));
        if (remainingBalance > 0) {
            _safeTransfer(address(wMLP), msg.sender, remainingBalance);
        }
    }

    /**
     * @notice
     *  Remove liquidity from a wMLP-TOKEN LP, and convert wMLP to a given underlying.
     * @param _targetToken Address of our desired wMLP underlying to withdraw to.
     * @param _token The other token paired with wMLP in our LP.
     * @param _liquidity The amount of LP tokens we want to burn.
     * @param _amountWrappedMLPMin The minimum amount of wMLP we will accept from the LP.
     * @param _amountTokenMin The minimum amount of our other token we will accept from the
     *  LP.
     * @param _to Address that will receive the LP token.
     * @return amountWrappedMLP Amount of wMLP actually received from the LP.
     * @return amountToken Amount of other token actually received from the LP.
     * @return amountUnderlying Amount of our underlying token received from the wMLP.
     */
    function removeLiquidity(
        address _targetToken,
        address _token,
        uint256 _liquidity,
        uint256 _amountWrappedMLPMin,
        uint256 _amountTokenMin,
        address _to
    )
        external
        returns (
            uint256 amountWrappedMLP,
            uint256 amountToken,
            uint256 amountUnderlying
        )
    {
        // stable is dumb with wMLP
        address pair = pairFor(address(wMLP), _token, false);
        // send liquidity to pair
        require(IPair(pair).transferFrom(msg.sender, pair, _liquidity));
        (uint256 amount0, uint256 amount1) = IPair(pair).burn(address(this));
        (address token0, ) = sortTokens(address(wMLP), _token);
        (amountWrappedMLP, amountToken) = address(wMLP) == token0
            ? (amount0, amount1)
            : (amount1, amount0);
        require(
            amountWrappedMLP >= _amountWrappedMLPMin,
            "Router: INSUFFICIENT_A_AMOUNT"
        );
        require(
            amountToken >= _amountTokenMin,
            "Router: INSUFFICIENT_B_AMOUNT"
        );

        _safeTransfer(_token, _to, amountToken);

        amountUnderlying = _withdrawFromWrappedMLP(_targetToken);
        _safeTransfer(_targetToken, _to, amountUnderlying);
    }

    /**
     * @notice
     *  Remove liquidity from a wMLP-TOKEN LP, and convert wMLP to FTM.
     * @param _token The other token paired with wMLP in our LP.
     * @param _liquidity The amount of LP tokens we want to burn.
     * @param _amountWrappedMLPMin The minimum amount of wMLP we will accept from the LP.
     * @param _amountTokenMin The minimum amount of our other token we will accept from the
     *  LP.
     * @param _to Address that will receive the LP token.
     * @return amountWrappedMLP Amount of wMLP actually received from the LP.
     * @return amountToken Amount of other token actually received from the LP.
     * @return amountUnderlying Amount of FTM received from the wMLP.
     */
    function removeLiquidityETH(
        address _token,
        uint256 _liquidity,
        uint256 _amountWrappedMLPMin,
        uint256 _amountTokenMin,
        address _to
    )
        external
        returns (
            uint256 amountWrappedMLP,
            uint256 amountToken,
            uint256 amountUnderlying
        )
    {
        // stable is dumb with wMLP
        address pair = pairFor(address(wMLP), _token, false);
        // send liquidity to pair
        require(IPair(pair).transferFrom(msg.sender, pair, _liquidity));
        (uint256 amount0, uint256 amount1) = IPair(pair).burn(address(this));
        (address token0, ) = sortTokens(address(wMLP), _token);
        (amountWrappedMLP, amountToken) = address(wMLP) == token0
            ? (amount0, amount1)
            : (amount1, amount0);
        require(
            amountWrappedMLP >= _amountWrappedMLPMin,
            "Router: INSUFFICIENT_A_AMOUNT"
        );
        require(
            amountToken >= _amountTokenMin,
            "Router: INSUFFICIENT_B_AMOUNT"
        );

        // send our FTM and token to their final destination
        _safeTransfer(_token, _to, amountToken);
        amountUnderlying = _withdrawFromWrappedMLP(address(wftm));
        wftm.withdraw(amountUnderlying);
        _safeTransferETH(_to, amountUnderlying);
    }

    /**
     * @notice
     *  Exercise our oToken options using one of wMLP's underlying tokens.
     * @param _oToken The option token we are exercising.
     * @param _tokenToUse Address of our desired wMLP underlying to use for exercising
     *  our option.
     * @param _amount The amount of our token to use to generate our wMLP for exercising.
     * @param _oTokenAmount The amount of option tokens to exercise.
     * @param _discount Our discount in exercising the option; this determines our lockup
     *  time.
     * @param _deadline Deadline for transaction to complete.
     * @return paymentAmount How much wMLP we spend to exercise.
     * @return lpAmount Amount of our LP we generate.
     */
    function exerciseLpWithUnderlying(
        address _oToken,
        address _tokenToUse,
        uint256 _amount,
        uint256 _oTokenAmount,
        uint256 _discount,
        uint256 _deadline
    ) external returns (uint256 paymentAmount, uint256 lpAmount) {
        // first person does the approvals for everyone else, what a nice person!
        _checkAllowance(_oToken);

        // transfer in our funds
        _safeTransferFrom(_tokenToUse, msg.sender, address(this), _amount);
        _safeTransferFrom(_oToken, msg.sender, address(this), _oTokenAmount);
        uint256 wBltToLp = _depositToWrappedMLP(_tokenToUse);

        (paymentAmount, lpAmount) = IBMX(_oToken).exerciseLp(
            _oTokenAmount,
            wBltToLp,
            msg.sender,
            _discount,
            _deadline
        );

        // return any leftover wMLP or underlying
        IERC20 token = IERC20(_tokenToUse);
        uint256 remainingUnderlying = token.balanceOf(address(this));
        uint256 remainingBalance = wMLP.balanceOf(address(this));

        if (remainingBalance > 0) {
            _safeTransfer(address(wMLP), msg.sender, remainingBalance);
        }

        if (remainingUnderlying > 0) {
            _safeTransfer(_tokenToUse, msg.sender, remainingUnderlying);
        }
    }

    /**
     * @notice
     *  Exercise our oToken options using raw FTM.
     * @param _oToken The option token we are exercising.
     * @param _amount The amount of FTM to use to generate our wMLP for exercising.
     * @param _oTokenAmount The amount of option tokens to exercise.
     * @param _discount Our discount in exercising the option; this determines our lockup
     *  time.
     * @param _deadline Deadline for transaction to complete.
     * @return paymentAmount How much wMLP we spend to exercise.
     * @return lpAmount Amount of our LP we generate.
     */
    function exerciseLpWithUnderlyingETH(
        address _oToken,
        uint256 _amount,
        uint256 _oTokenAmount,
        uint256 _discount,
        uint256 _deadline
    ) external payable returns (uint256 paymentAmount, uint256 lpAmount) {
        // first person does the approvals for everyone else, what a nice person!
        _checkAllowance(_oToken);

        // deposit to wftm, then everything is the same
        wftm.deposit{value: _amount}();
        if (wftm.balanceOf(address(this)) != _amount) {
            revert("WFTM not sent");
        }

        // pull oToken
        _safeTransferFrom(_oToken, msg.sender, address(this), _oTokenAmount);

        // deposit our WFTM to wMLP
        uint256 wBltToLp = _depositToWrappedMLP(address(wftm));

        // exercise as normal
        (paymentAmount, lpAmount) = IBMX(_oToken).exerciseLp(
            _oTokenAmount,
            wBltToLp,
            msg.sender,
            _discount,
            _deadline
        );

        // return any leftover wMLP or WFTM
        uint256 remainingUnderlying = wftm.balanceOf(address(this));
        uint256 remainingBalance = wMLP.balanceOf(address(this));

        if (remainingBalance > 0) {
            _safeTransfer(address(wMLP), msg.sender, remainingBalance);
        }

        if (remainingUnderlying > 0) {
            _safeTransfer(address(wftm), msg.sender, remainingUnderlying);
        }
    }

    // helper to approve new oTokens to spend wMLP from this router
    function _checkAllowance(address _token) internal {
        if (wMLP.allowance(address(this), _token) == 0) {
            wMLP.approve(_token, type(uint256).max);
        }
    }

    /**
     * @notice
     *  Check how much underlying (or FTM) we need to exercise to LP.
     * @param _oToken The option token we are exercising.
     * @param _tokenToUse The token to deposit to wMLP.
     * @param _oTokenAmount The amount of oToken to exercise.
     * @param _discount Our discount in exercising the option; this determines our lockup
     *  time.
     * @return atomicAmount The amount of token needed if exercising atomically from this
     *  calculation.
     * @return safeAmount Add an extra 0.01% to allow for per-second wMLP share price
     *  increases.
     */
    function quoteTokenNeededToExerciseLp(
        address _oToken,
        address _tokenToUse,
        uint256 _oTokenAmount,
        uint256 _discount
    ) external view returns (uint256 atomicAmount, uint256 safeAmount) {
        // calculate the exact amount we need
        (uint256 amountNeeded, uint256 amount2) = IBMX(_oToken)
            .getPaymentTokenAmountForExerciseLp(_oTokenAmount, _discount);

        amountNeeded += amount2;

        atomicAmount = quoteMintAmountMLP(_tokenToUse, amountNeeded);

        // give ourselves 0.01% of space for wMLP share price rising
        safeAmount = (atomicAmount * 10_001) / 10_000;
    }

    /**
     * @notice
     *  Check how much wMLP we get from a given amount of underlying.
     * @dev Since this uses minPrice, we likely underestimate wMLP received. By using
     *  normal solidity division, we are also truncating (rounding down) all operations.
     * @param _token The token to deposit to wMLP.
     * @param _amount The amount of the token to deposit.
     * @return wrappedMLPMintAmount Amount of wMLP received.
     */
    function getMintAmountWrappedMLP(
        address _token,
        uint256 _amount
    ) public view returns (uint256 wrappedMLPMintAmount) {
        require(_amount > 0, "invalid _amount");

        // calculate aum before buyUSDG
        (uint256 aumInUsdg, uint256 mlpSupply) = _getMlpInfo(true);
        uint256 price = morphexVault.getMinPrice(_token);

        // save some gas
        uint256 _precision = PRICE_PRECISION;
        uint256 _divisor = BASIS_POINTS_DIVISOR;

        uint256 usdgAmount = (_amount * price) / _precision;
        usdgAmount = morphexVault.adjustForDecimals(
            usdgAmount,
            _token,
            morphexVault.usdg()
        );

        uint256 feeBasisPoints = vaultUtils.getBuyUsdgFeeBasisPoints(
            _token,
            usdgAmount
        );
        uint256 afterFeeAmount = (_amount * (_divisor - feeBasisPoints)) /
            _divisor;

        uint256 usdgMintAmount = (afterFeeAmount * price) / _precision;
        usdgMintAmount = morphexVault.adjustForDecimals(
            usdgMintAmount,
            _token,
            morphexVault.usdg()
        );
        uint256 MLPMintAmount = aumInUsdg == 0
            ? usdgMintAmount
            : (usdgMintAmount * mlpSupply) / aumInUsdg;

        // convert our MLP amount to wMLP
        wrappedMLPMintAmount = shareValueHelper.amountToShares(
            address(wMLP),
            MLPMintAmount,
            false
        );
    }

    /**
     * @notice
     *  Check how much underlying we get from redeeming a given amount of wMLP.
     * @dev By default we round down and use getMaxPrice to underestimate underlying
     *  received. This is important so that we don't ever revert in a swap due to
     *  overestimation, as getAmountsOut calls this function.
     * @param _tokenOut The token to withdraw from wMLP.
     * @param _amount The amount of wMLP to burn.
     * @param _roundUp Whether we round up or not.
     * @return underlyingReceived Amount of underlying token received.
     */
    function getRedeemAmountWrappedMLP(
        address _tokenOut,
        uint256 _amount,
        bool _roundUp
    ) public view returns (uint256 underlyingReceived) {
        require(_amount > 0, "invalid _amount");

        // convert our wMLP amount to MLP
        _amount = shareValueHelper.sharesToAmount(
            address(wMLP),
            _amount,
            _roundUp
        );

        // convert our MLP to bUSD (USDG)
        (uint256 aumInUsdg, uint256 mlpSupply) = _getMlpInfo(false);
        uint256 usdgAmount;

        // round up if needed
        if (_roundUp) {
            usdgAmount = Math.ceilDiv((_amount * aumInUsdg), mlpSupply);
        } else {
            usdgAmount = (_amount * aumInUsdg) / mlpSupply;
        }

        // use min or max price depending on how we want to estimate
        uint256 price;
        if (_roundUp) {
            price = morphexVault.getMinPrice(_tokenOut);
        } else {
            price = morphexVault.getMaxPrice(_tokenOut);
        }

        // convert USDG to _tokenOut amounts. no need to round this one since we adjust
        //  decimals and compensate below

        uint256 redeemAmount = (usdgAmount * PRICE_PRECISION) / price;

        redeemAmount = morphexVault.adjustForDecimals(
            redeemAmount,
            morphexVault.usdg(),
            _tokenOut
        );

        // add one wei to compensate for truncating when adjusting decimals
        if (_roundUp) {
            redeemAmount += 1;
        }

        // calculate our fees
        uint256 feeBasisPoints = vaultUtils.getSellUsdgFeeBasisPoints(
            _tokenOut,
            usdgAmount
        );

        // save some gas
        uint256 _divisor = BASIS_POINTS_DIVISOR;

        // adjust for fees, round up if needed
        if (_roundUp) {
            underlyingReceived = Math.ceilDiv(
                (redeemAmount * (_divisor - feeBasisPoints)),
                _divisor
            );
        } else {
            underlyingReceived = ((redeemAmount * (_divisor - feeBasisPoints)) /
                _divisor);
        }
    }

    /**
     * @notice
     *  Check how much wMLP we need to redeem for a given amount of underlying.
     * @dev Here we do everything we can, including adding an additional Wei of Defeat, to
     *  ensure that our estimated wMLP amount always provides enough underlying.
     * @param _underlyingToken The token to withdraw from wMLP.
     * @param _amount The amount of underlying we need.
     * @return wMLPAmount Amount of wMLP needed.
     */
    function quoteRedeemAmountMLP(
        address _underlyingToken,
        uint256 _amount
    ) external view returns (uint256 wMLPAmount) {
        require(_amount > 0, "invalid _amount");

        // add an additional wei to our input amount because of persistent rounding
        //  issues, AKA the Wei of Defeat
        _amount += 1;

        // get our info for MLP
        (uint256 aumInUsdg, uint256 mlpSupply) = _getMlpInfo(false);

        // convert our underlying amount to USDG
        uint256 underlyingPrice = morphexVault.getMaxPrice(_underlyingToken);
        uint256 usdgNeeded = Math.ceilDiv(
            (_amount * underlyingPrice),
            PRICE_PRECISION
        );

        // convert USDG needed to MLP. no need for rounding here since we will truncate
        //  in the next step anyway
        uint256 mlpAmount = (usdgNeeded * mlpSupply) / aumInUsdg;

        mlpAmount = morphexVault.adjustForDecimals(
            mlpAmount,
            morphexVault.usdg(),
            _underlyingToken
        );

        // add one wei since adjustForDecimals truncates instead of rounding up
        mlpAmount += 1;

        // save some gas
        uint256 _divisor = BASIS_POINTS_DIVISOR;

        // check current fees
        uint256 feeBasisPoints = vaultUtils.getSellUsdgFeeBasisPoints(
            _underlyingToken,
            usdgNeeded
        );

        // adjust for fees
        mlpAmount = Math.ceilDiv(
            (mlpAmount * _divisor),
            (_divisor - feeBasisPoints)
        );

        // convert our MLP to wMLP
        wMLPAmount = shareValueHelper.amountToShares(
            address(wMLP),
            mlpAmount,
            true
        );
    }

    /**
     * @notice
     *  Check how much underlying we need to mint a given amount of wMLP.
     * @dev Since this uses minPrice, we likely overestimate underlying
     *  needed. To be cautious of rounding down, use ceiling division.
     * @param _underlyingToken The token to deposit to wMLP.
     * @param _amount The amount of wMLP we need.
     * @return startingTokenAmount Amount of underlying token needed.
     */
    function quoteMintAmountMLP(
        address _underlyingToken,
        uint256 _amount
    ) public view returns (uint256 startingTokenAmount) {
        require(_amount > 0, "invalid _amount");

        // convert our wMLP amount to MLP
        _amount = shareValueHelper.sharesToAmount(address(wMLP), _amount, true);

        // convert our MLP to bUSD (USDG)
        // maximize here to use max MLP price, to make sure we get enough MLP out
        (uint256 aumInUsdg, uint256 mlpSupply) = _getMlpInfo(true);
        uint256 usdgAmount = Math.ceilDiv((_amount * aumInUsdg), mlpSupply);

        // price is returned in 1e30 from vault
        uint256 tokenPrice = morphexVault.getMinPrice(_underlyingToken);

        startingTokenAmount = Math.ceilDiv(
            usdgAmount * PRICE_PRECISION,
            tokenPrice
        );

        startingTokenAmount = morphexVault.adjustForDecimals(
            startingTokenAmount,
            morphexVault.usdg(),
            _underlyingToken
        );

        // add one wei since adjustForDecimals truncates instead of rounding up
        startingTokenAmount += 1;

        // calculate extra needed due to fees
        uint256 feeBasisPoints = vaultUtils.getBuyUsdgFeeBasisPoints(
            _underlyingToken,
            usdgAmount
        );

        // save some gas
        uint256 _divisor = BASIS_POINTS_DIVISOR;

        startingTokenAmount = Math.ceilDiv(
            startingTokenAmount * _divisor,
            (_divisor - feeBasisPoints)
        );
    }

    // standard data needed to calculate MLP pricing
    function _getMlpInfo(
        bool _maximize
    ) internal view returns (uint256 aumInUsdg, uint256 mlpSupply) {
        mlpSupply = sMLP.totalSupply();
        aumInUsdg = mlpManager.getAumInUsdg(_maximize);
    }

    // check if a token is in MLP
    function _isMLPToken(address _tokenToCheck) internal view returns (bool) {
        for (uint256 i = 0; i < mlpTokens.length; ++i) {
            if (mlpTokens[i] == _tokenToCheck) {
                return true;
            }
        }
        return false;
    }

    // withdraw all of the wMLP we have to a given underlying token
    function _withdrawFromWrappedMLP(
        address _targetToken
    ) internal returns (uint256) {
        if (!_isMLPToken(_targetToken)) {
            revert("Token not in wMLP");
        }

        // withdraw from the vault first, make sure it comes here
        uint256 toWithdraw = wMLP.withdraw(type(uint256).max, address(this));

        // withdraw our targetToken
        return
            rewardRouter.unstakeAndRedeemGlp(
                _targetToken,
                toWithdraw,
                0,
                address(this)
            );
    }

    /**
     * @notice Withdraws a specified amount of wMLP to a target underlying token.
     * @param _receiver The address to receive underlying tokens to.
     * @param _targetToken The address of the target token to which the wMLP is withdrawn.
     * @param _amount The amount of wMLP to withdraw.
     * @return amountWithdrawn The amount of target tokens received from the withdrawal.
     */
    function withdrawFromWrappedMLP(address _receiver, address _targetToken, uint256 _amount) external returns (uint256) {
        // Transfer wMLP from the user to the router
        _safeTransferFrom(address(wMLP), msg.sender, address(this), _amount);

        if (!_isMLPToken(_targetToken)) {
            revert("Token not in wMLP");
        }

        // withdraw from the vault first, make sure it comes here
        uint256 toWithdraw = wMLP.withdraw(type(uint256).max, address(this));

        // withdraw our targetToken
        return
            rewardRouter.unstakeAndRedeemGlp(
                _targetToken,
                toWithdraw,
                0,
                _receiver
            );
    }

    // deposit all of the underlying we have to wMLP
    function _depositToWrappedMLP(
        address _fromToken
    ) internal returns (uint256 tokens) {
        if (!_isMLPToken(_fromToken)) {
            revert("Token not in wMLP");
        }

        // deposit to MLP and then the vault
        IERC20 token = IERC20(_fromToken);
        uint256 newMlp = rewardRouter.mintAndStakeGlp(
            address(_fromToken),
            token.balanceOf(address(this)),
            0,
            0
        );

        // specify that router should get the vault tokens
        tokens = wMLP.deposit(newMlp, address(this));
    }

    /**
     * @notice Deposits a specified amount of an underlying token to wMLP.
     * @param _receiver The address to receive underlying tokens to.
     * @param _fromToken The address of the token to be deposited to wMLP.
     * @param _amount The amount of the token to deposit.
     * @return amountReceived The amount of wMLP received from the deposit.
     */
    function depositToWrappedMLP(address _receiver, address _fromToken, uint256 _amount) external returns (uint256 amountReceived) {
        // Transfer the _fromToken from the user to the contract
        _safeTransferFrom(_fromToken, msg.sender, address(this), _amount);

        if (!_isMLPToken(_fromToken)) {
            revert("Token not in wMLP");
        }

        // deposit to MLP and then the vault
        IERC20 token = IERC20(_fromToken);
        uint256 newMlp = rewardRouter.mintAndStakeGlp(
            address(_fromToken),
            token.balanceOf(address(this)),
            0,
            0
        );

        // specify that user should get the vault tokens
        amountReceived = wMLP.deposit(newMlp, _receiver);
    }

    /**
     * @notice
     *  Zap out into a wMLP LP with an underlying token.
     * @param _underlyingToken The token to zap in to wMLP.
     * @param _token The token paired with wMLP.
     * @param _amountUnderlyingDesired The amount of underlying we would like to deposit.
     * @param _amountTokenDesired The amount of token to pair with our wMLP.
     * @return amountUnderlying Amount of underlying token to deposit.
     * @return amountWrappedMLP Amount of wMLP we will deposit.
     * @return amountToken Amount of other token to deposit.
     * @return liquidity Amount of LP token received.
     */
    function quoteAddLiquidityUnderlying(
        address _underlyingToken,
        address _token,
        uint256 _amountUnderlyingDesired,
        uint256 _amountTokenDesired
    )
        external
        view
        returns (
            uint256 amountUnderlying,
            uint256 amountWrappedMLP,
            uint256 amountToken,
            uint256 liquidity
        )
    {
        // create the pair if it doesn't exist yet
        address _pair = IPairFactory(factory).getPair(
            address(wMLP),
            _token,
            false
        );
        (uint256 reserveA, uint256 reserveB) = (0, 0);
        uint256 _totalSupply = 0;

        // convert our _amountUnderlyingDesired to amountWrappedMLPDesired. make sure to
        //  underestimate the amount out here so no risk of reverting
        uint256 amountWrappedMLPDesired = getMintAmountWrappedMLP(
            _underlyingToken,
            _amountUnderlyingDesired
        );

        if (_pair != address(0)) {
            _totalSupply = IERC20(_pair).totalSupply();
            (reserveA, reserveB) = getReserves(address(wMLP), _token, false);
        }
        if (reserveA == 0 && reserveB == 0) {
            (amountWrappedMLP, amountToken) = (
                amountWrappedMLPDesired,
                _amountTokenDesired
            );
            liquidity =
                Math.sqrt(amountWrappedMLP * amountToken) -
                MINIMUM_LIQUIDITY;
        } else {
            uint256 amountTokenOptimal = _quoteLiquidity(
                amountWrappedMLPDesired,
                reserveA,
                reserveB
            );
            if (amountTokenOptimal <= _amountTokenDesired) {
                (amountWrappedMLP, amountToken) = (
                    amountWrappedMLPDesired,
                    amountTokenOptimal
                );
                liquidity = Math.min(
                    (amountWrappedMLP * _totalSupply) / reserveA,
                    (amountToken * _totalSupply) / reserveB
                );
            } else {
                uint256 amountWrappedMLPOptimal = _quoteLiquidity(
                    _amountTokenDesired,
                    reserveB,
                    reserveA
                );
                (amountWrappedMLP, amountToken) = (
                    amountWrappedMLPOptimal,
                    _amountTokenDesired
                );
                liquidity = Math.min(
                    (amountWrappedMLP * _totalSupply) / reserveA,
                    (amountToken * _totalSupply) / reserveB
                );
            }
        }
        // based on the amount of wMLP, calculate how much of our underlying token we
        //  need to zap in
        amountUnderlying = quoteMintAmountMLP(
            _underlyingToken,
            amountWrappedMLP
        );
    }

    /**
     * @notice
     *  Zap out from a wMLP LP to an underlying token.
     * @param _underlyingToken The token to withdraw from wMLP.
     * @param _token The token paired with wMLP.
     * @param _liquidity The amount of wMLP LP to burn.
     * @return amountUnderlying Amount of underlying token received.
     * @return amountWrappedMLP Amount of wMLP token received before being converted to
     *  underlying.
     * @return amountToken Amount of other token received.
     */
    function quoteRemoveLiquidityUnderlying(
        address _underlyingToken,
        address _token,
        uint256 _liquidity
    )
        external
        view
        returns (
            uint256 amountUnderlying,
            uint256 amountWrappedMLP,
            uint256 amountToken
        )
    {
        // create the pair if it doesn't exist yet
        address _pair = IPairFactory(factory).getPair(
            address(wMLP),
            _token,
            false
        );

        if (_pair == address(0)) {
            return (0, 0, 0);
        }

        (uint256 reserveA, uint256 reserveB) = getReserves(
            address(wMLP),
            _token,
            false
        );
        uint256 _totalSupply = IERC20(_pair).totalSupply();

        // using balances ensures pro-rata distribution
        amountWrappedMLP = (_liquidity * reserveA) / _totalSupply;

        // using balances ensures pro-rata distribution
        amountToken = (_liquidity * reserveB) / _totalSupply;

        // simulate zapping out of wMLP to the selected underlying
        amountUnderlying = getRedeemAmountWrappedMLP(
            _underlyingToken,
            amountWrappedMLP,
            false
        );
    }

    /* ========== UNMODIFIED FUNCTIONS ========== */

    // calculates the CREATE2 address for a pair without making any external calls
    function pairFor(
        address _tokenA,
        address _tokenB,
        bool _stable
    ) public view returns (address pair) {
        (address token0, address token1) = sortTokens(_tokenA, _tokenB);
        pair = address(
            uint160(
                uint256(
                    keccak256(
                        abi.encodePacked(
                            hex"ff",
                            factory,
                            keccak256(
                                abi.encodePacked(token0, token1, _stable)
                            ),
                            pairCodeHash // init code hash
                        )
                    )
                )
            )
        );
    }

    function sortTokens(
        address _tokenA,
        address _tokenB
    ) public pure returns (address token0, address token1) {
        require(_tokenA != _tokenB, "Router: IDENTICAL_ADDRESSES");
        (token0, token1) = _tokenA < _tokenB
            ? (_tokenA, _tokenB)
            : (_tokenB, _tokenA);
        require(token0 != address(0), "Router: ZERO_ADDRESS");
    }

    // fetches and sorts the reserves for a pair
    function getReserves(
        address _tokenA,
        address _tokenB,
        bool _stable
    ) public view returns (uint256 reserveA, uint256 reserveB) {
        (address token0, ) = sortTokens(_tokenA, _tokenB);
        (uint256 reserve0, uint256 reserve1, ) = IPair(
            pairFor(_tokenA, _tokenB, _stable)
        ).getReserves();
        (reserveA, reserveB) = _tokenA == token0
            ? (reserve0, reserve1)
            : (reserve1, reserve0);
    }

    // determine whether to use stable or volatile pools for a given pair of tokens
    function getAmountOut(
        uint256 _amountIn,
        address _tokenIn,
        address _tokenOut
    ) public view returns (uint256 amount, bool stable) {
        address pair = pairFor(_tokenIn, _tokenOut, true);
        uint256 amountStable;
        uint256 amountVolatile;
        if (IPairFactory(factory).isPair(pair)) {
            amountStable = IPair(pair).getAmountOut(_amountIn, _tokenIn);
        }
        pair = pairFor(_tokenIn, _tokenOut, false);
        if (IPairFactory(factory).isPair(pair)) {
            amountVolatile = IPair(pair).getAmountOut(_amountIn, _tokenIn);
        }
        return
            amountStable > amountVolatile
                ? (amountStable, true)
                : (amountVolatile, false);
    }

    //@override
    //getAmountOut	:	bool stable
    //Gets exact output for specific pair-type(S|V)
    function getAmountOut(
        uint256 _amountIn,
        address _tokenIn,
        address _tokenOut,
        bool _stable
    ) public view returns (uint256 amount) {
        address pair = pairFor(_tokenIn, _tokenOut, _stable);
        if (IPairFactory(factory).isPair(pair)) {
            amount = IPair(pair).getAmountOut(_amountIn, _tokenIn);
        }
    }

    // given some amount of an asset and pair reserves, returns an equivalent amount of
    //  the other asset
    function _quoteLiquidity(
        uint256 _amountA,
        uint256 _reserveA,
        uint256 _reserveB
    ) internal pure returns (uint256 amountB) {
        require(_amountA > 0, "Router: INSUFFICIENT_AMOUNT");
        require(
            _reserveA > 0 && _reserveB > 0,
            "Router: INSUFFICIENT_LIQUIDITY"
        );
        amountB = (_amountA * _reserveB) / _reserveA;
    }

    function _addLiquidity(
        address _tokenA,
        address _tokenB,
        bool _stable,
        uint256 _amountADesired,
        uint256 _amountBDesired,
        uint256 _amountAMin,
        uint256 _amountBMin
    ) internal returns (uint256 amountA, uint256 amountB) {
        require(_amountADesired >= _amountAMin);
        require(_amountBDesired >= _amountBMin);

        address _pair = IPairFactory(factory).getPair(
            _tokenA,
            _tokenB,
            _stable
        );
        if (_pair == address(0)) {
            _pair = IPairFactory(factory).createPair(_tokenA, _tokenB, _stable);
        }

        // desired is the amount desired to be deposited for each token
        // optimal of one asset is the amount that is equal in value to our desired of the
        //  other asset
        // so, if our optimal is less than our min, we have an issue and pricing is likely
        //  off
        (uint256 reserveA, uint256 reserveB) = getReserves(
            _tokenA,
            _tokenB,
            _stable
        );
        if (reserveA == 0 && reserveB == 0) {
            (amountA, amountB) = (_amountADesired, _amountBDesired);
        } else {
            uint256 amountBOptimal = _quoteLiquidity(
                _amountADesired,
                reserveA,
                reserveB
            );
            if (amountBOptimal <= _amountBDesired) {
                require(
                    amountBOptimal >= _amountBMin,
                    "Router: INSUFFICIENT_B_AMOUNT"
                );
                (amountA, amountB) = (_amountADesired, amountBOptimal);
            } else {
                uint256 amountAOptimal = _quoteLiquidity(
                    _amountBDesired,
                    reserveB,
                    reserveA
                );
                assert(amountAOptimal <= _amountADesired);
                require(
                    amountAOptimal >= _amountAMin,
                    "Router: INSUFFICIENT_A_AMOUNT"
                );
                (amountA, amountB) = (amountAOptimal, _amountBDesired);
            }
        }
    }

    function _safeTransferETH(address _to, uint256 _value) internal {
        (bool success, ) = _to.call{value: _value}(new bytes(0));
        require(success, "TransferHelper: FTM_TRANSFER_FAILED");
    }

    function _safeTransfer(
        address _token,
        address _to,
        uint256 _value
    ) internal {
        require(_token.code.length > 0);
        (bool success, bytes memory data) = _token.call(
            abi.encodeWithSelector(IERC20.transfer.selector, _to, _value)
        );
        require(success && (data.length == 0 || abi.decode(data, (bool))));
    }

    function _safeTransferFrom(
        address _token,
        address _from,
        address _to,
        uint256 _value
    ) internal {
        require(_token.code.length > 0);
        (bool success, bytes memory data) = _token.call(
            abi.encodeWithSelector(
                IERC20.transferFrom.selector,
                _from,
                _to,
                _value
            )
        );
        require(success && (data.length == 0 || abi.decode(data, (bool))));
    }
}

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_underlyingToken","type":"address"},{"internalType":"uint256","name":"_amountToZapIn","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"_amountWrappedMLPDesired","type":"uint256"},{"internalType":"uint256","name":"_amountTokenDesired","type":"uint256"},{"internalType":"uint256","name":"_amountWrappedMLPMin","type":"uint256"},{"internalType":"uint256","name":"_amountTokenMin","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"addLiquidity","outputs":[{"internalType":"uint256","name":"amountWrappedMLP","type":"uint256"},{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountToZapIn","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"_amountWrappedMLPDesired","type":"uint256"},{"internalType":"uint256","name":"_amountTokenDesired","type":"uint256"},{"internalType":"uint256","name":"_amountWrappedMLPMin","type":"uint256"},{"internalType":"uint256","name":"_amountTokenMin","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"addLiquidityETH","outputs":[{"internalType":"uint256","name":"amountWrappedMLP","type":"uint256"},{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"address","name":"_fromToken","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"depositToWrappedMLP","outputs":[{"internalType":"uint256","name":"amountReceived","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_oToken","type":"address"},{"internalType":"address","name":"_tokenToUse","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_oTokenAmount","type":"uint256"},{"internalType":"uint256","name":"_discount","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"exerciseLpWithUnderlying","outputs":[{"internalType":"uint256","name":"paymentAmount","type":"uint256"},{"internalType":"uint256","name":"lpAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_oToken","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_oTokenAmount","type":"uint256"},{"internalType":"uint256","name":"_discount","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"exerciseLpWithUnderlyingETH","outputs":[{"internalType":"uint256","name":"paymentAmount","type":"uint256"},{"internalType":"uint256","name":"lpAmount","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountIn","type":"uint256"},{"internalType":"address","name":"_tokenIn","type":"address"},{"internalType":"address","name":"_tokenOut","type":"address"}],"name":"getAmountOut","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"stable","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountIn","type":"uint256"},{"internalType":"address","name":"_tokenIn","type":"address"},{"internalType":"address","name":"_tokenOut","type":"address"},{"internalType":"bool","name":"_stable","type":"bool"}],"name":"getAmountOut","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountIn","type":"uint256"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"}],"internalType":"struct wMLPRouter.Route[]","name":"_routes","type":"tuple[]"}],"name":"getAmountsOut","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"getMintAmountWrappedMLP","outputs":[{"internalType":"uint256","name":"wrappedMLPMintAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenOut","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bool","name":"_roundUp","type":"bool"}],"name":"getRedeemAmountWrappedMLP","outputs":[{"internalType":"uint256","name":"underlyingReceived","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenA","type":"address"},{"internalType":"address","name":"_tokenB","type":"address"},{"internalType":"bool","name":"_stable","type":"bool"}],"name":"getReserves","outputs":[{"internalType":"uint256","name":"reserveA","type":"uint256"},{"internalType":"uint256","name":"reserveB","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"mlpTokens","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenA","type":"address"},{"internalType":"address","name":"_tokenB","type":"address"},{"internalType":"bool","name":"_stable","type":"bool"}],"name":"pairFor","outputs":[{"internalType":"address","name":"pair","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_underlyingToken","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amountUnderlyingDesired","type":"uint256"},{"internalType":"uint256","name":"_amountTokenDesired","type":"uint256"}],"name":"quoteAddLiquidityUnderlying","outputs":[{"internalType":"uint256","name":"amountUnderlying","type":"uint256"},{"internalType":"uint256","name":"amountWrappedMLP","type":"uint256"},{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_underlyingToken","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"quoteMintAmountMLP","outputs":[{"internalType":"uint256","name":"startingTokenAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_underlyingToken","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"quoteRedeemAmountMLP","outputs":[{"internalType":"uint256","name":"wMLPAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_underlyingToken","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_liquidity","type":"uint256"}],"name":"quoteRemoveLiquidityUnderlying","outputs":[{"internalType":"uint256","name":"amountUnderlying","type":"uint256"},{"internalType":"uint256","name":"amountWrappedMLP","type":"uint256"},{"internalType":"uint256","name":"amountToken","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_oToken","type":"address"},{"internalType":"address","name":"_tokenToUse","type":"address"},{"internalType":"uint256","name":"_oTokenAmount","type":"uint256"},{"internalType":"uint256","name":"_discount","type":"uint256"}],"name":"quoteTokenNeededToExerciseLp","outputs":[{"internalType":"uint256","name":"atomicAmount","type":"uint256"},{"internalType":"uint256","name":"safeAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_targetToken","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_liquidity","type":"uint256"},{"internalType":"uint256","name":"_amountWrappedMLPMin","type":"uint256"},{"internalType":"uint256","name":"_amountTokenMin","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"removeLiquidity","outputs":[{"internalType":"uint256","name":"amountWrappedMLP","type":"uint256"},{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountUnderlying","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_liquidity","type":"uint256"},{"internalType":"uint256","name":"_amountWrappedMLPMin","type":"uint256"},{"internalType":"uint256","name":"_amountTokenMin","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"removeLiquidityETH","outputs":[{"internalType":"uint256","name":"amountWrappedMLP","type":"uint256"},{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountUnderlying","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenA","type":"address"},{"internalType":"address","name":"_tokenB","type":"address"}],"name":"sortTokens","outputs":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountIn","type":"uint256"},{"internalType":"uint256","name":"_amountOutMin","type":"uint256"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"}],"internalType":"struct wMLPRouter.Route[]","name":"_routes","type":"tuple[]"},{"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":"_amountIn","type":"uint256"},{"internalType":"uint256","name":"_amountOutMin","type":"uint256"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"}],"internalType":"struct wMLPRouter.Route[]","name":"_routes","type":"tuple[]"},{"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"},{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"stable","type":"bool"}],"internalType":"struct wMLPRouter.Route[]","name":"_routes","type":"tuple[]"},{"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":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updateAllowances","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"wftm","outputs":[{"internalType":"contract IWETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"address","name":"_targetToken","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawFromWrappedMLP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60e06040523480156200001157600080fd5b506200001d336200023d565b73472f3c3c9608fe0ae8d702f3f8a2d12c410c881a6001600160a01b0316639aab92486040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000070573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000096919062000627565b60805260405163095ea7b360e01b8152736e3e180b1c5742fc445f0bbdab7aa7b9025606309063095ea7b390620000ea9073ae4846b148a65782865a4849e940575f77359b2b906000199060040162000641565b6020604051808303816000875af11580156200010a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200013091906200065a565b506200013b6200025b565b73245cd6d33578de9af75a3c0c636c726b1a8cbdaa6001600160a01b03166395082d256040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200018e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001b4919062000627565b60a0818152505073245cd6d33578de9af75a3c0c636c726b1a8cbdaa6001600160a01b031663126082cf6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200020e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000234919062000627565b60c052620006ee565b600180546001600160a01b0319169055620002588162000541565b50565b6200026562000591565b60005b60025481101562000338576000600282815481106200028b576200028b62000685565b600091825260208220015460405163095ea7b360e01b81526001600160a01b039091169250829163095ea7b391620002dc91733a15bac2d87c89f08147353fc9ae27080631b73d9160040162000641565b6020604051808303816000875af1158015620002fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200032291906200065a565b50508062000330906200069b565b905062000268565b506200034760026000620005f2565b600073245cd6d33578de9af75a3c0c636c726b1a8cbdaa6001600160a01b03166362287a326040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200039c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003c2919062000627565b905060005b818110156200053d57604051630e468baf60e41b81526004810182905260009073245cd6d33578de9af75a3c0c636c726b1a8cbdaa9063e468baf090602401602060405180830381865afa15801562000424573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200044a9190620006c3565b60405163095ea7b360e01b81529091506001600160a01b0382169063095ea7b3906200049390733a15bac2d87c89f08147353fc9ae27080631b73d906000199060040162000641565b6020604051808303816000875af1158015620004b3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004d991906200065a565b50600280546001810182556000919091527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace0180546001600160a01b0319166001600160a01b039290921691909117905562000535816200069b565b9050620003c7565b5050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000546001600160a01b03163314620005f05760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640160405180910390fd5b565b50805460008255906000526020600020908101906200025891905b808211156200062357600081556001016200060d565b5090565b6000602082840312156200063a57600080fd5b5051919050565b6001600160a01b03929092168252602082015260400190565b6000602082840312156200066d57600080fd5b815180151581146200067e57600080fd5b9392505050565b634e487b7160e01b600052603260045260246000fd5b600060018201620006bc57634e487b7160e01b600052601160045260246000fd5b5060010190565b600060208284031215620006d657600080fd5b81516001600160a01b03811681146200067e57600080fd5b60805160a05160c051615fc86200074860003960008181611e1501528181612c010152818161329b01526136ae015260008181611cc901528181612be0015281816130ef01526134f8015260006110e50152615fc86000f3fe6080604052600436106101825760003560e01c806305a7cc62146101ab57806318a13086146101e55780631d0e30c21461021257806326ebe0111461023257806332155ad81461026d5780634c1ee03e1461029b5780634c64fc6b146102c8578063544caa561461030857806356a9a68b146103365780635e1e63251461034b5780635e60dab5146103805780636587e4ce146103a0578063682ff52e146103c0578063715018a6146103e057806379ba5097146103f55780637e9fde1e1461040a5780638050712e1461041d5780638da5cb5b1461043d5780639881fcb4146104525780639be434c1146104725780639dea548b14610485578063a0eaa71c146104a5578063aee599b7146104c5578063b105f0fc146104e5578063c0e3ee6b14610505578063c45a015514610525578063da21423114610547578063e30c397814610567578063e54f8fc01461057c578063f2fde38b1461059c578063f41766d8146105bc578063f4f3de4f146105dc578063f4f45b46146105ef57600080fd5b366101a65733600080516020615f73833981519152146101a4576101a461532c565b005b600080fd5b3480156101b757600080fd5b506101cb6101c6366004615357565b610611565b604080519283526020830191909152015b60405180910390f35b3480156101f157600080fd5b5061020561020036600461539d565b6106cc565b6040516101dc9190615442565b34801561021e57600080fd5b506101cb61022d366004615486565b610ba2565b34801561023e57600080fd5b5061025261024d3660046154df565b610d7a565b604080519384526020840192909252908201526060016101dc565b34801561027957600080fd5b5061028d61028836600461555b565b610f13565b6040519081526020016101dc565b3480156102a757600080fd5b506102bb6102b63660046155aa565b61105a565b6040516101dc91906155f5565b3480156102d457600080fd5b506102e86102e3366004615357565b611130565b6040805194855260208501939093529183015260608201526080016101dc565b34801561031457600080fd5b50610328610323366004615609565b611359565b6040516101dc929190615642565b34801561034257600080fd5b506101a4611437565b34801561035757600080fd5b5061036b61036636600461565c565b6116f2565b604080519283529015156020830152016101dc565b34801561038c57600080fd5b506101cb61039b3660046155aa565b61190e565b3480156103ac57600080fd5b506102526103bb366004615693565b6119c6565b3480156103cc57600080fd5b5061028d6103db3660046156e9565b611c01565b3480156103ec57600080fd5b506101a4611f5f565b34801561040157600080fd5b506101a4611f73565b610252610418366004615715565b611ff1565b34801561042957600080fd5b5061028d61043836600461555b565b61227e565b34801561044957600080fd5b506102bb612429565b34801561045e57600080fd5b5061020561046d366004615839565b612438565b6101cb6104803660046158f4565b612858565b34801561049157600080fd5b5061028d6104a03660046156e9565b612b34565b3480156104b157600080fd5b5061028d6104c03660046156e9565b612f98565b3480156104d157600080fd5b506102bb6104e0366004615938565b6132de565b3480156104f157600080fd5b5061028d610500366004615951565b613308565b34801561051157600080fd5b50610252610520366004615988565b613721565b34801561053157600080fd5b506102bb600080516020615f1383398151915281565b34801561055357600080fd5b5061028d6105623660046159ef565b6138f0565b34801561057357600080fd5b506102bb6139f3565b34801561058857600080fd5b5061025261059736600461555b565b613a02565b3480156105a857600080fd5b506101a46105b7366004615a42565b613b88565b3480156105c857600080fd5b506102056105d736600461539d565b613bee565b6102056105ea36600461539d565b613e1f565b3480156105fb57600080fd5b506102bb600080516020615f7383398151915281565b604051639e66645b60e01b815260048101839052602481018290526000908190819081906001600160a01b03891690639e66645b906044016040805180830381865afa158015610665573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106899190615a5f565b90925090506106988183615a99565b91506106a48783612f98565b93506127106106b585612711615aac565b6106bf9190615ad9565b9250505094509492505050565b606081428110156106f85760405162461bcd60e51b81526004016106ef90615afb565b60405180910390fd5b610754888787808060200260200160405190810160405280939291908181526020016000905b8282101561074a5761073b60608302860136819003810190615b24565b8152602001906001019061071e565b5050505050612438565b91508682600184516107669190615b40565b8151811061077657610776615b53565b6020026020010151101561079c5760405162461bcd60e51b81526004016106ef90615b69565b600080516020615f7383398151915286866107b8600182615b40565b8181106107c7576107c7615b53565b90506060020160200160208101906107df9190615a42565b6001600160a01b0316146108355760405162461bcd60e51b815260206004820152601d60248201527f526f757465723a20454e445f524f5554455f494e5f46544d5f424f5a4f00000060448201526064016106ef565b600080516020615f53833981519152868660008161085557610855615b53565b61086b9260206060909202019081019150615a42565b6001600160a01b031614806108be5750600080516020615f53833981519152868660008161089b5761089b615b53565b90506060020160200160208101906108b39190615a42565b6001600160a01b0316145b15610a42576108f4868660008181106108d9576108d9615b53565b6108ef9260206060909202019081019150615a42565b6140f9565b8061092857506109288686600081811061091057610910615b53565b90506060020160200160208101906108ef9190615a42565b156109805761097b8686600081811061094357610943615b53565b6109599260206060909202019081019150615a42565b33308560008151811061096e5761096e615b53565b6020026020010151614160565b610a58565b61097b8686600081811061099657610996615b53565b6109ac9260206060909202019081019150615a42565b33610a2f898960008181106109c3576109c3615b53565b6109d99260206060909202019081019150615a42565b8a8a60008181106109ec576109ec615b53565b9050606002016020016020810190610a049190615a42565b8b8b6000818110610a1757610a17615b53565b90506060020160400160208101906102b69190615bab565b8560008151811061096e5761096e615b53565b610a588686600081811061099657610996615b53565b610ab5828787808060200260200160405190810160405280939291908181526020016000905b82821015610aaa57610a9b60608302860136819003810190615b24565b81526020019060010190610a7e565b50505050503061425c565b6040516370a0823160e01b8152600090600080516020615f73833981519152906370a0823190610ae99030906004016155f5565b602060405180830381865afa158015610b06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b2a9190615bc8565b604051632e1a7d4d60e01b815260048101829052909150600080516020615f7383398151915290632e1a7d4d90602401600060405180830381600087803b158015610b7457600080fd5b505af1158015610b88573d6000803e3d6000fd5b50505050610b96858261474c565b50509695505050505050565b600080610bae8861481a565b610bba87333089614160565b610bc688333088614160565b6000610bd18861490d565b60405163f897bd1d60e01b81529091506001600160a01b038a169063f897bd1d90610c08908990859033908b908b90600401615be1565b60408051808303816000875af1158015610c26573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c4a9190615a5f565b6040516370a0823160e01b8152919450925088906000906001600160a01b038316906370a0823190610c809030906004016155f5565b602060405180830381865afa158015610c9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc19190615bc8565b6040516370a0823160e01b8152909150600090600080516020615f53833981519152906370a0823190610cf89030906004016155f5565b602060405180830381865afa158015610d15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d399190615bc8565b90508015610d5a57610d5a600080516020615f538339815191523383614aaa565b8115610d6b57610d6b8b3384614aaa565b50505050965096945050505050565b6000806000610d8b8b33308d614160565b610d948b61490d565b9750610db4600080516020615f538339815191528a60008b8b8b8b614ba3565b90935091506000610dd4600080516020615f538339815191528b8361105a565b9050610def600080516020615f538339815191528286614aaa565b610dfb8a338386614160565b6040516335313c2160e11b81526001600160a01b03821690636a62784290610e279088906004016155f5565b6020604051808303816000875af1158015610e46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e6a9190615bc8565b6040516370a0823160e01b8152909250600090600080516020615f53833981519152906370a0823190610ea19030906004016155f5565b602060405180830381865afa158015610ebe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ee29190615bc8565b90508015610f0357610f03600080516020615f538339815191523383614aaa565b5050985098509895505050505050565b6000610f2f600080516020615f53833981519152333085614160565b610f38836140f9565b610f545760405162461bcd60e51b81526004016106ef90615c0d565b604051627b8a6760e11b8152600090600080516020615f538339815191529062f714ce90610f8a90600019903090600401615c38565b6020604051808303816000875af1158015610fa9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fcd9190615bc8565b6040516303cea95560e21b815290915073d6489eaf13f61822356f30618e1d9947fa1ef46f90630f3aa5549061100e90879085906000908b90600401615c4f565b6020604051808303816000875af115801561102d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110519190615bc8565b95945050505050565b60008060006110698686611359565b604080516001600160601b0319606094851b81166020808401919091529390941b909316603484015295151560f81b6048830152855180830360290181526049830187528051908201206001600160f81b031960698401527323979e1e4b047f05746b8179fc5168962086440d60611b606a840152607e8301527f0000000000000000000000000000000000000000000000000000000000000000609e808401919091528651808403909101815260be909201909552805194019390932095945050505050565b6000806000806000600080516020615f138339815191526001600160a01b0316636801cc30600080516020615f538339815191528a60006040518463ffffffff1660e01b815260040161118593929190615c7a565b602060405180830381865afa1580156111a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111c69190615c9e565b905060008080806111d78d8c612b34565b90506001600160a01b0385161561126c57846001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611226573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061124a9190615bc8565b9150611266600080516020615f538339815191528d600061190e565b90945092505b83158015611278575082155b156112a9579650889550866103e86112986112938984615aac565b614d8b565b6112a29190615b40565b955061133d565b60006112b6828686614e7a565b90508a81116112ff57909750955086866112f8856112d48585615aac565b6112de9190615ad9565b856112e9868c615aac565b6112f39190615ad9565b614f3a565b965061133b565b600061130c8c8688614e7a565b99508b9850899050611337866113228684615aac565b61132c9190615ad9565b866112e9878d615aac565b9750505b505b6113478d89612f98565b98505050505050945094509450949050565b600080826001600160a01b0316846001600160a01b0316036113bb5760405162461bcd60e51b815260206004820152601b60248201527a526f757465723a204944454e544943414c5f41444452455353455360281b60448201526064016106ef565b826001600160a01b0316846001600160a01b0316106113db5782846113de565b83835b90925090506001600160a01b0382166114305760405162461bcd60e51b8152602060048201526014602482015273526f757465723a205a45524f5f4144445245535360601b60448201526064016106ef565b9250929050565b61143f614f54565b60005b6002548110156115065760006002828154811061146157611461615b53565b600091825260208220015460405163095ea7b360e01b81526001600160a01b039091169250829163095ea7b3916114b091733a15bac2d87c89f08147353fc9ae27080631b73d91600401615cbb565b6020604051808303816000875af11580156114cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f39190615cd4565b5050806114ff90615cf1565b9050611442565b50611513600260006152fa565b6000600080516020615f338339815191526001600160a01b03166362287a326040518163ffffffff1660e01b8152600401602060405180830381865afa158015611561573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115859190615bc8565b905060005b818110156116ee57604051630e468baf60e41b815260048101829052600090600080516020615f338339815191529063e468baf090602401602060405180830381865afa1580156115df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116039190615c9e565b60405163095ea7b360e01b81529091506001600160a01b0382169063095ea7b39061164a90733a15bac2d87c89f08147353fc9ae27080631b73d9060001990600401615cbb565b6020604051808303816000875af1158015611669573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061168d9190615cd4565b50600280546001810182556000919091527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace0180546001600160a01b0319166001600160a01b03929092169190911790556116e781615cf1565b905061158a565b5050565b60008060006117038585600161105a565b60405163e5e31b1360e01b81529091506000908190600080516020615f138339815191529063e5e31b139061173c9086906004016155f5565b602060405180830381865afa158015611759573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061177d9190615cd4565b156117f4576040516378a051ad60e11b81526001600160a01b0384169063f140a35a906117b0908b908b90600401615c38565b602060405180830381865afa1580156117cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117f19190615bc8565b91505b6118008787600061105a565b60405163e5e31b1360e01b8152909350600080516020615f138339815191529063e5e31b13906118349086906004016155f5565b602060405180830381865afa158015611851573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118759190615cd4565b156118ec576040516378a051ad60e11b81526001600160a01b0384169063f140a35a906118a8908b908b90600401615c38565b602060405180830381865afa1580156118c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118e99190615bc8565b90505b8082116118fb578060006118ff565b8160015b94509450505050935093915050565b600080600061191d8686611359565b50905060008061192e88888861105a565b6001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa15801561196b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061198f9190615d0a565b5091509150826001600160a01b0316886001600160a01b0316146119b45780826119b7565b81815b90999098509650505050505050565b6000806000806119e6600080516020615f538339815191528a600061105a565b6040516323b872dd60e01b81529091506001600160a01b038216906323b872dd90611a1990339085908d90600401615d38565b6020604051808303816000875af1158015611a38573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a5c9190615cd4565b611a6557600080fd5b600080826001600160a01b03166389afcb44306040518263ffffffff1660e01b8152600401611a9491906155f5565b60408051808303816000875af1158015611ab2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ad69190615a5f565b915091506000611af4600080516020615f538339815191528d611359565b509050600080516020615f538339815191526001600160a01b03821614611b1c578183611b1f565b82825b909750955089871015611b445760405162461bcd60e51b81526004016106ef90615d5c565b88861015611b645760405162461bcd60e51b81526004016106ef90615d93565b611b6f8c8988614aaa565b611b86600080516020615f73833981519152614fb3565b604051632e1a7d4d60e01b815260048101829052909550600080516020615f7383398151915290632e1a7d4d90602401600060405180830381600087803b158015611bd057600080fd5b505af1158015611be4573d6000803e3d6000fd5b50505050611bf2888661474c565b50505050955095509592505050565b6000808211611c225760405162461bcd60e51b81526004016106ef90615dca565b611c2d600183615a99565b9150600080611c3c60006150d7565b604051637092736960e11b81529193509150600090600080516020615f338339815191529063e124e6d290611c759089906004016155f5565b602060405180830381865afa158015611c92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cb69190615bc8565b90506000611ced611cc78388615aac565b7f00000000000000000000000000000000000000000000000000000000000000006151cf565b9050600084611cfc8584615aac565b611d069190615ad9565b9050600080516020615f338339815191526001600160a01b0316634215287382600080516020615f338339815191526001600160a01b031663f5b91b7b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d72573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d969190615c9e565b8b6040518463ffffffff1660e01b8152600401611db593929190615df3565b602060405180830381865afa158015611dd2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611df69190615bc8565b9050611e03600182615a99565b60405163eb0835bf60e01b81529091507f000000000000000000000000000000000000000000000000000000000000000090600090736280873ffdb6a9c8fd601b323f609800616273849063eb0835bf90611e64908d908890600401615cbb565b602060405180830381865afa158015611e81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ea59190615bc8565b9050611ec3611eb48385615aac565b611ebe8385615b40565b6151cf565b604051630f342ee960e01b815290935073b643724c5c364d1f1971edb7bab059cb9ab6567d90630f342ee990611f1090600080516020615f53833981519152908790600190600401615e12565b602060405180830381865afa158015611f2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f519190615bc8565b9a9950505050505050505050565b611f67614f54565b611f7160006151fd565b565b3380611f7d6139f3565b6001600160a01b031614611fe55760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016106ef565b611fee816151fd565b50565b6000806000600080516020615f738339815191526001600160a01b031663d0e30db08b6040518263ffffffff1660e01b81526004016000604051808303818588803b15801561203f57600080fd5b505af1158015612053573d6000803e3d6000fd5b50506040516370a0823160e01b81528d9350600080516020615f7383398151915292506370a08231915061208b9030906004016155f5565b602060405180830381865afa1580156120a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120cc9190615bc8565b146120e95760405162461bcd60e51b81526004016106ef90615e35565b612100600080516020615f7383398151915261490d565b9750612120600080516020615f538339815191528a60008b8b8b8b614ba3565b90935091506000612140600080516020615f538339815191528b8361105a565b905061215b600080516020615f538339815191528286614aaa565b6121678a338386614160565b6040516335313c2160e11b81526001600160a01b03821690636a627842906121939088906004016155f5565b6020604051808303816000875af11580156121b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121d69190615bc8565b6040516370a0823160e01b8152909250600090600080516020615f53833981519152906370a082319061220d9030906004016155f5565b602060405180830381865afa15801561222a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061224e9190615bc8565b9050801561226f5761226f600080516020615f538339815191523383614aaa565b50509750975097945050505050565b600061228c83333085614160565b612295836140f9565b6122b15760405162461bcd60e51b81526004016106ef90615c0d565b6040516370a0823160e01b8152839060009073d6489eaf13f61822356f30618e1d9947fa1ef46f9063364e23119084906001600160a01b038216906370a08231906123009030906004016155f5565b602060405180830381865afa15801561231d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123419190615bc8565b6000806040518563ffffffff1660e01b81526004016123639493929190615e5c565b6020604051808303816000875af1158015612382573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123a69190615bc8565b604051636e553f6560e01b8152909150600080516020615f5383398151915290636e553f65906123dc9084908a90600401615c38565b6020604051808303816000875af11580156123fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061241f9190615bc8565b9695505050505050565b6000546001600160a01b031690565b60606001825110156124835760405162461bcd60e51b81526020600482015260146024820152730a4deeae8cae47440929cac82989288bea082a8960631b60448201526064016106ef565b8151612490906001615a99565b6001600160401b038111156124a7576124a761577e565b6040519080825280602002602001820160405280156124d0578160200160208202803683370190505b50905082816000815181106124e7576124e7615b53565b60200260200101818152505060005b825181101561285157600080516020615f538339815191526001600160a01b031683828151811061252957612529615b53565b6020026020010151600001516001600160a01b0316036125e25761256983828151811061255857612558615b53565b6020026020010151602001516140f9565b156125dd576125b083828151811061258357612583615b53565b6020026020010151602001518383815181106125a1576125a1615b53565b60200260200101516000613308565b826125bc836001615a99565b815181106125cc576125cc615b53565b60200260200101818152505061283f565b612691565b600080516020615f538339815191526001600160a01b031683828151811061260c5761260c615b53565b6020026020010151602001516001600160a01b0316036126915761264c83828151811061263b5761263b615b53565b6020026020010151600001516140f9565b15612691576125b083828151811061266657612666615b53565b60200260200101516000015183838151811061268457612684615b53565b6020026020010151612b34565b60006126f58483815181106126a8576126a8615b53565b6020026020010151600001518584815181106126c6576126c6615b53565b6020026020010151602001518685815181106126e4576126e4615b53565b60200260200101516040015161105a565b60405163e5e31b1360e01b8152909150600080516020615f138339815191529063e5e31b13906127299084906004016155f5565b602060405180830381865afa158015612746573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061276a9190615cd4565b1561283d57806001600160a01b031663f140a35a84848151811061279057612790615b53565b60200260200101518685815181106127aa576127aa615b53565b6020026020010151600001516040518363ffffffff1660e01b81526004016127d3929190615c38565b602060405180830381865afa1580156127f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128149190615bc8565b83612820846001615a99565b8151811061283057612830615b53565b6020026020010181815250505b505b8061284981615cf1565b9150506124f6565b5092915050565b6000806128648761481a565b600080516020615f738339815191526001600160a01b031663d0e30db0876040518263ffffffff1660e01b81526004016000604051808303818588803b1580156128ad57600080fd5b505af11580156128c1573d6000803e3d6000fd5b50506040516370a0823160e01b8152899350600080516020615f7383398151915292506370a0823191506128f99030906004016155f5565b602060405180830381865afa158015612916573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061293a9190615bc8565b146129575760405162461bcd60e51b81526004016106ef90615e35565b61296387333088614160565b600061297c600080516020615f7383398151915261490d565b60405163f897bd1d60e01b81529091506001600160a01b0389169063f897bd1d906129b3908990859033908b908b90600401615be1565b60408051808303816000875af11580156129d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129f59190615a5f565b6040516370a0823160e01b81529194509250600090600080516020615f73833981519152906370a0823190612a2e9030906004016155f5565b602060405180830381865afa158015612a4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a6f9190615bc8565b6040516370a0823160e01b8152909150600090600080516020615f53833981519152906370a0823190612aa69030906004016155f5565b602060405180830381865afa158015612ac3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ae79190615bc8565b90508015612b0857612b08600080516020615f538339815191523383614aaa565b8115612b2757612b27600080516020615f738339815191523384614aaa565b5050509550959350505050565b6000808211612b555760405162461bcd60e51b81526004016106ef90615dca565b600080612b6260016150d7565b6040516340d3096b60e11b81529193509150600090600080516020615f33833981519152906381a612d690612b9b9089906004016155f5565b602060405180830381865afa158015612bb8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bdc9190615bc8565b90507f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000600082612c2d858a615aac565b612c379190615ad9565b9050600080516020615f338339815191526001600160a01b03166342152873828b600080516020615f338339815191526001600160a01b031663f5b91b7b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ca4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cc89190615c9e565b6040518463ffffffff1660e01b8152600401612ce693929190615df3565b602060405180830381865afa158015612d03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d279190615bc8565b60405163256f6ee360e11b8152909150600090736280873ffdb6a9c8fd601b323f6098006162738490634adeddc690612d66908d908690600401615cbb565b602060405180830381865afa158015612d83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612da79190615bc8565b9050600083612db68382615b40565b612dc0908c615aac565b612dca9190615ad9565b9050600085612dd98884615aac565b612de39190615ad9565b9050600080516020615f338339815191526001600160a01b03166342152873828e600080516020615f338339815191526001600160a01b031663f5b91b7b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612e50573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e749190615c9e565b6040518463ffffffff1660e01b8152600401612e9293929190615df3565b602060405180830381865afa158015612eaf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ed39190615bc8565b905060008915612ef75789612ee88a84615aac565b612ef29190615ad9565b612ef9565b815b604051630f342ee960e01b815290915073b643724c5c364d1f1971edb7bab059cb9ab6567d90630f342ee990612f4690600080516020615f53833981519152908590600090600401615e12565b602060405180830381865afa158015612f63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f879190615bc8565b9d9c50505050505050505050505050565b6000808211612fb95760405162461bcd60e51b81526004016106ef90615dca565b60405163fdda829560e01b815273b643724c5c364d1f1971edb7bab059cb9ab6567d9063fdda82959061300390600080516020615f53833981519152908690600190600401615e12565b602060405180830381865afa158015613020573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130449190615bc8565b915060008061305360016150d7565b9092509050600061306d6130678487615aac565b836151cf565b6040516340d3096b60e11b8152909150600090600080516020615f33833981519152906381a612d6906130a4908a906004016155f5565b602060405180830381865afa1580156130c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130e59190615bc8565b905061311a6131147f000000000000000000000000000000000000000000000000000000000000000084615aac565b826151cf565b9450600080516020615f338339815191526001600160a01b0316634215287386600080516020615f338339815191526001600160a01b031663f5b91b7b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613186573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131aa9190615c9e565b8a6040518463ffffffff1660e01b81526004016131c993929190615df3565b602060405180830381865afa1580156131e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061320a9190615bc8565b9450613217600186615a99565b60405163256f6ee360e11b8152909550600090736280873ffdb6a9c8fd601b323f6098006162738490634adeddc690613256908b908790600401615cbb565b602060405180830381865afa158015613273573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132979190615bc8565b90507f00000000000000000000000000000000000000000000000000000000000000006132d16132c78289615aac565b611ebe8484615b40565b9998505050505050505050565b600281815481106132ee57600080fd5b6000918252602090912001546001600160a01b0316905081565b60008083116133295760405162461bcd60e51b81526004016106ef90615dca565b60405163fdda829560e01b815273b643724c5c364d1f1971edb7bab059cb9ab6567d9063fdda82959061337290600080516020615f538339815191529087908790600401615e12565b602060405180830381865afa15801561338f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133b39190615bc8565b92506000806133c260006150d7565b91509150600084156133e2576133db6130678488615aac565b90506133fa565b816133ed8488615aac565b6133f79190615ad9565b90505b6000851561347b576040516340d3096b60e11b8152600080516020615f33833981519152906381a612d690613433908b906004016155f5565b602060405180830381865afa158015613450573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134749190615bc8565b90506134f0565b604051637092736960e11b8152600080516020615f338339815191529063e124e6d2906134ac908b906004016155f5565b602060405180830381865afa1580156134c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134ed9190615bc8565b90505b60008161351d7f000000000000000000000000000000000000000000000000000000000000000085615aac565b6135279190615ad9565b9050600080516020615f338339815191526001600160a01b0316634215287382600080516020615f338339815191526001600160a01b031663f5b91b7b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613593573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135b79190615c9e565b8c6040518463ffffffff1660e01b81526004016135d693929190615df3565b602060405180830381865afa1580156135f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136179190615bc8565b9050861561362d5761362a600182615a99565b90505b60405163eb0835bf60e01b8152600090736280873ffdb6a9c8fd601b323f609800616273849063eb0835bf90613669908d908890600401615cbb565b602060405180830381865afa158015613686573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136aa9190615bc8565b90507f000000000000000000000000000000000000000000000000000000000000000088156136f1576136ea6136e08383615b40565b6131149085615aac565b9750613713565b806136fc8382615b40565b6137069085615aac565b6137109190615ad9565b97505b505050505050509392505050565b600080600080613741600080516020615f538339815191528a600061105a565b6040516323b872dd60e01b81529091506001600160a01b038216906323b872dd9061377490339085908d90600401615d38565b6020604051808303816000875af1158015613793573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137b79190615cd4565b6137c057600080fd5b600080826001600160a01b03166389afcb44306040518263ffffffff1660e01b81526004016137ef91906155f5565b60408051808303816000875af115801561380d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138319190615a5f565b91509150600061384f600080516020615f538339815191528d611359565b509050600080516020615f538339815191526001600160a01b0382161461387757818361387a565b82825b90975095508987101561389f5760405162461bcd60e51b81526004016106ef90615d5c565b888610156138bf5760405162461bcd60e51b81526004016106ef90615d93565b6138ca8c8988614aaa565b6138d38d614fb3565b94506138e08d8987614aaa565b5050505096509650969350505050565b6000806138fe85858561105a565b60405163e5e31b1360e01b8152909150600080516020615f138339815191529063e5e31b13906139329084906004016155f5565b602060405180830381865afa15801561394f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139739190615cd4565b156139ea576040516378a051ad60e11b81526001600160a01b0382169063f140a35a906139a69089908990600401615c38565b602060405180830381865afa1580156139c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139e79190615bc8565b91505b50949350505050565b6001546001600160a01b031690565b600080600080600080516020615f138339815191526001600160a01b0316636801cc30600080516020615f538339815191528860006040518463ffffffff1660e01b8152600401613a5593929190615c7a565b602060405180830381865afa158015613a72573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a969190615c9e565b90506001600160a01b038116613ab757600080600093509350935050613b7f565b600080613ad4600080516020615f5383398151915289600061190e565b915091506000836001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613b18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b3c9190615bc8565b905080613b49848a615aac565b613b539190615ad9565b955080613b60838a615aac565b613b6a9190615ad9565b9450613b788a876000613308565b9650505050505b93509350939050565b613b90614f54565b600180546001600160a01b0319166001600160a01b038316908117909155613bb6612429565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b60608142811015613c115760405162461bcd60e51b81526004016106ef90615afb565b613c63888787808060200260200160405190810160405280939291908181526020016000905b8282101561074a57613c5460608302860136819003810190615b24565b81526020019060010190613c37565b9150868260018451613c759190615b40565b81518110613c8557613c85615b53565b60200260200101511015613cab5760405162461bcd60e51b81526004016106ef90615b69565b600080516020615f538339815191528686600081613ccb57613ccb615b53565b613ce19260206060909202019081019150615a42565b6001600160a01b03161480613d345750600080516020615f538339815191528686600081613d1157613d11615b53565b9050606002016020016020810190613d299190615a42565b6001600160a01b0316145b15613da157613d4f868660008181106108d9576108d9615b53565b80613d6b5750613d6b8686600081811061091057610910615b53565b15613d8b57613d868686600081811061094357610943615b53565b613db7565b613d868686600081811061099657610996615b53565b613db78686600081811061099657610996615b53565b613e14828787808060200260200160405190810160405280939291908181526020016000905b82821015613e0957613dfa60608302860136819003810190615b24565b81526020019060010190613ddd565b50505050508661425c565b509695505050505050565b60608142811015613e425760405162461bcd60e51b81526004016106ef90615afb565b613e94888787808060200260200160405190810160405280939291908181526020016000905b8282101561074a57613e8560608302860136819003810190615b24565b81526020019060010190613e68565b9150868260018451613ea69190615b40565b81518110613eb657613eb6615b53565b60200260200101511015613edc5760405162461bcd60e51b81526004016106ef90615b69565b600080516020615f738339815191526001600160a01b031663d0e30db0896040518263ffffffff1660e01b81526004016000604051808303818588803b158015613f2557600080fd5b505af1158015613f39573d6000803e3d6000fd5b50506040516370a0823160e01b81528b9350600080516020615f7383398151915292506370a082319150613f719030906004016155f5565b602060405180830381865afa158015613f8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fb29190615bc8565b14613fcf5760405162461bcd60e51b81526004016106ef90615e35565b600080516020615f738339815191528686600081613fef57613fef615b53565b6140059260206060909202019081019150615a42565b6001600160a01b031614158061405a5750600080516020615f53833981519152868660008161403657614036615b53565b905060600201602001602081019061404e9190615a42565b6001600160a01b031614155b156140a75760405162461bcd60e51b815260206004820152601d60248201527f526f757465206d757374207374617274205746544d202d3e20774d4c5000000060448201526064016106ef565b613e14828787808060200260200160405190810160405280939291908181526020016000905b82821015613e09576140ea60608302860136819003810190615b24565b815260200190600101906140cd565b6000805b60025481101561415757826001600160a01b03166002828154811061412457614124615b53565b6000918252602090912001546001600160a01b0316036141475750600192915050565b61415081615cf1565b90506140fd565b50600092915050565b6000846001600160a01b03163b1161417757600080fd5b600080856001600160a01b03166323b872dd60e01b8686866040516024016141a193929190615d38565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516141df9190615ea6565b6000604051808303816000865af19150503d806000811461421c576040519150601f19603f3d011682016040523d82523d6000602084013e614221565b606091505b509150915081801561424b57508051158061424b57508080602001905181019061424b9190615cd4565b61425457600080fd5b505050505050565b60005b82518110156147465760006142ae84838151811061427f5761427f615b53565b60200260200101516000015185848151811061429d5761429d615b53565b602002602001015160200151611359565b5090506000856142bf846001615a99565b815181106142cf576142cf615b53565b60200260200101519050600080836001600160a01b03168786815181106142f8576142f8615b53565b6020026020010151600001516001600160a01b03161461431a5782600061431e565b6000835b915091506000806000600080516020615f538339815191526001600160a01b03168a898151811061435157614351615b53565b6020026020010151600001516001600160a01b031603614405576143808a898151811061255857612558615b53565b15614400576143ab8a898151811061439a5761439a615b53565b602002602001015160200151614fb3565b915060018a516143bb9190615b40565b8810156143cb57600192506144a5565b6143f38a89815181106143e0576143e0615b53565b6020026020010151602001518a84614aaa565b5050505050505050505050565b6144a5565b600080516020615f538339815191526001600160a01b03168a898151811061442f5761442f615b53565b6020026020010151602001516001600160a01b0316036144a55761445e8a898151811061263b5761263b615b53565b156144a5576144898a898151811061447857614478615b53565b60200260200101516000015161490d565b915060018a516144999190615b40565b8810156143cb57600192505b60018a516144b39190615b40565b88036144c0575087614618565b6144df8a6144cf8a6001615a99565b8151811061263b5761263b615b53565b80156145285750600080516020615f538339815191528a6145018a6001615a99565b8151811061451157614511615b53565b6020026020010151602001516001600160a01b0316145b80614596575061454d8a61453d8a6001615a99565b8151811061255857612558615b53565b80156145965750600080516020615f538339815191528a61456f8a6001615a99565b8151811061457f5761457f615b53565b6020026020010151600001516001600160a01b0316145b156145a2575030614618565b6146158a6145b18a6001615a99565b815181106145c1576145c1615b53565b6020026020010151600001518b8a60016145db9190615a99565b815181106145eb576145eb615b53565b6020026020010151602001518c8b60016146059190615a99565b815181106126e4576126e4615b53565b90505b821561464b576146468a898151811061463357614633615b53565b6020026020010151602001518284614aaa565b61472c565b61469c8a898151811061466057614660615b53565b6020026020010151600001518b8a8151811061467e5761467e615b53565b6020026020010151602001518c8b815181106126e4576126e4615b53565b6001600160a01b031663022c0d9f86868460006040519080825280601f01601f1916602001820160405280156146d9576020820181803683370190505b506040518563ffffffff1660e01b81526004016146f99493929190615ec2565b600060405180830381600087803b15801561471357600080fd5b505af1158015614727573d6000803e3d6000fd5b505050505b50505050505050808061473e90615cf1565b91505061425f565b50505050565b604080516000808252602082019092526001600160a01b0384169083906040516147769190615ea6565b60006040518083038185875af1925050503d80600081146147b3576040519150601f19603f3d011682016040523d82523d6000602084013e6147b8565b606091505b50509050806148155760405162461bcd60e51b815260206004820152602360248201527f5472616e7366657248656c7065723a2046544d5f5452414e534645525f46414960448201526213115160ea1b60648201526084016106ef565b505050565b604051636eb1769f60e11b8152600080516020615f538339815191529063dd62ed3e9061484d9030908590600401615642565b602060405180830381865afa15801561486a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061488e9190615bc8565b600003611fee5760405163095ea7b360e01b8152600080516020615f538339815191529063095ea7b3906148ca90849060001990600401615cbb565b6020604051808303816000875af11580156148e9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116ee9190615cd4565b6000614918826140f9565b6149345760405162461bcd60e51b81526004016106ef90615c0d565b6040516370a0823160e01b8152829060009073d6489eaf13f61822356f30618e1d9947fa1ef46f9063364e23119084906001600160a01b038216906370a08231906149839030906004016155f5565b602060405180830381865afa1580156149a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149c49190615bc8565b6000806040518563ffffffff1660e01b81526004016149e69493929190615e5c565b6020604051808303816000875af1158015614a05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614a299190615bc8565b604051636e553f6560e01b8152909150600080516020615f5383398151915290636e553f6590614a5f9084903090600401615c38565b6020604051808303816000875af1158015614a7e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614aa29190615bc8565b949350505050565b6000836001600160a01b03163b11614ac157600080fd5b600080846001600160a01b031663a9059cbb60e01b8585604051602401614ae9929190615cbb565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051614b279190615ea6565b6000604051808303816000865af19150503d8060008114614b64576040519150601f19603f3d011682016040523d82523d6000602084013e614b69565b606091505b5091509150818015614b93575080511580614b93575080806020019051810190614b939190615cd4565b614b9c57600080fd5b5050505050565b60008083861015614bb357600080fd5b82851015614bc057600080fd5b6040516306801cc360e41b8152600090600080516020615f1383398151915290636801cc3090614bf8908d908d908d90600401615c7a565b602060405180830381865afa158015614c15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614c399190615c9e565b90506001600160a01b038116614cc4576040516320b7f73960e21b8152600080516020615f13833981519152906382dfdce490614c7e908d908d908d90600401615c7a565b6020604051808303816000875af1158015614c9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614cc19190615c9e565b90505b600080614cd28c8c8c61190e565b91509150816000148015614ce4575080155b15614cf457889450879350614d7c565b6000614d018a8484614e7a565b9050888111614d355786811015614d2a5760405162461bcd60e51b81526004016106ef90615d93565b899550935083614d7a565b6000614d428a8486614e7a565b90508a811115614d5457614d5461532c565b88811015614d745760405162461bcd60e51b81526004016106ef90615d5c565b95508894505b505b50505097509795505050505050565b600081600003614d9d57506000919050565b60006001614daa84615216565b901c6001901b90506001818481614dc357614dc3615ac3565b048201901c90506001818481614ddb57614ddb615ac3565b048201901c90506001818481614df357614df3615ac3565b048201901c90506001818481614e0b57614e0b615ac3565b048201901c90506001818481614e2357614e23615ac3565b048201901c90506001818481614e3b57614e3b615ac3565b048201901c90506001818481614e5357614e53615ac3565b048201901c9050614e7381828581614e6d57614e6d615ac3565b04614f3a565b9392505050565b6000808411614ec95760405162461bcd60e51b815260206004820152601b60248201527a149bdd5d195c8e88125394d551919250d251539517d05353d55395602a1b60448201526064016106ef565b600083118015614ed95750600082115b614f255760405162461bcd60e51b815260206004820152601e60248201527f526f757465723a20494e53554646494349454e545f4c4951554944495459000060448201526064016106ef565b82614f308386615aac565b614aa29190615ad9565b6000818310614f495781614f4b565b825b90505b92915050565b33614f5d612429565b6001600160a01b031614611f715760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016106ef565b6000614fbe826140f9565b614fda5760405162461bcd60e51b81526004016106ef90615c0d565b604051627b8a6760e11b8152600090600080516020615f538339815191529062f714ce9061501090600019903090600401615c38565b6020604051808303816000875af115801561502f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906150539190615bc8565b6040516303cea95560e21b815290915073d6489eaf13f61822356f30618e1d9947fa1ef46f90630f3aa5549061509490869085906000903090600401615c4f565b6020604051808303816000875af11580156150b3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614e739190615bc8565b600080736e3e180b1c5742fc445f0bbdab7aa7b9025606306001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561512c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906151509190615bc8565b604051630345051f60e51b81528415156004820152909150733a15bac2d87c89f08147353fc9ae27080631b73d906368a0a3e090602401602060405180830381865afa1580156151a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906151c89190615bc8565b9150915091565b6000821561415757816151e3600185615b40565b6151ed9190615ad9565b6151f8906001615a99565b614f4b565b600180546001600160a01b0319169055611fee816152aa565b600080608083901c1561522b57608092831c92015b604083901c1561523d57604092831c92015b602083901c1561524f57602092831c92015b601083901c1561526157601092831c92015b600883901c1561527357600892831c92015b600483901c1561528557600492831c92015b600283901c1561529757600292831c92015b600183901c15614f4e5760010192915050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5080546000825590600052602060002090810190611fee91905b808211156153285760008155600101615314565b5090565b634e487b7160e01b600052600160045260246000fd5b6001600160a01b0381168114611fee57600080fd5b6000806000806080858703121561536d57600080fd5b843561537881615342565b9350602085013561538881615342565b93969395505050506040820135916060013590565b60008060008060008060a087890312156153b657600080fd5b863595506020870135945060408701356001600160401b03808211156153db57600080fd5b818901915089601f8301126153ef57600080fd5b8135818111156153fe57600080fd5b8a602060608302850101111561541357600080fd5b602083019650809550505050606087013561542d81615342565b80925050608087013590509295509295509295565b6020808252825182820181905260009190848201906040850190845b8181101561547a5783518352928401929184019160010161545e565b50909695505050505050565b60008060008060008060c0878903121561549f57600080fd5b86356154aa81615342565b955060208701356154ba81615342565b95989597505050506040840135936060810135936080820135935060a0909101359150565b600080600080600080600080610100898b0312156154fc57600080fd5b883561550781615342565b975060208901359650604089013561551e81615342565b9550606089013594506080890135935060a0890135925060c0890135915060e089013561554a81615342565b809150509295985092959890939650565b60008060006060848603121561557057600080fd5b833561557b81615342565b9250602084013561558b81615342565b929592945050506040919091013590565b8015158114611fee57600080fd5b6000806000606084860312156155bf57600080fd5b83356155ca81615342565b925060208401356155da81615342565b915060408401356155ea8161559c565b809150509250925092565b6001600160a01b0391909116815260200190565b6000806040838503121561561c57600080fd5b823561562781615342565b9150602083013561563781615342565b809150509250929050565b6001600160a01b0392831681529116602082015260400190565b60008060006060848603121561567157600080fd5b83359250602084013561568381615342565b915060408401356155ea81615342565b600080600080600060a086880312156156ab57600080fd5b85356156b681615342565b945060208601359350604086013592506060860135915060808601356156db81615342565b809150509295509295909350565b600080604083850312156156fc57600080fd5b823561570781615342565b946020939093013593505050565b600080600080600080600060e0888a03121561573057600080fd5b87359650602088013561574281615342565b955060408801359450606088013593506080880135925060a0880135915060c088013561576e81615342565b8091505092959891949750929550565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156157bc576157bc61577e565b604052919050565b6000606082840312156157d657600080fd5b604051606081016001600160401b03811182821017156157f8576157f861577e565b604052905080823561580981615342565b8152602083013561581981615342565b6020820152604083013561582c8161559c565b6040919091015292915050565b6000806040838503121561584c57600080fd5b823591506020808401356001600160401b038082111561586b57600080fd5b818601915086601f83011261587f57600080fd5b8135818111156158915761589161577e565b61589f848260051b01615794565b818152848101925060609182028401850191898311156158be57600080fd5b938501935b828510156158e4576158d58a866157c4565b845293840193928501926158c3565b5080955050505050509250929050565b600080600080600060a0868803121561590c57600080fd5b853561591781615342565b97602087013597506040870135966060810135965060800135945092505050565b60006020828403121561594a57600080fd5b5035919050565b60008060006060848603121561596657600080fd5b833561597181615342565b92506020840135915060408401356155ea8161559c565b60008060008060008060c087890312156159a157600080fd5b86356159ac81615342565b955060208701356159bc81615342565b945060408701359350606087013592506080870135915060a08701356159e181615342565b809150509295509295509295565b60008060008060808587031215615a0557600080fd5b843593506020850135615a1781615342565b92506040850135615a2781615342565b91506060850135615a378161559c565b939692955090935050565b600060208284031215615a5457600080fd5b8135614e7381615342565b60008060408385031215615a7257600080fd5b505080516020909101519092909150565b634e487b7160e01b600052601160045260246000fd5b80820180821115614f4e57614f4e615a83565b8082028115828204841417614f4e57614f4e615a83565b634e487b7160e01b600052601260045260246000fd5b600082615af657634e487b7160e01b600052601260045260246000fd5b500490565b6020808252600f908201526e149bdd5d195c8e8811561412549151608a1b604082015260600190565b600060608284031215615b3657600080fd5b614f4b83836157c4565b81810381811115614f4e57614f4e615a83565b634e487b7160e01b600052603260045260246000fd5b60208082526022908201527f526f757465723a20494e53554646494349454e545f4f55545055545f414d4f55604082015261139560f21b606082015260800190565b600060208284031215615bbd57600080fd5b8135614e738161559c565b600060208284031215615bda57600080fd5b5051919050565b94855260208501939093526001600160a01b039190911660408401526060830152608082015260a00190565b6020808252601190820152700546f6b656e206e6f7420696e20774d4c5607c1b604082015260600190565b9182526001600160a01b0316602082015260400190565b6001600160a01b03948516815260208101939093526040830191909152909116606082015260800190565b6001600160a01b039384168152919092166020820152901515604082015260600190565b600060208284031215615cb057600080fd5b8151614e7381615342565b6001600160a01b03929092168252602082015260400190565b600060208284031215615ce657600080fd5b8151614e738161559c565b600060018201615d0357615d03615a83565b5060010190565b600080600060608486031215615d1f57600080fd5b8351925060208401519150604084015190509250925092565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6020808252601d908201527f526f757465723a20494e53554646494349454e545f415f414d4f554e54000000604082015260600190565b6020808252601d908201527f526f757465723a20494e53554646494349454e545f425f414d4f554e54000000604082015260600190565b6020808252600f908201526e1a5b9d985b1a590817d85b5bdd5b9d608a1b604082015260600190565b9283526001600160a01b03918216602084015216604082015260600190565b6001600160a01b0393909316835260208301919091521515604082015260600190565b6020808252600d908201526c15d19513481b9bdd081cd95b9d609a1b604082015260600190565b6001600160a01b0394909416845260208401929092526040830152606082015260800190565b60005b83811015615e9d578181015183820152602001615e85565b50506000910152565b60008251615eb8818460208701615e82565b9190910192915050565b84815283602082015260018060a01b03831660408201526080606082015260008251806080840152615efb8160a0850160208701615e82565b601f01601f19169190910160a0019594505050505056fe000000000000000000000000472f3c3c9608fe0ae8d702f3f8a2d12c410c881a000000000000000000000000245cd6d33578de9af75a3c0c636c726b1a8cbdaa000000000000000000000000ae4846b148a65782865a4849e940575f77359b2b00000000000000000000000021be370d5312f44cb42ce377bc9b8a0cef1a4c83a2646970667358221220962c69b3e6c25963573d8820f016d9a4a42c0c25b722f03ef2a495f6a011862b64736f6c63430008130033

Deployed Bytecode

0x6080604052600436106101825760003560e01c806305a7cc62146101ab57806318a13086146101e55780631d0e30c21461021257806326ebe0111461023257806332155ad81461026d5780634c1ee03e1461029b5780634c64fc6b146102c8578063544caa561461030857806356a9a68b146103365780635e1e63251461034b5780635e60dab5146103805780636587e4ce146103a0578063682ff52e146103c0578063715018a6146103e057806379ba5097146103f55780637e9fde1e1461040a5780638050712e1461041d5780638da5cb5b1461043d5780639881fcb4146104525780639be434c1146104725780639dea548b14610485578063a0eaa71c146104a5578063aee599b7146104c5578063b105f0fc146104e5578063c0e3ee6b14610505578063c45a015514610525578063da21423114610547578063e30c397814610567578063e54f8fc01461057c578063f2fde38b1461059c578063f41766d8146105bc578063f4f3de4f146105dc578063f4f45b46146105ef57600080fd5b366101a65733600080516020615f73833981519152146101a4576101a461532c565b005b600080fd5b3480156101b757600080fd5b506101cb6101c6366004615357565b610611565b604080519283526020830191909152015b60405180910390f35b3480156101f157600080fd5b5061020561020036600461539d565b6106cc565b6040516101dc9190615442565b34801561021e57600080fd5b506101cb61022d366004615486565b610ba2565b34801561023e57600080fd5b5061025261024d3660046154df565b610d7a565b604080519384526020840192909252908201526060016101dc565b34801561027957600080fd5b5061028d61028836600461555b565b610f13565b6040519081526020016101dc565b3480156102a757600080fd5b506102bb6102b63660046155aa565b61105a565b6040516101dc91906155f5565b3480156102d457600080fd5b506102e86102e3366004615357565b611130565b6040805194855260208501939093529183015260608201526080016101dc565b34801561031457600080fd5b50610328610323366004615609565b611359565b6040516101dc929190615642565b34801561034257600080fd5b506101a4611437565b34801561035757600080fd5b5061036b61036636600461565c565b6116f2565b604080519283529015156020830152016101dc565b34801561038c57600080fd5b506101cb61039b3660046155aa565b61190e565b3480156103ac57600080fd5b506102526103bb366004615693565b6119c6565b3480156103cc57600080fd5b5061028d6103db3660046156e9565b611c01565b3480156103ec57600080fd5b506101a4611f5f565b34801561040157600080fd5b506101a4611f73565b610252610418366004615715565b611ff1565b34801561042957600080fd5b5061028d61043836600461555b565b61227e565b34801561044957600080fd5b506102bb612429565b34801561045e57600080fd5b5061020561046d366004615839565b612438565b6101cb6104803660046158f4565b612858565b34801561049157600080fd5b5061028d6104a03660046156e9565b612b34565b3480156104b157600080fd5b5061028d6104c03660046156e9565b612f98565b3480156104d157600080fd5b506102bb6104e0366004615938565b6132de565b3480156104f157600080fd5b5061028d610500366004615951565b613308565b34801561051157600080fd5b50610252610520366004615988565b613721565b34801561053157600080fd5b506102bb600080516020615f1383398151915281565b34801561055357600080fd5b5061028d6105623660046159ef565b6138f0565b34801561057357600080fd5b506102bb6139f3565b34801561058857600080fd5b5061025261059736600461555b565b613a02565b3480156105a857600080fd5b506101a46105b7366004615a42565b613b88565b3480156105c857600080fd5b506102056105d736600461539d565b613bee565b6102056105ea36600461539d565b613e1f565b3480156105fb57600080fd5b506102bb600080516020615f7383398151915281565b604051639e66645b60e01b815260048101839052602481018290526000908190819081906001600160a01b03891690639e66645b906044016040805180830381865afa158015610665573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106899190615a5f565b90925090506106988183615a99565b91506106a48783612f98565b93506127106106b585612711615aac565b6106bf9190615ad9565b9250505094509492505050565b606081428110156106f85760405162461bcd60e51b81526004016106ef90615afb565b60405180910390fd5b610754888787808060200260200160405190810160405280939291908181526020016000905b8282101561074a5761073b60608302860136819003810190615b24565b8152602001906001019061071e565b5050505050612438565b91508682600184516107669190615b40565b8151811061077657610776615b53565b6020026020010151101561079c5760405162461bcd60e51b81526004016106ef90615b69565b600080516020615f7383398151915286866107b8600182615b40565b8181106107c7576107c7615b53565b90506060020160200160208101906107df9190615a42565b6001600160a01b0316146108355760405162461bcd60e51b815260206004820152601d60248201527f526f757465723a20454e445f524f5554455f494e5f46544d5f424f5a4f00000060448201526064016106ef565b600080516020615f53833981519152868660008161085557610855615b53565b61086b9260206060909202019081019150615a42565b6001600160a01b031614806108be5750600080516020615f53833981519152868660008161089b5761089b615b53565b90506060020160200160208101906108b39190615a42565b6001600160a01b0316145b15610a42576108f4868660008181106108d9576108d9615b53565b6108ef9260206060909202019081019150615a42565b6140f9565b8061092857506109288686600081811061091057610910615b53565b90506060020160200160208101906108ef9190615a42565b156109805761097b8686600081811061094357610943615b53565b6109599260206060909202019081019150615a42565b33308560008151811061096e5761096e615b53565b6020026020010151614160565b610a58565b61097b8686600081811061099657610996615b53565b6109ac9260206060909202019081019150615a42565b33610a2f898960008181106109c3576109c3615b53565b6109d99260206060909202019081019150615a42565b8a8a60008181106109ec576109ec615b53565b9050606002016020016020810190610a049190615a42565b8b8b6000818110610a1757610a17615b53565b90506060020160400160208101906102b69190615bab565b8560008151811061096e5761096e615b53565b610a588686600081811061099657610996615b53565b610ab5828787808060200260200160405190810160405280939291908181526020016000905b82821015610aaa57610a9b60608302860136819003810190615b24565b81526020019060010190610a7e565b50505050503061425c565b6040516370a0823160e01b8152600090600080516020615f73833981519152906370a0823190610ae99030906004016155f5565b602060405180830381865afa158015610b06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b2a9190615bc8565b604051632e1a7d4d60e01b815260048101829052909150600080516020615f7383398151915290632e1a7d4d90602401600060405180830381600087803b158015610b7457600080fd5b505af1158015610b88573d6000803e3d6000fd5b50505050610b96858261474c565b50509695505050505050565b600080610bae8861481a565b610bba87333089614160565b610bc688333088614160565b6000610bd18861490d565b60405163f897bd1d60e01b81529091506001600160a01b038a169063f897bd1d90610c08908990859033908b908b90600401615be1565b60408051808303816000875af1158015610c26573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c4a9190615a5f565b6040516370a0823160e01b8152919450925088906000906001600160a01b038316906370a0823190610c809030906004016155f5565b602060405180830381865afa158015610c9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc19190615bc8565b6040516370a0823160e01b8152909150600090600080516020615f53833981519152906370a0823190610cf89030906004016155f5565b602060405180830381865afa158015610d15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d399190615bc8565b90508015610d5a57610d5a600080516020615f538339815191523383614aaa565b8115610d6b57610d6b8b3384614aaa565b50505050965096945050505050565b6000806000610d8b8b33308d614160565b610d948b61490d565b9750610db4600080516020615f538339815191528a60008b8b8b8b614ba3565b90935091506000610dd4600080516020615f538339815191528b8361105a565b9050610def600080516020615f538339815191528286614aaa565b610dfb8a338386614160565b6040516335313c2160e11b81526001600160a01b03821690636a62784290610e279088906004016155f5565b6020604051808303816000875af1158015610e46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e6a9190615bc8565b6040516370a0823160e01b8152909250600090600080516020615f53833981519152906370a0823190610ea19030906004016155f5565b602060405180830381865afa158015610ebe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ee29190615bc8565b90508015610f0357610f03600080516020615f538339815191523383614aaa565b5050985098509895505050505050565b6000610f2f600080516020615f53833981519152333085614160565b610f38836140f9565b610f545760405162461bcd60e51b81526004016106ef90615c0d565b604051627b8a6760e11b8152600090600080516020615f538339815191529062f714ce90610f8a90600019903090600401615c38565b6020604051808303816000875af1158015610fa9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fcd9190615bc8565b6040516303cea95560e21b815290915073d6489eaf13f61822356f30618e1d9947fa1ef46f90630f3aa5549061100e90879085906000908b90600401615c4f565b6020604051808303816000875af115801561102d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110519190615bc8565b95945050505050565b60008060006110698686611359565b604080516001600160601b0319606094851b81166020808401919091529390941b909316603484015295151560f81b6048830152855180830360290181526049830187528051908201206001600160f81b031960698401527323979e1e4b047f05746b8179fc5168962086440d60611b606a840152607e8301527fac4013aa7118234c1dd1f9cc4cdd3933d5a426224bc691c1bde3d8930a7e6151609e808401919091528651808403909101815260be909201909552805194019390932095945050505050565b6000806000806000600080516020615f138339815191526001600160a01b0316636801cc30600080516020615f538339815191528a60006040518463ffffffff1660e01b815260040161118593929190615c7a565b602060405180830381865afa1580156111a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111c69190615c9e565b905060008080806111d78d8c612b34565b90506001600160a01b0385161561126c57846001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611226573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061124a9190615bc8565b9150611266600080516020615f538339815191528d600061190e565b90945092505b83158015611278575082155b156112a9579650889550866103e86112986112938984615aac565b614d8b565b6112a29190615b40565b955061133d565b60006112b6828686614e7a565b90508a81116112ff57909750955086866112f8856112d48585615aac565b6112de9190615ad9565b856112e9868c615aac565b6112f39190615ad9565b614f3a565b965061133b565b600061130c8c8688614e7a565b99508b9850899050611337866113228684615aac565b61132c9190615ad9565b866112e9878d615aac565b9750505b505b6113478d89612f98565b98505050505050945094509450949050565b600080826001600160a01b0316846001600160a01b0316036113bb5760405162461bcd60e51b815260206004820152601b60248201527a526f757465723a204944454e544943414c5f41444452455353455360281b60448201526064016106ef565b826001600160a01b0316846001600160a01b0316106113db5782846113de565b83835b90925090506001600160a01b0382166114305760405162461bcd60e51b8152602060048201526014602482015273526f757465723a205a45524f5f4144445245535360601b60448201526064016106ef565b9250929050565b61143f614f54565b60005b6002548110156115065760006002828154811061146157611461615b53565b600091825260208220015460405163095ea7b360e01b81526001600160a01b039091169250829163095ea7b3916114b091733a15bac2d87c89f08147353fc9ae27080631b73d91600401615cbb565b6020604051808303816000875af11580156114cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f39190615cd4565b5050806114ff90615cf1565b9050611442565b50611513600260006152fa565b6000600080516020615f338339815191526001600160a01b03166362287a326040518163ffffffff1660e01b8152600401602060405180830381865afa158015611561573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115859190615bc8565b905060005b818110156116ee57604051630e468baf60e41b815260048101829052600090600080516020615f338339815191529063e468baf090602401602060405180830381865afa1580156115df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116039190615c9e565b60405163095ea7b360e01b81529091506001600160a01b0382169063095ea7b39061164a90733a15bac2d87c89f08147353fc9ae27080631b73d9060001990600401615cbb565b6020604051808303816000875af1158015611669573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061168d9190615cd4565b50600280546001810182556000919091527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace0180546001600160a01b0319166001600160a01b03929092169190911790556116e781615cf1565b905061158a565b5050565b60008060006117038585600161105a565b60405163e5e31b1360e01b81529091506000908190600080516020615f138339815191529063e5e31b139061173c9086906004016155f5565b602060405180830381865afa158015611759573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061177d9190615cd4565b156117f4576040516378a051ad60e11b81526001600160a01b0384169063f140a35a906117b0908b908b90600401615c38565b602060405180830381865afa1580156117cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117f19190615bc8565b91505b6118008787600061105a565b60405163e5e31b1360e01b8152909350600080516020615f138339815191529063e5e31b13906118349086906004016155f5565b602060405180830381865afa158015611851573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118759190615cd4565b156118ec576040516378a051ad60e11b81526001600160a01b0384169063f140a35a906118a8908b908b90600401615c38565b602060405180830381865afa1580156118c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118e99190615bc8565b90505b8082116118fb578060006118ff565b8160015b94509450505050935093915050565b600080600061191d8686611359565b50905060008061192e88888861105a565b6001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa15801561196b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061198f9190615d0a565b5091509150826001600160a01b0316886001600160a01b0316146119b45780826119b7565b81815b90999098509650505050505050565b6000806000806119e6600080516020615f538339815191528a600061105a565b6040516323b872dd60e01b81529091506001600160a01b038216906323b872dd90611a1990339085908d90600401615d38565b6020604051808303816000875af1158015611a38573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a5c9190615cd4565b611a6557600080fd5b600080826001600160a01b03166389afcb44306040518263ffffffff1660e01b8152600401611a9491906155f5565b60408051808303816000875af1158015611ab2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ad69190615a5f565b915091506000611af4600080516020615f538339815191528d611359565b509050600080516020615f538339815191526001600160a01b03821614611b1c578183611b1f565b82825b909750955089871015611b445760405162461bcd60e51b81526004016106ef90615d5c565b88861015611b645760405162461bcd60e51b81526004016106ef90615d93565b611b6f8c8988614aaa565b611b86600080516020615f73833981519152614fb3565b604051632e1a7d4d60e01b815260048101829052909550600080516020615f7383398151915290632e1a7d4d90602401600060405180830381600087803b158015611bd057600080fd5b505af1158015611be4573d6000803e3d6000fd5b50505050611bf2888661474c565b50505050955095509592505050565b6000808211611c225760405162461bcd60e51b81526004016106ef90615dca565b611c2d600183615a99565b9150600080611c3c60006150d7565b604051637092736960e11b81529193509150600090600080516020615f338339815191529063e124e6d290611c759089906004016155f5565b602060405180830381865afa158015611c92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cb69190615bc8565b90506000611ced611cc78388615aac565b7f000000000000000000000000000000000000000c9f2c9cd04674edea400000006151cf565b9050600084611cfc8584615aac565b611d069190615ad9565b9050600080516020615f338339815191526001600160a01b0316634215287382600080516020615f338339815191526001600160a01b031663f5b91b7b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d72573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d969190615c9e565b8b6040518463ffffffff1660e01b8152600401611db593929190615df3565b602060405180830381865afa158015611dd2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611df69190615bc8565b9050611e03600182615a99565b60405163eb0835bf60e01b81529091507f000000000000000000000000000000000000000000000000000000000000271090600090736280873ffdb6a9c8fd601b323f609800616273849063eb0835bf90611e64908d908890600401615cbb565b602060405180830381865afa158015611e81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ea59190615bc8565b9050611ec3611eb48385615aac565b611ebe8385615b40565b6151cf565b604051630f342ee960e01b815290935073b643724c5c364d1f1971edb7bab059cb9ab6567d90630f342ee990611f1090600080516020615f53833981519152908790600190600401615e12565b602060405180830381865afa158015611f2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f519190615bc8565b9a9950505050505050505050565b611f67614f54565b611f7160006151fd565b565b3380611f7d6139f3565b6001600160a01b031614611fe55760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016106ef565b611fee816151fd565b50565b6000806000600080516020615f738339815191526001600160a01b031663d0e30db08b6040518263ffffffff1660e01b81526004016000604051808303818588803b15801561203f57600080fd5b505af1158015612053573d6000803e3d6000fd5b50506040516370a0823160e01b81528d9350600080516020615f7383398151915292506370a08231915061208b9030906004016155f5565b602060405180830381865afa1580156120a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120cc9190615bc8565b146120e95760405162461bcd60e51b81526004016106ef90615e35565b612100600080516020615f7383398151915261490d565b9750612120600080516020615f538339815191528a60008b8b8b8b614ba3565b90935091506000612140600080516020615f538339815191528b8361105a565b905061215b600080516020615f538339815191528286614aaa565b6121678a338386614160565b6040516335313c2160e11b81526001600160a01b03821690636a627842906121939088906004016155f5565b6020604051808303816000875af11580156121b2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121d69190615bc8565b6040516370a0823160e01b8152909250600090600080516020615f53833981519152906370a082319061220d9030906004016155f5565b602060405180830381865afa15801561222a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061224e9190615bc8565b9050801561226f5761226f600080516020615f538339815191523383614aaa565b50509750975097945050505050565b600061228c83333085614160565b612295836140f9565b6122b15760405162461bcd60e51b81526004016106ef90615c0d565b6040516370a0823160e01b8152839060009073d6489eaf13f61822356f30618e1d9947fa1ef46f9063364e23119084906001600160a01b038216906370a08231906123009030906004016155f5565b602060405180830381865afa15801561231d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123419190615bc8565b6000806040518563ffffffff1660e01b81526004016123639493929190615e5c565b6020604051808303816000875af1158015612382573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123a69190615bc8565b604051636e553f6560e01b8152909150600080516020615f5383398151915290636e553f65906123dc9084908a90600401615c38565b6020604051808303816000875af11580156123fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061241f9190615bc8565b9695505050505050565b6000546001600160a01b031690565b60606001825110156124835760405162461bcd60e51b81526020600482015260146024820152730a4deeae8cae47440929cac82989288bea082a8960631b60448201526064016106ef565b8151612490906001615a99565b6001600160401b038111156124a7576124a761577e565b6040519080825280602002602001820160405280156124d0578160200160208202803683370190505b50905082816000815181106124e7576124e7615b53565b60200260200101818152505060005b825181101561285157600080516020615f538339815191526001600160a01b031683828151811061252957612529615b53565b6020026020010151600001516001600160a01b0316036125e25761256983828151811061255857612558615b53565b6020026020010151602001516140f9565b156125dd576125b083828151811061258357612583615b53565b6020026020010151602001518383815181106125a1576125a1615b53565b60200260200101516000613308565b826125bc836001615a99565b815181106125cc576125cc615b53565b60200260200101818152505061283f565b612691565b600080516020615f538339815191526001600160a01b031683828151811061260c5761260c615b53565b6020026020010151602001516001600160a01b0316036126915761264c83828151811061263b5761263b615b53565b6020026020010151600001516140f9565b15612691576125b083828151811061266657612666615b53565b60200260200101516000015183838151811061268457612684615b53565b6020026020010151612b34565b60006126f58483815181106126a8576126a8615b53565b6020026020010151600001518584815181106126c6576126c6615b53565b6020026020010151602001518685815181106126e4576126e4615b53565b60200260200101516040015161105a565b60405163e5e31b1360e01b8152909150600080516020615f138339815191529063e5e31b13906127299084906004016155f5565b602060405180830381865afa158015612746573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061276a9190615cd4565b1561283d57806001600160a01b031663f140a35a84848151811061279057612790615b53565b60200260200101518685815181106127aa576127aa615b53565b6020026020010151600001516040518363ffffffff1660e01b81526004016127d3929190615c38565b602060405180830381865afa1580156127f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128149190615bc8565b83612820846001615a99565b8151811061283057612830615b53565b6020026020010181815250505b505b8061284981615cf1565b9150506124f6565b5092915050565b6000806128648761481a565b600080516020615f738339815191526001600160a01b031663d0e30db0876040518263ffffffff1660e01b81526004016000604051808303818588803b1580156128ad57600080fd5b505af11580156128c1573d6000803e3d6000fd5b50506040516370a0823160e01b8152899350600080516020615f7383398151915292506370a0823191506128f99030906004016155f5565b602060405180830381865afa158015612916573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061293a9190615bc8565b146129575760405162461bcd60e51b81526004016106ef90615e35565b61296387333088614160565b600061297c600080516020615f7383398151915261490d565b60405163f897bd1d60e01b81529091506001600160a01b0389169063f897bd1d906129b3908990859033908b908b90600401615be1565b60408051808303816000875af11580156129d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129f59190615a5f565b6040516370a0823160e01b81529194509250600090600080516020615f73833981519152906370a0823190612a2e9030906004016155f5565b602060405180830381865afa158015612a4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a6f9190615bc8565b6040516370a0823160e01b8152909150600090600080516020615f53833981519152906370a0823190612aa69030906004016155f5565b602060405180830381865afa158015612ac3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ae79190615bc8565b90508015612b0857612b08600080516020615f538339815191523383614aaa565b8115612b2757612b27600080516020615f738339815191523384614aaa565b5050509550959350505050565b6000808211612b555760405162461bcd60e51b81526004016106ef90615dca565b600080612b6260016150d7565b6040516340d3096b60e11b81529193509150600090600080516020615f33833981519152906381a612d690612b9b9089906004016155f5565b602060405180830381865afa158015612bb8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bdc9190615bc8565b90507f000000000000000000000000000000000000000c9f2c9cd04674edea400000007f0000000000000000000000000000000000000000000000000000000000002710600082612c2d858a615aac565b612c379190615ad9565b9050600080516020615f338339815191526001600160a01b03166342152873828b600080516020615f338339815191526001600160a01b031663f5b91b7b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ca4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cc89190615c9e565b6040518463ffffffff1660e01b8152600401612ce693929190615df3565b602060405180830381865afa158015612d03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d279190615bc8565b60405163256f6ee360e11b8152909150600090736280873ffdb6a9c8fd601b323f6098006162738490634adeddc690612d66908d908690600401615cbb565b602060405180830381865afa158015612d83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612da79190615bc8565b9050600083612db68382615b40565b612dc0908c615aac565b612dca9190615ad9565b9050600085612dd98884615aac565b612de39190615ad9565b9050600080516020615f338339815191526001600160a01b03166342152873828e600080516020615f338339815191526001600160a01b031663f5b91b7b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612e50573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e749190615c9e565b6040518463ffffffff1660e01b8152600401612e9293929190615df3565b602060405180830381865afa158015612eaf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ed39190615bc8565b905060008915612ef75789612ee88a84615aac565b612ef29190615ad9565b612ef9565b815b604051630f342ee960e01b815290915073b643724c5c364d1f1971edb7bab059cb9ab6567d90630f342ee990612f4690600080516020615f53833981519152908590600090600401615e12565b602060405180830381865afa158015612f63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f879190615bc8565b9d9c50505050505050505050505050565b6000808211612fb95760405162461bcd60e51b81526004016106ef90615dca565b60405163fdda829560e01b815273b643724c5c364d1f1971edb7bab059cb9ab6567d9063fdda82959061300390600080516020615f53833981519152908690600190600401615e12565b602060405180830381865afa158015613020573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130449190615bc8565b915060008061305360016150d7565b9092509050600061306d6130678487615aac565b836151cf565b6040516340d3096b60e11b8152909150600090600080516020615f33833981519152906381a612d6906130a4908a906004016155f5565b602060405180830381865afa1580156130c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130e59190615bc8565b905061311a6131147f000000000000000000000000000000000000000c9f2c9cd04674edea4000000084615aac565b826151cf565b9450600080516020615f338339815191526001600160a01b0316634215287386600080516020615f338339815191526001600160a01b031663f5b91b7b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613186573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131aa9190615c9e565b8a6040518463ffffffff1660e01b81526004016131c993929190615df3565b602060405180830381865afa1580156131e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061320a9190615bc8565b9450613217600186615a99565b60405163256f6ee360e11b8152909550600090736280873ffdb6a9c8fd601b323f6098006162738490634adeddc690613256908b908790600401615cbb565b602060405180830381865afa158015613273573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132979190615bc8565b90507f00000000000000000000000000000000000000000000000000000000000027106132d16132c78289615aac565b611ebe8484615b40565b9998505050505050505050565b600281815481106132ee57600080fd5b6000918252602090912001546001600160a01b0316905081565b60008083116133295760405162461bcd60e51b81526004016106ef90615dca565b60405163fdda829560e01b815273b643724c5c364d1f1971edb7bab059cb9ab6567d9063fdda82959061337290600080516020615f538339815191529087908790600401615e12565b602060405180830381865afa15801561338f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133b39190615bc8565b92506000806133c260006150d7565b91509150600084156133e2576133db6130678488615aac565b90506133fa565b816133ed8488615aac565b6133f79190615ad9565b90505b6000851561347b576040516340d3096b60e11b8152600080516020615f33833981519152906381a612d690613433908b906004016155f5565b602060405180830381865afa158015613450573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134749190615bc8565b90506134f0565b604051637092736960e11b8152600080516020615f338339815191529063e124e6d2906134ac908b906004016155f5565b602060405180830381865afa1580156134c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134ed9190615bc8565b90505b60008161351d7f000000000000000000000000000000000000000c9f2c9cd04674edea4000000085615aac565b6135279190615ad9565b9050600080516020615f338339815191526001600160a01b0316634215287382600080516020615f338339815191526001600160a01b031663f5b91b7b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613593573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135b79190615c9e565b8c6040518463ffffffff1660e01b81526004016135d693929190615df3565b602060405180830381865afa1580156135f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136179190615bc8565b9050861561362d5761362a600182615a99565b90505b60405163eb0835bf60e01b8152600090736280873ffdb6a9c8fd601b323f609800616273849063eb0835bf90613669908d908890600401615cbb565b602060405180830381865afa158015613686573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136aa9190615bc8565b90507f000000000000000000000000000000000000000000000000000000000000271088156136f1576136ea6136e08383615b40565b6131149085615aac565b9750613713565b806136fc8382615b40565b6137069085615aac565b6137109190615ad9565b97505b505050505050509392505050565b600080600080613741600080516020615f538339815191528a600061105a565b6040516323b872dd60e01b81529091506001600160a01b038216906323b872dd9061377490339085908d90600401615d38565b6020604051808303816000875af1158015613793573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137b79190615cd4565b6137c057600080fd5b600080826001600160a01b03166389afcb44306040518263ffffffff1660e01b81526004016137ef91906155f5565b60408051808303816000875af115801561380d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138319190615a5f565b91509150600061384f600080516020615f538339815191528d611359565b509050600080516020615f538339815191526001600160a01b0382161461387757818361387a565b82825b90975095508987101561389f5760405162461bcd60e51b81526004016106ef90615d5c565b888610156138bf5760405162461bcd60e51b81526004016106ef90615d93565b6138ca8c8988614aaa565b6138d38d614fb3565b94506138e08d8987614aaa565b5050505096509650969350505050565b6000806138fe85858561105a565b60405163e5e31b1360e01b8152909150600080516020615f138339815191529063e5e31b13906139329084906004016155f5565b602060405180830381865afa15801561394f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139739190615cd4565b156139ea576040516378a051ad60e11b81526001600160a01b0382169063f140a35a906139a69089908990600401615c38565b602060405180830381865afa1580156139c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139e79190615bc8565b91505b50949350505050565b6001546001600160a01b031690565b600080600080600080516020615f138339815191526001600160a01b0316636801cc30600080516020615f538339815191528860006040518463ffffffff1660e01b8152600401613a5593929190615c7a565b602060405180830381865afa158015613a72573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a969190615c9e565b90506001600160a01b038116613ab757600080600093509350935050613b7f565b600080613ad4600080516020615f5383398151915289600061190e565b915091506000836001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613b18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b3c9190615bc8565b905080613b49848a615aac565b613b539190615ad9565b955080613b60838a615aac565b613b6a9190615ad9565b9450613b788a876000613308565b9650505050505b93509350939050565b613b90614f54565b600180546001600160a01b0319166001600160a01b038316908117909155613bb6612429565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b60608142811015613c115760405162461bcd60e51b81526004016106ef90615afb565b613c63888787808060200260200160405190810160405280939291908181526020016000905b8282101561074a57613c5460608302860136819003810190615b24565b81526020019060010190613c37565b9150868260018451613c759190615b40565b81518110613c8557613c85615b53565b60200260200101511015613cab5760405162461bcd60e51b81526004016106ef90615b69565b600080516020615f538339815191528686600081613ccb57613ccb615b53565b613ce19260206060909202019081019150615a42565b6001600160a01b03161480613d345750600080516020615f538339815191528686600081613d1157613d11615b53565b9050606002016020016020810190613d299190615a42565b6001600160a01b0316145b15613da157613d4f868660008181106108d9576108d9615b53565b80613d6b5750613d6b8686600081811061091057610910615b53565b15613d8b57613d868686600081811061094357610943615b53565b613db7565b613d868686600081811061099657610996615b53565b613db78686600081811061099657610996615b53565b613e14828787808060200260200160405190810160405280939291908181526020016000905b82821015613e0957613dfa60608302860136819003810190615b24565b81526020019060010190613ddd565b50505050508661425c565b509695505050505050565b60608142811015613e425760405162461bcd60e51b81526004016106ef90615afb565b613e94888787808060200260200160405190810160405280939291908181526020016000905b8282101561074a57613e8560608302860136819003810190615b24565b81526020019060010190613e68565b9150868260018451613ea69190615b40565b81518110613eb657613eb6615b53565b60200260200101511015613edc5760405162461bcd60e51b81526004016106ef90615b69565b600080516020615f738339815191526001600160a01b031663d0e30db0896040518263ffffffff1660e01b81526004016000604051808303818588803b158015613f2557600080fd5b505af1158015613f39573d6000803e3d6000fd5b50506040516370a0823160e01b81528b9350600080516020615f7383398151915292506370a082319150613f719030906004016155f5565b602060405180830381865afa158015613f8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fb29190615bc8565b14613fcf5760405162461bcd60e51b81526004016106ef90615e35565b600080516020615f738339815191528686600081613fef57613fef615b53565b6140059260206060909202019081019150615a42565b6001600160a01b031614158061405a5750600080516020615f53833981519152868660008161403657614036615b53565b905060600201602001602081019061404e9190615a42565b6001600160a01b031614155b156140a75760405162461bcd60e51b815260206004820152601d60248201527f526f757465206d757374207374617274205746544d202d3e20774d4c5000000060448201526064016106ef565b613e14828787808060200260200160405190810160405280939291908181526020016000905b82821015613e09576140ea60608302860136819003810190615b24565b815260200190600101906140cd565b6000805b60025481101561415757826001600160a01b03166002828154811061412457614124615b53565b6000918252602090912001546001600160a01b0316036141475750600192915050565b61415081615cf1565b90506140fd565b50600092915050565b6000846001600160a01b03163b1161417757600080fd5b600080856001600160a01b03166323b872dd60e01b8686866040516024016141a193929190615d38565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516141df9190615ea6565b6000604051808303816000865af19150503d806000811461421c576040519150601f19603f3d011682016040523d82523d6000602084013e614221565b606091505b509150915081801561424b57508051158061424b57508080602001905181019061424b9190615cd4565b61425457600080fd5b505050505050565b60005b82518110156147465760006142ae84838151811061427f5761427f615b53565b60200260200101516000015185848151811061429d5761429d615b53565b602002602001015160200151611359565b5090506000856142bf846001615a99565b815181106142cf576142cf615b53565b60200260200101519050600080836001600160a01b03168786815181106142f8576142f8615b53565b6020026020010151600001516001600160a01b03161461431a5782600061431e565b6000835b915091506000806000600080516020615f538339815191526001600160a01b03168a898151811061435157614351615b53565b6020026020010151600001516001600160a01b031603614405576143808a898151811061255857612558615b53565b15614400576143ab8a898151811061439a5761439a615b53565b602002602001015160200151614fb3565b915060018a516143bb9190615b40565b8810156143cb57600192506144a5565b6143f38a89815181106143e0576143e0615b53565b6020026020010151602001518a84614aaa565b5050505050505050505050565b6144a5565b600080516020615f538339815191526001600160a01b03168a898151811061442f5761442f615b53565b6020026020010151602001516001600160a01b0316036144a55761445e8a898151811061263b5761263b615b53565b156144a5576144898a898151811061447857614478615b53565b60200260200101516000015161490d565b915060018a516144999190615b40565b8810156143cb57600192505b60018a516144b39190615b40565b88036144c0575087614618565b6144df8a6144cf8a6001615a99565b8151811061263b5761263b615b53565b80156145285750600080516020615f538339815191528a6145018a6001615a99565b8151811061451157614511615b53565b6020026020010151602001516001600160a01b0316145b80614596575061454d8a61453d8a6001615a99565b8151811061255857612558615b53565b80156145965750600080516020615f538339815191528a61456f8a6001615a99565b8151811061457f5761457f615b53565b6020026020010151600001516001600160a01b0316145b156145a2575030614618565b6146158a6145b18a6001615a99565b815181106145c1576145c1615b53565b6020026020010151600001518b8a60016145db9190615a99565b815181106145eb576145eb615b53565b6020026020010151602001518c8b60016146059190615a99565b815181106126e4576126e4615b53565b90505b821561464b576146468a898151811061463357614633615b53565b6020026020010151602001518284614aaa565b61472c565b61469c8a898151811061466057614660615b53565b6020026020010151600001518b8a8151811061467e5761467e615b53565b6020026020010151602001518c8b815181106126e4576126e4615b53565b6001600160a01b031663022c0d9f86868460006040519080825280601f01601f1916602001820160405280156146d9576020820181803683370190505b506040518563ffffffff1660e01b81526004016146f99493929190615ec2565b600060405180830381600087803b15801561471357600080fd5b505af1158015614727573d6000803e3d6000fd5b505050505b50505050505050808061473e90615cf1565b91505061425f565b50505050565b604080516000808252602082019092526001600160a01b0384169083906040516147769190615ea6565b60006040518083038185875af1925050503d80600081146147b3576040519150601f19603f3d011682016040523d82523d6000602084013e6147b8565b606091505b50509050806148155760405162461bcd60e51b815260206004820152602360248201527f5472616e7366657248656c7065723a2046544d5f5452414e534645525f46414960448201526213115160ea1b60648201526084016106ef565b505050565b604051636eb1769f60e11b8152600080516020615f538339815191529063dd62ed3e9061484d9030908590600401615642565b602060405180830381865afa15801561486a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061488e9190615bc8565b600003611fee5760405163095ea7b360e01b8152600080516020615f538339815191529063095ea7b3906148ca90849060001990600401615cbb565b6020604051808303816000875af11580156148e9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116ee9190615cd4565b6000614918826140f9565b6149345760405162461bcd60e51b81526004016106ef90615c0d565b6040516370a0823160e01b8152829060009073d6489eaf13f61822356f30618e1d9947fa1ef46f9063364e23119084906001600160a01b038216906370a08231906149839030906004016155f5565b602060405180830381865afa1580156149a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149c49190615bc8565b6000806040518563ffffffff1660e01b81526004016149e69493929190615e5c565b6020604051808303816000875af1158015614a05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614a299190615bc8565b604051636e553f6560e01b8152909150600080516020615f5383398151915290636e553f6590614a5f9084903090600401615c38565b6020604051808303816000875af1158015614a7e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614aa29190615bc8565b949350505050565b6000836001600160a01b03163b11614ac157600080fd5b600080846001600160a01b031663a9059cbb60e01b8585604051602401614ae9929190615cbb565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051614b279190615ea6565b6000604051808303816000865af19150503d8060008114614b64576040519150601f19603f3d011682016040523d82523d6000602084013e614b69565b606091505b5091509150818015614b93575080511580614b93575080806020019051810190614b939190615cd4565b614b9c57600080fd5b5050505050565b60008083861015614bb357600080fd5b82851015614bc057600080fd5b6040516306801cc360e41b8152600090600080516020615f1383398151915290636801cc3090614bf8908d908d908d90600401615c7a565b602060405180830381865afa158015614c15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614c399190615c9e565b90506001600160a01b038116614cc4576040516320b7f73960e21b8152600080516020615f13833981519152906382dfdce490614c7e908d908d908d90600401615c7a565b6020604051808303816000875af1158015614c9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614cc19190615c9e565b90505b600080614cd28c8c8c61190e565b91509150816000148015614ce4575080155b15614cf457889450879350614d7c565b6000614d018a8484614e7a565b9050888111614d355786811015614d2a5760405162461bcd60e51b81526004016106ef90615d93565b899550935083614d7a565b6000614d428a8486614e7a565b90508a811115614d5457614d5461532c565b88811015614d745760405162461bcd60e51b81526004016106ef90615d5c565b95508894505b505b50505097509795505050505050565b600081600003614d9d57506000919050565b60006001614daa84615216565b901c6001901b90506001818481614dc357614dc3615ac3565b048201901c90506001818481614ddb57614ddb615ac3565b048201901c90506001818481614df357614df3615ac3565b048201901c90506001818481614e0b57614e0b615ac3565b048201901c90506001818481614e2357614e23615ac3565b048201901c90506001818481614e3b57614e3b615ac3565b048201901c90506001818481614e5357614e53615ac3565b048201901c9050614e7381828581614e6d57614e6d615ac3565b04614f3a565b9392505050565b6000808411614ec95760405162461bcd60e51b815260206004820152601b60248201527a149bdd5d195c8e88125394d551919250d251539517d05353d55395602a1b60448201526064016106ef565b600083118015614ed95750600082115b614f255760405162461bcd60e51b815260206004820152601e60248201527f526f757465723a20494e53554646494349454e545f4c4951554944495459000060448201526064016106ef565b82614f308386615aac565b614aa29190615ad9565b6000818310614f495781614f4b565b825b90505b92915050565b33614f5d612429565b6001600160a01b031614611f715760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016106ef565b6000614fbe826140f9565b614fda5760405162461bcd60e51b81526004016106ef90615c0d565b604051627b8a6760e11b8152600090600080516020615f538339815191529062f714ce9061501090600019903090600401615c38565b6020604051808303816000875af115801561502f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906150539190615bc8565b6040516303cea95560e21b815290915073d6489eaf13f61822356f30618e1d9947fa1ef46f90630f3aa5549061509490869085906000903090600401615c4f565b6020604051808303816000875af11580156150b3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614e739190615bc8565b600080736e3e180b1c5742fc445f0bbdab7aa7b9025606306001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561512c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906151509190615bc8565b604051630345051f60e51b81528415156004820152909150733a15bac2d87c89f08147353fc9ae27080631b73d906368a0a3e090602401602060405180830381865afa1580156151a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906151c89190615bc8565b9150915091565b6000821561415757816151e3600185615b40565b6151ed9190615ad9565b6151f8906001615a99565b614f4b565b600180546001600160a01b0319169055611fee816152aa565b600080608083901c1561522b57608092831c92015b604083901c1561523d57604092831c92015b602083901c1561524f57602092831c92015b601083901c1561526157601092831c92015b600883901c1561527357600892831c92015b600483901c1561528557600492831c92015b600283901c1561529757600292831c92015b600183901c15614f4e5760010192915050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5080546000825590600052602060002090810190611fee91905b808211156153285760008155600101615314565b5090565b634e487b7160e01b600052600160045260246000fd5b6001600160a01b0381168114611fee57600080fd5b6000806000806080858703121561536d57600080fd5b843561537881615342565b9350602085013561538881615342565b93969395505050506040820135916060013590565b60008060008060008060a087890312156153b657600080fd5b863595506020870135945060408701356001600160401b03808211156153db57600080fd5b818901915089601f8301126153ef57600080fd5b8135818111156153fe57600080fd5b8a602060608302850101111561541357600080fd5b602083019650809550505050606087013561542d81615342565b80925050608087013590509295509295509295565b6020808252825182820181905260009190848201906040850190845b8181101561547a5783518352928401929184019160010161545e565b50909695505050505050565b60008060008060008060c0878903121561549f57600080fd5b86356154aa81615342565b955060208701356154ba81615342565b95989597505050506040840135936060810135936080820135935060a0909101359150565b600080600080600080600080610100898b0312156154fc57600080fd5b883561550781615342565b975060208901359650604089013561551e81615342565b9550606089013594506080890135935060a0890135925060c0890135915060e089013561554a81615342565b809150509295985092959890939650565b60008060006060848603121561557057600080fd5b833561557b81615342565b9250602084013561558b81615342565b929592945050506040919091013590565b8015158114611fee57600080fd5b6000806000606084860312156155bf57600080fd5b83356155ca81615342565b925060208401356155da81615342565b915060408401356155ea8161559c565b809150509250925092565b6001600160a01b0391909116815260200190565b6000806040838503121561561c57600080fd5b823561562781615342565b9150602083013561563781615342565b809150509250929050565b6001600160a01b0392831681529116602082015260400190565b60008060006060848603121561567157600080fd5b83359250602084013561568381615342565b915060408401356155ea81615342565b600080600080600060a086880312156156ab57600080fd5b85356156b681615342565b945060208601359350604086013592506060860135915060808601356156db81615342565b809150509295509295909350565b600080604083850312156156fc57600080fd5b823561570781615342565b946020939093013593505050565b600080600080600080600060e0888a03121561573057600080fd5b87359650602088013561574281615342565b955060408801359450606088013593506080880135925060a0880135915060c088013561576e81615342565b8091505092959891949750929550565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156157bc576157bc61577e565b604052919050565b6000606082840312156157d657600080fd5b604051606081016001600160401b03811182821017156157f8576157f861577e565b604052905080823561580981615342565b8152602083013561581981615342565b6020820152604083013561582c8161559c565b6040919091015292915050565b6000806040838503121561584c57600080fd5b823591506020808401356001600160401b038082111561586b57600080fd5b818601915086601f83011261587f57600080fd5b8135818111156158915761589161577e565b61589f848260051b01615794565b818152848101925060609182028401850191898311156158be57600080fd5b938501935b828510156158e4576158d58a866157c4565b845293840193928501926158c3565b5080955050505050509250929050565b600080600080600060a0868803121561590c57600080fd5b853561591781615342565b97602087013597506040870135966060810135965060800135945092505050565b60006020828403121561594a57600080fd5b5035919050565b60008060006060848603121561596657600080fd5b833561597181615342565b92506020840135915060408401356155ea8161559c565b60008060008060008060c087890312156159a157600080fd5b86356159ac81615342565b955060208701356159bc81615342565b945060408701359350606087013592506080870135915060a08701356159e181615342565b809150509295509295509295565b60008060008060808587031215615a0557600080fd5b843593506020850135615a1781615342565b92506040850135615a2781615342565b91506060850135615a378161559c565b939692955090935050565b600060208284031215615a5457600080fd5b8135614e7381615342565b60008060408385031215615a7257600080fd5b505080516020909101519092909150565b634e487b7160e01b600052601160045260246000fd5b80820180821115614f4e57614f4e615a83565b8082028115828204841417614f4e57614f4e615a83565b634e487b7160e01b600052601260045260246000fd5b600082615af657634e487b7160e01b600052601260045260246000fd5b500490565b6020808252600f908201526e149bdd5d195c8e8811561412549151608a1b604082015260600190565b600060608284031215615b3657600080fd5b614f4b83836157c4565b81810381811115614f4e57614f4e615a83565b634e487b7160e01b600052603260045260246000fd5b60208082526022908201527f526f757465723a20494e53554646494349454e545f4f55545055545f414d4f55604082015261139560f21b606082015260800190565b600060208284031215615bbd57600080fd5b8135614e738161559c565b600060208284031215615bda57600080fd5b5051919050565b94855260208501939093526001600160a01b039190911660408401526060830152608082015260a00190565b6020808252601190820152700546f6b656e206e6f7420696e20774d4c5607c1b604082015260600190565b9182526001600160a01b0316602082015260400190565b6001600160a01b03948516815260208101939093526040830191909152909116606082015260800190565b6001600160a01b039384168152919092166020820152901515604082015260600190565b600060208284031215615cb057600080fd5b8151614e7381615342565b6001600160a01b03929092168252602082015260400190565b600060208284031215615ce657600080fd5b8151614e738161559c565b600060018201615d0357615d03615a83565b5060010190565b600080600060608486031215615d1f57600080fd5b8351925060208401519150604084015190509250925092565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6020808252601d908201527f526f757465723a20494e53554646494349454e545f415f414d4f554e54000000604082015260600190565b6020808252601d908201527f526f757465723a20494e53554646494349454e545f425f414d4f554e54000000604082015260600190565b6020808252600f908201526e1a5b9d985b1a590817d85b5bdd5b9d608a1b604082015260600190565b9283526001600160a01b03918216602084015216604082015260600190565b6001600160a01b0393909316835260208301919091521515604082015260600190565b6020808252600d908201526c15d19513481b9bdd081cd95b9d609a1b604082015260600190565b6001600160a01b0394909416845260208401929092526040830152606082015260800190565b60005b83811015615e9d578181015183820152602001615e85565b50506000910152565b60008251615eb8818460208701615e82565b9190910192915050565b84815283602082015260018060a01b03831660408201526080606082015260008251806080840152615efb8160a0850160208701615e82565b601f01601f19169190910160a0019594505050505056fe000000000000000000000000472f3c3c9608fe0ae8d702f3f8a2d12c410c881a000000000000000000000000245cd6d33578de9af75a3c0c636c726b1a8cbdaa000000000000000000000000ae4846b148a65782865a4849e940575f77359b2b00000000000000000000000021be370d5312f44cb42ce377bc9b8a0cef1a4c83a2646970667358221220962c69b3e6c25963573d8820f016d9a4a42c0c25b722f03ef2a495f6a011862b64736f6c63430008130033

Deployed Bytecode Sourcemap

37175:55464:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;39274:10;-1:-1:-1;;;;;;;;;;;39274:27:0;39267:35;;;;:::i;:::-;37175:55464;;;;;66541:659;;;;;;;;;;-1:-1:-1;66541:659:0;;;;;:::i;:::-;;:::i;:::-;;;;986:25:1;;;1042:2;1027:18;;1020:34;;;;959:18;66541:659:0;;;;;;;;42897:1921;;;;;;;;;;-1:-1:-1;42897:1921:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;62270:1337::-;;;;;;;;;;-1:-1:-1;62270:1337:0;;;;;:::i;:::-;;:::i;52918:1713::-;;;;;;;;;;-1:-1:-1;52918:1713:0;;;;;:::i;:::-;;:::i;:::-;;;;4442:25:1;;;4498:2;4483:18;;4476:34;;;;4526:18;;;4519:34;4430:2;4415:18;52918:1713:0;4240:319:1;77797:729:0;;;;;;;;;;-1:-1:-1;77797:729:0;;;;;:::i;:::-;;:::i;:::-;;;5171:25:1;;;5159:2;5144:18;77797:729:0;5025:177:1;85786:743:0;;;;;;;;;;-1:-1:-1;85786:743:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;80957:2910::-;;;;;;;;;;-1:-1:-1;80957:2910:0;;;;;:::i;:::-;;:::i;:::-;;;;6297:25:1;;;6353:2;6338:18;;6331:34;;;;6381:18;;;6374:34;6439:2;6424:18;;6417:34;6284:3;6269:19;80957:2910:0;6066:391:1;86537:388:0;;;;;;;;;;-1:-1:-1;86537:388:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;;:::i;39545:697::-;;;;;;;;;;;;;:::i;87558:766::-;;;;;;;;;;-1:-1:-1;87558:766:0;;;;;:::i;:::-;;:::i;:::-;;;;7793:25:1;;;7861:14;;7854:22;7849:2;7834:18;;7827:50;7766:18;87558:766:0;7625:258:1;86983:482:0;;;;;;;;;;-1:-1:-1;86983:482:0;;;;;:::i;:::-;;:::i;60164:1369::-;;;;;;;;;;-1:-1:-1;60164:1369:0;;;;;:::i;:::-;;:::i;72373:1753::-;;;;;;;;;;-1:-1:-1;72373:1753:0;;;;;:::i;:::-;;:::i;15525:103::-;;;;;;;;;;;;;:::i;17963:216::-;;;;;;;;;;;;;:::i;55513:1761::-;;;;;;:::i;:::-;;:::i;79561:762::-;;;;;;;;;;-1:-1:-1;79561:762:0;;;;;:::i;:::-;;:::i;14884:87::-;;;;;;;;;;;;;:::i;40614:1810::-;;;;;;;;;;-1:-1:-1;40614:1810:0;;;;;:::i;:::-;;:::i;64205:1459::-;;;;;;:::i;:::-;;:::i;67663:1494::-;;;;;;;;;;-1:-1:-1;67663:1494:0;;;;;:::i;:::-;;:::i;74572:1560::-;;;;;;;;;;-1:-1:-1;74572:1560:0;;;;;:::i;:::-;;:::i;37846:26::-;;;;;;;;;;-1:-1:-1;37846:26:0;;;;;:::i;:::-;;:::i;69745:2159::-;;;;;;;;;;-1:-1:-1;69745:2159:0;;;;;:::i;:::-;;:::i;58124:1305::-;;;;;;;;;;-1:-1:-1;58124:1305:0;;;;;:::i;:::-;;:::i;37380:85::-;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;37380:85:0;;88436:374;;;;;;;;;;-1:-1:-1;88436:374:0;;;;;:::i;:::-;;:::i;17051:101::-;;;;;;;;;;;;;:::i;84377:1261::-;;;;;;;;;;-1:-1:-1;84377:1261:0;;;;;:::i;:::-;;:::i;17351:181::-;;;;;;;;;;-1:-1:-1;17351:181:0;;;;;:::i;:::-;;:::i;46723:1592::-;;;;;;;;;;-1:-1:-1;46723:1592:0;;;;;:::i;:::-;;:::i;45336:854::-;;;;;;:::i;:::-;;:::i;37474:87::-;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;37474:87:0;;66541:659;66867:88;;-1:-1:-1;;;66867:88:0;;;;;986:25:1;;;1027:18;;;1020:34;;;66725:20:0;;;;;;;;-1:-1:-1;;;;;66867:62:0;;;;;959:18:1;;66867:88:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;66825:130;;-1:-1:-1;66825:130:0;-1:-1:-1;66968:23:0;66825:130;;66968:23;:::i;:::-;;;67019:45;67038:11;67051:12;67019:18;:45::i;:::-;67004:60;-1:-1:-1;67186:6:0;67161:21;67004:60;67176:6;67161:21;:::i;:::-;67160:32;;;;:::i;:::-;67147:45;;66767:433;;66541:659;;;;;;;:::o;42897:1921::-;43116:24;43096:9;39106:15;39093:9;:28;;39085:56;;;;-1:-1:-1;;;39085:56:0;;;;;;;:::i;:::-;;;;;;;;;43163:33:::1;43177:9;43188:7;;43163:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;::::1;;::::0;;::::1;::::0;::::1;::::0;::::1;:::i;:::-;;;;;;;;;;;;;;;;;:13;:33::i;:::-;43153:43;;43260:13;43229:7;43254:1;43237:7;:14;:18;;;;:::i;:::-;43229:27;;;;;;;;:::i;:::-;;;;;;;:44;;43207:128;;;;-1:-1:-1::0;;;43207:128:0::1;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;;;;;;;43368:7:0;;43376:18:::1;43393:1;43368:7:::0;43376:18:::1;:::i;:::-;43368:27;;;;;;;:::i;:::-;;;;;;:30;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;43368:47:0::1;;43346:126;;;::::0;-1:-1:-1;;;43346:126:0;;17245:2:1;43346:126:0::1;::::0;::::1;17227:21:1::0;17284:2;17264:18;;;17257:30;17323:31;17303:18;;;17296:59;17372:18;;43346:126:0::1;17043:353:1::0;43346:126:0::1;-1:-1:-1::0;;;;;;;;;;;43578:7:0;;43586:1:::1;43578:10:::0;::::1;;;;:::i;:::-;:15;::::0;::::1;:10;::::0;;::::1;;:15:::0;;::::1;::::0;-1:-1:-1;43578:15:0::1;:::i;:::-;-1:-1:-1::0;;;;;43578:32:0::1;;:66;;;-1:-1:-1::0;;;;;;;;;;;;43614:7:0;;43622:1:::1;43614:10:::0;::::1;;;;:::i;:::-;;;;;;:13;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;43614:30:0::1;;43578:66;43560:1015;;;43675:28;43687:7;;43695:1;43687:10;;;;;;;:::i;:::-;:15;::::0;::::1;:10;::::0;;::::1;;:15:::0;;::::1;::::0;-1:-1:-1;43687:15:0::1;:::i;:::-;43675:11;:28::i;:::-;:58;;;;43707:26;43719:7;;43727:1;43719:10;;;;;;;:::i;:::-;;;;;;:13;;;;;;;;;;:::i;43707:26::-;43671:659;;;43754:176;43794:7;;43802:1;43794:10;;;;;;;:::i;:::-;:15;::::0;::::1;:10;::::0;;::::1;;:15:::0;;::::1;::::0;-1:-1:-1;43794:15:0::1;:::i;:::-;43832:10;43873:4;43901:7;43909:1;43901:10;;;;;;;;:::i;:::-;;;;;;;43754:17;:176::i;:::-;43560:1015;;43671:659;44093:221;44133:7;;44141:1;44133:10;;;;;;;:::i;:::-;:15;::::0;::::1;:10;::::0;;::::1;;:15:::0;;::::1;::::0;-1:-1:-1;44133:15:0::1;:::i;:::-;44171:10;44204:58;44212:7;;44220:1;44212:10;;;;;;;:::i;:::-;:15;::::0;::::1;:10;::::0;;::::1;;:15:::0;;::::1;::::0;-1:-1:-1;44212:15:0::1;:::i;:::-;44229:7;;44237:1;44229:10;;;;;;;:::i;:::-;;;;;;:13;;;;;;;;;;:::i;:::-;44244:7;;44252:1;44244:10;;;;;;;:::i;:::-;;;;;;:17;;;;;;;;;;:::i;44204:58::-;44285:7;44293:1;44285:10;;;;;;;;:::i;43560:1015::-;44362:201;44398:7;;44406:1;44398:10;;;;;;;:::i;44362:201::-;44587:38;44593:7;44602;;44587:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;::::1;;::::0;;::::1;::::0;::::1;::::0;::::1;:::i;:::-;;;;;;;;;;;;;;;;;44619:4;44587:5;:38::i;:::-;44689:29;::::0;-1:-1:-1;;;44689:29:0;;44662:24:::1;::::0;-1:-1:-1;;;;;;;;;;;37518:42:0;44689:14:::1;::::0;:29:::1;::::0;44712:4:::1;::::0;44689:29:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;44729:31;::::0;-1:-1:-1;;;44729:31:0;;::::1;::::0;::::1;5171:25:1::0;;;44662:56:0;;-1:-1:-1;;;;;;;;;;;;37518:42:0;44729:13:::1;::::0;5144:18:1;;44729:31:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;44771:39;44788:3;44793:16;44771;:39::i;:::-;43142:1676;42897:1921:::0;;;;;;;;;:::o;62270:1337::-;62499:21;62522:16;62634:24;62650:7;62634:15;:24::i;:::-;62705:66;62723:11;62736:10;62756:4;62763:7;62705:17;:66::i;:::-;62782:68;62800:7;62809:10;62829:4;62836:13;62782:17;:68::i;:::-;62861:16;62880:33;62901:11;62880:20;:33::i;:::-;62954:159;;-1:-1:-1;;;62954:159:0;;62861:52;;-1:-1:-1;;;;;;62954:24:0;;;;;:159;;62993:13;;62861:52;;63044:10;;63069:9;;63093;;62954:159;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;63252:30;;-1:-1:-1;;;63252:30:0;;62926:187;;-1:-1:-1;62926:187:0;-1:-1:-1;63199:11:0;;63177:12;;-1:-1:-1;;;;;63252:15:0;;;;;:30;;63276:4;;63252:30;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;63320:29;;-1:-1:-1;;;63320:29:0;;63222:60;;-1:-1:-1;63293:24:0;;-1:-1:-1;;;;;;;;;;;37975:42:0;63320:14;;:29;;63343:4;;63320:29;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;63293:56;-1:-1:-1;63366:20:0;;63362:111;;63403:58;-1:-1:-1;;;;;;;;;;;63432:10:0;63444:16;63403:13;:58::i;:::-;63489:23;;63485:115;;63529:59;63543:11;63556:10;63568:19;63529:13;:59::i;:::-;62540:1067;;;;62270:1337;;;;;;;;;:::o;52918:1713::-;53265:24;53304:19;53338:17;53383:141;53415:16;53446:10;53479:4;53499:14;53383:17;:141::i;:::-;53690:38;53711:16;53690:20;:38::i;:::-;53663:65;;53775:273;-1:-1:-1;;;;;;;;;;;53831:5:0;53851;53914:24;53953:19;53987:20;54022:15;53775:13;:273::i;:::-;53741:307;;-1:-1:-1;53741:307:0;-1:-1:-1;54059:12:0;54074:36;-1:-1:-1;;;;;;;;;;;54097:5:0;54059:12;54074:7;:36::i;:::-;54059:51;;54234:52;-1:-1:-1;;;;;;;;;;;54263:4:0;54269:16;54234:13;:52::i;:::-;54297:55;54315:5;54322:10;54334:4;54340:11;54297:17;:55::i;:::-;54377:21;;-1:-1:-1;;;54377:21:0;;-1:-1:-1;;;;;54377:16:0;;;;;:21;;54394:3;;54377:21;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;54436:29;;-1:-1:-1;;;54436:29:0;;54365:33;;-1:-1:-1;54409:24:0;;-1:-1:-1;;;;;;;;;;;37975:42:0;54436:14;;:29;;54459:4;;54436:29;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;54409:56;-1:-1:-1;54517:20:0;;54513:111;;54554:58;-1:-1:-1;;;;;;;;;;;54583:10:0;54595:16;54554:13;:58::i;:::-;53372:1259;;52918:1713;;;;;;;;;;;;:::o;77797:729::-;77905:7;77979:68;-1:-1:-1;;;;;;;;;;;78012:10:0;78032:4;78039:7;77979:17;:68::i;:::-;78065:25;78077:12;78065:11;:25::i;:::-;78060:86;;78107:27;;-1:-1:-1;;;78107:27:0;;;;;;;:::i;78060:86::-;78246:47;;-1:-1:-1;;;78246:47:0;;78225:18;;-1:-1:-1;;;;;;;;;;;37975:42:0;78246:13;;:47;;-1:-1:-1;;78260:17:0;78287:4;;78246:47;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;78363:155;;-1:-1:-1;;;78363:155:0;;78225:68;;-1:-1:-1;38175:42:0;;78363:32;;:155;;78414:12;;78225:68;;78474:1;;78494:9;;78363:155;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;78343:175;77797:729;-1:-1:-1;;;;;77797:729:0:o;85786:743::-;85906:12;85932:14;85948;85966:28;85977:7;85986;85966:10;:28::i;:::-;86293:41;;;-1:-1:-1;;;;;;19616:2:1;19652:15;;;19648:24;;86293:41:0;;;;19636:37:1;;;;19707:15;;;;19703:24;;;19689:12;;;19682:46;19774:14;;19767:22;19762:3;19758:32;19744:12;;;19737:54;86293:41:0;;;;;;;;;19807:12:1;;;86293:41:0;;86249:116;;;;;;-1:-1:-1;;;;;;86126:327:0;;;20116:26:1;-1:-1:-1;;;20158:11:1;;;20151:66;20233:12;;;20226:28;86396:12:0;20270::1;;;;20263:28;;;;86126:327:0;;;;;;;;;;20307:12:1;;;;86126:327:0;;;86090:386;;;;;;;;;;-1:-1:-1;;;;;85786:743:0:o;80957:2910::-;81206:24;81245;81284:19;81318:17;81415:13;-1:-1:-1;;;;;;;;;;;;;;;;81431:29:0;;-1:-1:-1;;;;;;;;;;;81503:6:0;81524:5;81431:109;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;81415:125;-1:-1:-1;81552:16:0;;;;81839:104;81877:16;81908:24;81839:23;:104::i;:::-;81805:138;-1:-1:-1;;;;;;81960:19:0;;;81956:173;;82018:5;-1:-1:-1;;;;;82011:25:0;;:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;81996:42;;82076:41;-1:-1:-1;;;;;;;;;;;82103:6:0;82111:5;82076:11;:41::i;:::-;82053:64;;-1:-1:-1;82053:64:0;-1:-1:-1;81956:173:0;82143:13;;:30;;;;-1:-1:-1;82160:13:0;;82143:30;82139:1485;;;82243:23;-1:-1:-1;82285:19:0;;-1:-1:-1;82243:23:0;37614:7;82363:41;82373:30;82285:19;82243:23;82373:30;:::i;:::-;82363:9;:41::i;:::-;:78;;;;:::i;:::-;82334:107;;82139:1485;;;82474:26;82503:126;82537:23;82579:8;82606;82503:15;:126::i;:::-;82474:155;;82670:19;82648:18;:41;82644:969;;82767:23;;-1:-1:-1;82813:18:0;-1:-1:-1;82767:23:0;82813:18;82881:156;82948:8;82913:31;82932:12;82767:23;82913:31;:::i;:::-;82912:44;;;;:::i;:::-;83010:8;82980:26;82994:12;82980:11;:26;:::i;:::-;82979:39;;;;:::i;:::-;82881:8;:156::i;:::-;82869:168;;82644:969;;;83078:31;83112:138;83150:19;83192:8;83223;83112:15;:138::i;:::-;83078:172;-1:-1:-1;83372:19:0;;-1:-1:-1;83078:172:0;;-1:-1:-1;83441:156:0;83508:8;83473:31;83492:12;83078:172;83473:31;:::i;:::-;83472:44;;;;:::i;:::-;83570:8;83540:26;83554:12;83540:11;:26;:::i;83441:156::-;83429:168;;83059:554;82644:969;82459:1165;82139:1485;83768:91;83801:16;83832;83768:18;:91::i;:::-;83749:110;;81352:2515;;;;;80957:2910;;;;;;;;;:::o;86537:388::-;86637:14;86653;86699:7;-1:-1:-1;;;;;86688:18:0;:7;-1:-1:-1;;;;;86688:18:0;;86680:58;;;;-1:-1:-1;;;86680:58:0;;21178:2:1;86680:58:0;;;21160:21:1;21217:2;21197:18;;;21190:30;-1:-1:-1;;;21236:18:1;;;21229:57;21303:18;;86680:58:0;20976:351:1;86680:58:0;86778:7;-1:-1:-1;;;;;86768:17:0;:7;-1:-1:-1;;;;;86768:17:0;;:85;;86836:7;86845;86768:85;;;86802:7;86811;86768:85;86749:104;;-1:-1:-1;86749:104:0;-1:-1:-1;;;;;;86872:20:0;;86864:53;;;;-1:-1:-1;;;86864:53:0;;21534:2:1;86864:53:0;;;21516:21:1;21573:2;21553:18;;;21546:30;-1:-1:-1;;;21592:18:1;;;21585:50;21652:18;;86864:53:0;21332:344:1;86864:53:0;86537:388;;;;;:::o;39545:697::-;14770:13;:11;:13::i;:::-;39659:9:::1;39654:161;39678:9;:16:::0;39674:20;::::1;39654:161;;;39716:12;39738:9;39748:1;39738:12;;;;;;;;:::i;:::-;;::::0;;;::::1;::::0;;::::1;::::0;39766:37:::1;::::0;-1:-1:-1;;;39766:37:0;;-1:-1:-1;;;;;39738:12:0;;::::1;::::0;-1:-1:-1;39738:12:0;;39766:13:::1;::::0;:37:::1;::::0;38381:42:::1;::::0;39766:37:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;39701:114;39696:3;;;;:::i;:::-;;;39654:161;;;-1:-1:-1::0;39865:16:0::1;39872:9;;39865:16;:::i;:::-;39925:19;-1:-1:-1::0;;;;;;;;;;;;;;;;39947:34:0::1;;:36;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;39925:58;;39999:9;39994:241;40018:11;40014:1;:15;39994:241;;;40073:36;::::0;-1:-1:-1;;;40073:36:0;;::::1;::::0;::::1;5171:25:1::0;;;40051:12:0::1;::::0;-1:-1:-1;;;;;;;;;;;38279:42:0;40073:33:::1;::::0;5144:18:1;;40073:36:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;40125:53;::::0;-1:-1:-1;;;40125:53:0;;40051:59;;-1:-1:-1;;;;;;40125:13:0;::::1;::::0;::::1;::::0;:53:::1;::::0;38381:42:::1;::::0;-1:-1:-1;;40160:17:0;40125:53:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;40193:9:0::1;:30:::0;;::::1;::::0;::::1;::::0;;-1:-1:-1;40193:30:0;;;;;::::1;::::0;;-1:-1:-1;;;;;;40193:30:0::1;-1:-1:-1::0;;;;;40193:30:0;;;::::1;::::0;;;::::1;::::0;;40031:3:::1;::::0;::::1;:::i;:::-;;;39994:241;;;;39590:652;39545:697::o:0;87558:766::-;87691:14;87707:11;87731:12;87746:34;87754:8;87764:9;87775:4;87746:7;:34::i;:::-;87859;;-1:-1:-1;;;87859:34:0;;87731:49;;-1:-1:-1;87791:20:0;;;;-1:-1:-1;;;;;;;;;;;37423:42:0;87859:28;;:34;;87731:49;;87859:34;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;87855:127;;;87925:45;;-1:-1:-1;;;87925:45:0;;-1:-1:-1;;;;;87925:24:0;;;;;:45;;87950:9;;87961:8;;87925:45;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;87910:60;;87855:127;87999:35;88007:8;88017:9;88028:5;87999:7;:35::i;:::-;88049:34;;-1:-1:-1;;;88049:34:0;;87992:42;;-1:-1:-1;;;;;;;;;;;;37423:42:0;88049:28;;:34;;87992:42;;88049:34;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;88045:129;;;88117:45;;-1:-1:-1;;;88117:45:0;;-1:-1:-1;;;;;88117:24:0;;;;;:45;;88142:9;;88153:8;;88117:45;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;88100:62;;88045:129;88219:14;88204:12;:29;:112;;88294:14;88310:5;88204:112;;;88254:12;88268:4;88204:112;88184:132;;;;;;;87558:766;;;;;;:::o;86983:482::-;87107:16;87125;87155:14;87175:28;87186:7;87195;87175:10;:28::i;:::-;87154:49;;;87215:16;87233;87275:34;87283:7;87292;87301;87275;:34::i;:::-;-1:-1:-1;;;;;87255:77:0;;:79;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;87214:120;;;;;87379:6;-1:-1:-1;;;;;87368:17:0;:7;-1:-1:-1;;;;;87368:17:0;;:89;;87438:8;87448;87368:89;;;87402:8;87412;87368:89;87345:112;;;;-1:-1:-1;86983:482:0;-1:-1:-1;;;;;;;86983:482:0:o;60164:1369::-;60398:24;60437:19;60471:24;60560:12;60575:37;-1:-1:-1;;;;;;;;;;;60598:6:0;60606:5;60575:7;:37::i;:::-;60666:54;;-1:-1:-1;;;60666:54:0;;60560:52;;-1:-1:-1;;;;;;60666:24:0;;;;;:54;;60691:10;;60560:52;;60709:10;;60666:54;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;60658:63;;;;;;60733:15;60750;60775:4;-1:-1:-1;;;;;60769:16:0;;60794:4;60769:31;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;60732:68;;;;60812:14;60832:33;-1:-1:-1;;;;;;;;;;;60858:6:0;60832:10;:33::i;:::-;-1:-1:-1;60811:54:0;-1:-1:-1;;;;;;;;;;;;;;;;;60910:23:0;;;:91;;60984:7;60993;60910:91;;;60950:7;60959;60910:91;60876:125;;-1:-1:-1;60876:125:0;-1:-1:-1;61034:40:0;;;;61012:119;;;;-1:-1:-1;;;61012:119:0;;;;;;;:::i;:::-;61179:15;61164:11;:30;;61142:109;;;;-1:-1:-1;;;61142:109:0;;;;;;;:::i;:::-;61326:39;61340:6;61348:3;61353:11;61326:13;:39::i;:::-;61395:38;-1:-1:-1;;;;;;;;;;;61395:23:0;:38::i;:::-;61444:31;;-1:-1:-1;;;61444:31:0;;;;;5171:25:1;;;61376:57:0;;-1:-1:-1;;;;;;;;;;;;37518:42:0;61444:13;;5144:18:1;;61444:31:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;61486:39;61503:3;61508:16;61486;:39::i;:::-;60512:1021;;;;60164:1369;;;;;;;;;:::o;72373:1753::-;72494:18;72543:1;72533:7;:11;72525:39;;;;-1:-1:-1;;;72525:39:0;;;;;;;:::i;:::-;72705:12;72716:1;72705:12;;:::i;:::-;;;72764:17;72783;72804:18;72816:5;72804:11;:18::i;:::-;72911:42;;-1:-1:-1;;;72911:42:0;;72763:59;;-1:-1:-1;72763:59:0;-1:-1:-1;72885:23:0;;-1:-1:-1;;;;;;;;;;;38279:42:0;72911:24;;:42;;72936:16;;72911:42;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;72885:68;-1:-1:-1;72964:18:0;72985:95;73013:25;72885:68;73013:7;:25;:::i;:::-;73054:15;72985:12;:95::i;:::-;72964:116;-1:-1:-1;73219:17:0;73266:9;73240:22;73253:9;72964:116;73240:22;:::i;:::-;73239:36;;;;:::i;:::-;73219:56;;-1:-1:-1;;;;;;;;;;;;;;;;73300:30:0;;73345:9;-1:-1:-1;;;;;;;;;;;;;;;;73369:17:0;;:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;73403:16;73300:130;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;73288:142;-1:-1:-1;73524:14:0;73537:1;73288:142;73524:14;:::i;:::-;73685:103;;-1:-1:-1;;;73685:103:0;;73524:14;;-1:-1:-1;73596:20:0;;73577:16;;38483:42;;73685:36;;:103;;73736:16;;73767:10;;73685:103;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;73660:128;-1:-1:-1;73841:102:0;73869:20;73881:8;73869:9;:20;:::i;:::-;73906:25;73917:14;73906:8;:25;:::i;:::-;73841:12;:102::i;:::-;74005:113;;-1:-1:-1;;;74005:113:0;;73829:114;;-1:-1:-1;38607:42:0;;74005:31;;:113;;-1:-1:-1;;;;;;;;;;;37975:42:0;73829:114;;74103:4;;74005:113;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;73992:126;72373:1753;-1:-1:-1;;;;;;;;;;72373:1753:0:o;15525:103::-;14770:13;:11;:13::i;:::-;15590:30:::1;15617:1;15590:18;:30::i;:::-;15525:103::o:0;17963:216::-;13673:10;;18064:14;:12;:14::i;:::-;-1:-1:-1;;;;;18064:24:0;;18056:78;;;;-1:-1:-1;;;18056:78:0;;25330:2:1;18056:78:0;;;25312:21:1;25369:2;25349:18;;;25342:30;25408:34;25388:18;;;25381:62;-1:-1:-1;;;25459:18:1;;;25452:39;25508:19;;18056:78:0;25128:405:1;18056:78:0;18145:26;18164:6;18145:18;:26::i;:::-;18005:174;17963:216::o;55513:1761::-;55845:24;55884:19;55918:17;-1:-1:-1;;;;;;;;;;;;;;;;56020:12:0;;56040:14;56020:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;56072:29:0;;-1:-1:-1;;;56072:29:0;;56105:14;;-1:-1:-1;;;;;;;;;;;;37518:42:0;-1:-1:-1;56072:14:0;;-1:-1:-1;56072:29:0;;56095:4;;56072:29;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:47;56068:103;;56136:23;;-1:-1:-1;;;56136:23:0;;;;;;;:::i;56068:103::-;56336:35;-1:-1:-1;;;;;;;;;;;56336:20:0;:35::i;:::-;56309:62;;56418:273;-1:-1:-1;;;;;;;;;;;56474:5:0;56494;56557:24;56596:19;56630:20;56665:15;56418:13;:273::i;:::-;56384:307;;-1:-1:-1;56384:307:0;-1:-1:-1;56702:12:0;56717:36;-1:-1:-1;;;;;;;;;;;56740:5:0;56702:12;56717:7;:36::i;:::-;56702:51;;56877:52;-1:-1:-1;;;;;;;;;;;56906:4:0;56912:16;56877:13;:52::i;:::-;56940:55;56958:5;56965:10;56977:4;56983:11;56940:17;:55::i;:::-;57018:21;;-1:-1:-1;;;57018:21:0;;-1:-1:-1;;;;;57018:16:0;;;;;:21;;57035:3;;57018:21;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;57116:29;;-1:-1:-1;;;57116:29:0;;57006:33;;-1:-1:-1;57089:24:0;;-1:-1:-1;;;;;;;;;;;37975:42:0;57116:14;;:29;;57139:4;;57116:29;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;57089:56;-1:-1:-1;57160:20:0;;57156:111;;57197:58;-1:-1:-1;;;;;;;;;;;57226:10:0;57238:16;57197:13;:58::i;:::-;55952:1322;;55513:1761;;;;;;;;;;;:::o;79561:762::-;79664:22;79765:65;79783:10;79795;79815:4;79822:7;79765:17;:65::i;:::-;79848:23;79860:10;79848:11;:23::i;:::-;79843:84;;79888:27;;-1:-1:-1;;;79888:27:0;;;;;;;:::i;79843:84::-;80123:30;;-1:-1:-1;;;80123:30:0;;80007:10;;79985:12;;38175:42;;80046:28;;80007:10;;-1:-1:-1;;;;;80123:15:0;;;;;:30;;80147:4;;80123:30;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;80168:1;80184;80046:150;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;80284:31;;-1:-1:-1;;;80284:31:0;;80029:167;;-1:-1:-1;;;;;;;;;;;;37975:42:0;80284:12;;:31;;80029:167;;80305:9;;80284:31;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;80267:48;79561:762;-1:-1:-1;;;;;;79561:762:0:o;14884:87::-;14930:7;14957:6;-1:-1:-1;;;;;14957:6:0;;14884:87::o;40614:1810::-;40726:24;40789:1;40771:7;:14;:19;;40763:52;;;;-1:-1:-1;;;40763:52:0;;26520:2:1;40763:52:0;;;26502:21:1;26559:2;26539:18;;;26532:30;-1:-1:-1;;;26578:18:1;;;26571:50;26638:18;;40763:52:0;26318:344:1;40763:52:0;40850:14;;:18;;40867:1;40850:18;:::i;:::-;-1:-1:-1;;;;;40836:33:0;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;40836:33:0;;40826:43;;40893:9;40880:7;40888:1;40880:10;;;;;;;;:::i;:::-;;;;;;:22;;;;;40918:9;40913:1504;40937:7;:14;40933:1;:18;40913:1504;;;-1:-1:-1;;;;;;;;;;;;;;;;41037:32:0;:7;41045:1;41037:10;;;;;;;;:::i;:::-;;;;;;;:15;;;-1:-1:-1;;;;;41037:32:0;;41033:887;;41163:26;41175:7;41183:1;41175:10;;;;;;;;:::i;:::-;;;;;;;:13;;;41163:11;:26::i;:::-;41159:280;;;41231:157;41283:7;41291:1;41283:10;;;;;;;;:::i;:::-;;;;;;;:13;;;41323:7;41331:1;41323:10;;;;;;;;:::i;:::-;;;;;;;41360:5;41231:25;:157::i;:::-;41214:7;41222:5;:1;41226;41222:5;:::i;:::-;41214:14;;;;;;;;:::i;:::-;;;;;;:174;;;;;41411:8;;41159:280;41033:887;;;-1:-1:-1;;;;;;;;;;;;;;;;41464:30:0;:7;41472:1;41464:10;;;;;;;;:::i;:::-;;;;;;;:13;;;-1:-1:-1;;;;;41464:30:0;;41460:460;;41588:28;41600:7;41608:1;41600:10;;;;;;;;:::i;:::-;;;;;;;:15;;;41588:11;:28::i;:::-;41584:321;;;41729:125;41779:7;41787:1;41779:10;;;;;;;;:::i;:::-;;;;;;;:15;;;41821:7;41829:1;41821:10;;;;;;;;:::i;:::-;;;;;;;41729:23;:125::i;41584:321::-;42046:12;42061:124;42087:7;42095:1;42087:10;;;;;;;;:::i;:::-;;;;;;;:15;;;42121:7;42129:1;42121:10;;;;;;;;:::i;:::-;;;;;;;:13;;;42153:7;42161:1;42153:10;;;;;;;;:::i;:::-;;;;;;;:17;;;42061:7;:124::i;:::-;42204:34;;-1:-1:-1;;;42204:34:0;;42046:139;;-1:-1:-1;;;;;;;;;;;;37423:42:0;42204:28;;:34;;42046:139;;42204:34;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;42200:206;;;42282:4;-1:-1:-1;;;;;42276:24:0;;42323:7;42331:1;42323:10;;;;;;;;:::i;:::-;;;;;;;42356:7;42364:1;42356:10;;;;;;;;:::i;:::-;;;;;;;:15;;;42276:114;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;42259:7;42267:5;:1;42271;42267:5;:::i;:::-;42259:14;;;;;;;;:::i;:::-;;;;;;:131;;;;;42200:206;40958:1459;40913:1504;40953:3;;;;:::i;:::-;;;;40913:1504;;;;40614:1810;;;;:::o;64205:1459::-;64415:21;64438:16;64550:24;64566:7;64550:15;:24::i;:::-;-1:-1:-1;;;;;;;;;;;;;;;;64644:12:0;;64664:7;64644:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;64689:29:0;;-1:-1:-1;;;64689:29:0;;64722:7;;-1:-1:-1;;;;;;;;;;;;37518:42:0;-1:-1:-1;64689:14:0;;-1:-1:-1;64689:29:0;;64712:4;;64689:29;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:40;64685:96;;64746:23;;-1:-1:-1;;;64746:23:0;;;;;;;:::i;64685:96::-;64817:68;64835:7;64844:10;64864:4;64871:13;64817:17;:68::i;:::-;64935:16;64954:35;-1:-1:-1;;;;;;;;;;;64954:20:0;:35::i;:::-;65061:159;;-1:-1:-1;;;65061:159:0;;64935:54;;-1:-1:-1;;;;;;65061:24:0;;;;;:159;;65100:13;;64935:54;;65151:10;;65176:9;;65200;;65061:159;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;65308:29;;-1:-1:-1;;;65308:29:0;;65033:187;;-1:-1:-1;65033:187:0;-1:-1:-1;65278:27:0;;-1:-1:-1;;;;;;;;;;;37518:42:0;65308:14;;:29;;65331:4;;65308:29;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;65375;;-1:-1:-1;;;65375:29:0;;65278:59;;-1:-1:-1;65348:24:0;;-1:-1:-1;;;;;;;;;;;37975:42:0;65375:14;;:29;;65398:4;;65375:29;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;65348:56;-1:-1:-1;65421:20:0;;65417:111;;65458:58;-1:-1:-1;;;;;;;;;;;65487:10:0;65499:16;65458:13;:58::i;:::-;65544:23;;65540:117;;65584:61;-1:-1:-1;;;;;;;;;;;65613:10:0;65625:19;65584:13;:61::i;:::-;64456:1208;;;64205:1459;;;;;;;;:::o;67663:1494::-;67775:28;67834:1;67824:7;:11;67816:39;;;;-1:-1:-1;;;67816:39:0;;;;;;;:::i;:::-;67910:17;67929;67950;67962:4;67950:11;:17::i;:::-;67994:32;;-1:-1:-1;;;67994:32:0;;67909:58;;-1:-1:-1;67909:58:0;-1:-1:-1;67978:13:0;;-1:-1:-1;;;;;;;;;;;38279:42:0;67994:24;;:32;;68019:6;;67994:32;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;67978:48;-1:-1:-1;68086:15:0;68131:20;68065:18;68086:15;68186;67978:48;68186:7;:15;:::i;:::-;68185:30;;;;:::i;:::-;68164:51;;-1:-1:-1;;;;;;;;;;;;;;;;68239:30:0;;68284:10;68309:6;-1:-1:-1;;;;;;;;;;;;;;;;68330:17:0;;:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;68239:121;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;68398:92;;-1:-1:-1;;;68398:92:0;;68226:134;;-1:-1:-1;68373:22:0;;38483:42;;68398:35;;:92;;68448:6;;68226:134;;68398:92;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;68373:117;-1:-1:-1;68501:22:0;68581:8;68538:25;68373:117;68581:8;68538:25;:::i;:::-;68527:37;;:7;:37;:::i;:::-;68526:63;;;;:::i;:::-;68501:88;-1:-1:-1;68602:22:0;68654:10;68628:22;68645:5;68501:88;68628:22;:::i;:::-;68627:37;;;;:::i;:::-;68602:62;;-1:-1:-1;;;;;;;;;;;;;;;;68692:30:0;;68737:14;68766:6;-1:-1:-1;;;;;;;;;;;;;;;;68787:17:0;;:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;68692:125;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;68675:142;-1:-1:-1;68828:21:0;68852:14;;:100;;68943:9;68913:26;68930:9;68913:14;:26;:::i;:::-;68912:40;;;;:::i;:::-;68852:100;;;68882:14;68852:100;69031:118;;-1:-1:-1;;;69031:118:0;;68828:124;;-1:-1:-1;38607:42:0;;69031:31;;:118;;-1:-1:-1;;;;;;;;;;;37975:42:0;68828:124;;69133:5;;69031:118;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;69008:141;67663:1494;-1:-1:-1;;;;;;;;;;;;;67663:1494:0:o;74572:1560::-;74689:27;74747:1;74737:7;:11;74729:39;;;;-1:-1:-1;;;74729:39:0;;;;;;;:::i;:::-;74834:61;;-1:-1:-1;;;74834:61:0;;38607:42;;74834:31;;:61;;-1:-1:-1;;;;;;;;;;;37975:42:0;74881:7;;74890:4;;74834:61;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;74824:71;;75035:17;75054;75075;75087:4;75075:11;:17::i;:::-;75034:58;;-1:-1:-1;75034:58:0;-1:-1:-1;75103:18:0;75124:46;75138:19;75034:58;75138:7;:19;:::i;:::-;75160:9;75124:12;:46::i;:::-;75253:42;;-1:-1:-1;;;75253:42:0;;75103:67;;-1:-1:-1;75232:18:0;;-1:-1:-1;;;;;;;;;;;38279:42:0;75253:24;;:42;;75278:16;;75253:42;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;75232:63;-1:-1:-1;75330:91:0;75357:28;75370:15;75357:10;:28;:::i;:::-;75400:10;75330:12;:91::i;:::-;75308:113;;-1:-1:-1;;;;;;;;;;;;;;;;75456:30:0;;75501:19;-1:-1:-1;;;;;;;;;;;;;;;;75535:17:0;;:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;75569:16;75456:140;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;75434:162;-1:-1:-1;75690:24:0;75713:1;75434:162;75690:24;:::i;:::-;75799:102;;-1:-1:-1;;;75799:102:0;;75690:24;;-1:-1:-1;75774:22:0;;38483:42;;75799:35;;:102;;75849:16;;75880:10;;75799:102;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;75774:127;-1:-1:-1;75959:20:0;76014:110;76041:30;75959:20;76041:19;:30;:::i;:::-;76087:25;76098:14;76087:8;:25;:::i;76014:110::-;75992:132;74572:1560;-1:-1:-1;;;;;;;;;74572:1560:0:o;37846:26::-;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;37846:26:0;;-1:-1:-1;37846:26:0;:::o;69745:2159::-;69886:26;69943:1;69933:7;:11;69925:39;;;;-1:-1:-1;;;69925:39:0;;;;;;;:::i;:::-;70030:115;;-1:-1:-1;;;70030:115:0;;38607:42;;70030:31;;:115;;-1:-1:-1;;;;;;;;;;;37975:42:0;70104:7;;70126:8;;70030:115;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;70020:125;;70202:17;70221;70242:18;70254:5;70242:11;:18::i;:::-;70201:59;;;;70271:18;70337:8;70333:179;;;70375:46;70389:19;70399:9;70389:7;:19;:::i;70375:46::-;70362:59;;70333:179;;;70491:9;70468:19;70478:9;70468:7;:19;:::i;:::-;70467:33;;;;:::i;:::-;70454:46;;70333:179;70594:13;70622:8;70618:160;;;70655:35;;-1:-1:-1;;;70655:35:0;;-1:-1:-1;;;;;;;;;;;38279:42:0;70655:24;;:35;;70680:9;;70655:35;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;70647:43;;70618:160;;;70731:35;;-1:-1:-1;;;70731:35:0;;-1:-1:-1;;;;;;;;;;;38279:42:0;70731:24;;:35;;70756:9;;70731:35;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;70723:43;;70618:160;70924:20;70980:5;70948:28;70961:15;70948:10;:28;:::i;:::-;70947:38;;;;:::i;:::-;70924:61;;-1:-1:-1;;;;;;;;;;;;;;;;71013:30:0;;71058:12;-1:-1:-1;;;;;;;;;;;;;;;;71085:17:0;;:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;71119:9;71013:126;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;70998:141;;71233:8;71229:58;;;71258:17;71274:1;71258:17;;:::i;:::-;;;71229:58;71355:96;;-1:-1:-1;;;71355:96:0;;71330:22;;38483:42;;71355:36;;:96;;71406:9;;71430:10;;71355:96;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;71330:121;-1:-1:-1;71509:20:0;71590:307;;;;71640:117;71688:25;71699:14;71688:8;:25;:::i;:::-;71672:42;;:12;:42;:::i;71640:117::-;71619:138;;71590:307;;;71876:8;71829:25;71840:14;71876:8;71829:25;:::i;:::-;71813:42;;:12;:42;:::i;:::-;71812:72;;;;:::i;:::-;71790:95;;71590:307;69914:1990;;;;;;;69745:2159;;;;;:::o;58124:1305::-;58386:24;58425:19;58459:24;58548:12;58563:37;-1:-1:-1;;;;;;;;;;;58586:6:0;58594:5;58563:7;:37::i;:::-;58654:54;;-1:-1:-1;;;58654:54:0;;58548:52;;-1:-1:-1;;;;;;58654:24:0;;;;;:54;;58679:10;;58548:52;;58697:10;;58654:54;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;58646:63;;;;;;58721:15;58738;58763:4;-1:-1:-1;;;;;58757:16:0;;58782:4;58757:31;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;58720:68;;;;58800:14;58820:33;-1:-1:-1;;;;;;;;;;;58846:6:0;58820:10;:33::i;:::-;-1:-1:-1;58799:54:0;-1:-1:-1;;;;;;;;;;;;;;;;;58898:23:0;;;:91;;58972:7;58981;58898:91;;;58938:7;58947;58898:91;58864:125;;-1:-1:-1;58864:125:0;-1:-1:-1;59022:40:0;;;;59000:119;;;;-1:-1:-1;;;59000:119:0;;;;;;;:::i;:::-;59167:15;59152:11;:30;;59130:109;;;;-1:-1:-1;;;59130:109:0;;;;;;;:::i;:::-;59252:39;59266:6;59274:3;59279:11;59252:13;:39::i;:::-;59323:37;59347:12;59323:23;:37::i;:::-;59304:56;;59371:50;59385:12;59399:3;59404:16;59371:13;:50::i;:::-;58500:929;;;;58124:1305;;;;;;;;;;:::o;88436:374::-;88592:14;88619:12;88634:37;88642:8;88652:9;88663:7;88634;:37::i;:::-;88686:34;;-1:-1:-1;;;88686:34:0;;88619:52;;-1:-1:-1;;;;;;;;;;;;37423:42:0;88686:28;;:34;;88619:52;;88686:34;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;88682:121;;;88746:45;;-1:-1:-1;;;88746:45:0;;-1:-1:-1;;;;;88746:24:0;;;;;:45;;88771:9;;88782:8;;88746:45;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;88737:54;;88682:121;88608:202;88436:374;;;;;;:::o;17051:101::-;17131:13;;-1:-1:-1;;;;;17131:13:0;;17051:101::o;84377:1261::-;84577:24;84616;84655:19;84754:13;-1:-1:-1;;;;;;;;;;;;;;;;84770:29:0;;-1:-1:-1;;;;;;;;;;;84842:6:0;84863:5;84770:109;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;84754:125;-1:-1:-1;;;;;;84896:19:0;;84892:68;;84940:1;84943;84946;84932:16;;;;;;;;;84892:68;84973:16;84991;85011:91;-1:-1:-1;;;;;;;;;;;85065:6:0;85086:5;85011:11;:91::i;:::-;84972:130;;;;85113:20;85143:5;-1:-1:-1;;;;;85136:25:0;;:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;85113:50;-1:-1:-1;85113:50:0;85253:21;85266:8;85253:10;:21;:::i;:::-;85252:38;;;;:::i;:::-;85233:57;-1:-1:-1;85400:12:0;85375:21;85388:8;85375:10;:21;:::i;:::-;85374:38;;;;:::i;:::-;85360:52;;85512:118;85552:16;85583;85614:5;85512:25;:118::i;:::-;85493:137;;84691:947;;;;84377:1261;;;;;;;;:::o;17351:181::-;14770:13;:11;:13::i;:::-;17441::::1;:24:::0;;-1:-1:-1;;;;;;17441:24:0::1;-1:-1:-1::0;;;;;17441:24:0;::::1;::::0;;::::1;::::0;;;17506:7:::1;:5;:7::i;:::-;-1:-1:-1::0;;;;;17481:43:0::1;;;;;;;;;;;17351:181:::0;:::o;46723:1592::-;46945:24;46925:9;39106:15;39093:9;:28;;39085:56;;;;-1:-1:-1;;;39085:56:0;;;;;;;:::i;:::-;46992:33:::1;47006:9;47017:7;;46992:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;::::1;;::::0;;::::1;::::0;::::1;::::0;::::1;:::i;:::-;;;;;;;;;;;;46982:43;;47089:13;47058:7;47083:1;47066:7;:14;:18;;;;:::i;:::-;47058:27;;;;;;;;:::i;:::-;;;;;;;:44;;47036:128;;;;-1:-1:-1::0;;;47036:128:0::1;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;;;;;;;47270:7:0;;47278:1:::1;47270:10:::0;::::1;;;;:::i;:::-;:15;::::0;::::1;:10;::::0;;::::1;;:15:::0;;::::1;::::0;-1:-1:-1;47270:15:0::1;:::i;:::-;-1:-1:-1::0;;;;;47270:32:0::1;;:66;;;-1:-1:-1::0;;;;;;;;;;;;47306:7:0;;47314:1:::1;47306:10:::0;::::1;;;;:::i;:::-;;;;;;:13;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;47306:30:0::1;;47270:66;47252:1015;;;47367:28;47379:7;;47387:1;47379:10;;;;;;;:::i;47367:28::-;:58;;;;47399:26;47411:7;;47419:1;47411:10;;;;;;;:::i;47399:26::-;47363:659;;;47446:176;47486:7;;47494:1;47486:10;;;;;;;:::i;47446:176::-;47252:1015;;47363:659;47785:221;47825:7;;47833:1;47825:10;;;;;;;:::i;47252:1015::-;48054:201;48090:7;;48098:1;48090:10;;;;;;;:::i;48054:201::-;48279:28;48285:7;48294;;48279:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;::::1;;::::0;;::::1;::::0;::::1;::::0;::::1;:::i;:::-;;;;;;;;;;;;;;;;;48303:3;48279:5;:28::i;:::-;46723:1592:::0;;;;;;;;;:::o;45336:854::-;45561:24;45541:9;39106:15;39093:9;:28;;39085:56;;;;-1:-1:-1;;;39085:56:0;;;;;;;:::i;:::-;45608:33:::1;45622:9;45633:7;;45608:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;::::1;;::::0;;::::1;::::0;::::1;::::0;::::1;:::i;:::-;;;;;;;;;;;;45598:43;;45705:13;45674:7;45699:1;45682:7;:14;:18;;;;:::i;:::-;45674:27;;;;;;;;:::i;:::-;;;;;;;:44;;45652:128;;;;-1:-1:-1::0;;;45652:128:0::1;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;;;;;;;;;;;;45827:12:0::1;;45847:9;45827:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;;45874:29:0::1;::::0;-1:-1:-1;;;45874:29:0;;45907:9;;-1:-1:-1;;;;;;;;;;;;37518:42:0;-1:-1:-1;45874:14:0::1;::::0;-1:-1:-1;45874:29:0::1;::::0;45897:4:::1;::::0;45874:29:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:42;45870:98;;45933:23;;-1:-1:-1::0;;;45933:23:0::1;;;;;;;:::i;45870:98::-;-1:-1:-1::0;;;;;;;;;;;45998:7:0;;46006:1:::1;45998:10:::0;::::1;;;;:::i;:::-;:15;::::0;::::1;:10;::::0;;::::1;;:15:::0;;::::1;::::0;-1:-1:-1;45998:15:0::1;:::i;:::-;-1:-1:-1::0;;;;;45998:32:0::1;;;:66;;;-1:-1:-1::0;;;;;;;;;;;;46034:7:0;;46042:1:::1;46034:10:::0;::::1;;;;:::i;:::-;;;;;;:13;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;46034:30:0::1;;;45998:66;45980:162;;;46091:39;::::0;-1:-1:-1;;;46091:39:0;;26869:2:1;46091:39:0::1;::::0;::::1;26851:21:1::0;26908:2;26888:18;;;26881:30;26947:31;26927:18;;;26920:59;26996:18;;46091:39:0::1;26667:353:1::0;45980:162:0::1;46154:28;46160:7;46169;;46154:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;::::1;;::::0;;::::1;::::0;::::1;::::0;::::1;:::i;:::-;;;;;;;;;;;76457:268:::0;76524:4;;76541:154;76565:9;:16;76561:20;;76541:154;;;76623:13;-1:-1:-1;;;;;76607:29:0;:9;76617:1;76607:12;;;;;;;;:::i;:::-;;;;;;;;;;;-1:-1:-1;;;;;76607:12:0;:29;76603:81;;-1:-1:-1;76664:4:0;;76457:268;-1:-1:-1;;76457:268:0:o;76603:81::-;76583:3;;;:::i;:::-;;;76541:154;;;-1:-1:-1;76712:5:0;;76457:268;-1:-1:-1;;76457:268:0:o;92131:505::-;92310:1;92289:6;-1:-1:-1;;;;;92289:18:0;;:22;92281:31;;;;;;92324:12;92338:17;92359:6;-1:-1:-1;;;;;92359:11:0;92426:28;;;92473:5;92497:3;92519:6;92385:155;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;92385:155:0;;;;;;;;;;;;;;-1:-1:-1;;;;;92385:155:0;-1:-1:-1;;;;;;92385:155:0;;;;;;;;;;92359:192;;;;92385:155;92359:192;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;92323:228;;;;92570:7;:57;;;;-1:-1:-1;92582:11:0;;:16;;:44;;;92613:4;92602:24;;;;;;;;;;;;:::i;:::-;92562:66;;;;;;92270:366;;92131:505;;;;:::o;48506:3275::-;48652:9;48647:3127;48671:7;:14;48667:1;:18;48647:3127;;;48708:14;48728:42;48739:7;48747:1;48739:10;;;;;;;;:::i;:::-;;;;;;;:15;;;48756:7;48764:1;48756:10;;;;;;;;:::i;:::-;;;;;;;:13;;;48728:10;:42::i;:::-;-1:-1:-1;48707:63:0;-1:-1:-1;48785:17:0;48805:8;48814:5;:1;48818;48814:5;:::i;:::-;48805:15;;;;;;;;:::i;:::-;;;;;;;48785:35;;48836:18;48856;48897:6;-1:-1:-1;;;;;48878:25:0;:7;48886:1;48878:10;;;;;;;;:::i;:::-;;;;;;;:15;;;-1:-1:-1;;;;;48878:25:0;;:111;;48967:9;48986:1;48878:111;;;48932:1;48936:9;48878:111;48835:154;;;;49093:15;49123:16;49154:10;-1:-1:-1;;;;;;;;;;;;;;;;49245:32:0;:7;49253:1;49245:10;;;;;;;;:::i;:::-;;;;;;;:15;;;-1:-1:-1;;;;;49245:32:0;;49241:1367;;49368:26;49380:7;49388:1;49380:10;;;;;;;;:::i;49368:26::-;49364:540;;;49430:38;49454:7;49462:1;49454:10;;;;;;;;:::i;:::-;;;;;;;:13;;;49430:23;:38::i;:::-;49419:49;;49517:1;49500:7;:14;:18;;;;:::i;:::-;49495:1;:24;49491:394;;;49645:4;49632:17;;49241:1367;;49491:394;49785:43;49799:7;49807:1;49799:10;;;;;;;;:::i;:::-;;;;;;;:13;;;49814:3;49819:8;49785:13;:43::i;:::-;49855:7;;;;;;;;48506:3275;;;:::o;49491:394::-;49241:1367;;;-1:-1:-1;;;;;;;;;;;;;;;;49929:30:0;:7;49937:1;49929:10;;;;;;;;:::i;:::-;;;;;;;:13;;;-1:-1:-1;;;;;49929:30:0;;49925:683;;50053:28;50065:7;50073:1;50065:10;;;;;;;;:::i;50053:28::-;50049:544;;;50117:37;50138:7;50146:1;50138:10;;;;;;;;:::i;:::-;;;;;;;:15;;;50117:20;:37::i;:::-;50106:48;;50203:1;50186:7;:14;:18;;;;:::i;:::-;50181:1;:24;50177:397;;;50334:4;50321:17;;50177:397;50650:1;50633:7;:14;:18;;;;:::i;:::-;50628:1;:23;50624:837;;-1:-1:-1;50736:3:0;50624:837;;;50784:32;50796:7;50804:5;:1;50808;50804:5;:::i;:::-;50796:14;;;;;;;;:::i;50784:32::-;:91;;;;-1:-1:-1;;;;;;;;;;;;50841:7:0;50849:5;:1;50853;50849:5;:::i;:::-;50841:14;;;;;;;;:::i;:::-;;;;;;;:17;;;-1:-1:-1;;;;;50841:34:0;;50784:91;50783:207;;;-1:-1:-1;50898:30:0;50910:7;50918:5;:1;50922;50918:5;:::i;:::-;50910:14;;;;;;;;:::i;50898:30::-;:91;;;;-1:-1:-1;;;;;;;;;;;;50953:7:0;50961:5;:1;50965;50961:5;:::i;:::-;50953:14;;;;;;;;:::i;:::-;;;;;;;:19;;;-1:-1:-1;;;;;50953:36:0;;50898:91;50761:700;;;-1:-1:-1;51200:4:0;50761:700;;;51293:152;51323:7;51331:5;:1;51335;51331:5;:::i;:::-;51323:14;;;;;;;;:::i;:::-;;;;;;;:19;;;51365:7;51373:1;51377;51373:5;;;;:::i;:::-;51365:14;;;;;;;;:::i;:::-;;;;;;;:17;;;51405:7;51413:1;51417;51413:5;;;;:::i;:::-;51405:14;;;;;;;;:::i;51293:152::-;51288:157;;50761:700;51481:10;51477:286;;;51512:42;51526:7;51534:1;51526:10;;;;;;;;:::i;:::-;;;;;;;:13;;;51541:2;51545:8;51512:13;:42::i;:::-;51477:286;;;51623:58;51631:7;51639:1;51631:10;;;;;;;;:::i;:::-;;;;;;;:15;;;51648:7;51656:1;51648:10;;;;;;;;:::i;:::-;;;;;;;:13;;;51663:7;51671:1;51663:10;;;;;;;;:::i;51623:58::-;-1:-1:-1;;;;;51595:110:0;;51706:10;51718;51730:2;51744:1;51734:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;51734:12:0;;51595:152;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;51477:286;48692:3082;;;;;;;48687:3;;;;;:::i;:::-;;;;48647:3127;;;;48506:3275;;;:::o;91527:205::-;91645:12;;;91603;91645;;;;;;;;;-1:-1:-1;;;;;91621:8:0;;;91637:6;;91621:37;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;91602:56;;;91677:7;91669:55;;;;-1:-1:-1;;;91669:55:0;;28416:2:1;91669:55:0;;;28398:21:1;28455:2;28435:18;;;28428:30;28494:34;28474:18;;;28467:62;-1:-1:-1;;;28545:18:1;;;28538:33;28588:19;;91669:55:0;28214:399:1;91669:55:0;91591:141;91527:205;;:::o;65741:182::-;65806:37;;-1:-1:-1;;;65806:37:0;;-1:-1:-1;;;;;;;;;;;37975:42:0;65806:14;;:37;;65829:4;;65836:6;;65806:37;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;65847:1;65806:42;65802:114;;65865:39;;-1:-1:-1;;;65865:39:0;;-1:-1:-1;;;;;;;;;;;37975:42:0;65865:12;;:39;;65878:6;;-1:-1:-1;;65886:17:0;65865:39;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;78588:589::-;78672:14;78704:23;78716:10;78704:11;:23::i;:::-;78699:84;;78744:27;;-1:-1:-1;;;78744:27:0;;;;;;;:::i;78699:84::-;78979:30;;-1:-1:-1;;;78979:30:0;;78863:10;;78841:12;;38175:42;;78902:28;;78863:10;;-1:-1:-1;;;;;78979:15:0;;;;;:30;;79003:4;;78979:30;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;79024:1;79040;78902:150;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;79134:35;;-1:-1:-1;;;79134:35:0;;78885:167;;-1:-1:-1;;;;;;;;;;;;37975:42:0;79134:12;;:35;;78885:167;;79163:4;;79134:35;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;79125:44;78588:589;-1:-1:-1;;;;78588:589:0:o;91740:383::-;91891:1;91870:6;-1:-1:-1;;;;;91870:18:0;;:22;91862:31;;;;;;91905:12;91919:17;91940:6;-1:-1:-1;;;;;91940:11:0;91989:24;;;92015:3;92020:6;91966:61;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;91966:61:0;;;;;;;;;;;;;;-1:-1:-1;;;;;91966:61:0;-1:-1:-1;;;;;;91966:61:0;;;;;;;;;;91940:98;;;;91966:61;91940:98;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;91904:134;;;;92057:7;:57;;;;-1:-1:-1;92069:11:0;;:16;;:44;;;92100:4;92089:24;;;;;;;;;;;;:::i;:::-;92049:66;;;;;;91851:272;;91740:383;;;:::o;89342:2177::-;89593:15;89610;89665:11;89646:15;:30;;89638:39;;;;;;89715:11;89696:15;:30;;89688:39;;;;;;89756:106;;-1:-1:-1;;;89756:106:0;;89740:13;;-1:-1:-1;;;;;;;;;;;37423:42:0;89756:29;;:106;;89800:7;;89822;;89844;;89756:106;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;89740:122;-1:-1:-1;;;;;;89877:19:0;;89873:119;;89921:59;;-1:-1:-1;;;89921:59:0;;-1:-1:-1;;;;;;;;;;;37423:42:0;89921:32;;:59;;89954:7;;89963;;89972;;89921:59;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;89913:67;;89873:119;90304:16;90322;90342:88;90368:7;90390;90412;90342:11;:88::i;:::-;90303:127;;;;90445:8;90457:1;90445:13;:30;;;;-1:-1:-1;90462:13:0;;90445:30;90441:1071;;;90514:15;;-1:-1:-1;90531:15:0;;-1:-1:-1;90441:1071:0;;;90580:22;90605:118;90639:15;90673:8;90700;90605:15;:118::i;:::-;90580:143;;90760:15;90742:14;:33;90738:763;;90844:11;90826:14;:29;;90796:132;;;;-1:-1:-1;;;90796:132:0;;;;;;;:::i;:::-;90969:15;;-1:-1:-1;90986:14:0;-1:-1:-1;90986:14:0;90738:763;;;91042:22;91067:134;91105:15;91143:8;91174;91067:15;:134::i;:::-;91042:159;;91245:15;91227:14;:33;;91220:41;;;;:::i;:::-;91328:11;91310:14;:29;;91280:132;;;;-1:-1:-1;;;91280:132:0;;;;;;;:::i;:::-;91453:14;-1:-1:-1;91469:15:0;;-1:-1:-1;90738:763:0;90565:947;90441:1071;89627:1892;;;89342:2177;;;;;;;;;;:::o;6608:1673::-;6656:7;6680:1;6685;6680:6;6676:47;;-1:-1:-1;6710:1:0;;6608:1673;-1:-1:-1;6608:1673:0:o;6676:47::-;7414:14;7448:1;7437:7;7442:1;7437:4;:7::i;:::-;:12;;7431:1;:19;;7414:36;;7916:1;7905:6;7901:1;:10;;;;;:::i;:::-;;7892:6;:19;7891:26;;7882:35;;7966:1;7955:6;7951:1;:10;;;;;:::i;:::-;;7942:6;:19;7941:26;;7932:35;;8016:1;8005:6;8001:1;:10;;;;;:::i;:::-;;7992:6;:19;7991:26;;7982:35;;8066:1;8055:6;8051:1;:10;;;;;:::i;:::-;;8042:6;:19;8041:26;;8032:35;;8116:1;8105:6;8101:1;:10;;;;;:::i;:::-;;8092:6;:19;8091:26;;8082:35;;8166:1;8155:6;8151:1;:10;;;;;:::i;:::-;;8142:6;:19;8141:26;;8132:35;;8216:1;8205:6;8201:1;:10;;;;;:::i;:::-;;8192:6;:19;8191:26;;8182:35;;8239:23;8243:6;8255;8251:1;:10;;;;;:::i;:::-;;8239:3;:23::i;:::-;8232:30;6608:1673;-1:-1:-1;;;6608:1673:0:o;88932:402::-;89070:15;89117:1;89106:8;:12;89098:52;;;;-1:-1:-1;;;89098:52:0;;28820:2:1;89098:52:0;;;28802:21:1;28859:2;28839:18;;;28832:30;-1:-1:-1;;;28878:18:1;;;28871:57;28945:18;;89098:52:0;28618:351:1;89098:52:0;89195:1;89183:9;:13;:30;;;;;89212:1;89200:9;:13;89183:30;89161:110;;;;-1:-1:-1;;;89161:110:0;;29176:2:1;89161:110:0;;;29158:21:1;29215:2;29195:18;;;29188:30;29254:32;29234:18;;;29227:60;29304:18;;89161:110:0;28974:354:1;89161:110:0;89317:9;89293:20;89304:9;89293:8;:20;:::i;:::-;89292:34;;;;:::i;540:106::-;598:7;629:1;625;:5;:13;;637:1;625:13;;;633:1;625:13;618:20;;540:106;;;;;:::o;15049:132::-;13673:10;15113:7;:5;:7::i;:::-;-1:-1:-1;;;;;15113:23:0;;15105:68;;;;-1:-1:-1;;;15105:68:0;;29535:2:1;15105:68:0;;;29517:21:1;;;29554:18;;;29547:30;29613:34;29593:18;;;29586:62;29665:18;;15105:68:0;29333:356:1;76802:579:0;76891:7;76916:25;76928:12;76916:11;:25::i;:::-;76911:86;;76958:27;;-1:-1:-1;;;76958:27:0;;;;;;;:::i;76911:86::-;77097:47;;-1:-1:-1;;;77097:47:0;;77076:18;;-1:-1:-1;;;;;;;;;;;37975:42:0;77097:13;;:47;;-1:-1:-1;;77111:17:0;77138:4;;77097:47;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;77214:159;;-1:-1:-1;;;77214:159:0;;77076:68;;-1:-1:-1;38175:42:0;;77214:32;;:159;;77265:12;;77076:68;;77325:1;;77353:4;;77214:159;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;76194:220::-;76270:17;76289;38071:42;-1:-1:-1;;;;;76331:16:0;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;76372:34;;-1:-1:-1;;;76372:34:0;;29859:14:1;;29852:22;76372:34:0;;;29834:41:1;76319:30:0;;-1:-1:-1;38381:42:0;;76372:23;;29807:18:1;;76372:34:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;76360:46;;76194:220;;;:::o;1128:197::-;1190:7;1289:6;;:28;;1312:1;1303:5;1307:1;1303;:5;:::i;:::-;1302:11;;;;:::i;:::-;:15;;1316:1;1302:15;:::i;:::-;1289:28;;17722:156;17812:13;17805:20;;-1:-1:-1;;;;;;17805:20:0;;;17836:34;17861:8;17836:24;:34::i;8758:1019::-;8810:7;;8897:3;8888:12;;;:16;8884:102;;8935:3;8925:13;;;;8957;8884:102;9013:2;9004:11;;;:15;9000:99;;9050:2;9040:12;;;;9071;9000:99;9126:2;9117:11;;;:15;9113:99;;9163:2;9153:12;;;;9184;9113:99;9239:2;9230:11;;;:15;9226:99;;9276:2;9266:12;;;;9297;9226:99;9352:1;9343:10;;;:14;9339:96;;9388:1;9378:11;;;;9408;9339:96;9462:1;9453:10;;;:14;9449:96;;9498:1;9488:11;;;;9518;9449:96;9572:1;9563:10;;;:14;9559:96;;9608:1;9598:11;;;;9628;9559:96;9682:1;9673:10;;;:14;9669:66;;9718:1;9708:11;9763:6;8758:1019;-1:-1:-1;;8758:1019:0:o;16144:191::-;16218:16;16237:6;;-1:-1:-1;;;;;16254:17:0;;;-1:-1:-1;;;;;;16254:17:0;;;;;;16287:40;;16237:6;;;;;;;16287:40;;16218:16;16287:40;16207:128;16144:191;:::o;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;14:127:1:-;75:10;70:3;66:20;63:1;56:31;106:4;103:1;96:15;130:4;127:1;120:15;146:131;-1:-1:-1;;;;;221:31:1;;211:42;;201:70;;267:1;264;257:12;282:525;368:6;376;384;392;445:3;433:9;424:7;420:23;416:33;413:53;;;462:1;459;452:12;413:53;501:9;488:23;520:31;545:5;520:31;:::i;:::-;570:5;-1:-1:-1;627:2:1;612:18;;599:32;640:33;599:32;640:33;:::i;:::-;282:525;;692:7;;-1:-1:-1;;;;746:2:1;731:18;;718:32;;797:2;782:18;769:32;;282:525::o;1065:986::-;1212:6;1220;1228;1236;1244;1252;1305:3;1293:9;1284:7;1280:23;1276:33;1273:53;;;1322:1;1319;1312:12;1273:53;1345:23;;;-1:-1:-1;1415:2:1;1400:18;;1387:32;;-1:-1:-1;1470:2:1;1455:18;;1442:32;-1:-1:-1;;;;;1523:14:1;;;1520:34;;;1550:1;1547;1540:12;1520:34;1588:6;1577:9;1573:22;1563:32;;1633:7;1626:4;1622:2;1618:13;1614:27;1604:55;;1655:1;1652;1645:12;1604:55;1695:2;1682:16;1721:2;1713:6;1710:14;1707:34;;;1737:1;1734;1727:12;1707:34;1793:7;1788:2;1780:4;1772:6;1768:17;1764:2;1760:26;1756:35;1753:48;1750:68;;;1814:1;1811;1804:12;1750:68;1845:2;1841;1837:11;1827:21;;1867:6;1857:16;;;;;1923:4;1912:9;1908:20;1895:34;1938:31;1963:5;1938:31;:::i;:::-;1988:5;1978:15;;;2040:3;2029:9;2025:19;2012:33;2002:43;;1065:986;;;;;;;;:::o;2056:632::-;2227:2;2279:21;;;2349:13;;2252:18;;;2371:22;;;2198:4;;2227:2;2450:15;;;;2424:2;2409:18;;;2198:4;2493:169;2507:6;2504:1;2501:13;2493:169;;;2568:13;;2556:26;;2637:15;;;;2602:12;;;;2529:1;2522:9;2493:169;;;-1:-1:-1;2679:3:1;;2056:632;-1:-1:-1;;;;;;2056:632:1:o;2693:663::-;2797:6;2805;2813;2821;2829;2837;2890:3;2878:9;2869:7;2865:23;2861:33;2858:53;;;2907:1;2904;2897:12;2858:53;2946:9;2933:23;2965:31;2990:5;2965:31;:::i;:::-;3015:5;-1:-1:-1;3072:2:1;3057:18;;3044:32;3085:33;3044:32;3085:33;:::i;:::-;2693:663;;3137:7;;-1:-1:-1;;;;3191:2:1;3176:18;;3163:32;;3242:2;3227:18;;3214:32;;3293:3;3278:19;;3265:33;;-1:-1:-1;3345:3:1;3330:19;;;3317:33;;-1:-1:-1;2693:663:1:o;3361:874::-;3483:6;3491;3499;3507;3515;3523;3531;3539;3592:3;3580:9;3571:7;3567:23;3563:33;3560:53;;;3609:1;3606;3599:12;3560:53;3648:9;3635:23;3667:31;3692:5;3667:31;:::i;:::-;3717:5;-1:-1:-1;3769:2:1;3754:18;;3741:32;;-1:-1:-1;3825:2:1;3810:18;;3797:32;3838:33;3797:32;3838:33;:::i;:::-;3890:7;-1:-1:-1;3944:2:1;3929:18;;3916:32;;-1:-1:-1;3995:3:1;3980:19;;3967:33;;-1:-1:-1;4047:3:1;4032:19;;4019:33;;-1:-1:-1;4099:3:1;4084:19;;4071:33;;-1:-1:-1;4156:3:1;4141:19;;4128:33;4170;4128;4170;:::i;:::-;4222:7;4212:17;;;3361:874;;;;;;;;;;;:::o;4564:456::-;4641:6;4649;4657;4710:2;4698:9;4689:7;4685:23;4681:32;4678:52;;;4726:1;4723;4716:12;4678:52;4765:9;4752:23;4784:31;4809:5;4784:31;:::i;:::-;4834:5;-1:-1:-1;4891:2:1;4876:18;;4863:32;4904:33;4863:32;4904:33;:::i;:::-;4564:456;;4956:7;;-1:-1:-1;;;5010:2:1;4995:18;;;;4982:32;;4564:456::o;5207:118::-;5293:5;5286:13;5279:21;5272:5;5269:32;5259:60;;5315:1;5312;5305:12;5330:523;5404:6;5412;5420;5473:2;5461:9;5452:7;5448:23;5444:32;5441:52;;;5489:1;5486;5479:12;5441:52;5528:9;5515:23;5547:31;5572:5;5547:31;:::i;:::-;5597:5;-1:-1:-1;5654:2:1;5639:18;;5626:32;5667:33;5626:32;5667:33;:::i;:::-;5719:7;-1:-1:-1;5778:2:1;5763:18;;5750:32;5791:30;5750:32;5791:30;:::i;:::-;5840:7;5830:17;;;5330:523;;;;;:::o;5858:203::-;-1:-1:-1;;;;;6022:32:1;;;;6004:51;;5992:2;5977:18;;5858:203::o;6462:388::-;6530:6;6538;6591:2;6579:9;6570:7;6566:23;6562:32;6559:52;;;6607:1;6604;6597:12;6559:52;6646:9;6633:23;6665:31;6690:5;6665:31;:::i;:::-;6715:5;-1:-1:-1;6772:2:1;6757:18;;6744:32;6785:33;6744:32;6785:33;:::i;:::-;6837:7;6827:17;;;6462:388;;;;;:::o;6855:304::-;-1:-1:-1;;;;;7085:15:1;;;7067:34;;7137:15;;7132:2;7117:18;;7110:43;7017:2;7002:18;;6855:304::o;7164:456::-;7241:6;7249;7257;7310:2;7298:9;7289:7;7285:23;7281:32;7278:52;;;7326:1;7323;7316:12;7278:52;7362:9;7349:23;7339:33;;7422:2;7411:9;7407:18;7394:32;7435:31;7460:5;7435:31;:::i;:::-;7485:5;-1:-1:-1;7542:2:1;7527:18;;7514:32;7555:33;7514:32;7555:33;:::i;7888:594::-;7983:6;7991;7999;8007;8015;8068:3;8056:9;8047:7;8043:23;8039:33;8036:53;;;8085:1;8082;8075:12;8036:53;8124:9;8111:23;8143:31;8168:5;8143:31;:::i;:::-;8193:5;-1:-1:-1;8245:2:1;8230:18;;8217:32;;-1:-1:-1;8296:2:1;8281:18;;8268:32;;-1:-1:-1;8347:2:1;8332:18;;8319:32;;-1:-1:-1;8403:3:1;8388:19;;8375:33;8417;8375;8417;:::i;:::-;8469:7;8459:17;;;7888:594;;;;;;;;:::o;8487:315::-;8555:6;8563;8616:2;8604:9;8595:7;8591:23;8587:32;8584:52;;;8632:1;8629;8622:12;8584:52;8671:9;8658:23;8690:31;8715:5;8690:31;:::i;:::-;8740:5;8792:2;8777:18;;;;8764:32;;-1:-1:-1;;;8487:315:1:o;8807:732::-;8920:6;8928;8936;8944;8952;8960;8968;9021:3;9009:9;9000:7;8996:23;8992:33;8989:53;;;9038:1;9035;9028:12;8989:53;9074:9;9061:23;9051:33;;9134:2;9123:9;9119:18;9106:32;9147:31;9172:5;9147:31;:::i;:::-;9197:5;-1:-1:-1;9249:2:1;9234:18;;9221:32;;-1:-1:-1;9300:2:1;9285:18;;9272:32;;-1:-1:-1;9351:3:1;9336:19;;9323:33;;-1:-1:-1;9403:3:1;9388:19;;9375:33;;-1:-1:-1;9460:3:1;9445:19;;9432:33;9474;9432;9474;:::i;:::-;9526:7;9516:17;;;8807:732;;;;;;;;;;:::o;9544:127::-;9605:10;9600:3;9596:20;9593:1;9586:31;9636:4;9633:1;9626:15;9660:4;9657:1;9650:15;9676:275;9747:2;9741:9;9812:2;9793:13;;-1:-1:-1;;9789:27:1;9777:40;;-1:-1:-1;;;;;9832:34:1;;9868:22;;;9829:62;9826:88;;;9894:18;;:::i;:::-;9930:2;9923:22;9676:275;;-1:-1:-1;9676:275:1:o;9956:752::-;10008:5;10056:4;10044:9;10039:3;10035:19;10031:30;10028:50;;;10074:1;10071;10064:12;10028:50;10107:2;10101:9;10149:4;10137:17;;-1:-1:-1;;;;;10169:34:1;;10205:22;;;10166:62;10163:88;;;10231:18;;:::i;:::-;10267:2;10260:22;10300:6;-1:-1:-1;10300:6:1;10330:23;;10362:33;10330:23;10362:33;:::i;:::-;10404:23;;10479:2;10464:18;;10451:32;10492:33;10451:32;10492:33;:::i;:::-;10553:2;10541:15;;10534:32;10618:2;10603:18;;10590:32;10631:30;10590:32;10631:30;:::i;:::-;10689:2;10677:15;;;;10670:32;9956:752;;-1:-1:-1;;9956:752:1:o;10713:1068::-;10829:6;10837;10890:2;10878:9;10869:7;10865:23;10861:32;10858:52;;;10906:1;10903;10896:12;10858:52;10929:23;;;-1:-1:-1;10971:2:1;11009:18;;;10996:32;-1:-1:-1;;;;;11077:14:1;;;11074:34;;;11104:1;11101;11094:12;11074:34;11142:6;11131:9;11127:22;11117:32;;11187:7;11180:4;11176:2;11172:13;11168:27;11158:55;;11209:1;11206;11199:12;11158:55;11245:2;11232:16;11267:2;11263;11260:10;11257:36;;;11273:18;;:::i;:::-;11313:36;11345:2;11340;11337:1;11333:10;11329:19;11313:36;:::i;:::-;11383:15;;;11414:12;;;;-1:-1:-1;11445:4:1;11484:11;;;11476:20;;11472:29;;;11513:19;;;11510:39;;;11545:1;11542;11535:12;11510:39;11569:11;;;;11589:162;11605:6;11600:3;11597:15;11589:162;;;11671:37;11700:7;11695:3;11671:37;:::i;:::-;11659:50;;11622:12;;;;11729;;;;11589:162;;;11593:3;11770:5;11760:15;;;;;;;10713:1068;;;;;:::o;11786:521::-;11881:6;11889;11897;11905;11913;11966:3;11954:9;11945:7;11941:23;11937:33;11934:53;;;11983:1;11980;11973:12;11934:53;12022:9;12009:23;12041:31;12066:5;12041:31;:::i;:::-;12091:5;12143:2;12128:18;;12115:32;;-1:-1:-1;12194:2:1;12179:18;;12166:32;;12245:2;12230:18;;12217:32;;-1:-1:-1;12296:3:1;12281:19;12268:33;;-1:-1:-1;11786:521:1;-1:-1:-1;;;11786:521:1:o;12312:180::-;12371:6;12424:2;12412:9;12403:7;12399:23;12395:32;12392:52;;;12440:1;12437;12430:12;12392:52;-1:-1:-1;12463:23:1;;12312:180;-1:-1:-1;12312:180:1:o;12497:450::-;12571:6;12579;12587;12640:2;12628:9;12619:7;12615:23;12611:32;12608:52;;;12656:1;12653;12646:12;12608:52;12695:9;12682:23;12714:31;12739:5;12714:31;:::i;:::-;12764:5;-1:-1:-1;12816:2:1;12801:18;;12788:32;;-1:-1:-1;12872:2:1;12857:18;;12844:32;12885:30;12844:32;12885:30;:::i;12952:736::-;13056:6;13064;13072;13080;13088;13096;13149:3;13137:9;13128:7;13124:23;13120:33;13117:53;;;13166:1;13163;13156:12;13117:53;13205:9;13192:23;13224:31;13249:5;13224:31;:::i;:::-;13274:5;-1:-1:-1;13331:2:1;13316:18;;13303:32;13344:33;13303:32;13344:33;:::i;:::-;13396:7;-1:-1:-1;13450:2:1;13435:18;;13422:32;;-1:-1:-1;13501:2:1;13486:18;;13473:32;;-1:-1:-1;13552:3:1;13537:19;;13524:33;;-1:-1:-1;13609:3:1;13594:19;;13581:33;13623;13581;13623;:::i;:::-;13675:7;13665:17;;;12952:736;;;;;;;;:::o;13693:592::-;13776:6;13784;13792;13800;13853:3;13841:9;13832:7;13828:23;13824:33;13821:53;;;13870:1;13867;13860:12;13821:53;13906:9;13893:23;13883:33;;13966:2;13955:9;13951:18;13938:32;13979:31;14004:5;13979:31;:::i;:::-;14029:5;-1:-1:-1;14086:2:1;14071:18;;14058:32;14099:33;14058:32;14099:33;:::i;:::-;14151:7;-1:-1:-1;14210:2:1;14195:18;;14182:32;14223:30;14182:32;14223:30;:::i;:::-;13693:592;;;;-1:-1:-1;13693:592:1;;-1:-1:-1;;13693:592:1:o;14290:247::-;14349:6;14402:2;14390:9;14381:7;14377:23;14373:32;14370:52;;;14418:1;14415;14408:12;14370:52;14457:9;14444:23;14476:31;14501:5;14476:31;:::i;14764:245::-;14843:6;14851;14904:2;14892:9;14883:7;14879:23;14875:32;14872:52;;;14920:1;14917;14910:12;14872:52;-1:-1:-1;;14943:16:1;;14999:2;14984:18;;;14978:25;14943:16;;14978:25;;-1:-1:-1;14764:245:1:o;15014:127::-;15075:10;15070:3;15066:20;15063:1;15056:31;15106:4;15103:1;15096:15;15130:4;15127:1;15120:15;15146:125;15211:9;;;15232:10;;;15229:36;;;15245:18;;:::i;15276:168::-;15349:9;;;15380;;15397:15;;;15391:22;;15377:37;15367:71;;15418:18;;:::i;15449:127::-;15510:10;15505:3;15501:20;15498:1;15491:31;15541:4;15538:1;15531:15;15565:4;15562:1;15555:15;15581:217;15621:1;15647;15637:132;;15691:10;15686:3;15682:20;15679:1;15672:31;15726:4;15723:1;15716:15;15754:4;15751:1;15744:15;15637:132;-1:-1:-1;15783:9:1;;15581:217::o;15803:339::-;16005:2;15987:21;;;16044:2;16024:18;;;16017:30;-1:-1:-1;;;16078:2:1;16063:18;;16056:45;16133:2;16118:18;;15803:339::o;16147:223::-;16229:6;16282:2;16270:9;16261:7;16257:23;16253:32;16250:52;;;16298:1;16295;16288:12;16250:52;16321:43;16356:7;16345:9;16321:43;:::i;16375:128::-;16442:9;;;16463:11;;;16460:37;;;16477:18;;:::i;16508:127::-;16569:10;16564:3;16560:20;16557:1;16550:31;16600:4;16597:1;16590:15;16624:4;16621:1;16614:15;16640:398;16842:2;16824:21;;;16881:2;16861:18;;;16854:30;16920:34;16915:2;16900:18;;16893:62;-1:-1:-1;;;16986:2:1;16971:18;;16964:32;17028:3;17013:19;;16640:398::o;17401:241::-;17457:6;17510:2;17498:9;17489:7;17485:23;17481:32;17478:52;;;17526:1;17523;17516:12;17478:52;17565:9;17552:23;17584:28;17606:5;17584:28;:::i;17647:184::-;17717:6;17770:2;17758:9;17749:7;17745:23;17741:32;17738:52;;;17786:1;17783;17776:12;17738:52;-1:-1:-1;17809:16:1;;17647:184;-1:-1:-1;17647:184:1:o;17836:489::-;18095:25;;;18151:2;18136:18;;18129:34;;;;-1:-1:-1;;;;;18199:32:1;;;;18194:2;18179:18;;18172:60;18263:2;18248:18;;18241:34;18306:3;18291:19;;18284:35;18082:3;18067:19;;17836:489::o;18330:341::-;18532:2;18514:21;;;18571:2;18551:18;;;18544:30;-1:-1:-1;;;18605:2:1;18590:18;;18583:47;18662:2;18647:18;;18330:341::o;18676:274::-;18850:25;;;-1:-1:-1;;;;;18911:32:1;18906:2;18891:18;;18884:60;18838:2;18823:18;;18676:274::o;18955:455::-;-1:-1:-1;;;;;19250:15:1;;;19232:34;;19297:2;19282:18;;19275:34;;;;19340:2;19325:18;;19318:34;;;;19388:15;;;19383:2;19368:18;;19361:43;19181:3;19166:19;;18955:455::o;20330:385::-;-1:-1:-1;;;;;20582:15:1;;;20564:34;;20634:15;;;;20629:2;20614:18;;20607:43;20693:14;;20686:22;20681:2;20666:18;;20659:50;20514:2;20499:18;;20330:385::o;20720:251::-;20790:6;20843:2;20831:9;20822:7;20818:23;20814:32;20811:52;;;20859:1;20856;20849:12;20811:52;20891:9;20885:16;20910:31;20935:5;20910:31;:::i;21681:282::-;-1:-1:-1;;;;;21881:32:1;;;;21863:51;;21945:2;21930:18;;21923:34;21851:2;21836:18;;21681:282::o;21968:245::-;22035:6;22088:2;22076:9;22067:7;22063:23;22059:32;22056:52;;;22104:1;22101;22094:12;22056:52;22136:9;22130:16;22155:28;22177:5;22155:28;:::i;22218:135::-;22257:3;22278:17;;;22275:43;;22298:18;;:::i;:::-;-1:-1:-1;22345:1:1;22334:13;;22218:135::o;22637:306::-;22725:6;22733;22741;22794:2;22782:9;22773:7;22769:23;22765:32;22762:52;;;22810:1;22807;22800:12;22762:52;22839:9;22833:16;22823:26;;22889:2;22878:9;22874:18;22868:25;22858:35;;22933:2;22922:9;22918:18;22912:25;22902:35;;22637:306;;;;;:::o;22948:375::-;-1:-1:-1;;;;;23206:15:1;;;23188:34;;23258:15;;;;23253:2;23238:18;;23231:43;23305:2;23290:18;;23283:34;;;;23138:2;23123:18;;22948:375::o;23328:353::-;23530:2;23512:21;;;23569:2;23549:18;;;23542:30;23608:31;23603:2;23588:18;;23581:59;23672:2;23657:18;;23328:353::o;23686:::-;23888:2;23870:21;;;23927:2;23907:18;;;23900:30;23966:31;23961:2;23946:18;;23939:59;24030:2;24015:18;;23686:353::o;24044:339::-;24246:2;24228:21;;;24285:2;24265:18;;;24258:30;-1:-1:-1;;;24319:2:1;24304:18;;24297:45;24374:2;24359:18;;24044:339::o;24388:375::-;24590:25;;;-1:-1:-1;;;;;24689:15:1;;;24684:2;24669:18;;24662:43;24741:15;24736:2;24721:18;;24714:43;24578:2;24563:18;;24388:375::o;24768:355::-;-1:-1:-1;;;;;24982:32:1;;;;24964:51;;25046:2;25031:18;;25024:34;;;;25101:14;25094:22;25089:2;25074:18;;25067:50;24952:2;24937:18;;24768:355::o;25538:337::-;25740:2;25722:21;;;25779:2;25759:18;;;25752:30;-1:-1:-1;;;25813:2:1;25798:18;;25791:43;25866:2;25851:18;;25538:337::o;25880:433::-;-1:-1:-1;;;;;26145:32:1;;;;26127:51;;26209:2;26194:18;;26187:34;;;;26252:2;26237:18;;26230:34;26295:2;26280:18;;26273:34;26114:3;26099:19;;25880:433::o;27025:250::-;27110:1;27120:113;27134:6;27131:1;27128:13;27120:113;;;27210:11;;;27204:18;27191:11;;;27184:39;27156:2;27149:10;27120:113;;;-1:-1:-1;;27267:1:1;27249:16;;27242:27;27025:250::o;27280:287::-;27409:3;27447:6;27441:13;27463:66;27522:6;27517:3;27510:4;27502:6;27498:17;27463:66;:::i;:::-;27545:16;;;;;27280:287;-1:-1:-1;;27280:287:1:o;27572:637::-;27803:6;27792:9;27785:25;27846:6;27841:2;27830:9;27826:18;27819:34;27918:1;27914;27909:3;27905:11;27901:19;27893:6;27889:32;27884:2;27873:9;27869:18;27862:60;27958:3;27953:2;27942:9;27938:18;27931:31;27766:4;27991:6;27985:13;28035:6;28029:3;28018:9;28014:19;28007:35;28051:80;28124:6;28118:3;28107:9;28103:19;28098:2;28090:6;28086:15;28051:80;:::i;:::-;28192:2;28171:15;-1:-1:-1;;28167:29:1;28152:45;;;;28199:3;28148:55;;27572:637;-1:-1:-1;;;;;27572:637:1:o

Swarm Source

ipfs://962c69b3e6c25963573d8820f016d9a4a42c0c25b722f03ef2a495f6a011862b

Block Transaction Gas Used Reward
view all blocks produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.