ETH Price: $3,609.18 (-0.20%)

Token

ERC-20: Staked ERN Vault (stERN)

Overview

Max Total Supply

10,055.206401832586793648 stERN

Holders

471

Market

Price

$0.00 @ 0.000000 ETH

Onchain Market Cap

$0.00

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 18 Decimals)

Balance
0.025513402508328031 stERN

Value
$0.00
0xbf49b454818783d12bf4f3375ff17c59015e66cb
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information

Contract Source Code Verified (Exact Match)

Contract Name:
ReaperVaultERC4626

Compiler Version
v0.8.18+commit.87f61d96

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, BSL 1.1 license

Contract Source Code (Solidity)

/**
 *Submitted for verification at optimistic.etherscan.io on 2023-07-12
*/

// SPDX-License-Identifier: BUSL-1.1

pragma solidity ^0.8.0;









interface IERC4626Events {
    event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);
    event Withdraw(
        address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares
    );
}





interface IStrategy {
    //vault only - withdraws funds from the strategy
    function withdraw(uint256 _amount) external returns (uint256 loss);

    //claims rewards, charges fees, and re-deposits; returns roi (+ve for profit, -ve for loss).
    function harvest() external returns (int256 roi);

    //returns the balance of all tokens managed by the strategy
    function balanceOf() external view returns (uint256);

    //returns the address of the vault that the strategy is serving
    function vault() external view returns (address);

    //returns the address of the token that the strategy needs to operate
    function want() external view returns (address);
}





library ReaperMathUtils {
    /**
     * @notice For doing an unchecked increment of an index for gas optimization purposes
     * @param _i - The number to increment
     * @return The incremented number
     */
    function uncheckedInc(uint256 _i) internal pure returns (uint256) {
        unchecked {
            return _i + 1;
        }
    }
}







/**
 * A mixin to provide access control to a variety of roles. Designed to be compatible
 * with both upgradeable and non-upgradble contracts. HAS NO STORAGE.
 */
abstract contract ReaperAccessControl {
    using ReaperMathUtils for uint256;

    /**
     * @notice Checks cascading role privileges to ensure that caller has at least role {_role}.
     * Any higher privileged role should be able to perform all the functions of any lower privileged role.
     * This is accomplished using the {cascadingAccess} array that lists all roles from most privileged
     * to least privileged.
     * @param _role - The role in bytes from the keccak256 hash of the role name
     */
    function _atLeastRole(bytes32 _role) internal view {
        bytes32[] memory cascadingAccessRoles = _cascadingAccessRoles();
        uint256 numRoles = cascadingAccessRoles.length;
        bool specifiedRoleFound = false;
        bool senderHighestRoleFound = false;

        // {_role} must be found in the {cascadingAccessRoles} array.
        // Also, msg.sender's highest role index <= specified role index.
        for (uint256 i = 0; i < numRoles; i = i.uncheckedInc()) {
            if (!senderHighestRoleFound && _hasRole(cascadingAccessRoles[i], msg.sender)) {
                senderHighestRoleFound = true;
            }
            if (_role == cascadingAccessRoles[i]) {
                specifiedRoleFound = true;
                break;
            }
        }

        require(specifiedRoleFound && senderHighestRoleFound, "Unauthorized access");
    }

    /**
     * @dev Returns an array of all the relevant roles arranged in descending order of privilege.
     *      Subclasses should override this to specify their unique roles arranged in the correct
     *      order, for example, [SUPER-ADMIN, ADMIN, GUARDIAN, STRATEGIST].
     */
    function _cascadingAccessRoles() internal view virtual returns (bytes32[] memory);

    /**
     * @dev Returns {true} if {_account} has been granted {_role}. Subclasses should override
     *      this to specify their unique role-checking criteria.
     */
    function _hasRole(bytes32 _role, address _account) internal view virtual returns (bool);
}


// OpenZeppelin Contracts (last updated v4.5.0) (access/AccessControlEnumerable.sol)




// OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol)




// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)



/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControl {
    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     *
     * _Available since v3.1._
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {AccessControl-_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) external;
}


/**
 * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.
 */
interface IAccessControlEnumerable is IAccessControl {
    /**
     * @dev Returns one of the accounts that have `role`. `index` must be a
     * value between 0 and {getRoleMemberCount}, non-inclusive.
     *
     * Role bearers are not sorted in any particular way, and their ordering may
     * change at any point.
     *
     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
     * you perform all queries on the same block. See the following
     * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
     * for more information.
     */
    function getRoleMember(bytes32 role, uint256 index) external view returns (address);

    /**
     * @dev Returns the number of accounts that have `role`. Can be used
     * together with {getRoleMember} to enumerate all bearers of a role.
     */
    function getRoleMemberCount(bytes32 role) external view returns (uint256);
}


// OpenZeppelin Contracts (last updated v4.8.0) (access/AccessControl.sol)





// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)



/**
 * @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;
    }
}


// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)




// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)



/**
 * @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) {
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1);

            ///////////////////////////////////////////////
            // 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 10, 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 * 8) < value ? 1 : 0);
        }
    }
}


/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _SYMBOLS = "0123456789abcdef";
    uint8 private constant _ADDRESS_LENGTH = 20;

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
    }
}


// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)




// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)



/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}


/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}


/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms. This is a lightweight version that doesn't allow enumerating role
 * members except through off-chain means by accessing the contract event logs. Some
 * applications may benefit from on-chain enumerability, for those cases see
 * {AccessControlEnumerable}.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it.
 */
abstract contract AccessControl is Context, IAccessControl, ERC165 {
    struct RoleData {
        mapping(address => bool) members;
        bytes32 adminRole;
    }

    mapping(bytes32 => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with a standardized message including the required role.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     *
     * _Available since v4.1._
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role);
        _;
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
        return _roles[role].members[account];
    }

    /**
     * @dev Revert with a standard message if `_msgSender()` is missing `role`.
     * Overriding this function changes the behavior of the {onlyRole} modifier.
     *
     * Format of the revert message is described in {_checkRole}.
     *
     * _Available since v4.6._
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, _msgSender());
    }

    /**
     * @dev Revert with a standard message if `account` is missing `role`.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert(
                string(
                    abi.encodePacked(
                        "AccessControl: account ",
                        Strings.toHexString(account),
                        " is missing role ",
                        Strings.toHexString(uint256(role), 32)
                    )
                )
            );
        }
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
        return _roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleGranted} event.
     */
    function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleRevoked} event.
     */
    function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been revoked `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     *
     * May emit a {RoleRevoked} event.
     */
    function renounceRole(bytes32 role, address account) public virtual override {
        require(account == _msgSender(), "AccessControl: can only renounce roles for self");

        _revokeRole(role, account);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event. Note that unlike {grantRole}, this function doesn't perform any
     * checks on the calling account.
     *
     * May emit a {RoleGranted} event.
     *
     * [WARNING]
     * ====
     * This function should only be called from the constructor when setting
     * up the initial roles for the system.
     *
     * Using this function in any other way is effectively circumventing the admin
     * system imposed by {AccessControl}.
     * ====
     *
     * NOTE: This function is deprecated in favor of {_grantRole}.
     */
    function _setupRole(bytes32 role, address account) internal virtual {
        _grantRole(role, account);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        bytes32 previousAdminRole = getRoleAdmin(role);
        _roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleGranted} event.
     */
    function _grantRole(bytes32 role, address account) internal virtual {
        if (!hasRole(role, account)) {
            _roles[role].members[account] = true;
            emit RoleGranted(role, account, _msgSender());
        }
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleRevoked} event.
     */
    function _revokeRole(bytes32 role, address account) internal virtual {
        if (hasRole(role, account)) {
            _roles[role].members[account] = false;
            emit RoleRevoked(role, account, _msgSender());
        }
    }
}


// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.



/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 *
 * [WARNING]
 * ====
 * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
 * unusable.
 * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
 *
 * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
 * array of EnumerableSet.
 * ====
 */
library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;
        // Position of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping(bytes32 => uint256) _indexes;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We read and store the value's index to prevent multiple reads from the same storage slot
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) {
            // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = valueIndex - 1;
            uint256 lastIndex = set._values.length - 1;

            if (lastIndex != toDeleteIndex) {
                bytes32 lastValue = set._values[lastIndex];

                // Move the last value to the index where the value to delete is
                set._values[toDeleteIndex] = lastValue;
                // Update the index for the moved value
                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
            }

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the index for the deleted slot
            delete set._indexes[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._indexes[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        return set._values[index];
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function _values(Set storage set) private view returns (bytes32[] memory) {
        return set._values;
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
        bytes32[] memory store = _values(set._inner);
        bytes32[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(AddressSet storage set) internal view returns (address[] memory) {
        bytes32[] memory store = _values(set._inner);
        address[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(UintSet storage set) internal view returns (uint256[] memory) {
        bytes32[] memory store = _values(set._inner);
        uint256[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }
}


/**
 * @dev Extension of {AccessControl} that allows enumerating the members of each role.
 */
abstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {
    using EnumerableSet for EnumerableSet.AddressSet;

    mapping(bytes32 => EnumerableSet.AddressSet) private _roleMembers;

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns one of the accounts that have `role`. `index` must be a
     * value between 0 and {getRoleMemberCount}, non-inclusive.
     *
     * Role bearers are not sorted in any particular way, and their ordering may
     * change at any point.
     *
     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
     * you perform all queries on the same block. See the following
     * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
     * for more information.
     */
    function getRoleMember(bytes32 role, uint256 index) public view virtual override returns (address) {
        return _roleMembers[role].at(index);
    }

    /**
     * @dev Returns the number of accounts that have `role`. Can be used
     * together with {getRoleMember} to enumerate all bearers of a role.
     */
    function getRoleMemberCount(bytes32 role) public view virtual override returns (uint256) {
        return _roleMembers[role].length();
    }

    /**
     * @dev Overload {_grantRole} to track enumerable memberships
     */
    function _grantRole(bytes32 role, address account) internal virtual override {
        super._grantRole(role, account);
        _roleMembers[role].add(account);
    }

    /**
     * @dev Overload {_revokeRole} to track enumerable memberships
     */
    function _revokeRole(bytes32 role, address account) internal virtual override {
        super._revokeRole(role, account);
        _roleMembers[role].remove(account);
    }
}


// OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)



/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be _NOT_ENTERED
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}


// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol)




// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)



/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

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

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

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

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

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

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


// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)





/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}



/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 * For a generic mechanism see {ERC20PresetMinterPauser}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * We have followed general OpenZeppelin Contracts guidelines: functions revert
 * instead returning `false` on failure. This behavior is nonetheless
 * conventional and does not conflict with the expectations of ERC20
 * applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See {IERC20-approve}.
 */
contract ERC20 is Context, IERC20, IERC20Metadata {
    mapping(address => uint256) private _balances;

    mapping(address => mapping(address => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * The default value of {decimals} is 18. To select a different value for
     * {decimals} you should overload it.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the value {ERC20} uses, unless this function is
     * overridden;
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual override returns (uint8) {
        return 18;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual override returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address to, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
     * `transferFrom`. This is semantically equivalent to an infinite approval.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * NOTE: Does not update the allowance if the current allowance
     * is the maximum `uint256`.
     *
     * Requirements:
     *
     * - `from` and `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     * - the caller must have allowance for ``from``'s tokens of at least
     * `amount`.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual override returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, amount);
        _transfer(from, to, amount);
        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, allowance(owner, spender) + addedValue);
        return true;
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
        address owner = _msgSender();
        uint256 currentAllowance = allowance(owner, spender);
        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
        unchecked {
            _approve(owner, spender, currentAllowance - subtractedValue);
        }

        return true;
    }

    /**
     * @dev Moves `amount` of tokens from `from` to `to`.
     *
     * This internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     */
    function _transfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {
        require(from != address(0), "ERC20: transfer from the zero address");
        require(to != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(from, to, amount);

        uint256 fromBalance = _balances[from];
        require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
        unchecked {
            _balances[from] = fromBalance - amount;
            // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
            // decrementing then incrementing.
            _balances[to] += amount;
        }

        emit Transfer(from, to, amount);

        _afterTokenTransfer(from, to, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: mint to the zero address");

        _beforeTokenTransfer(address(0), account, amount);

        _totalSupply += amount;
        unchecked {
            // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
            _balances[account] += amount;
        }
        emit Transfer(address(0), account, amount);

        _afterTokenTransfer(address(0), account, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: burn from the zero address");

        _beforeTokenTransfer(account, address(0), amount);

        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        unchecked {
            _balances[account] = accountBalance - amount;
            // Overflow not possible: amount <= accountBalance <= totalSupply.
            _totalSupply -= amount;
        }

        emit Transfer(account, address(0), amount);

        _afterTokenTransfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.
     *
     * Does not update the allowance amount in case of infinite allowance.
     * Revert if not enough allowance is available.
     *
     * Might emit an {Approval} event.
     */
    function _spendAllowance(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            require(currentAllowance >= amount, "ERC20: insufficient allowance");
            unchecked {
                _approve(owner, spender, currentAllowance - amount);
            }
        }
    }

    /**
     * @dev Hook that is called before any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * will be transferred to `to`.
     * - when `from` is zero, `amount` tokens will be minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}

    /**
     * @dev Hook that is called after any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * has been transferred to `to`.
     * - when `from` is zero, `amount` tokens have been minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _afterTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}
}



// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)





// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)



/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}


// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)



/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

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

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

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

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

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

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

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}


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

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

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

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

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

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

    function safePermit(
        IERC20Permit token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

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

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



/**
 * @notice Implementation of a vault to deposit funds for yield optimizing.
 * This is the contract that receives funds and that users interface with.
 * The yield optimizing strategy itself is implemented in a separate 'Strategy.sol' contract.
 */
contract ReaperVaultV2 is ReaperAccessControl, ERC20, IERC4626Events, AccessControlEnumerable, ReentrancyGuard {
    using ReaperMathUtils for uint256;
    using SafeERC20 for IERC20Metadata;

    struct StrategyParams {
        uint256 activation; // Activation block.timestamp
        uint256 feeBPS; // Performance fee taken from profit, in BPS
        uint256 allocBPS; // Allocation in BPS of vault's total assets
        uint256 allocated; // Amount of capital allocated to this strategy
        uint256 gains; // Total returns that Strategy has realized for Vault
        uint256 losses; // Total losses that Strategy has realized for Vault
        uint256 lastReport; // block.timestamp of the last time a report occured
    }

    mapping(address => StrategyParams) public strategies;

    // Ordering that `withdraw` uses to determine which strategies to pull funds from
    address[] public withdrawalQueue;

    uint256 public constant DEGRADATION_COEFFICIENT = 10 ** 18; // The unit for calculating profit degradation.
    uint256 public constant PERCENT_DIVISOR = 10000;
    uint256 public tvlCap;

    uint256 public totalIdle; // Amount of tokens in the vault
    uint256 public totalAllocBPS; // Sum of allocBPS across all strategies (in BPS, <= 10k)
    uint256 public totalAllocated; // Amount of tokens that have been allocated to all strategies
    uint256 public lastReport; // block.timestamp of last report from any strategy

    uint256 public immutable constructionTime;
    bool public emergencyShutdown;

    // The token the vault accepts and looks to maximize.
    IERC20Metadata public immutable token;

    // Max slippage(loss) allowed when withdrawing, in BPS (0.01%)
    uint256 public withdrawMaxLoss = 1;
    uint256 public lockedProfitDegradation; // rate per block of degradation. DEGRADATION_COEFFICIENT is 100% per block
    uint256 public lockedProfit; // how much profit is locked and cant be withdrawn

    /**
     * Reaper Roles in increasing order of privilege.
     * {STRATEGIST} - Role conferred to authors of the strategy, allows for tweaking non-critical params.
     * {GUARDIAN} - Multisig requiring 2 signatures for invoking emergency measures.
     * {ADMIN}- Multisig requiring 3 signatures for deactivating emergency measures and changing TVL cap.
     *
     * The DEFAULT_ADMIN_ROLE (in-built access control role) will be granted to a multisig requiring 4
     * signatures. This role would have the ability to add strategies, as well as the ability to grant any other
     * roles.
     *
     * Also note that roles are cascading. So any higher privileged role should be able to perform all the functions
     * of any lower privileged role.
     */
    bytes32 public constant STRATEGIST = keccak256("STRATEGIST");
    bytes32 public constant GUARDIAN = keccak256("GUARDIAN");
    bytes32 public constant ADMIN = keccak256("ADMIN");

    address public treasury; // address to whom performance fee is remitted in the form of vault shares

    event StrategyAdded(address indexed strategy, uint256 feeBPS, uint256 allocBPS);
    event StrategyFeeBPSUpdated(address indexed strategy, uint256 feeBPS);
    event StrategyAllocBPSUpdated(address indexed strategy, uint256 allocBPS);
    event StrategyRevoked(address indexed strategy);
    event UpdateWithdrawalQueue(address[] withdrawalQueue);
    event WithdrawMaxLossUpdated(uint256 withdrawMaxLoss);
    event EmergencyShutdown(bool active);
    event InCaseTokensGetStuckCalled(address token, uint256 amount);
    event TvlCapUpdated(uint256 newTvlCap);
    event LockedProfitDegradationUpdated(uint256 degradation);
    event StrategyReported(
        address indexed strategy,
        uint256 gain,
        uint256 loss,
        uint256 debtPaid,
        uint256 gains,
        uint256 losses,
        uint256 allocated,
        uint256 allocationAdded,
        uint256 allocBPS
    );

    /**
     * @notice Initializes the vault's own 'RF' token.
     * This token is minted when someone does a deposit. It is burned in order
     * to withdraw the corresponding portion of the underlying assets.
     * @param _token the token to maximize.
     * @param _name the name of the vault token.
     * @param _symbol the symbol of the vault token.
     * @param _tvlCap initial deposit cap for scaling TVL safely
     */
    constructor(
        address _token,
        string memory _name,
        string memory _symbol,
        uint256 _tvlCap,
        address _treasury,
        address[] memory _strategists,
        address[] memory _multisigRoles
    ) ERC20(string(_name), string(_symbol)) {
        token = IERC20Metadata(_token);
        constructionTime = block.timestamp;
        lastReport = block.timestamp;
        tvlCap = _tvlCap;
        treasury = _treasury;
        lockedProfitDegradation = (DEGRADATION_COEFFICIENT * 46) / 10 ** 6; // 6 hours in blocks

        uint256 numStrategists = _strategists.length;
        for (uint256 i = 0; i < numStrategists; i = i.uncheckedInc()) {
            _grantRole(STRATEGIST, _strategists[i]);
        }

        _grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
        _grantRole(DEFAULT_ADMIN_ROLE, _multisigRoles[0]);
        _grantRole(ADMIN, _multisigRoles[1]);
        _grantRole(GUARDIAN, _multisigRoles[2]);
    }

    /**
     * @notice Adds a new strategy to the vault with a given allocation amount in basis points.
     * @param _strategy The strategy to add.
     * @param _feeBPS The performance fee (taken from profit) in basis points
     * @param _allocBPS The strategy allocation in basis points
     */
    function addStrategy(address _strategy, uint256 _feeBPS, uint256 _allocBPS) external {
        _atLeastRole(DEFAULT_ADMIN_ROLE);
        require(!emergencyShutdown, "Cannot add strategy during emergency shutdown");
        require(_strategy != address(0), "Invalid strategy address");
        require(strategies[_strategy].activation == 0, "Strategy already added");
        require(address(this) == IStrategy(_strategy).vault(), "Strategy's vault does not match");
        require(address(token) == IStrategy(_strategy).want(), "Strategy's want does not match");
        require(_feeBPS <= PERCENT_DIVISOR / 5, "Fee cannot be higher than 20 BPS");
        require(_allocBPS + totalAllocBPS <= PERCENT_DIVISOR, "Invalid allocBPS value");

        strategies[_strategy] = StrategyParams({
            activation: block.timestamp,
            feeBPS: _feeBPS,
            allocBPS: _allocBPS,
            allocated: 0,
            gains: 0,
            losses: 0,
            lastReport: block.timestamp
        });

        totalAllocBPS += _allocBPS;
        withdrawalQueue.push(_strategy);
        emit StrategyAdded(_strategy, _feeBPS, _allocBPS);
    }

    /**
     * @notice Updates the strategy's performance fee.
     * @param _strategy The strategy to update.
     * @param _feeBPS The new performance fee in basis points.
     */
    function updateStrategyFeeBPS(address _strategy, uint256 _feeBPS) external {
        _atLeastRole(ADMIN);
        require(strategies[_strategy].activation != 0, "Invalid strategy address");
        require(_feeBPS <= PERCENT_DIVISOR / 5, "Fee cannot be higher than 20 BPS");
        strategies[_strategy].feeBPS = _feeBPS;
        emit StrategyFeeBPSUpdated(_strategy, _feeBPS);
    }

    /**
     * @notice Updates the allocation points for a given strategy.
     * @param _strategy The strategy to update.
     * @param _allocBPS The strategy allocation in basis points
     */
    function updateStrategyAllocBPS(address _strategy, uint256 _allocBPS) external {
        require(strategies[_strategy].activation != 0, "Invalid strategy address");
        uint256 currentStrategyAllocBPS = strategies[_strategy].allocBPS;
        if (currentStrategyAllocBPS != 0) {
            _atLeastRole(STRATEGIST);
        } else {
            // prevent STRATEGIST/GUARDIAN from re-allocating to potentially revoked strategy
            _atLeastRole(ADMIN);
        }
        totalAllocBPS -= currentStrategyAllocBPS;
        strategies[_strategy].allocBPS = _allocBPS;
        totalAllocBPS += _allocBPS;
        require(totalAllocBPS <= PERCENT_DIVISOR, "Invalid BPS value");
        emit StrategyAllocBPSUpdated(_strategy, _allocBPS);
    }

    /**
     * @notice Removes any allocation to a given strategy.
     * @param _strategy The strategy to revoke.
     */
    function revokeStrategy(address _strategy) external {
        if (msg.sender != _strategy) {
            _atLeastRole(GUARDIAN);
        }

        if (strategies[_strategy].allocBPS == 0) {
            return;
        }

        totalAllocBPS -= strategies[_strategy].allocBPS;
        strategies[_strategy].allocBPS = 0;
        emit StrategyRevoked(_strategy);
    }

    /**
     * @notice Called by a strategy to determine the amount of capital that the vault is
     * able to provide it. A positive amount means that vault has excess capital to provide
     * the strategy, while a negative amount means that the strategy has a balance owing to
     * the vault.
     */
    function availableCapital() public view returns (int256) {
        address stratAddr = msg.sender;
        if (totalAllocBPS == 0 || emergencyShutdown) {
            return -int256(strategies[stratAddr].allocated);
        }

        uint256 stratMaxAllocation = (strategies[stratAddr].allocBPS * balance()) / PERCENT_DIVISOR;
        uint256 stratCurrentAllocation = strategies[stratAddr].allocated;

        if (stratCurrentAllocation > stratMaxAllocation) {
            return -int256(stratCurrentAllocation - stratMaxAllocation);
        } else if (stratCurrentAllocation < stratMaxAllocation) {
            uint256 vaultMaxAllocation = (totalAllocBPS * balance()) / PERCENT_DIVISOR;
            uint256 vaultCurrentAllocation = totalAllocated;

            if (vaultCurrentAllocation >= vaultMaxAllocation) {
                return 0;
            }

            uint256 available = stratMaxAllocation - stratCurrentAllocation;
            available = Math.min(available, vaultMaxAllocation - vaultCurrentAllocation);
            available = Math.min(available, totalIdle);

            return int256(available);
        } else {
            return 0;
        }
    }

    /**
     * @notice Updates the withdrawalQueue to match the addresses and order specified.
     * @param _withdrawalQueue The new withdrawalQueue to update to.
     */
    function setWithdrawalQueue(address[] calldata _withdrawalQueue) external {
        _atLeastRole(ADMIN);
        uint256 queueLength = _withdrawalQueue.length;
        require(queueLength != 0, "Queue must not be empty");

        delete withdrawalQueue;
        for (uint256 i = 0; i < queueLength; i = i.uncheckedInc()) {
            address strategy = _withdrawalQueue[i];
            StrategyParams storage params = strategies[strategy];
            require(params.activation != 0, "Invalid strategy address");
            withdrawalQueue.push(strategy);
        }
        emit UpdateWithdrawalQueue(_withdrawalQueue);
    }

    /**
     * @dev It calculates the total underlying value of {token} held by the system.
     * It takes into account the vault contract idle funds, and the capital deployed across
     * all the strategies.
     */
    function balance() public view returns (uint256) {
        return totalIdle + totalAllocated;
    }

    /**
     * @notice It calculates the amount of free funds available after profit locking.
     * For calculating share price, issuing shares during deposit, or burning shares during withdrawal.
     * @return freeFunds - the total amount of free funds available.
     */
    function _freeFunds() internal view returns (uint256) {
        return balance() - _calculateLockedProfit();
    }

    /**
     * @dev Function for various UIs to display the current value of one of our yield tokens.
     * Returns an uint256 with 18 decimals of how much underlying asset one vault share represents.
     */
    function getPricePerFullShare() public view returns (uint256) {
        return totalSupply() == 0 ? 10 ** decimals() : (_freeFunds() * 10 ** decimals()) / totalSupply();
    }

    /**
     * @dev A helper function to call deposit() with all the sender's funds.
     */
    function depositAll() external {
        _deposit(token.balanceOf(msg.sender), msg.sender);
    }

    /**
     * @notice The entrypoint of funds into the system. People deposit with this function
     * into the vault.
     * @param _amount The amount of assets to deposit
     */
    function deposit(uint256 _amount) external {
        _deposit(_amount, msg.sender);
    }

    // Internal helper function to deposit {_amount} of assets and mint corresponding
    // shares to {_receiver}. Returns the number of shares that were minted.
    function _deposit(uint256 _amount, address _receiver) internal nonReentrant returns (uint256 shares) {
        require(!emergencyShutdown, "Cannot deposit during emergency shutdown");
        require(_amount != 0, "Invalid amount");
        require(balance() + _amount <= tvlCap, "Vault is full");

        uint256 supply = totalSupply();
        if (supply == 0) {
            shares = _amount;
        } else {
            shares = (_amount * supply) / _freeFunds(); // use "freeFunds" instead of "balance"
        }

        _mint(_receiver, shares);
        totalIdle += _amount;
        token.safeTransferFrom(msg.sender, address(this), _amount);
        emit Deposit(msg.sender, _receiver, _amount, shares);
    }

    /**
     * @dev A helper function to call withdraw() with all the sender's funds.
     */
    function withdrawAll() external {
        _withdraw(balanceOf(msg.sender), msg.sender, msg.sender);
    }

    /**
     * @notice Function to exit the system. The vault will withdraw the required tokens
     * from the strategies and pay up the token holder. A proportional number of IOU
     * tokens are burned in the process.
     * @param _shares the number of shares to burn
     */
    function withdraw(uint256 _shares) external {
        _withdraw(_shares, msg.sender, msg.sender);
    }

    // Internal helper function to burn {_shares} of vault shares belonging to {_owner}
    // and return corresponding assets to {_receiver}. Returns the number of assets that were returned.
    function _withdraw(uint256 _shares, address _receiver, address _owner)
        internal
        nonReentrant
        returns (uint256 value)
    {
        require(_shares != 0, "Invalid amount");
        value = (_freeFunds() * _shares) / totalSupply();

        uint256 vaultBalance = totalIdle;
        if (value > vaultBalance) {
            uint256 totalLoss = 0;
            uint256 queueLength = withdrawalQueue.length;
            for (uint256 i = 0; i < queueLength; i = i.uncheckedInc()) {
                if (value <= vaultBalance) {
                    break;
                }

                address stratAddr = withdrawalQueue[i];
                uint256 strategyBal = strategies[stratAddr].allocated;
                if (strategyBal == 0) {
                    continue;
                }

                uint256 remaining = value - vaultBalance;
                uint256 preWithdrawBal = token.balanceOf(address(this));
                uint256 loss = IStrategy(stratAddr).withdraw(Math.min(remaining, strategyBal));
                uint256 actualWithdrawn = token.balanceOf(address(this)) - preWithdrawBal;
                vaultBalance += actualWithdrawn;

                // Withdrawer incurs any losses from withdrawing as reported by strat
                if (loss != 0) {
                    value -= loss;
                    totalLoss += loss;
                    _reportLoss(stratAddr, loss);
                }

                strategies[stratAddr].allocated -= actualWithdrawn;
                totalAllocated -= actualWithdrawn;
            }

            totalIdle = vaultBalance;
            if (value > vaultBalance) {
                value = vaultBalance;
                _shares = ((value + totalLoss) * totalSupply()) / _freeFunds();
            }

            require(
                totalLoss <= ((value + totalLoss) * withdrawMaxLoss) / PERCENT_DIVISOR, "Withdraw loss exceeds slippage"
            );
        }

        _burn(_owner, _shares);
        totalIdle -= value;
        token.safeTransfer(_receiver, value);
        emit Withdraw(msg.sender, _receiver, _owner, value, _shares);
    }

    /**
     * @notice It calculates the amount of locked profit from recent harvests.
     * @return the amount of locked profit.
     */
    function _calculateLockedProfit() internal view returns (uint256) {
        uint256 lockedFundsRatio = (block.timestamp - lastReport) * lockedProfitDegradation;
        if (lockedFundsRatio < DEGRADATION_COEFFICIENT) {
            return lockedProfit - ((lockedFundsRatio * lockedProfit) / DEGRADATION_COEFFICIENT);
        }

        return 0;
    }

    /**
     * @notice Helper function to report a loss by a given strategy.
     * @param strategy The strategy to report the loss for.
     * @param loss The amount lost.
     */
    function _reportLoss(address strategy, uint256 loss) internal {
        StrategyParams storage stratParams = strategies[strategy];
        // Loss can only be up the amount of capital allocated to the strategy
        uint256 allocation = stratParams.allocated;
        require(loss <= allocation, "Strategy loss cannot be greater than allocation");

        if (totalAllocBPS != 0) {
            // reduce strat's allocBPS proportional to loss
            uint256 bpsChange = Math.min((loss * totalAllocBPS) / totalAllocated, stratParams.allocBPS);

            // If the loss is too small, bpsChange will be 0
            if (bpsChange != 0) {
                stratParams.allocBPS -= bpsChange;
                totalAllocBPS -= bpsChange;
            }
        }

        // Finally, adjust our strategy's parameters by the loss
        stratParams.losses += loss;
        stratParams.allocated -= loss;
        totalAllocated -= loss;
    }

    /**
     * @notice Helper function to charge fees from the gain reported by a strategy.
     * Fees is charged by issuing the corresponding amount of vault shares to the treasury.
     * @param strategy The strategy that reported gain.
     * @param gain The amount of profit reported.
     * @return The fee amount in assets.
     */
    function _chargeFees(address strategy, uint256 gain) internal returns (uint256) {
        uint256 performanceFee = (gain * strategies[strategy].feeBPS) / PERCENT_DIVISOR;
        if (performanceFee != 0) {
            uint256 supply = totalSupply();
            uint256 shares = supply == 0 ? performanceFee : (performanceFee * supply) / _freeFunds();
            _mint(treasury, shares);
        }
        return performanceFee;
    }

    // To avoid "stack too deep" errors
    struct LocalVariables_report {
        address stratAddr;
        uint256 loss;
        uint256 gain;
        uint256 fees;
        int256 available;
        uint256 debt;
        uint256 credit;
        uint256 debtPayment;
        uint256 freeWantInStrat;
        uint256 lockedProfitBeforeLoss;
    }

    /**
     * @notice Main contact point where each strategy interacts with the vault during its harvest
     * to report profit/loss as well as any repayment of debt.
     * @param _roi The return on investment (positive or negative) given as the total amount
     * gained or lost from the harvest.
     * @param _repayment The repayment of debt by the strategy.
     */
    function report(int256 _roi, uint256 _repayment) external returns (uint256) {
        LocalVariables_report memory vars;
        vars.stratAddr = msg.sender;
        StrategyParams storage strategy = strategies[vars.stratAddr];
        require(strategy.activation != 0, "Unauthorized strategy");

        if (_roi < 0) {
            vars.loss = uint256(-_roi);
            _reportLoss(vars.stratAddr, vars.loss);
        } else if (_roi > 0) {
            vars.gain = uint256(_roi);
            vars.fees = _chargeFees(vars.stratAddr, vars.gain);
            strategy.gains += vars.gain;
        }

        vars.available = availableCapital();
        if (vars.available < 0) {
            vars.debt = uint256(-vars.available);
            vars.debtPayment = Math.min(vars.debt, _repayment);

            if (vars.debtPayment != 0) {
                strategy.allocated -= vars.debtPayment;
                totalAllocated -= vars.debtPayment;
                vars.debt -= vars.debtPayment; // tracked for return value
            }
        } else if (vars.available > 0) {
            vars.credit = uint256(vars.available);
            strategy.allocated += vars.credit;
            totalAllocated += vars.credit;
        }

        vars.freeWantInStrat = vars.gain + vars.debtPayment;
        if (vars.credit > vars.freeWantInStrat) {
            totalIdle -= (vars.credit - vars.freeWantInStrat);
            token.safeTransfer(vars.stratAddr, vars.credit - vars.freeWantInStrat);
        } else if (vars.credit < vars.freeWantInStrat) {
            totalIdle += (vars.freeWantInStrat - vars.credit);
            token.safeTransferFrom(vars.stratAddr, address(this), vars.freeWantInStrat - vars.credit);
        }

        // Profit is locked and gradually released per block
        // NOTE: compute current locked profit and replace with sum of current and new
        vars.lockedProfitBeforeLoss = _calculateLockedProfit() + vars.gain - vars.fees;
        if (vars.lockedProfitBeforeLoss > vars.loss) {
            lockedProfit = vars.lockedProfitBeforeLoss - vars.loss;
        } else {
            lockedProfit = 0;
        }

        strategy.lastReport = block.timestamp;
        lastReport = block.timestamp;

        emit StrategyReported(
            vars.stratAddr,
            vars.gain,
            vars.loss,
            vars.debtPayment,
            strategy.gains,
            strategy.losses,
            strategy.allocated,
            vars.credit,
            strategy.allocBPS
        );

        if (strategy.allocBPS == 0 || emergencyShutdown) {
            return IStrategy(vars.stratAddr).balanceOf();
        }

        return vars.debt;
    }

    /**
     * @notice Updates the withdrawMaxLoss which is the maximum allowed slippage.
     * @param _withdrawMaxLoss The new value, in basis points.
     */
    function updateWithdrawMaxLoss(uint256 _withdrawMaxLoss) external {
        _atLeastRole(STRATEGIST);
        require(_withdrawMaxLoss <= PERCENT_DIVISOR, "Invalid BPS value");
        withdrawMaxLoss = _withdrawMaxLoss;
        emit WithdrawMaxLossUpdated(_withdrawMaxLoss);
    }

    /**
     * @notice Updates the vault tvl cap (the max amount of assets held by the vault).
     * @dev pass in max value of uint to effectively remove TVL cap.
     * @param _newTvlCap The new tvl cap.
     */
    function updateTvlCap(uint256 _newTvlCap) public {
        _atLeastRole(ADMIN);
        tvlCap = _newTvlCap;
        emit TvlCapUpdated(tvlCap);
    }

    /**
     * @dev helper function to remove TVL cap
     */
    function removeTvlCap() external {
        updateTvlCap(type(uint256).max);
    }

    /**
     * Activates or deactivates Vault mode where all Strategies go into full
     * withdrawal.
     * During Emergency Shutdown:
     * 1. No Users may deposit into the Vault (but may withdraw as usual.)
     * 2. New Strategies may not be added.
     * 3. Each Strategy must pay back their debt as quickly as reasonable to
     * minimally affect their position.
     *
     * If true, the Vault goes into Emergency Shutdown. If false, the Vault
     * goes back into Normal Operation.
     */
    function setEmergencyShutdown(bool _active) external {
        if (_active) {
            _atLeastRole(GUARDIAN);
        } else {
            _atLeastRole(ADMIN);
        }
        emergencyShutdown = _active;
        emit EmergencyShutdown(_active);
    }

    /**
     * @notice Changes the locked profit degradation.
     * @param degradation - The rate of degradation in percent per second scaled to 1e18.
     */
    function setLockedProfitDegradation(uint256 degradation) external {
        _atLeastRole(ADMIN);
        require(degradation <= DEGRADATION_COEFFICIENT, "Degradation cannot be more than 100%");
        lockedProfitDegradation = degradation;
        emit LockedProfitDegradationUpdated(degradation);
    }

    /**
     * @notice Only DEFAULT_ADMIN_ROLE can update treasury address.
     */
    function updateTreasury(address newTreasury) external {
        _atLeastRole(DEFAULT_ADMIN_ROLE);
        require(newTreasury != address(0), "Invalid address");
        treasury = newTreasury;
    }

    /**
     * @dev Rescues random funds stuck that the strat can't handle.
     * @param _token address of the token to rescue.
     */
    function inCaseTokensGetStuck(address _token) external {
        _atLeastRole(ADMIN);

        uint256 amount = IERC20Metadata(_token).balanceOf(address(this));
        if (_token == address(token)) {
            amount -= totalIdle;
        }
        require(amount != 0, "Zero amount");

        IERC20Metadata(_token).safeTransfer(msg.sender, amount);
        emit InCaseTokensGetStuckCalled(_token, amount);
    }

    /**
     * @dev Overrides the default 18 decimals for the vault ERC20 to
     * match the same decimals as the underlying token used
     */
    function decimals() public view override returns (uint8) {
        return token.decimals();
    }

    /**
     * @dev Returns an array of all the relevant roles arranged in descending order of privilege.
     *      Subclasses should override this to specify their unique roles arranged in the correct
     *      order, for example, [SUPER-ADMIN, ADMIN, GUARDIAN, STRATEGIST].
     */
    function _cascadingAccessRoles() internal pure override returns (bytes32[] memory) {
        bytes32[] memory cascadingAccessRoles = new bytes32[](4);
        cascadingAccessRoles[0] = DEFAULT_ADMIN_ROLE;
        cascadingAccessRoles[1] = ADMIN;
        cascadingAccessRoles[2] = GUARDIAN;
        cascadingAccessRoles[3] = STRATEGIST;
        return cascadingAccessRoles;
    }

    /**
     * @dev Returns {true} if {_account} has been granted {_role}. Subclasses should override
     *      this to specify their unique role-checking criteria.
     */
    function _hasRole(bytes32 _role, address _account) internal view override returns (bool) {
        return hasRole(_role, _account);
    }
}





interface IERC4626Functions {
    function asset() external view returns (address assetTokenAddress);

    function totalAssets() external view returns (uint256 totalManagedAssets);

    function convertToShares(uint256 assets) external view returns (uint256 shares);

    function convertToAssets(uint256 shares) external view returns (uint256 assets);

    function maxDeposit(address receiver) external view returns (uint256 maxAssets);

    function previewDeposit(uint256 assets) external view returns (uint256 shares);

    function deposit(uint256 assets, address receiver) external returns (uint256 shares);

    function maxMint(address receiver) external view returns (uint256 maxShares);

    function previewMint(uint256 shares) external view returns (uint256 assets);

    function mint(uint256 shares, address receiver) external returns (uint256 assets);

    function maxWithdraw(address owner) external view returns (uint256 maxAssets);

    function previewWithdraw(uint256 assets) external view returns (uint256 shares);

    function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);

    function maxRedeem(address owner) external view returns (uint256 maxShares);

    function previewRedeem(uint256 shares) external view returns (uint256 assets);

    function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);
}


// Extension of ReaperVaultV2 that implements all ERC4626 functions.
// ReaperVaultV2 still extends IERC4626Events so it can have access to the Deposit
// and Withdraw events to log within its own internal _deposit() and _withdraw()
// functions.
contract ReaperVaultERC4626 is ReaperVaultV2, IERC4626Functions {
    using SafeERC20 for IERC20Metadata;

    // See comments on ReaperVaultV2's constructor
    constructor(
        address _token,
        string memory _name,
        string memory _symbol,
        uint256 _tvlCap,
        address _treasury,
        address[] memory _strategists,
        address[] memory _multisigRoles
    ) ReaperVaultV2(_token, _name, _symbol, _tvlCap, _treasury, _strategists, _multisigRoles) {}

    // The address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
    // MUST be an ERC-20 token contract.
    // MUST NOT revert.
    function asset() external view override returns (address assetTokenAddress) {
        return address(token);
    }

    // Total amount of the underlying asset that is “managed” by Vault.
    // SHOULD include any compounding that occurs from yield.
    // MUST be inclusive of any fees that are charged against assets in the Vault.
    // MUST NOT revert.
    function totalAssets() external view override returns (uint256 totalManagedAssets) {
        return balance();
    }

    // The amount of shares that the Vault would exchange for the amount of assets provided,
    // in an ideal scenario where all the conditions are met.
    //
    // MUST NOT be inclusive of any fees that are charged against assets in the Vault.
    // MUST NOT show any variations depending on the caller.
    // MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
    // MUST NOT revert unless due to integer overflow caused by an unreasonably large input.
    // MUST round down towards 0.
    // This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect
    // the “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and from.
    function convertToShares(uint256 assets) public view override returns (uint256 shares) {
        if (totalSupply() == 0 || _freeFunds() == 0) return assets;
        return (assets * totalSupply()) / _freeFunds();
    }

    // The amount of assets that the Vault would exchange for the amount of shares provided,
    // in an ideal scenario where all the conditions are met.
    //
    // MUST NOT be inclusive of any fees that are charged against assets in the Vault.
    // MUST NOT show any variations depending on the caller.
    // MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
    // MUST NOT revert unless due to integer overflow caused by an unreasonably large input.
    // MUST round down towards 0.
    // This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect
    // the “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and from.
    function convertToAssets(uint256 shares) public view override returns (uint256 assets) {
        if (totalSupply() == 0) return shares;
        return (shares * _freeFunds()) / totalSupply();
    }

    // Maximum amount of the underlying asset that can be deposited into the Vault for the receiver, through a deposit call.
    // MUST return the maximum amount of assets deposit would allow to be deposited for receiver and not cause a revert,
    // which MUST NOT be higher than the actual maximum that would be accepted (it should underestimate if necessary).
    //
    // This assumes that the user has infinite assets, i.e. MUST NOT rely on balanceOf of asset.
    // MUST factor in both global and user-specific limits, like if deposits are entirely disabled (even temporarily) it MUST return 0.
    // MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.
    // MUST NOT revert.
    function maxDeposit(address) external view override returns (uint256 maxAssets) {
        if (emergencyShutdown || balance() >= tvlCap) return 0;
        if (tvlCap == type(uint256).max) return type(uint256).max;
        return tvlCap - balance();
    }

    // Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given current on-chain conditions.
    // MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit call in the same transaction.
    // I.e. deposit should return the same or more shares as previewDeposit if called in the same transaction.
    //
    // MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the deposit would be accepted,
    // regardless if the user has enough tokens approved, etc.
    //
    // MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
    // MUST NOT revert due to vault specific user/global limits. MAY revert due to other conditions that would also cause deposit to revert.
    // Note that any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in share price
    // or some other type of condition, meaning the depositor will lose assets by depositing.
    function previewDeposit(uint256 assets) external view override returns (uint256 shares) {
        return convertToShares(assets);
    }

    // Mints shares Vault shares to receiver by depositing exactly assets of underlying tokens.
    // MUST emit the Deposit event.
    // MUST support ERC-20 approve / transferFrom on asset as a deposit flow.
    // MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the deposit execution,
    // and are accounted for during deposit.
    //
    // MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage,
    // the user not approving enough underlying tokens to the Vault contract, etc).
    //
    // Note that most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
    function deposit(uint256 assets, address receiver) external override returns (uint256 shares) {
        shares = _deposit(assets, receiver);
    }

    // Maximum amount of shares that can be minted from the Vault for the receiver, through a mint call.
    // MUST return the maximum amount of shares mint would allow to be deposited to receiver and not cause a revert,
    // which MUST NOT be higher than the actual maximum that would be accepted (it should underestimate if necessary).
    // This assumes that the user has infinite assets, i.e. MUST NOT rely on balanceOf of asset.
    //
    // MUST factor in both global and user-specific limits, like if mints are entirely disabled (even temporarily) it MUST return 0.
    // MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.
    // MUST NOT revert.
    function maxMint(address) external view override returns (uint256 maxShares) {
        if (emergencyShutdown || balance() >= tvlCap) return 0;
        if (tvlCap == type(uint256).max) return type(uint256).max;
        return convertToShares(tvlCap - balance());
    }

    // Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given current on-chain conditions.
    // MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call
    // in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the same transaction.
    //
    // MUST NOT account for mint limits like those returned from maxMint and should always act as though
    // the mint would be accepted, regardless if the user has enough tokens approved, etc.
    //
    // MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
    // MUST NOT revert due to vault specific user/global limits. MAY revert due to other conditions that would also cause mint to revert.
    // Note that any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered
    // slippage in share price or some other type of condition, meaning the depositor will lose assets by minting.
    function previewMint(uint256 shares) public view override returns (uint256 assets) {
        if (totalSupply() == 0) return shares;
        assets = roundUpDiv(shares * _freeFunds(), totalSupply());
    }

    // Mints exactly shares Vault shares to receiver by depositing assets of underlying tokens.
    // MUST emit the Deposit event.
    // MUST support ERC-20 approve / transferFrom on asset as a mint flow. MAY support an additional
    // flow in which the underlying tokens are owned by the Vault contract before the mint execution,
    // and are accounted for during mint.
    //
    // MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage,
    // the user not approving enough underlying tokens to the Vault contract, etc).
    //
    // Note that most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
    function mint(uint256 shares, address receiver) external override returns (uint256 assets) {
        assets = previewMint(shares); // previewMint rounds up so exactly "shares" should be minted and not 1 wei less
        _deposit(assets, receiver);
    }

    // Maximum amount of the underlying asset that can be withdrawn from the owner balance in the Vault, through a withdraw call.
    // MUST return the maximum amount of assets that could be transferred from owner through withdraw and not cause a revert,
    // which MUST NOT be higher than the actual maximum that would be accepted (it should underestimate if necessary).
    //
    // MUST factor in both global and user-specific limits, like if withdrawals are entirely disabled (even temporarily) it MUST return 0.
    // MUST NOT revert.
    function maxWithdraw(address owner) external view override returns (uint256 maxAssets) {
        return convertToAssets(balanceOf(owner));
    }

    // Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,
    // given current on-chain conditions.
    //
    // MUST return as close to and no fewer than the exact amount of Vault shares that would be burned
    // in a withdraw call in the same transaction. I.e. withdraw should return the same or fewer shares
    // as previewWithdraw if called in the same transaction.
    //
    // MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act
    // as though the withdrawal would be accepted, regardless if the user has enough shares, etc.
    //
    // MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
    // MUST NOT revert due to vault specific user/global limits. MAY revert due to other conditions that would also cause withdraw to revert.
    // Note that any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be
    // considered slippage in share price or some other type of condition, meaning the depositor will lose assets by depositing.
    function previewWithdraw(uint256 assets) public view override returns (uint256 shares) {
        if (totalSupply() == 0 || _freeFunds() == 0) return 0;
        shares = roundUpDiv(assets * totalSupply(), _freeFunds());
    }

    // Burns shares from owner and sends exactly assets of underlying tokens to receiver.
    // MUST emit the Withdraw event.
    // MUST support a withdraw flow where the shares are burned from owner directly where owner is msg.sender.
    // MUST support a withdraw flow where the shares are burned from owner directly where msg.sender has
    // ERC-20 approval over the shares of owner.
    //
    // MAY support an additional flow in which the shares are transferred to the Vault contract before the
    // withdraw execution, and are accounted for during withdraw.
    //
    // MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage,
    // the owner not having enough shares, etc).
    //
    // Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
    // Those methods should be performed separately.
    function withdraw(uint256 assets, address receiver, address owner) external override returns (uint256 shares) {
        shares = previewWithdraw(assets); // previewWithdraw() rounds up so exactly "assets" are withdrawn and not 1 wei less
        if (msg.sender != owner) _spendAllowance(owner, msg.sender, shares);
        require(_withdraw(shares, receiver, owner) == assets, "All assets could not be withdrawn");
    }

    // Maximum amount of Vault shares that can be redeemed from the owner balance in the Vault, through a redeem call.
    // MUST return the maximum amount of shares that could be transferred from owner through redeem and not cause a
    // revert, which MUST NOT be higher than the actual maximum that would be accepted (it should underestimate if necessary).
    //
    // MUST factor in both global and user-specific limits, like if redemption is entirely disabled
    // (even temporarily) it MUST return 0.
    //
    // MUST NOT revert.
    function maxRedeem(address owner) external view override returns (uint256 maxShares) {
        return balanceOf(owner);
    }

    // Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,
    // given current on-chain conditions.
    //
    // MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call
    // in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the
    // same transaction.
    //
    // MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though
    // the redemption would be accepted, regardless if the user has enough shares, etc.
    //
    // MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
    // MUST NOT revert due to vault specific user/global limits. MAY revert due to other conditions that would
    // also cause redeem to revert.
    //
    // Note that any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage
    // in share price or some other type of condition, meaning the depositor will lose assets by redeeming.
    function previewRedeem(uint256 shares) external view override returns (uint256 assets) {
        return convertToAssets(shares);
    }

    // Burns exactly shares from owner and sends assets of underlying tokens to receiver.
    // MUST emit the Withdraw event.
    // MUST support a redeem flow where the shares are burned from owner directly where owner is msg.sender.
    // MUST support a redeem flow where the shares are burned from owner directly where msg.sender has ERC-20
    // approval over the shares of owner.
    //
    // MAY support an additional flow in which the shares are transferred to the Vault contract before the redeem
    // execution, and are accounted for during redeem.
    //
    // MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage,
    // the owner not having enough shares, etc).
    //
    // Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
    // Those methods should be performed separately.
    function redeem(uint256 shares, address receiver, address owner) external override returns (uint256 assets) {
        uint256 ownerShareBalBefore = balanceOf(owner);
        if (msg.sender != owner) _spendAllowance(owner, msg.sender, shares);
        assets = _withdraw(shares, receiver, owner);
        uint256 ownerSharesBurned = ownerShareBalBefore - balanceOf(owner);
        require(ownerSharesBurned == shares, "All shares could not be redeemed");
    }

    /**
     * @dev Super-Admin function to inject tokens directly into the vault
     *      without going through the deposit flow. Used in tests to verify
     *      ERC4626 share price behavior.
     * @param _amount Amount of tokens to inject.
     */
    function injectTokens(uint256 _amount) external {
        _atLeastRole(DEFAULT_ADMIN_ROLE);
        totalIdle += _amount;
        token.safeTransferFrom(msg.sender, address(this), _amount);
    }

    // Helper function to perform round-up/ceiling integer division.
    // Based on the formula: x / y + (x % y != 0)
    function roundUpDiv(uint256 x, uint256 y) internal pure returns (uint256) {
        require(y != 0, "Division by 0");

        uint256 q = x / y;
        if (x % y != 0) q++;
        return q;
    }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint256","name":"_tvlCap","type":"uint256"},{"internalType":"address","name":"_treasury","type":"address"},{"internalType":"address[]","name":"_strategists","type":"address[]"},{"internalType":"address[]","name":"_multisigRoles","type":"address[]"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"active","type":"bool"}],"name":"EmergencyShutdown","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"InCaseTokensGetStuckCalled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"degradation","type":"uint256"}],"name":"LockedProfitDegradationUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"strategy","type":"address"},{"indexed":false,"internalType":"uint256","name":"feeBPS","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"allocBPS","type":"uint256"}],"name":"StrategyAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"strategy","type":"address"},{"indexed":false,"internalType":"uint256","name":"allocBPS","type":"uint256"}],"name":"StrategyAllocBPSUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"strategy","type":"address"},{"indexed":false,"internalType":"uint256","name":"feeBPS","type":"uint256"}],"name":"StrategyFeeBPSUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"strategy","type":"address"},{"indexed":false,"internalType":"uint256","name":"gain","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"loss","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debtPaid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"gains","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"losses","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"allocated","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"allocationAdded","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"allocBPS","type":"uint256"}],"name":"StrategyReported","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"strategy","type":"address"}],"name":"StrategyRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newTvlCap","type":"uint256"}],"name":"TvlCapUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"withdrawalQueue","type":"address[]"}],"name":"UpdateWithdrawalQueue","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Withdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"withdrawMaxLoss","type":"uint256"}],"name":"WithdrawMaxLossUpdated","type":"event"},{"inputs":[],"name":"ADMIN","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEGRADATION_COEFFICIENT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARDIAN","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERCENT_DIVISOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STRATEGIST","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_strategy","type":"address"},{"internalType":"uint256","name":"_feeBPS","type":"uint256"},{"internalType":"uint256","name":"_allocBPS","type":"uint256"}],"name":"addStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"asset","outputs":[{"internalType":"address","name":"assetTokenAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"availableCapital","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"balance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"constructionTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"convertToAssets","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"convertToShares","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"depositAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emergencyShutdown","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPricePerFullShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"inCaseTokensGetStuck","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"injectTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lastReport","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lockedProfit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lockedProfitDegradation","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxDeposit","outputs":[{"internalType":"uint256","name":"maxAssets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxMint","outputs":[{"internalType":"uint256","name":"maxShares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxRedeem","outputs":[{"internalType":"uint256","name":"maxShares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxWithdraw","outputs":[{"internalType":"uint256","name":"maxAssets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewDeposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewMint","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewRedeem","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewWithdraw","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"removeTvlCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"int256","name":"_roi","type":"int256"},{"internalType":"uint256","name":"_repayment","type":"uint256"}],"name":"report","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_strategy","type":"address"}],"name":"revokeStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_active","type":"bool"}],"name":"setEmergencyShutdown","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"degradation","type":"uint256"}],"name":"setLockedProfitDegradation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_withdrawalQueue","type":"address[]"}],"name":"setWithdrawalQueue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"strategies","outputs":[{"internalType":"uint256","name":"activation","type":"uint256"},{"internalType":"uint256","name":"feeBPS","type":"uint256"},{"internalType":"uint256","name":"allocBPS","type":"uint256"},{"internalType":"uint256","name":"allocated","type":"uint256"},{"internalType":"uint256","name":"gains","type":"uint256"},{"internalType":"uint256","name":"losses","type":"uint256"},{"internalType":"uint256","name":"lastReport","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"contract IERC20Metadata","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAllocBPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAllocated","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAssets","outputs":[{"internalType":"uint256","name":"totalManagedAssets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalIdle","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tvlCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_strategy","type":"address"},{"internalType":"uint256","name":"_allocBPS","type":"uint256"}],"name":"updateStrategyAllocBPS","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_strategy","type":"address"},{"internalType":"uint256","name":"_feeBPS","type":"uint256"}],"name":"updateStrategyFeeBPS","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newTreasury","type":"address"}],"name":"updateTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newTvlCap","type":"uint256"}],"name":"updateTvlCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_withdrawMaxLoss","type":"uint256"}],"name":"updateWithdrawMaxLoss","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_shares","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawMaxLoss","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"withdrawalQueue","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

60c060405260016010553480156200001657600080fd5b5060405162004e2838038062004e288339810160408190526200003991620004d7565b86868686868686858560036200005083826200064e565b5060046200005f82826200064e565b50506001600755506001600160a01b0387811660a052426080819052600e55600a859055601380546001600160a01b031916918516919091179055620f4240620000b3670de0b6b3a7640000602e6200071a565b620000bf919062000740565b601155815160005b818110156200013c576200011e7fb17d0a42cc710456bf9c3efb785dcd0cb93a0ac358113307b5c64b285b516b5c8583815181106200010a576200010a62000763565b6020026020010151620001f360201b60201c565b62000134816200023660201b620026181760201c565b9050620000c7565b506200014a600033620001f3565b620001686000801b836000815181106200010a576200010a62000763565b620001a37fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec42836001815181106200010a576200010a62000763565b620001de7f8b5b16d04624687fcf0d0228f19993c9157c1ed07b41d8d430fd9100eb099fe8836002815181106200010a576200010a62000763565b50505050505050505050505050505062000779565b6200020a82826200023c60201b6200261e1760201c565b600082815260066020908152604090912062000231918390620026a4620002e1821b17901c565b505050565b60010190565b60008281526005602090815260408083206001600160a01b038516845290915290205460ff16620002dd5760008281526005602090815260408083206001600160a01b03851684529091529020805460ff191660011790556200029c3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b6000620002f8836001600160a01b03841662000301565b90505b92915050565b60008181526001830160205260408120546200034a57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155620002fb565b506000620002fb565b80516001600160a01b03811681146200036b57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715620003b157620003b162000370565b604052919050565b600082601f830112620003cb57600080fd5b81516001600160401b03811115620003e757620003e762000370565b6020620003fd601f8301601f1916820162000386565b82815285828487010111156200041257600080fd5b60005b838110156200043257858101830151828201840152820162000415565b506000928101909101919091529392505050565b600082601f8301126200045857600080fd5b815160206001600160401b0382111562000476576200047662000370565b8160051b6200048782820162000386565b9283528481018201928281019087851115620004a257600080fd5b83870192505b84831015620004cc57620004bc8362000353565b82529183019190830190620004a8565b979650505050505050565b600080600080600080600060e0888a031215620004f357600080fd5b620004fe8862000353565b60208901519097506001600160401b03808211156200051c57600080fd5b6200052a8b838c01620003b9565b975060408a01519150808211156200054157600080fd5b6200054f8b838c01620003b9565b965060608a015195506200056660808b0162000353565b945060a08a01519150808211156200057d57600080fd5b6200058b8b838c0162000446565b935060c08a0151915080821115620005a257600080fd5b50620005b18a828b0162000446565b91505092959891949750929550565b600181811c90821680620005d557607f821691505b602082108103620005f657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200023157600081815260208120601f850160051c81016020861015620006255750805b601f850160051c820191505b81811015620006465782815560010162000631565b505050505050565b81516001600160401b038111156200066a576200066a62000370565b62000682816200067b8454620005c0565b84620005fc565b602080601f831160018114620006ba5760008415620006a15750858301515b600019600386901b1c1916600185901b17855562000646565b600085815260208120601f198616915b82811015620006eb57888601518255948401946001909101908401620006ca565b50858210156200070a5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b8082028115828204841417620002fb57634e487b7160e01b600052601160045260246000fd5b6000826200075e57634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052603260045260246000fd5b60805160a051614635620007f3600039600081816105f701528181610a1e01528181610e8201528181610f12015281816112f30152818161135b01528181611fc9015281816120c8015281816123d901528181612f9a015281816130a80152818161328e01526134c7015260006109e401526146356000f3fe608060405234801561001057600080fd5b50600436106104535760003560e01c8063724c184c11610241578063b6b55f251161013b578063d250f088116100c3578063def68a9c11610087578063def68a9c146109b9578063ef8b30f7146109cc578063f06c5610146109df578063fa34d61114610a06578063fc0c546a14610a1957600080fd5b8063d250f08814610969578063d547741f14610978578063d905777e1461098b578063dd62ed3e1461099e578063de5f6268146109b157600080fd5b8063c63d75b61161010a578063c63d75b61461090a578063c6e6f5921461091d578063c822adda14610930578063ca15c87314610943578063ce96cb771461095657600080fd5b8063b6b55f25146108c8578063ba087652146108db578063bb994d48146108ee578063c3535b521461090157600080fd5b806395d89b41116101c9578063a9059cbb1161018d578063a9059cbb14610874578063ac579b7714610887578063b3d7f6b91461089a578063b460af94146108ad578063b69ef8a8146108c057600080fd5b806395d89b41146108335780639aa7df941461083b5780639cfdede314610844578063a217fddf14610859578063a457c2d71461086157600080fd5b80637f51bb1f116102105780637f51bb1f146107df578063853828b6146107f25780639010d07c146107fa57806391d148541461080d57806394bf804d1461082057600080fd5b8063724c184c1461079c57806377c7b8fc146107b15780637a550365146107b95780637d6205be146107cc57600080fd5b80633403c2fc1161035257806345f7f249116102da5780635f3d3a0e1161029e5780635f3d3a0e1461073157806361d027b3146107445780636e553f65146107575780636f9c94a81461076a57806370a082311461077357600080fd5b806345f7f249146106f0578063462f82f4146106f9578063483b60311461070c5780634870dd9a146107155780634cdad5061461071e57600080fd5b806339ebf8231161032157806339ebf823146106425780633f23fa1a146106c2578063402d267d146106cb57806342232716146106de57806344b81396146106e757600080fd5b80633403c2fc146105d557806336568abe146105e257806338d52e0f146105f5578063395093511461062f57600080fd5b806318160ddd116103e05780632a0acc6a116103a45780632a0acc6a1461056d5780632b3b0693146105825780632e1a7d4d146105955780632f2ff15d146105a8578063313ce567146105bb57600080fd5b806318160ddd1461051f578063199cb7d81461052757806323b872dd1461052f578063248a9ca31461054257806329b9d6941461056557600080fd5b806307a2d13a1161042757806307a2d13a146104c0578063095ea7b3146104d35780630a28a477146104e65780630f3d249d146104f957806314c644021461050c57600080fd5b8062272d811461045857806301e1d1141461046d57806301ffc9a71461048857806306fdde03146104ab575b600080fd5b61046b610466366004613ef7565b610a40565b005b610475610a93565b6040519081526020015b60405180910390f35b61049b610496366004613f10565b610aa2565b604051901515815260200161047f565b6104b3610acd565b60405161047f9190613f5e565b6104756104ce366004613ef7565b610b5f565b61049b6104e1366004613fa6565b610b94565b6104756104f4366004613ef7565b610bac565b610475610507366004613fd2565b610bf8565b61046b61051a366004614002565b6110c9565b600254610475565b610475611143565b61049b61053d36600461401f565b611291565b610475610550366004613ef7565b60009081526005602052604090206001015490565b61046b6112b7565b6104756000805160206145c083398151915281565b61046b610590366004613ef7565b6112c4565b61046b6105a3366004613ef7565b61131e565b61046b6105b6366004614060565b61132d565b6105c3611357565b60405160ff909116815260200161047f565b600f5461049b9060ff1681565b61046b6105f0366004614060565b6113db565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b03909116815260200161047f565b61049b61063d366004613fa6565b611455565b61068d610650366004614090565b6008602052600090815260409020805460018201546002830154600384015460048501546005860154600690960154949593949293919290919087565b604080519788526020880196909652948601939093526060850191909152608084015260a083015260c082015260e00161047f565b610475600a5481565b6104756106d9366004614090565b611477565b61047560115481565b61047560125481565b610475600d5481565b61046b610707366004613ef7565b6114ca565b61047560105481565b61047561271081565b61047561072c366004613ef7565b61155c565b61046b61073f366004613fa6565b611567565b601354610617906001600160a01b031681565b610475610765366004614060565b6116cf565b610475600c5481565b610475610781366004614090565b6001600160a01b031660009081526020819052604090205490565b6104756000805160206145a083398151915281565b6104756116db565b61046b6107c7366004613ef7565b611730565b61046b6107da366004613fa6565b6117e0565b61046b6107ed366004614090565b6118e6565b61046b61195a565b610617610808366004613fd2565b611974565b61049b61081b366004614060565b61198c565b61047561082e366004614060565b6119b7565b6104b36119d5565b610475600b5481565b6104756000805160206145e083398151915281565b610475600081565b61049b61086f366004613fa6565b6119e4565b61049b610882366004613fa6565b611a6a565b61046b6108953660046140ad565b611a78565b6104756108a8366004613ef7565b611bf5565b6104756108bb366004614122565b611c28565b610475611cb3565b61046b6108d6366004613ef7565b611cc5565b6104756108e9366004614122565b611ccf565b61046b6108fc366004614090565b611d8d565b610475600e5481565b610475610918366004614090565b611e54565b61047561092b366004613ef7565b611eaa565b61061761093e366004613ef7565b611edf565b610475610951366004613ef7565b611f09565b610475610964366004614090565b611f20565b610475670de0b6b3a764000081565b61046b610986366004614060565b611f42565b610475610999366004614090565b611f67565b6104756109ac366004614164565b611f85565b61046b611fb0565b61046b6109c7366004614090565b612042565b6104756109da366004613ef7565b6121a7565b6104757f000000000000000000000000000000000000000000000000000000000000000081565b61046b610a14366004614192565b6121b2565b6106177f000000000000000000000000000000000000000000000000000000000000000081565b610a576000805160206145c08339815191526126b9565b600a8190556040518181527f2923cecec41b7140eaf657a035af4abb23ed61d16b1fc20a986838eb3ad99bd0906020015b60405180910390a150565b6000610a9d611cb3565b905090565b60006001600160e01b03198216635a05180f60e01b1480610ac75750610ac782612790565b92915050565b606060038054610adc906141c7565b80601f0160208091040260200160405190810160405280929190818152602001828054610b08906141c7565b8015610b555780601f10610b2a57610100808354040283529160200191610b55565b820191906000526020600020905b815481529060010190602001808311610b3857829003601f168201915b5050505050905090565b6000610b6a60025490565b600003610b75575090565b600254610b806127c5565b610b8a9084614217565b610ac79190614244565b600033610ba28185856127e1565b5060019392505050565b6000610bb760025490565b1580610bc85750610bc66127c5565b155b15610bd557506000919050565b610ac7610be160025490565b610beb9084614217565b610bf36127c5565b612905565b6000610c5960405180610140016040528060006001600160a01b031681526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b3380825260009081526008602052604081208054909103610cb95760405162461bcd60e51b8152602060048201526015602482015274556e617574686f72697a656420737472617465677960581b60448201526064015b60405180910390fd5b6000851215610ce257610ccb85614258565b602083018190528251610cdd91612977565b610d22565b6000851315610d2257604082018590528151610cfe9086612abe565b60608301526040820151600482018054600090610d1c908490614274565b90915550505b610d2a611143565b6080830181905260001315610dbc578160800151610d4790614258565b60a08301819052610d589085612b57565b60e0830181905215610db7578160e00151816003016000828254610d7c9190614287565b909155505060e0820151600d8054600090610d98908490614287565b909155505060e082015160a083018051610db3908390614287565b9052505b610e0b565b600082608001511315610e0b57608082015160c08301819052600382018054600090610de9908490614274565b909155505060c0820151600d8054600090610e05908490614274565b90915550505b8160e001518260400151610e1f9190614274565b610100830181905260c08301511115610eae578161010001518260c00151610e479190614287565b600b6000828254610e589190614287565b9091555050815161010083015160c0840151610ea99291610e7891614287565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169190612b6d565b610f3a565b8161010001518260c001511015610f3a578160c00151826101000151610ed49190614287565b600b6000828254610ee59190614274565b9091555050815160c0830151610100840151610f3a92913091610f089190614287565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016929190612bd0565b81606001518260400151610f4c612c0e565b610f569190614274565b610f609190614287565b610120830181905260208301511015610f90578160200151826101200151610f889190614287565b601255610f96565b60006012555b4260068201819055600e55815160408084015160208086015160e0808801516004880154600589015460038a015460c0808d015160028d01548b519a8b52988a0197909752888a01949094526060880192909252608087015260a086015284019190915282015290516001600160a01b03909216917f67f96d2854a335a4cadb49f84fd3ca6f990744ddb3feceeb4b349d2d53d32ad3918190036101000190a2600281015415806110495750600f5460ff165b156110bd5781600001516001600160a01b031663722713f76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611090573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110b4919061429a565b92505050610ac7565b5060a001519392505050565b80156110eb576110e66000805160206145a08339815191526126b9565b611102565b6111026000805160206145c08339815191526126b9565b600f805460ff19168215159081179091556040519081527fba40372a3a724dca3c57156128ef1e896724b65b37a17f190b1ad5de68f3a4f390602001610a88565b600c54600090339015806111595750600f5460ff165b15611189576001600160a01b03811660009081526008602052604090206003015461118390614258565b91505090565b6000612710611196611cb3565b6001600160a01b0384166000908152600860205260409020600201546111bc9190614217565b6111c69190614244565b6001600160a01b03831660009081526008602052604090206003015490915081811115611208576111f78282614287565b61120090614258565b935050505090565b8181101561128757600061271061121d611cb3565b600c5461122a9190614217565b6112349190614244565b600d5490915081811061124d5760009550505050505090565b60006112598486614287565b905061126e816112698486614287565b612b57565b905061127c81600b54612b57565b979650505050505050565b6000935050505090565b60003361129f858285612c74565b6112aa858585612ce8565b60019150505b9392505050565b6112c2600019610a40565b565b6112ce60006126b9565b80600b60008282546112e09190614274565b9091555061131b90506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016333084612bd0565b50565b611329813333612e8c565b5050565b6000828152600560205260409020600101546113488161330b565b6113528383613315565b505050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113b7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a9d91906142b3565b6001600160a01b038116331461144b5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610cb0565b6113298282613337565b600033610ba28185856114688383611f85565b6114729190614274565b6127e1565b600f5460009060ff16806114945750600a54611491611cb3565b10155b156114a157506000919050565b600019600a54036114b55750600019919050565b6114bd611cb3565b600a54610ac79190614287565b6114e16000805160206145e08339815191526126b9565b6127108111156115275760405162461bcd60e51b8152602060048201526011602482015270496e76616c6964204250532076616c756560781b6044820152606401610cb0565b60108190556040518181527f23e1382e62459214e4b3240fe95817b36865752f45f7569957018fe5a105f7b590602001610a88565b6000610ac782610b5f565b6001600160a01b038216600090815260086020526040812054900361159e5760405162461bcd60e51b8152600401610cb0906142d6565b6001600160a01b03821660009081526008602052604090206002015480156115dc576115d76000805160206145e08339815191526126b9565b6115f3565b6115f36000805160206145c08339815191526126b9565b80600c60008282546116059190614287565b90915550506001600160a01b0383166000908152600860205260408120600201839055600c805484929061163a908490614274565b9091555050600c5461271010156116875760405162461bcd60e51b8152602060048201526011602482015270496e76616c6964204250532076616c756560781b6044820152606401610cb0565b826001600160a01b03167f437afd93b1abdad7ff741b69dde7efdd15dba7fb6999ba3471db17fd029dced9836040516116c291815260200190565b60405180910390a2505050565b60006112b08383613359565b60006116e660025490565b1561171d576002546116f6611357565b61170190600a6143f1565b6117096127c5565b6117139190614217565b610a9d9190614244565b611725611357565b610a9d90600a6143f1565b6117476000805160206145c08339815191526126b9565b670de0b6b3a76400008111156117ab5760405162461bcd60e51b8152602060048201526024808201527f4465677261646174696f6e2063616e6e6f74206265206d6f7265207468616e206044820152633130302560e01b6064820152608401610cb0565b60118190556040518181527f056863905a721211fc4dda1d688efc8f120b4b689d2e41da8249cf6eff20069190602001610a88565b6117f76000805160206145c08339815191526126b9565b6001600160a01b038216600090815260086020526040812054900361182e5760405162461bcd60e51b8152600401610cb0906142d6565b61183b6005612710614244565b81111561188a5760405162461bcd60e51b815260206004820181905260248201527f4665652063616e6e6f7420626520686967686572207468616e203230204250536044820152606401610cb0565b6001600160a01b03821660008181526008602052604090819020600101839055517f8281ff4064168f20aa9abde7f62b8b72efb10b48e7e838af54dcabff3131474a906118da9084815260200190565b60405180910390a25050565b6118f060006126b9565b6001600160a01b0381166119385760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b6044820152606401610cb0565b601380546001600160a01b0319166001600160a01b0392909216919091179055565b3360008181526020819052604090205461131b9180612e8c565b60008281526006602052604081206112b09083613540565b60009182526005602090815260408084206001600160a01b0393909316845291905290205460ff1690565b60006119c283611bf5565b90506119ce8183613359565b5092915050565b606060048054610adc906141c7565b600033816119f28286611f85565b905083811015611a525760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610cb0565b611a5f82868684036127e1565b506001949350505050565b600033610ba2818585612ce8565b611a8f6000805160206145c08339815191526126b9565b806000819003611ae15760405162461bcd60e51b815260206004820152601760248201527f5175657565206d757374206e6f7420626520656d7074790000000000000000006044820152606401610cb0565b611aed60096000613ec5565b60005b81811015611bb6576000848483818110611b0c57611b0c614400565b9050602002016020810190611b219190614090565b6001600160a01b03811660009081526008602052604081208054929350919003611b5d5760405162461bcd60e51b8152600401610cb0906142d6565b5060098054600180820183556000929092527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af0180546001600160a01b0319166001600160a01b03939093169290921790915501611af0565b507fe159a1b5cb3e0bbe2f0caa53bcf2cd9ea0bc25a8c7b8302b1ac510f29cac8baa8383604051611be8929190614416565b60405180910390a1505050565b6000611c0060025490565b600003611c0b575090565b610ac7611c166127c5565b611c209084614217565b600254612905565b6000611c3384610bac565b9050336001600160a01b03831614611c5057611c50823383612c74565b83611c5c828585612e8c565b146112b05760405162461bcd60e51b815260206004820152602160248201527f416c6c2061737365747320636f756c64206e6f742062652077697468647261776044820152603760f91b6064820152608401610cb0565b6000600d54600b54610a9d9190614274565b6113298133613359565b6001600160a01b03811660008181526020819052604081205490913314611cfb57611cfb833387612c74565b611d06858585612e8c565b91506000611d29846001600160a01b031660009081526020819052604090205490565b611d339083614287565b9050858114611d845760405162461bcd60e51b815260206004820181905260248201527f416c6c2073686172657320636f756c64206e6f742062652072656465656d65646044820152606401610cb0565b50509392505050565b336001600160a01b03821614611db457611db46000805160206145a08339815191526126b9565b6001600160a01b0381166000908152600860205260408120600201549003611dd95750565b6001600160a01b038116600090815260086020526040812060020154600c805491929091611e08908490614287565b90915550506001600160a01b038116600081815260086020526040808220600201829055517f4201c688d84c01154d321afa0c72f1bffe9eef53005c9de9d035074e71e9b32a9190a250565b600f5460009060ff1680611e715750600a54611e6e611cb3565b10155b15611e7e57506000919050565b600019600a5403611e925750600019919050565b610ac7611e9d611cb3565b600a5461092b9190614287565b6000611eb560025490565b1580611ec65750611ec46127c5565b155b15611ecf575090565b611ed76127c5565b600254610b80565b60098181548110611eef57600080fd5b6000918252602090912001546001600160a01b0316905081565b6000818152600660205260408120610ac79061354c565b6001600160a01b038116600090815260208190526040812054610ac790610b5f565b600082815260056020526040902060010154611f5d8161330b565b6113528383613337565b6001600160a01b038116600090815260208190526040812054610ac7565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6040516370a0823160e01b815233600482015261131b907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015612018573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061203c919061429a565b33613359565b6120596000805160206145c08339815191526126b9565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa1580156120a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120c4919061429a565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03160361210f57600b5461210c9082614287565b90505b8060000361214d5760405162461bcd60e51b815260206004820152600b60248201526a16995c9bc8185b5bdd5b9d60aa1b6044820152606401610cb0565b6121616001600160a01b0383163383612b6d565b604080516001600160a01b0384168152602081018390527f741ee845808813887c0b0d54aa20a3d0f670bebce7b6a1face577afbc00d1d6c910160405180910390a15050565b6000610ac782611eaa565b6121bc60006126b9565b600f5460ff16156122255760405162461bcd60e51b815260206004820152602d60248201527f43616e6e6f742061646420737472617465677920647572696e6720656d65726760448201526c32b731bc9039b43aba3237bbb760991b6064820152608401610cb0565b6001600160a01b03831661224b5760405162461bcd60e51b8152600401610cb0906142d6565b6001600160a01b038316600090815260086020526040902054156122aa5760405162461bcd60e51b815260206004820152601660248201527514dd1c985d1959de48185b1c9958591e48185919195960521b6044820152606401610cb0565b826001600160a01b031663fbfa77cf6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156122e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061230c9190614464565b6001600160a01b0316306001600160a01b03161461236c5760405162461bcd60e51b815260206004820152601f60248201527f53747261746567792773207661756c7420646f6573206e6f74206d61746368006044820152606401610cb0565b826001600160a01b0316631f1fcd516040518163ffffffff1660e01b8152600401602060405180830381865afa1580156123aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123ce9190614464565b6001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03161461244e5760405162461bcd60e51b815260206004820152601e60248201527f537472617465677927732077616e7420646f6573206e6f74206d6174636800006044820152606401610cb0565b61245b6005612710614244565b8211156124aa5760405162461bcd60e51b815260206004820181905260248201527f4665652063616e6e6f7420626520686967686572207468616e203230204250536044820152606401610cb0565b612710600c54826124bb9190614274565b11156125025760405162461bcd60e51b8152602060048201526016602482015275496e76616c696420616c6c6f634250532076616c756560501b6044820152606401610cb0565b6040805160e0810182524280825260208083018681528385018681526000606086018181526080870182815260a0880183815260c089019788526001600160a01b038d1684526008909652978220965187559251600187015590516002860155905160038501559351600484015551600583015551600690910155600c805483929061258f908490614274565b9091555050600980546001810182556000919091527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af0180546001600160a01b0319166001600160a01b03851690811790915560408051848152602081018490527f45bb3eed5cd098efb0a286413fb1f3c11841762610cefbabae6a772963e916ba91016116c2565b60010190565b612628828261198c565b6113295760008281526005602090815260408083206001600160a01b03851684529091529020805460ff191660011790556126603390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b60006112b0836001600160a01b038416613556565b60006126c36135a5565b8051909150600080805b8381101561273c578115801561270157506127018582815181106126f3576126f3614400565b60200260200101513361367d565b1561270b57600191505b84818151811061271d5761271d614400565b60200260200101518603612734576001925061273c565b6001016126cd565b508180156127475750805b6127895760405162461bcd60e51b8152602060048201526013602482015272556e617574686f72697a65642061636365737360681b6044820152606401610cb0565b5050505050565b60006001600160e01b03198216637965db0b60e01b1480610ac757506301ffc9a760e01b6001600160e01b0319831614610ac7565b60006127cf612c0e565b6127d7611cb3565b610a9d9190614287565b6001600160a01b0383166128435760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610cb0565b6001600160a01b0382166128a45760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610cb0565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6000816000036129475760405162461bcd60e51b815260206004820152600d60248201526c04469766973696f6e206279203609c1b6044820152606401610cb0565b60006129538385614244565b905061295f8385614481565b156112b0578061296e81614495565b95945050505050565b6001600160a01b03821660009081526008602052604090206003810154808311156129fc5760405162461bcd60e51b815260206004820152602f60248201527f5374726174656779206c6f73732063616e6e6f7420626520677265617465722060448201526e3a3430b71030b63637b1b0ba34b7b760891b6064820152608401610cb0565b600c5415612a6b576000612a2e600d54600c5486612a1a9190614217565b612a249190614244565b8460020154612b57565b90508015612a695780836002016000828254612a4a9190614287565b9250508190555080600c6000828254612a639190614287565b90915550505b505b82826005016000828254612a7f9190614274565b9250508190555082826003016000828254612a9a9190614287565b9250508190555082600d6000828254612ab39190614287565b909155505050505050565b6001600160a01b038216600090815260086020526040812060010154819061271090612aea9085614217565b612af49190614244565b905080156112b0576000612b0760025490565b905060008115612b3257612b196127c5565b612b238385614217565b612b2d9190614244565b612b34565b825b601354909150612b4d906001600160a01b031682613689565b5050905092915050565b6000818310612b6657816112b0565b5090919050565b6040516001600160a01b03831660248201526044810182905261135290849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613748565b6040516001600160a01b0380851660248301528316604482015260648101829052612c089085906323b872dd60e01b90608401612b99565b50505050565b600080601154600e5442612c229190614287565b612c2c9190614217565b9050670de0b6b3a7640000811015612c6c57670de0b6b3a764000060125482612c559190614217565b612c5f9190614244565b6012546111839190614287565b600091505090565b6000612c808484611f85565b90506000198114612c085781811015612cdb5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610cb0565b612c0884848484036127e1565b6001600160a01b038316612d4c5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610cb0565b6001600160a01b038216612dae5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610cb0565b6001600160a01b03831660009081526020819052604090205481811015612e265760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610cb0565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3612c08565b6000612e9661381a565b83600003612ed75760405162461bcd60e51b815260206004820152600e60248201526d125b9d985b1a5908185b5bdd5b9d60921b6044820152606401610cb0565b60025484612ee36127c5565b612eed9190614217565b612ef79190614244565b600b549091508082111561325f57600954600090815b818110156131ab57838511156131ab57600060098281548110612f3257612f32614400565b60009182526020808320909101546001600160a01b03168083526008909152604082206003015490925090819003612f6b5750506131a3565b6000612f778789614287565b6040516370a0823160e01b81523060048201529091506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015612fe1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613005919061429a565b90506000846001600160a01b0316632e1a7d4d6130228587612b57565b6040518263ffffffff1660e01b815260040161304091815260200190565b6020604051808303816000875af115801561305f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613083919061429a565b6040516370a0823160e01b815230600482015290915060009083906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa1580156130ef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613113919061429a565b61311d9190614287565b9050613129818b614274565b995081156131535761313b828c614287565b9a50613147828a614274565b98506131538683612977565b6001600160a01b0386166000908152600860205260408120600301805483929061317e908490614287565b9250508190555080600d60008282546131979190614287565b90915550505050505050505b600101612f0d565b50600b839055828411156131e8578293506131c46127c5565b6002546131d18487614274565b6131db9190614217565b6131e59190614244565b96505b601054612710906131f98487614274565b6132039190614217565b61320d9190614244565b82111561325c5760405162461bcd60e51b815260206004820152601e60248201527f5769746864726177206c6f7373206578636565647320736c69707061676500006044820152606401610cb0565b50505b6132698386613873565b81600b600082825461327b9190614287565b909155506132b590506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168584612b6d565b60408051838152602081018790526001600160a01b03808616929087169133917ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db910160405180910390a4506112b06001600755565b61131b81336139a5565b61331f828261261e565b600082815260066020526040902061135290826126a4565b61334182826139fe565b60008281526006602052604090206113529082613a65565b600061336361381a565b600f5460ff16156133c75760405162461bcd60e51b815260206004820152602860248201527f43616e6e6f74206465706f73697420647572696e6720656d657267656e63792060448201526739b43aba3237bbb760c11b6064820152608401610cb0565b826000036134085760405162461bcd60e51b815260206004820152600e60248201526d125b9d985b1a5908185b5bdd5b9d60921b6044820152606401610cb0565b600a5483613414611cb3565b61341e9190614274565b111561345c5760405162461bcd60e51b815260206004820152600d60248201526c15985d5b1d081a5cc8199d5b1b609a1b6044820152606401610cb0565b600061346760025490565b90508060000361347957839150613498565b6134816127c5565b61348b8286614217565b6134959190614244565b91505b6134a28383613689565b83600b60008282546134b49190614274565b909155506134ef90506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016333087612bd0565b60408051858152602081018490526001600160a01b0385169133917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7910160405180910390a350610ac76001600755565b60006112b08383613a7a565b6000610ac7825490565b600081815260018301602052604081205461359d57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610ac7565b506000610ac7565b60408051600480825260a0820190925260609160009190602082016080803683370190505090506000801b816000815181106135e3576135e3614400565b6020026020010181815250506000805160206145c08339815191528160018151811061361157613611614400565b6020026020010181815250506000805160206145a08339815191528160028151811061363f5761363f614400565b6020026020010181815250506000805160206145e08339815191528160038151811061366d5761366d614400565b6020908102919091010152919050565b60006112b0838361198c565b6001600160a01b0382166136df5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610cb0565b80600260008282546136f19190614274565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600061379d826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613aa49092919063ffffffff16565b80519091501561135257808060200190518101906137bb91906144c4565b6113525760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610cb0565b60026007540361386c5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610cb0565b6002600755565b6001600160a01b0382166138d35760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610cb0565b6001600160a01b038216600090815260208190526040902054818110156139475760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610cb0565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b6139af828261198c565b611329576139bc81613abb565b6139c7836020613acd565b6040516020016139d89291906144e1565b60408051601f198184030181529082905262461bcd60e51b8252610cb091600401613f5e565b613a08828261198c565b156113295760008281526005602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60006112b0836001600160a01b038416613c69565b6000826000018281548110613a9157613a91614400565b9060005260206000200154905092915050565b6060613ab38484600085613d5c565b949350505050565b6060610ac76001600160a01b03831660145b60606000613adc836002614217565b613ae7906002614274565b67ffffffffffffffff811115613aff57613aff6144ae565b6040519080825280601f01601f191660200182016040528015613b29576020820181803683370190505b509050600360fc1b81600081518110613b4457613b44614400565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110613b7357613b73614400565b60200101906001600160f81b031916908160001a9053506000613b97846002614217565b613ba2906001614274565b90505b6001811115613c1a576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110613bd657613bd6614400565b1a60f81b828281518110613bec57613bec614400565b60200101906001600160f81b031916908160001a90535060049490941c93613c1381614556565b9050613ba5565b5083156112b05760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610cb0565b60008181526001830160205260408120548015613d52576000613c8d600183614287565b8554909150600090613ca190600190614287565b9050818114613d06576000866000018281548110613cc157613cc1614400565b9060005260206000200154905080876000018481548110613ce457613ce4614400565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080613d1757613d1761456d565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610ac7565b6000915050610ac7565b606082471015613dbd5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610cb0565b600080866001600160a01b03168587604051613dd99190614583565b60006040518083038185875af1925050503d8060008114613e16576040519150601f19603f3d011682016040523d82523d6000602084013e613e1b565b606091505b509150915061127c8783838760608315613e96578251600003613e8f576001600160a01b0385163b613e8f5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610cb0565b5081613ab3565b613ab38383815115613eab5781518083602001fd5b8060405162461bcd60e51b8152600401610cb09190613f5e565b508054600082559060005260206000209081019061131b91905b80821115613ef35760008155600101613edf565b5090565b600060208284031215613f0957600080fd5b5035919050565b600060208284031215613f2257600080fd5b81356001600160e01b0319811681146112b057600080fd5b60005b83811015613f55578181015183820152602001613f3d565b50506000910152565b6020815260008251806020840152613f7d816040850160208701613f3a565b601f01601f19169190910160400192915050565b6001600160a01b038116811461131b57600080fd5b60008060408385031215613fb957600080fd5b8235613fc481613f91565b946020939093013593505050565b60008060408385031215613fe557600080fd5b50508035926020909101359150565b801515811461131b57600080fd5b60006020828403121561401457600080fd5b81356112b081613ff4565b60008060006060848603121561403457600080fd5b833561403f81613f91565b9250602084013561404f81613f91565b929592945050506040919091013590565b6000806040838503121561407357600080fd5b82359150602083013561408581613f91565b809150509250929050565b6000602082840312156140a257600080fd5b81356112b081613f91565b600080602083850312156140c057600080fd5b823567ffffffffffffffff808211156140d857600080fd5b818501915085601f8301126140ec57600080fd5b8135818111156140fb57600080fd5b8660208260051b850101111561411057600080fd5b60209290920196919550909350505050565b60008060006060848603121561413757600080fd5b83359250602084013561414981613f91565b9150604084013561415981613f91565b809150509250925092565b6000806040838503121561417757600080fd5b823561418281613f91565b9150602083013561408581613f91565b6000806000606084860312156141a757600080fd5b83356141b281613f91565b95602085013595506040909401359392505050565b600181811c908216806141db57607f821691505b6020821081036141fb57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610ac757610ac7614201565b634e487b7160e01b600052601260045260246000fd5b6000826142535761425361422e565b500490565b6000600160ff1b820161426d5761426d614201565b5060000390565b80820180821115610ac757610ac7614201565b81810381811115610ac757610ac7614201565b6000602082840312156142ac57600080fd5b5051919050565b6000602082840312156142c557600080fd5b815160ff811681146112b057600080fd5b60208082526018908201527f496e76616c696420737472617465677920616464726573730000000000000000604082015260600190565b600181815b8085111561434857816000190482111561432e5761432e614201565b8085161561433b57918102915b93841c9390800290614312565b509250929050565b60008261435f57506001610ac7565b8161436c57506000610ac7565b8160018114614382576002811461438c576143a8565b6001915050610ac7565b60ff84111561439d5761439d614201565b50506001821b610ac7565b5060208310610133831016604e8410600b84101617156143cb575081810a610ac7565b6143d5838361430d565b80600019048211156143e9576143e9614201565b029392505050565b60006112b060ff841683614350565b634e487b7160e01b600052603260045260246000fd5b60208082528181018390526000908460408401835b8681101561445957823561443e81613f91565b6001600160a01b03168252918301919083019060010161442b565b509695505050505050565b60006020828403121561447657600080fd5b81516112b081613f91565b6000826144905761449061422e565b500690565b6000600182016144a7576144a7614201565b5060010190565b634e487b7160e01b600052604160045260246000fd5b6000602082840312156144d657600080fd5b81516112b081613ff4565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351614519816017850160208801613f3a565b7001034b99036b4b9b9b4b733903937b6329607d1b601791840191820152835161454a816028840160208801613f3a565b01602801949350505050565b60008161456557614565614201565b506000190190565b634e487b7160e01b600052603160045260246000fd5b60008251614595818460208701613f3a565b919091019291505056fe8b5b16d04624687fcf0d0228f19993c9157c1ed07b41d8d430fd9100eb099fe8df8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec42b17d0a42cc710456bf9c3efb785dcd0cb93a0ac358113307b5c64b285b516b5ca264697066735822122045bccccc4dd2ce219255c32cca105d63cc485c45dd094981e615928fee1f3c8c64736f6c63430008120033000000000000000000000000c5b001dc33727f8f26880b184090d3e252470d4500000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000a968163f0a57b400000000000000000000000000000eb9c9b785aa7818b2ebc8f9842926c4b9f707e4b0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000000105374616b65642045524e205661756c74000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005737445524e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000001e71aee6081f62053123140aacc7a06021d7734800000000000000000000000081876677843d00a7d792e1617459ac2e932025760000000000000000000000001a20d7a31e5b3bc5f02c8a146ef6f394502a10c40000000000000000000000004c3490df15edfa178333445ce568ec6d99b5d71c000000000000000000000000b26cd6633db6b0c9ae919049c1437271ae496d1500000000000000000000000060bc5e0440c867eeb4cbce84bb1123fad2b262b100000000000000000000000000000000000000000000000000000000000000030000000000000000000000009bc776dbb134ef9d7014db1823cd755ac5015203000000000000000000000000eb9c9b785aa7818b2ebc8f9842926c4b9f707e4b000000000000000000000000b0c9d5851def8a2aac4a23031ca2610f8c3483f9

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106104535760003560e01c8063724c184c11610241578063b6b55f251161013b578063d250f088116100c3578063def68a9c11610087578063def68a9c146109b9578063ef8b30f7146109cc578063f06c5610146109df578063fa34d61114610a06578063fc0c546a14610a1957600080fd5b8063d250f08814610969578063d547741f14610978578063d905777e1461098b578063dd62ed3e1461099e578063de5f6268146109b157600080fd5b8063c63d75b61161010a578063c63d75b61461090a578063c6e6f5921461091d578063c822adda14610930578063ca15c87314610943578063ce96cb771461095657600080fd5b8063b6b55f25146108c8578063ba087652146108db578063bb994d48146108ee578063c3535b521461090157600080fd5b806395d89b41116101c9578063a9059cbb1161018d578063a9059cbb14610874578063ac579b7714610887578063b3d7f6b91461089a578063b460af94146108ad578063b69ef8a8146108c057600080fd5b806395d89b41146108335780639aa7df941461083b5780639cfdede314610844578063a217fddf14610859578063a457c2d71461086157600080fd5b80637f51bb1f116102105780637f51bb1f146107df578063853828b6146107f25780639010d07c146107fa57806391d148541461080d57806394bf804d1461082057600080fd5b8063724c184c1461079c57806377c7b8fc146107b15780637a550365146107b95780637d6205be146107cc57600080fd5b80633403c2fc1161035257806345f7f249116102da5780635f3d3a0e1161029e5780635f3d3a0e1461073157806361d027b3146107445780636e553f65146107575780636f9c94a81461076a57806370a082311461077357600080fd5b806345f7f249146106f0578063462f82f4146106f9578063483b60311461070c5780634870dd9a146107155780634cdad5061461071e57600080fd5b806339ebf8231161032157806339ebf823146106425780633f23fa1a146106c2578063402d267d146106cb57806342232716146106de57806344b81396146106e757600080fd5b80633403c2fc146105d557806336568abe146105e257806338d52e0f146105f5578063395093511461062f57600080fd5b806318160ddd116103e05780632a0acc6a116103a45780632a0acc6a1461056d5780632b3b0693146105825780632e1a7d4d146105955780632f2ff15d146105a8578063313ce567146105bb57600080fd5b806318160ddd1461051f578063199cb7d81461052757806323b872dd1461052f578063248a9ca31461054257806329b9d6941461056557600080fd5b806307a2d13a1161042757806307a2d13a146104c0578063095ea7b3146104d35780630a28a477146104e65780630f3d249d146104f957806314c644021461050c57600080fd5b8062272d811461045857806301e1d1141461046d57806301ffc9a71461048857806306fdde03146104ab575b600080fd5b61046b610466366004613ef7565b610a40565b005b610475610a93565b6040519081526020015b60405180910390f35b61049b610496366004613f10565b610aa2565b604051901515815260200161047f565b6104b3610acd565b60405161047f9190613f5e565b6104756104ce366004613ef7565b610b5f565b61049b6104e1366004613fa6565b610b94565b6104756104f4366004613ef7565b610bac565b610475610507366004613fd2565b610bf8565b61046b61051a366004614002565b6110c9565b600254610475565b610475611143565b61049b61053d36600461401f565b611291565b610475610550366004613ef7565b60009081526005602052604090206001015490565b61046b6112b7565b6104756000805160206145c083398151915281565b61046b610590366004613ef7565b6112c4565b61046b6105a3366004613ef7565b61131e565b61046b6105b6366004614060565b61132d565b6105c3611357565b60405160ff909116815260200161047f565b600f5461049b9060ff1681565b61046b6105f0366004614060565b6113db565b7f000000000000000000000000c5b001dc33727f8f26880b184090d3e252470d455b6040516001600160a01b03909116815260200161047f565b61049b61063d366004613fa6565b611455565b61068d610650366004614090565b6008602052600090815260409020805460018201546002830154600384015460048501546005860154600690960154949593949293919290919087565b604080519788526020880196909652948601939093526060850191909152608084015260a083015260c082015260e00161047f565b610475600a5481565b6104756106d9366004614090565b611477565b61047560115481565b61047560125481565b610475600d5481565b61046b610707366004613ef7565b6114ca565b61047560105481565b61047561271081565b61047561072c366004613ef7565b61155c565b61046b61073f366004613fa6565b611567565b601354610617906001600160a01b031681565b610475610765366004614060565b6116cf565b610475600c5481565b610475610781366004614090565b6001600160a01b031660009081526020819052604090205490565b6104756000805160206145a083398151915281565b6104756116db565b61046b6107c7366004613ef7565b611730565b61046b6107da366004613fa6565b6117e0565b61046b6107ed366004614090565b6118e6565b61046b61195a565b610617610808366004613fd2565b611974565b61049b61081b366004614060565b61198c565b61047561082e366004614060565b6119b7565b6104b36119d5565b610475600b5481565b6104756000805160206145e083398151915281565b610475600081565b61049b61086f366004613fa6565b6119e4565b61049b610882366004613fa6565b611a6a565b61046b6108953660046140ad565b611a78565b6104756108a8366004613ef7565b611bf5565b6104756108bb366004614122565b611c28565b610475611cb3565b61046b6108d6366004613ef7565b611cc5565b6104756108e9366004614122565b611ccf565b61046b6108fc366004614090565b611d8d565b610475600e5481565b610475610918366004614090565b611e54565b61047561092b366004613ef7565b611eaa565b61061761093e366004613ef7565b611edf565b610475610951366004613ef7565b611f09565b610475610964366004614090565b611f20565b610475670de0b6b3a764000081565b61046b610986366004614060565b611f42565b610475610999366004614090565b611f67565b6104756109ac366004614164565b611f85565b61046b611fb0565b61046b6109c7366004614090565b612042565b6104756109da366004613ef7565b6121a7565b6104757f0000000000000000000000000000000000000000000000000000000064aee18f81565b61046b610a14366004614192565b6121b2565b6106177f000000000000000000000000c5b001dc33727f8f26880b184090d3e252470d4581565b610a576000805160206145c08339815191526126b9565b600a8190556040518181527f2923cecec41b7140eaf657a035af4abb23ed61d16b1fc20a986838eb3ad99bd0906020015b60405180910390a150565b6000610a9d611cb3565b905090565b60006001600160e01b03198216635a05180f60e01b1480610ac75750610ac782612790565b92915050565b606060038054610adc906141c7565b80601f0160208091040260200160405190810160405280929190818152602001828054610b08906141c7565b8015610b555780601f10610b2a57610100808354040283529160200191610b55565b820191906000526020600020905b815481529060010190602001808311610b3857829003601f168201915b5050505050905090565b6000610b6a60025490565b600003610b75575090565b600254610b806127c5565b610b8a9084614217565b610ac79190614244565b600033610ba28185856127e1565b5060019392505050565b6000610bb760025490565b1580610bc85750610bc66127c5565b155b15610bd557506000919050565b610ac7610be160025490565b610beb9084614217565b610bf36127c5565b612905565b6000610c5960405180610140016040528060006001600160a01b031681526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b3380825260009081526008602052604081208054909103610cb95760405162461bcd60e51b8152602060048201526015602482015274556e617574686f72697a656420737472617465677960581b60448201526064015b60405180910390fd5b6000851215610ce257610ccb85614258565b602083018190528251610cdd91612977565b610d22565b6000851315610d2257604082018590528151610cfe9086612abe565b60608301526040820151600482018054600090610d1c908490614274565b90915550505b610d2a611143565b6080830181905260001315610dbc578160800151610d4790614258565b60a08301819052610d589085612b57565b60e0830181905215610db7578160e00151816003016000828254610d7c9190614287565b909155505060e0820151600d8054600090610d98908490614287565b909155505060e082015160a083018051610db3908390614287565b9052505b610e0b565b600082608001511315610e0b57608082015160c08301819052600382018054600090610de9908490614274565b909155505060c0820151600d8054600090610e05908490614274565b90915550505b8160e001518260400151610e1f9190614274565b610100830181905260c08301511115610eae578161010001518260c00151610e479190614287565b600b6000828254610e589190614287565b9091555050815161010083015160c0840151610ea99291610e7891614287565b6001600160a01b037f000000000000000000000000c5b001dc33727f8f26880b184090d3e252470d45169190612b6d565b610f3a565b8161010001518260c001511015610f3a578160c00151826101000151610ed49190614287565b600b6000828254610ee59190614274565b9091555050815160c0830151610100840151610f3a92913091610f089190614287565b6001600160a01b037f000000000000000000000000c5b001dc33727f8f26880b184090d3e252470d4516929190612bd0565b81606001518260400151610f4c612c0e565b610f569190614274565b610f609190614287565b610120830181905260208301511015610f90578160200151826101200151610f889190614287565b601255610f96565b60006012555b4260068201819055600e55815160408084015160208086015160e0808801516004880154600589015460038a015460c0808d015160028d01548b519a8b52988a0197909752888a01949094526060880192909252608087015260a086015284019190915282015290516001600160a01b03909216917f67f96d2854a335a4cadb49f84fd3ca6f990744ddb3feceeb4b349d2d53d32ad3918190036101000190a2600281015415806110495750600f5460ff165b156110bd5781600001516001600160a01b031663722713f76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611090573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110b4919061429a565b92505050610ac7565b5060a001519392505050565b80156110eb576110e66000805160206145a08339815191526126b9565b611102565b6111026000805160206145c08339815191526126b9565b600f805460ff19168215159081179091556040519081527fba40372a3a724dca3c57156128ef1e896724b65b37a17f190b1ad5de68f3a4f390602001610a88565b600c54600090339015806111595750600f5460ff165b15611189576001600160a01b03811660009081526008602052604090206003015461118390614258565b91505090565b6000612710611196611cb3565b6001600160a01b0384166000908152600860205260409020600201546111bc9190614217565b6111c69190614244565b6001600160a01b03831660009081526008602052604090206003015490915081811115611208576111f78282614287565b61120090614258565b935050505090565b8181101561128757600061271061121d611cb3565b600c5461122a9190614217565b6112349190614244565b600d5490915081811061124d5760009550505050505090565b60006112598486614287565b905061126e816112698486614287565b612b57565b905061127c81600b54612b57565b979650505050505050565b6000935050505090565b60003361129f858285612c74565b6112aa858585612ce8565b60019150505b9392505050565b6112c2600019610a40565b565b6112ce60006126b9565b80600b60008282546112e09190614274565b9091555061131b90506001600160a01b037f000000000000000000000000c5b001dc33727f8f26880b184090d3e252470d4516333084612bd0565b50565b611329813333612e8c565b5050565b6000828152600560205260409020600101546113488161330b565b6113528383613315565b505050565b60007f000000000000000000000000c5b001dc33727f8f26880b184090d3e252470d456001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113b7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a9d91906142b3565b6001600160a01b038116331461144b5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610cb0565b6113298282613337565b600033610ba28185856114688383611f85565b6114729190614274565b6127e1565b600f5460009060ff16806114945750600a54611491611cb3565b10155b156114a157506000919050565b600019600a54036114b55750600019919050565b6114bd611cb3565b600a54610ac79190614287565b6114e16000805160206145e08339815191526126b9565b6127108111156115275760405162461bcd60e51b8152602060048201526011602482015270496e76616c6964204250532076616c756560781b6044820152606401610cb0565b60108190556040518181527f23e1382e62459214e4b3240fe95817b36865752f45f7569957018fe5a105f7b590602001610a88565b6000610ac782610b5f565b6001600160a01b038216600090815260086020526040812054900361159e5760405162461bcd60e51b8152600401610cb0906142d6565b6001600160a01b03821660009081526008602052604090206002015480156115dc576115d76000805160206145e08339815191526126b9565b6115f3565b6115f36000805160206145c08339815191526126b9565b80600c60008282546116059190614287565b90915550506001600160a01b0383166000908152600860205260408120600201839055600c805484929061163a908490614274565b9091555050600c5461271010156116875760405162461bcd60e51b8152602060048201526011602482015270496e76616c6964204250532076616c756560781b6044820152606401610cb0565b826001600160a01b03167f437afd93b1abdad7ff741b69dde7efdd15dba7fb6999ba3471db17fd029dced9836040516116c291815260200190565b60405180910390a2505050565b60006112b08383613359565b60006116e660025490565b1561171d576002546116f6611357565b61170190600a6143f1565b6117096127c5565b6117139190614217565b610a9d9190614244565b611725611357565b610a9d90600a6143f1565b6117476000805160206145c08339815191526126b9565b670de0b6b3a76400008111156117ab5760405162461bcd60e51b8152602060048201526024808201527f4465677261646174696f6e2063616e6e6f74206265206d6f7265207468616e206044820152633130302560e01b6064820152608401610cb0565b60118190556040518181527f056863905a721211fc4dda1d688efc8f120b4b689d2e41da8249cf6eff20069190602001610a88565b6117f76000805160206145c08339815191526126b9565b6001600160a01b038216600090815260086020526040812054900361182e5760405162461bcd60e51b8152600401610cb0906142d6565b61183b6005612710614244565b81111561188a5760405162461bcd60e51b815260206004820181905260248201527f4665652063616e6e6f7420626520686967686572207468616e203230204250536044820152606401610cb0565b6001600160a01b03821660008181526008602052604090819020600101839055517f8281ff4064168f20aa9abde7f62b8b72efb10b48e7e838af54dcabff3131474a906118da9084815260200190565b60405180910390a25050565b6118f060006126b9565b6001600160a01b0381166119385760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b6044820152606401610cb0565b601380546001600160a01b0319166001600160a01b0392909216919091179055565b3360008181526020819052604090205461131b9180612e8c565b60008281526006602052604081206112b09083613540565b60009182526005602090815260408084206001600160a01b0393909316845291905290205460ff1690565b60006119c283611bf5565b90506119ce8183613359565b5092915050565b606060048054610adc906141c7565b600033816119f28286611f85565b905083811015611a525760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610cb0565b611a5f82868684036127e1565b506001949350505050565b600033610ba2818585612ce8565b611a8f6000805160206145c08339815191526126b9565b806000819003611ae15760405162461bcd60e51b815260206004820152601760248201527f5175657565206d757374206e6f7420626520656d7074790000000000000000006044820152606401610cb0565b611aed60096000613ec5565b60005b81811015611bb6576000848483818110611b0c57611b0c614400565b9050602002016020810190611b219190614090565b6001600160a01b03811660009081526008602052604081208054929350919003611b5d5760405162461bcd60e51b8152600401610cb0906142d6565b5060098054600180820183556000929092527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af0180546001600160a01b0319166001600160a01b03939093169290921790915501611af0565b507fe159a1b5cb3e0bbe2f0caa53bcf2cd9ea0bc25a8c7b8302b1ac510f29cac8baa8383604051611be8929190614416565b60405180910390a1505050565b6000611c0060025490565b600003611c0b575090565b610ac7611c166127c5565b611c209084614217565b600254612905565b6000611c3384610bac565b9050336001600160a01b03831614611c5057611c50823383612c74565b83611c5c828585612e8c565b146112b05760405162461bcd60e51b815260206004820152602160248201527f416c6c2061737365747320636f756c64206e6f742062652077697468647261776044820152603760f91b6064820152608401610cb0565b6000600d54600b54610a9d9190614274565b6113298133613359565b6001600160a01b03811660008181526020819052604081205490913314611cfb57611cfb833387612c74565b611d06858585612e8c565b91506000611d29846001600160a01b031660009081526020819052604090205490565b611d339083614287565b9050858114611d845760405162461bcd60e51b815260206004820181905260248201527f416c6c2073686172657320636f756c64206e6f742062652072656465656d65646044820152606401610cb0565b50509392505050565b336001600160a01b03821614611db457611db46000805160206145a08339815191526126b9565b6001600160a01b0381166000908152600860205260408120600201549003611dd95750565b6001600160a01b038116600090815260086020526040812060020154600c805491929091611e08908490614287565b90915550506001600160a01b038116600081815260086020526040808220600201829055517f4201c688d84c01154d321afa0c72f1bffe9eef53005c9de9d035074e71e9b32a9190a250565b600f5460009060ff1680611e715750600a54611e6e611cb3565b10155b15611e7e57506000919050565b600019600a5403611e925750600019919050565b610ac7611e9d611cb3565b600a5461092b9190614287565b6000611eb560025490565b1580611ec65750611ec46127c5565b155b15611ecf575090565b611ed76127c5565b600254610b80565b60098181548110611eef57600080fd5b6000918252602090912001546001600160a01b0316905081565b6000818152600660205260408120610ac79061354c565b6001600160a01b038116600090815260208190526040812054610ac790610b5f565b600082815260056020526040902060010154611f5d8161330b565b6113528383613337565b6001600160a01b038116600090815260208190526040812054610ac7565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6040516370a0823160e01b815233600482015261131b907f000000000000000000000000c5b001dc33727f8f26880b184090d3e252470d456001600160a01b0316906370a0823190602401602060405180830381865afa158015612018573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061203c919061429a565b33613359565b6120596000805160206145c08339815191526126b9565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa1580156120a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120c4919061429a565b90507f000000000000000000000000c5b001dc33727f8f26880b184090d3e252470d456001600160a01b0316826001600160a01b03160361210f57600b5461210c9082614287565b90505b8060000361214d5760405162461bcd60e51b815260206004820152600b60248201526a16995c9bc8185b5bdd5b9d60aa1b6044820152606401610cb0565b6121616001600160a01b0383163383612b6d565b604080516001600160a01b0384168152602081018390527f741ee845808813887c0b0d54aa20a3d0f670bebce7b6a1face577afbc00d1d6c910160405180910390a15050565b6000610ac782611eaa565b6121bc60006126b9565b600f5460ff16156122255760405162461bcd60e51b815260206004820152602d60248201527f43616e6e6f742061646420737472617465677920647572696e6720656d65726760448201526c32b731bc9039b43aba3237bbb760991b6064820152608401610cb0565b6001600160a01b03831661224b5760405162461bcd60e51b8152600401610cb0906142d6565b6001600160a01b038316600090815260086020526040902054156122aa5760405162461bcd60e51b815260206004820152601660248201527514dd1c985d1959de48185b1c9958591e48185919195960521b6044820152606401610cb0565b826001600160a01b031663fbfa77cf6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156122e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061230c9190614464565b6001600160a01b0316306001600160a01b03161461236c5760405162461bcd60e51b815260206004820152601f60248201527f53747261746567792773207661756c7420646f6573206e6f74206d61746368006044820152606401610cb0565b826001600160a01b0316631f1fcd516040518163ffffffff1660e01b8152600401602060405180830381865afa1580156123aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123ce9190614464565b6001600160a01b03167f000000000000000000000000c5b001dc33727f8f26880b184090d3e252470d456001600160a01b03161461244e5760405162461bcd60e51b815260206004820152601e60248201527f537472617465677927732077616e7420646f6573206e6f74206d6174636800006044820152606401610cb0565b61245b6005612710614244565b8211156124aa5760405162461bcd60e51b815260206004820181905260248201527f4665652063616e6e6f7420626520686967686572207468616e203230204250536044820152606401610cb0565b612710600c54826124bb9190614274565b11156125025760405162461bcd60e51b8152602060048201526016602482015275496e76616c696420616c6c6f634250532076616c756560501b6044820152606401610cb0565b6040805160e0810182524280825260208083018681528385018681526000606086018181526080870182815260a0880183815260c089019788526001600160a01b038d1684526008909652978220965187559251600187015590516002860155905160038501559351600484015551600583015551600690910155600c805483929061258f908490614274565b9091555050600980546001810182556000919091527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af0180546001600160a01b0319166001600160a01b03851690811790915560408051848152602081018490527f45bb3eed5cd098efb0a286413fb1f3c11841762610cefbabae6a772963e916ba91016116c2565b60010190565b612628828261198c565b6113295760008281526005602090815260408083206001600160a01b03851684529091529020805460ff191660011790556126603390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b60006112b0836001600160a01b038416613556565b60006126c36135a5565b8051909150600080805b8381101561273c578115801561270157506127018582815181106126f3576126f3614400565b60200260200101513361367d565b1561270b57600191505b84818151811061271d5761271d614400565b60200260200101518603612734576001925061273c565b6001016126cd565b508180156127475750805b6127895760405162461bcd60e51b8152602060048201526013602482015272556e617574686f72697a65642061636365737360681b6044820152606401610cb0565b5050505050565b60006001600160e01b03198216637965db0b60e01b1480610ac757506301ffc9a760e01b6001600160e01b0319831614610ac7565b60006127cf612c0e565b6127d7611cb3565b610a9d9190614287565b6001600160a01b0383166128435760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610cb0565b6001600160a01b0382166128a45760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610cb0565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6000816000036129475760405162461bcd60e51b815260206004820152600d60248201526c04469766973696f6e206279203609c1b6044820152606401610cb0565b60006129538385614244565b905061295f8385614481565b156112b0578061296e81614495565b95945050505050565b6001600160a01b03821660009081526008602052604090206003810154808311156129fc5760405162461bcd60e51b815260206004820152602f60248201527f5374726174656779206c6f73732063616e6e6f7420626520677265617465722060448201526e3a3430b71030b63637b1b0ba34b7b760891b6064820152608401610cb0565b600c5415612a6b576000612a2e600d54600c5486612a1a9190614217565b612a249190614244565b8460020154612b57565b90508015612a695780836002016000828254612a4a9190614287565b9250508190555080600c6000828254612a639190614287565b90915550505b505b82826005016000828254612a7f9190614274565b9250508190555082826003016000828254612a9a9190614287565b9250508190555082600d6000828254612ab39190614287565b909155505050505050565b6001600160a01b038216600090815260086020526040812060010154819061271090612aea9085614217565b612af49190614244565b905080156112b0576000612b0760025490565b905060008115612b3257612b196127c5565b612b238385614217565b612b2d9190614244565b612b34565b825b601354909150612b4d906001600160a01b031682613689565b5050905092915050565b6000818310612b6657816112b0565b5090919050565b6040516001600160a01b03831660248201526044810182905261135290849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613748565b6040516001600160a01b0380851660248301528316604482015260648101829052612c089085906323b872dd60e01b90608401612b99565b50505050565b600080601154600e5442612c229190614287565b612c2c9190614217565b9050670de0b6b3a7640000811015612c6c57670de0b6b3a764000060125482612c559190614217565b612c5f9190614244565b6012546111839190614287565b600091505090565b6000612c808484611f85565b90506000198114612c085781811015612cdb5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610cb0565b612c0884848484036127e1565b6001600160a01b038316612d4c5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610cb0565b6001600160a01b038216612dae5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610cb0565b6001600160a01b03831660009081526020819052604090205481811015612e265760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610cb0565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3612c08565b6000612e9661381a565b83600003612ed75760405162461bcd60e51b815260206004820152600e60248201526d125b9d985b1a5908185b5bdd5b9d60921b6044820152606401610cb0565b60025484612ee36127c5565b612eed9190614217565b612ef79190614244565b600b549091508082111561325f57600954600090815b818110156131ab57838511156131ab57600060098281548110612f3257612f32614400565b60009182526020808320909101546001600160a01b03168083526008909152604082206003015490925090819003612f6b5750506131a3565b6000612f778789614287565b6040516370a0823160e01b81523060048201529091506000906001600160a01b037f000000000000000000000000c5b001dc33727f8f26880b184090d3e252470d4516906370a0823190602401602060405180830381865afa158015612fe1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613005919061429a565b90506000846001600160a01b0316632e1a7d4d6130228587612b57565b6040518263ffffffff1660e01b815260040161304091815260200190565b6020604051808303816000875af115801561305f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613083919061429a565b6040516370a0823160e01b815230600482015290915060009083906001600160a01b037f000000000000000000000000c5b001dc33727f8f26880b184090d3e252470d4516906370a0823190602401602060405180830381865afa1580156130ef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613113919061429a565b61311d9190614287565b9050613129818b614274565b995081156131535761313b828c614287565b9a50613147828a614274565b98506131538683612977565b6001600160a01b0386166000908152600860205260408120600301805483929061317e908490614287565b9250508190555080600d60008282546131979190614287565b90915550505050505050505b600101612f0d565b50600b839055828411156131e8578293506131c46127c5565b6002546131d18487614274565b6131db9190614217565b6131e59190614244565b96505b601054612710906131f98487614274565b6132039190614217565b61320d9190614244565b82111561325c5760405162461bcd60e51b815260206004820152601e60248201527f5769746864726177206c6f7373206578636565647320736c69707061676500006044820152606401610cb0565b50505b6132698386613873565b81600b600082825461327b9190614287565b909155506132b590506001600160a01b037f000000000000000000000000c5b001dc33727f8f26880b184090d3e252470d45168584612b6d565b60408051838152602081018790526001600160a01b03808616929087169133917ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db910160405180910390a4506112b06001600755565b61131b81336139a5565b61331f828261261e565b600082815260066020526040902061135290826126a4565b61334182826139fe565b60008281526006602052604090206113529082613a65565b600061336361381a565b600f5460ff16156133c75760405162461bcd60e51b815260206004820152602860248201527f43616e6e6f74206465706f73697420647572696e6720656d657267656e63792060448201526739b43aba3237bbb760c11b6064820152608401610cb0565b826000036134085760405162461bcd60e51b815260206004820152600e60248201526d125b9d985b1a5908185b5bdd5b9d60921b6044820152606401610cb0565b600a5483613414611cb3565b61341e9190614274565b111561345c5760405162461bcd60e51b815260206004820152600d60248201526c15985d5b1d081a5cc8199d5b1b609a1b6044820152606401610cb0565b600061346760025490565b90508060000361347957839150613498565b6134816127c5565b61348b8286614217565b6134959190614244565b91505b6134a28383613689565b83600b60008282546134b49190614274565b909155506134ef90506001600160a01b037f000000000000000000000000c5b001dc33727f8f26880b184090d3e252470d4516333087612bd0565b60408051858152602081018490526001600160a01b0385169133917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7910160405180910390a350610ac76001600755565b60006112b08383613a7a565b6000610ac7825490565b600081815260018301602052604081205461359d57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610ac7565b506000610ac7565b60408051600480825260a0820190925260609160009190602082016080803683370190505090506000801b816000815181106135e3576135e3614400565b6020026020010181815250506000805160206145c08339815191528160018151811061361157613611614400565b6020026020010181815250506000805160206145a08339815191528160028151811061363f5761363f614400565b6020026020010181815250506000805160206145e08339815191528160038151811061366d5761366d614400565b6020908102919091010152919050565b60006112b0838361198c565b6001600160a01b0382166136df5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610cb0565b80600260008282546136f19190614274565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600061379d826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613aa49092919063ffffffff16565b80519091501561135257808060200190518101906137bb91906144c4565b6113525760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610cb0565b60026007540361386c5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610cb0565b6002600755565b6001600160a01b0382166138d35760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610cb0565b6001600160a01b038216600090815260208190526040902054818110156139475760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610cb0565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b6139af828261198c565b611329576139bc81613abb565b6139c7836020613acd565b6040516020016139d89291906144e1565b60408051601f198184030181529082905262461bcd60e51b8252610cb091600401613f5e565b613a08828261198c565b156113295760008281526005602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60006112b0836001600160a01b038416613c69565b6000826000018281548110613a9157613a91614400565b9060005260206000200154905092915050565b6060613ab38484600085613d5c565b949350505050565b6060610ac76001600160a01b03831660145b60606000613adc836002614217565b613ae7906002614274565b67ffffffffffffffff811115613aff57613aff6144ae565b6040519080825280601f01601f191660200182016040528015613b29576020820181803683370190505b509050600360fc1b81600081518110613b4457613b44614400565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110613b7357613b73614400565b60200101906001600160f81b031916908160001a9053506000613b97846002614217565b613ba2906001614274565b90505b6001811115613c1a576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110613bd657613bd6614400565b1a60f81b828281518110613bec57613bec614400565b60200101906001600160f81b031916908160001a90535060049490941c93613c1381614556565b9050613ba5565b5083156112b05760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610cb0565b60008181526001830160205260408120548015613d52576000613c8d600183614287565b8554909150600090613ca190600190614287565b9050818114613d06576000866000018281548110613cc157613cc1614400565b9060005260206000200154905080876000018481548110613ce457613ce4614400565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080613d1757613d1761456d565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610ac7565b6000915050610ac7565b606082471015613dbd5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610cb0565b600080866001600160a01b03168587604051613dd99190614583565b60006040518083038185875af1925050503d8060008114613e16576040519150601f19603f3d011682016040523d82523d6000602084013e613e1b565b606091505b509150915061127c8783838760608315613e96578251600003613e8f576001600160a01b0385163b613e8f5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610cb0565b5081613ab3565b613ab38383815115613eab5781518083602001fd5b8060405162461bcd60e51b8152600401610cb09190613f5e565b508054600082559060005260206000209081019061131b91905b80821115613ef35760008155600101613edf565b5090565b600060208284031215613f0957600080fd5b5035919050565b600060208284031215613f2257600080fd5b81356001600160e01b0319811681146112b057600080fd5b60005b83811015613f55578181015183820152602001613f3d565b50506000910152565b6020815260008251806020840152613f7d816040850160208701613f3a565b601f01601f19169190910160400192915050565b6001600160a01b038116811461131b57600080fd5b60008060408385031215613fb957600080fd5b8235613fc481613f91565b946020939093013593505050565b60008060408385031215613fe557600080fd5b50508035926020909101359150565b801515811461131b57600080fd5b60006020828403121561401457600080fd5b81356112b081613ff4565b60008060006060848603121561403457600080fd5b833561403f81613f91565b9250602084013561404f81613f91565b929592945050506040919091013590565b6000806040838503121561407357600080fd5b82359150602083013561408581613f91565b809150509250929050565b6000602082840312156140a257600080fd5b81356112b081613f91565b600080602083850312156140c057600080fd5b823567ffffffffffffffff808211156140d857600080fd5b818501915085601f8301126140ec57600080fd5b8135818111156140fb57600080fd5b8660208260051b850101111561411057600080fd5b60209290920196919550909350505050565b60008060006060848603121561413757600080fd5b83359250602084013561414981613f91565b9150604084013561415981613f91565b809150509250925092565b6000806040838503121561417757600080fd5b823561418281613f91565b9150602083013561408581613f91565b6000806000606084860312156141a757600080fd5b83356141b281613f91565b95602085013595506040909401359392505050565b600181811c908216806141db57607f821691505b6020821081036141fb57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610ac757610ac7614201565b634e487b7160e01b600052601260045260246000fd5b6000826142535761425361422e565b500490565b6000600160ff1b820161426d5761426d614201565b5060000390565b80820180821115610ac757610ac7614201565b81810381811115610ac757610ac7614201565b6000602082840312156142ac57600080fd5b5051919050565b6000602082840312156142c557600080fd5b815160ff811681146112b057600080fd5b60208082526018908201527f496e76616c696420737472617465677920616464726573730000000000000000604082015260600190565b600181815b8085111561434857816000190482111561432e5761432e614201565b8085161561433b57918102915b93841c9390800290614312565b509250929050565b60008261435f57506001610ac7565b8161436c57506000610ac7565b8160018114614382576002811461438c576143a8565b6001915050610ac7565b60ff84111561439d5761439d614201565b50506001821b610ac7565b5060208310610133831016604e8410600b84101617156143cb575081810a610ac7565b6143d5838361430d565b80600019048211156143e9576143e9614201565b029392505050565b60006112b060ff841683614350565b634e487b7160e01b600052603260045260246000fd5b60208082528181018390526000908460408401835b8681101561445957823561443e81613f91565b6001600160a01b03168252918301919083019060010161442b565b509695505050505050565b60006020828403121561447657600080fd5b81516112b081613f91565b6000826144905761449061422e565b500690565b6000600182016144a7576144a7614201565b5060010190565b634e487b7160e01b600052604160045260246000fd5b6000602082840312156144d657600080fd5b81516112b081613ff4565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351614519816017850160208801613f3a565b7001034b99036b4b9b9b4b733903937b6329607d1b601791840191820152835161454a816028840160208801613f3a565b01602801949350505050565b60008161456557614565614201565b506000190190565b634e487b7160e01b600052603160045260246000fd5b60008251614595818460208701613f3a565b919091019291505056fe8b5b16d04624687fcf0d0228f19993c9157c1ed07b41d8d430fd9100eb099fe8df8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec42b17d0a42cc710456bf9c3efb785dcd0cb93a0ac358113307b5c64b285b516b5ca264697066735822122045bccccc4dd2ce219255c32cca105d63cc485c45dd094981e615928fee1f3c8c64736f6c63430008120033

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

000000000000000000000000c5b001dc33727f8f26880b184090d3e252470d4500000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000a968163f0a57b400000000000000000000000000000eb9c9b785aa7818b2ebc8f9842926c4b9f707e4b0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000000105374616b65642045524e205661756c74000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005737445524e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000001e71aee6081f62053123140aacc7a06021d7734800000000000000000000000081876677843d00a7d792e1617459ac2e932025760000000000000000000000001a20d7a31e5b3bc5f02c8a146ef6f394502a10c40000000000000000000000004c3490df15edfa178333445ce568ec6d99b5d71c000000000000000000000000b26cd6633db6b0c9ae919049c1437271ae496d1500000000000000000000000060bc5e0440c867eeb4cbce84bb1123fad2b262b100000000000000000000000000000000000000000000000000000000000000030000000000000000000000009bc776dbb134ef9d7014db1823cd755ac5015203000000000000000000000000eb9c9b785aa7818b2ebc8f9842926c4b9f707e4b000000000000000000000000b0c9d5851def8a2aac4a23031ca2610f8c3483f9

-----Decoded View---------------
Arg [0] : _token (address): 0xc5b001DC33727F8F26880B184090D3E252470D45
Arg [1] : _name (string): Staked ERN Vault
Arg [2] : _symbol (string): stERN
Arg [3] : _tvlCap (uint256): 50000000000000000000000
Arg [4] : _treasury (address): 0xeb9C9b785aA7818B2EBC8f9842926c4B9f707e4B
Arg [5] : _strategists (address[]): 0x1E71AEE6081f62053123140aacC7a06021D77348,0x81876677843D00a7D792E1617459aC2E93202576,0x1A20D7A31e5B3Bc5f02c8A146EF6f394502a10c4,0x4C3490dF15edFa178333445ce568EC6D99b5d71c,0xB26cd6633dB6B0C9AE919049c1437271Ae496D15,0x60BC5E0440C867eEb4CbcE84bB1123fad2b262B1
Arg [6] : _multisigRoles (address[]): 0x9BC776dBb134Ef9D7014dB1823Cd755Ac5015203,0xeb9C9b785aA7818B2EBC8f9842926c4B9f707e4B,0xb0C9D5851deF8A2Aac4A23031CA2610f8C3483F9

-----Encoded View---------------
22 Constructor Arguments found :
Arg [0] : 000000000000000000000000c5b001dc33727f8f26880b184090d3e252470d45
Arg [1] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000120
Arg [3] : 000000000000000000000000000000000000000000000a968163f0a57b400000
Arg [4] : 000000000000000000000000eb9c9b785aa7818b2ebc8f9842926c4b9f707e4b
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000160
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000240
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000010
Arg [8] : 5374616b65642045524e205661756c7400000000000000000000000000000000
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [10] : 737445524e000000000000000000000000000000000000000000000000000000
Arg [11] : 0000000000000000000000000000000000000000000000000000000000000006
Arg [12] : 0000000000000000000000001e71aee6081f62053123140aacc7a06021d77348
Arg [13] : 00000000000000000000000081876677843d00a7d792e1617459ac2e93202576
Arg [14] : 0000000000000000000000001a20d7a31e5b3bc5f02c8a146ef6f394502a10c4
Arg [15] : 0000000000000000000000004c3490df15edfa178333445ce568ec6d99b5d71c
Arg [16] : 000000000000000000000000b26cd6633db6b0c9ae919049c1437271ae496d15
Arg [17] : 00000000000000000000000060bc5e0440c867eeb4cbce84bb1123fad2b262b1
Arg [18] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [19] : 0000000000000000000000009bc776dbb134ef9d7014db1823cd755ac5015203
Arg [20] : 000000000000000000000000eb9c9b785aa7818b2ebc8f9842926c4b9f707e4b
Arg [21] : 000000000000000000000000b0c9d5851def8a2aac4a23031ca2610f8c3483f9


Deployed Bytecode Sourcemap

113934:17145:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;108490:154;;;;;;:::i;:::-;;:::i;:::-;;114988:118;;;:::i;:::-;;;345:25:1;;;333:2;318:18;114988:118:0;;;;;;;;47360:214;;;;;;:::i;:::-;;:::i;:::-;;;837:14:1;;830:22;812:41;;800:2;785:18;47360:214:0;672:187:1;57531:100:0;;;:::i;:::-;;;;;;;:::i;116905:200::-;;;;;;:::i;:::-;;:::i;59882:201::-;;;;;;:::i;:::-;;:::i;125331:227::-;;;;;;:::i;:::-;;:::i;105066:2738::-;;;;;;:::i;:::-;;:::i;109324:265::-;;;;;;:::i;:::-;;:::i;58651:108::-;58739:12;;58651:108;;94295:1198;;;:::i;60663:295::-;;;;;;:::i;:::-;;:::i;29849:131::-;;;;;;:::i;:::-;29923:7;29950:12;;;:6;:12;;;;;:22;;;;29849:131;108717:83;;;:::i;87903:50::-;;-1:-1:-1;;;;;;;;;;;87903:50:0;;130544:199;;;;;;:::i;:::-;;:::i;99359:105::-;;;;;;:::i;:::-;;:::i;30290:147::-;;;;;;:::i;:::-;;:::i;111101:99::-;;;:::i;:::-;;;4097:4:1;4085:17;;;4067:36;;4055:2;4040:18;111101:99:0;3925:184:1;86535:29:0;;;;;;;;;31434:218;;;;;;:::i;:::-;;:::i;114615:116::-;114717:5;114615:116;;;-1:-1:-1;;;;;4278:32:1;;;4260:51;;4248:2;4233:18;114615:116:0;4114:203:1;61367:238:0;;;;;;:::i;:::-;;:::i;85759:52::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4889:25:1;;;4945:2;4930:18;;4923:34;;;;4973:18;;;4966:34;;;;5031:2;5016:18;;5009:34;;;;5074:3;5059:19;;5052:35;5118:3;5103:19;;5096:35;5162:3;5147:19;;5140:35;4876:3;4861:19;85759:52:0;4574:607:1;86115:21:0;;;;;;117858:257;;;;;;:::i;:::-;;:::i;86787:38::-;;;;;;86908:27;;;;;;86302:29;;;;;;107977:286;;;;;;:::i;:::-;;:::i;86746:34::-;;;;;;86061:47;;86103:5;86061:47;;128747:136;;;;;;:::i;:::-;;:::i;92694:764::-;;;;;;:::i;:::-;;:::i;87962:23::-;;;;;-1:-1:-1;;;;;87962:23:0;;;120085:148;;;;;;:::i;:::-;;:::i;86209:28::-;;;;;;58822:127;;;;;;:::i;:::-;-1:-1:-1;;;;;58923:18:0;58896:7;58923:18;;;;;;;;;;;;58822:127;87840:56;;-1:-1:-1;;;;;;;;;;;87840:56:0;;97277:177;;;:::i;109761:309::-;;;;;;:::i;:::-;;:::i;92096:390::-;;;;;;:::i;:::-;;:::i;110165:202::-;;;;;;:::i;:::-;;:::i;98957:107::-;;;:::i;48173:153::-;;;;;;:::i;:::-;;:::i;28322:147::-;;;;;;:::i;:::-;;:::i;123224:256::-;;;;;;:::i;:::-;;:::i;57750:104::-;;;:::i;86145:24::-;;;;;;87773:60;;-1:-1:-1;;;;;;;;;;;87773:60:0;;27427:49;;27472:4;27427:49;;62108:436;;;;;;:::i;:::-;;:::i;59155:193::-;;;;;;:::i;:::-;;:::i;95677:641::-;;;;;;:::i;:::-;;:::i;122304:207::-;;;;;;:::i;:::-;;:::i;126491:424::-;;;;;;:::i;:::-;;:::i;96550:101::-;;;:::i;97853:91::-;;;;;;:::i;:::-;;:::i;129807:465::-;;;;;;:::i;:::-;;:::i;93593:381::-;;;;;;:::i;:::-;;:::i;86401:25::-;;;;;;120956:271;;;;;;:::i;:::-;;:::i;115895:221::-;;;;;;:::i;:::-;;:::i;85907:32::-;;;;;;:::i;:::-;;:::i;48500:142::-;;;;;;:::i;:::-;;:::i;124039:146::-;;;;;;:::i;:::-;;:::i;85948:58::-;;85998:8;85948:58;;30730:149;;;;;;:::i;:::-;;:::i;127475:127::-;;;;;;:::i;:::-;;:::i;59411:151::-;;;;;;:::i;:::-;;:::i;97558:99::-;;;:::i;110516:428::-;;;;;;:::i;:::-;;:::i;119223:137::-;;;;;;:::i;:::-;;:::i;86487:41::-;;;;;90722:1179;;;;;;:::i;:::-;;:::i;86632:37::-;;;;;108490:154;108550:19;-1:-1:-1;;;;;;;;;;;108550:12:0;:19::i;:::-;108580:6;:19;;;108615:21;;345:25:1;;;108615:21:0;;333:2:1;318:18;108615:21:0;;;;;;;;108490:154;:::o;114988:118::-;115043:26;115089:9;:7;:9::i;:::-;115082:16;;114988:118;:::o;47360:214::-;47445:4;-1:-1:-1;;;;;;47469:57:0;;-1:-1:-1;;;47469:57:0;;:97;;;47530:36;47554:11;47530:23;:36::i;:::-;47462:104;47360:214;-1:-1:-1;;47360:214:0:o;57531:100::-;57585:13;57618:5;57611:12;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;57531:100;:::o;116905:200::-;116976:14;117007:13;58739:12;;;58651:108;117007:13;117024:1;117007:18;117003:37;;-1:-1:-1;117034:6:0;116905:200::o;117003:37::-;58739:12;;117068;:10;:12::i;:::-;117059:21;;:6;:21;:::i;:::-;117058:39;;;;:::i;59882:201::-;59965:4;8681:10;60021:32;8681:10;60037:7;60046:6;60021:8;:32::i;:::-;-1:-1:-1;60071:4:0;;59882:201;-1:-1:-1;;;59882:201:0:o;125331:227::-;125402:14;125433:13;58739:12;;;58651:108;125433:13;:18;;:39;;;125455:12;:10;:12::i;:::-;:17;125433:39;125429:53;;;-1:-1:-1;125481:1:0;;125331:227;-1:-1:-1;125331:227:0:o;125429:53::-;125502:48;125522:13;58739:12;;;58651:108;125522:13;125513:22;;:6;:22;:::i;:::-;125537:12;:10;:12::i;:::-;125502:10;:48::i;105066:2738::-;105133:7;105153:33;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;105153:33:0;105214:10;105197:27;;;:14;105269:26;;;:10;:26;;;;;105314:19;;105269:26;;105314:24;105306:58;;;;-1:-1:-1;;;105306:58:0;;9001:2:1;105306:58:0;;;8983:21:1;9040:2;9020:18;;;9013:30;-1:-1:-1;;;9059:18:1;;;9052:51;9120:18;;105306:58:0;;;;;;;;;105388:1;105381:4;:8;105377:299;;;105426:5;105427:4;105426:5;:::i;:::-;105406:9;;;:26;;;105459:14;;105447:38;;:11;:38::i;:::-;105377:299;;;105514:1;105507:4;:8;105503:173;;;105532:9;;;:25;;;105596:14;;105584:38;;105552:4;105584:11;:38::i;:::-;105572:9;;;:50;105655:9;;;;105637:14;;;:27;;:14;;:27;;105655:9;;105637:27;:::i;:::-;;;;-1:-1:-1;;105503:173:0;105705:18;:16;:18::i;:::-;105688:14;;;:35;;;105755:1;-1:-1:-1;105734:583:0;;;105794:4;:14;;;105793:15;;;:::i;:::-;105773:9;;;:36;;;105843:31;;105863:10;105843:8;:31::i;:::-;105824:16;;;:50;;;105895:21;105891:229;;105959:4;:16;;;105937:8;:18;;;:38;;;;;;;:::i;:::-;;;;-1:-1:-1;;106012:16:0;;;;105994:14;:34;;:14;;:34;;106012:16;;105994:34;:::i;:::-;;;;-1:-1:-1;;106060:16:0;;;;106047:9;;;:29;;;;106060:16;;106047:29;:::i;:::-;;;-1:-1:-1;105891:229:0;105734:583;;;106158:1;106141:4;:14;;;:18;106137:180;;;106198:14;;;;106176:11;;;:37;;;106228:18;;;:33;;-1:-1:-1;;106228:33:0;;106198:14;;106228:33;:::i;:::-;;;;-1:-1:-1;;106294:11:0;;;;106276:14;:29;;:14;;:29;;106294:11;;106276:29;:::i;:::-;;;;-1:-1:-1;;106137:180:0;106364:4;:16;;;106352:4;:9;;;:28;;;;:::i;:::-;106329:20;;;:51;;;106395:11;;;;:34;106391:427;;;106474:4;:20;;;106460:4;:11;;;:34;;;;:::i;:::-;106446:9;;:49;;;;;;;:::i;:::-;;;;-1:-1:-1;;106529:14:0;;106559:20;;;;106545:11;;;;106510:70;;106529:14;106545:34;;;:::i;:::-;-1:-1:-1;;;;;106510:5:0;:18;;:70;:18;:70::i;:::-;106391:427;;;106616:4;:20;;;106602:4;:11;;;:34;106598:220;;;106690:4;:11;;;106667:4;:20;;;:34;;;;:::i;:::-;106653:9;;:49;;;;;;;:::i;:::-;;;;-1:-1:-1;;106740:14:0;;106794:11;;;;106771:20;;;;106717:89;;106740:14;106764:4;;106771:34;;106794:11;106771:34;:::i;:::-;-1:-1:-1;;;;;106717:5:0;:22;;:89;;:22;:89::i;:::-;107049:4;:9;;;107037:4;:9;;;107010:24;:22;:24::i;:::-;:36;;;;:::i;:::-;:48;;;;:::i;:::-;106980:27;;;:78;;;107103:9;;;;-1:-1:-1;107069:175:0;;;107174:4;:9;;;107144:4;:27;;;:39;;;;:::i;:::-;107129:12;:54;107069:175;;;107231:1;107216:12;:16;107069:175;107278:15;107256:19;;;:37;;;107304:10;:28;107381:14;;107410:9;;;;;107434;;;;;107458:16;;;;;107489:14;;;;107518:15;;;;107548:18;;;;107581:11;;;;;107607:17;;;;107350:285;;9896:25:1;;;9937:18;;;9930:34;;;;9980:18;;;9973:34;;;;10038:2;10023:18;;10016:34;;;;10081:3;10066:19;;10059:35;10125:3;10110:19;;10103:35;10154:19;;10147:35;;;;10198:19;;10191:35;107350:285:0;;-1:-1:-1;;;;;107350:285:0;;;;;;;;;9883:3:1;107350:285:0;;;107652:17;;;;:22;;:43;;-1:-1:-1;107678:17:0;;;;107652:43;107648:120;;;107729:4;:14;;;-1:-1:-1;;;;;107719:35:0;;:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;107712:44;;;;;;107648:120;-1:-1:-1;107787:9:0;;;;105066:2738;-1:-1:-1;;;105066:2738:0:o;109324:265::-;109392:7;109388:114;;;109416:22;-1:-1:-1;;;;;;;;;;;109416:12:0;:22::i;:::-;109388:114;;;109471:19;-1:-1:-1;;;;;;;;;;;109471:12:0;:19::i;:::-;109512:17;:27;;-1:-1:-1;;109512:27:0;;;;;;;;;;109555:26;;812:41:1;;;109555:26:0;;800:2:1;785:18;109555:26:0;672:187:1;94295:1198:0;94408:13;;94344:6;;94383:10;;94408:18;;:39;;-1:-1:-1;94430:17:0;;;;94408:39;94404:119;;;-1:-1:-1;;;;;94479:21:0;;;;;;:10;:21;;;;;:31;;;94471:40;;;:::i;:::-;94464:47;;;94295:1198;:::o;94404:119::-;94535:26;86103:5;94598:9;:7;:9::i;:::-;-1:-1:-1;;;;;94565:21:0;;;;;;:10;:21;;;;;:30;;;:42;;;;:::i;:::-;94564:62;;;;:::i;:::-;-1:-1:-1;;;;;94670:21:0;;94637:30;94670:21;;;:10;:21;;;;;:31;;;94535:91;;-1:-1:-1;94718:43:0;;;94714:772;;;94793:43;94818:18;94793:22;:43;:::i;:::-;94785:52;;;:::i;:::-;94778:59;;;;;94295:1198;:::o;94714:772::-;94884:18;94859:22;:43;94855:631;;;94919:26;86103:5;94965:9;:7;:9::i;:::-;94949:13;;:25;;;;:::i;:::-;94948:45;;;;:::i;:::-;95041:14;;94919:74;;-1:-1:-1;95076:44:0;;;95072:93;;95148:1;95141:8;;;;;;;94295:1198;:::o;95072:93::-;95181:17;95201:43;95222:22;95201:18;:43;:::i;:::-;95181:63;-1:-1:-1;95271:64:0;95181:63;95291:43;95312:22;95291:18;:43;:::i;:::-;95271:8;:64::i;:::-;95259:76;;95362:30;95371:9;95382;;95362:8;:30::i;:::-;95350:42;94295:1198;-1:-1:-1;;;;;;;94295:1198:0:o;94855:631::-;95473:1;95466:8;;;;;94295:1198;:::o;60663:295::-;60794:4;8681:10;60852:38;60868:4;8681:10;60883:6;60852:15;:38::i;:::-;60901:27;60911:4;60917:2;60921:6;60901:9;:27::i;:::-;60946:4;60939:11;;;60663:295;;;;;;:::o;108717:83::-;108761:31;-1:-1:-1;;108761:12:0;:31::i;:::-;108717:83::o;130544:199::-;130603:32;27472:4;130603:12;:32::i;:::-;130659:7;130646:9;;:20;;;;;;;:::i;:::-;;;;-1:-1:-1;130677:58:0;;-1:-1:-1;;;;;;130677:5:0;:22;130700:10;130720:4;130727:7;130677:22;:58::i;:::-;130544:199;:::o;99359:105::-;99414:42;99424:7;99433:10;99445;99414:9;:42::i;:::-;;99359:105;:::o;30290:147::-;29923:7;29950:12;;;:6;:12;;;;;:22;;;27918:16;27929:4;27918:10;:16::i;:::-;30404:25:::1;30415:4;30421:7;30404:10;:25::i;:::-;30290:147:::0;;;:::o;111101:99::-;111151:5;111176;-1:-1:-1;;;;;111176:14:0;;:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;31434:218::-;-1:-1:-1;;;;;31530:23:0;;8681:10;31530:23;31522:83;;;;-1:-1:-1;;;31522:83:0;;10906:2:1;31522:83:0;;;10888:21:1;10945:2;10925:18;;;10918:30;10984:34;10964:18;;;10957:62;-1:-1:-1;;;11035:18:1;;;11028:45;11090:19;;31522:83:0;10704:411:1;31522:83:0;31618:26;31630:4;31636:7;31618:11;:26::i;61367:238::-;61455:4;8681:10;61511:64;8681:10;61527:7;61564:10;61536:25;8681:10;61527:7;61536:9;:25::i;:::-;:38;;;;:::i;:::-;61511:8;:64::i;117858:257::-;117953:17;;117919;;117953;;;:40;;;117987:6;;117974:9;:7;:9::i;:::-;:19;;117953:40;117949:54;;;-1:-1:-1;118002:1:0;;117858:257;-1:-1:-1;117858:257:0:o;117949:54::-;-1:-1:-1;;118018:6:0;;:27;118014:57;;-1:-1:-1;;;118054:17:0;117858:257;-1:-1:-1;117858:257:0:o;118014:57::-;118098:9;:7;:9::i;:::-;118089:6;;:18;;;;:::i;107977:286::-;108054:24;-1:-1:-1;;;;;;;;;;;108054:12:0;:24::i;:::-;86103:5;108097:16;:35;;108089:65;;;;-1:-1:-1;;;108089:65:0;;11322:2:1;108089:65:0;;;11304:21:1;11361:2;11341:18;;;11334:30;-1:-1:-1;;;11380:18:1;;;11373:47;11437:18;;108089:65:0;11120:341:1;108089:65:0;108165:15;:34;;;108215:40;;345:25:1;;;108215:40:0;;333:2:1;318:18;108215:40:0;199:177:1;128747:136:0;128818:14;128852:23;128868:6;128852:15;:23::i;92694:764::-;-1:-1:-1;;;;;92792:21:0;;;;;;:10;:21;;;;;:32;:37;;92784:74;;;;-1:-1:-1;;;92784:74:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;92903:21:0;;92869:31;92903:21;;;:10;:21;;;;;:30;;;92948:28;;92944:232;;92993:24;-1:-1:-1;;;;;;;;;;;92993:12:0;:24::i;:::-;92944:232;;;93145:19;-1:-1:-1;;;;;;;;;;;93145:12:0;:19::i;:::-;93203:23;93186:13;;:40;;;;;;;:::i;:::-;;;;-1:-1:-1;;;;;;;93237:21:0;;;;;;:10;:21;;;;;:30;;:42;;;93290:13;:26;;93270:9;;93237:21;93290:26;;93270:9;;93290:26;:::i;:::-;;;;-1:-1:-1;;93335:13:0;;86103:5;-1:-1:-1;93335:32:0;93327:62;;;;-1:-1:-1;;;93327:62:0;;11322:2:1;93327:62:0;;;11304:21:1;11361:2;11341:18;;;11334:30;-1:-1:-1;;;11380:18:1;;;11373:47;11437:18;;93327:62:0;11120:341:1;93327:62:0;93429:9;-1:-1:-1;;;;;93405:45:0;;93440:9;93405:45;;;;345:25:1;;333:2;318:18;;199:177;93405:45:0;;;;;;;;92773:685;92694:764;;:::o;120085:148::-;120163:14;120199:26;120208:6;120216:8;120199;:26::i;97277:177::-;97330:7;97357:13;58739:12;;;58651:108;97357:13;:18;:89;;58739:12;;97419:10;:8;:10::i;:::-;97413:16;;:2;:16;:::i;:::-;97398:12;:10;:12::i;:::-;:31;;;;:::i;:::-;97397:49;;;;:::i;97357:89::-;97384:10;:8;:10::i;:::-;97378:16;;:2;:16;:::i;109761:309::-;109838:19;-1:-1:-1;;;;;;;;;;;109838:12:0;:19::i;:::-;85998:8;109876:11;:38;;109868:87;;;;-1:-1:-1;;;109868:87:0;;13404:2:1;109868:87:0;;;13386:21:1;13443:2;13423:18;;;13416:30;13482:34;13462:18;;;13455:62;-1:-1:-1;;;13533:18:1;;;13526:34;13577:19;;109868:87:0;13202:400:1;109868:87:0;109966:23;:37;;;110019:43;;345:25:1;;;110019:43:0;;333:2:1;318:18;110019:43:0;199:177:1;92096:390:0;92182:19;-1:-1:-1;;;;;;;;;;;92182:12:0;:19::i;:::-;-1:-1:-1;;;;;92220:21:0;;;;;;:10;:21;;;;;:32;:37;;92212:74;;;;-1:-1:-1;;;92212:74:0;;;;;;;:::i;:::-;92316:19;92334:1;86103:5;92316:19;:::i;:::-;92305:7;:30;;92297:75;;;;-1:-1:-1;;;92297:75:0;;13809:2:1;92297:75:0;;;13791:21:1;;;13828:18;;;13821:30;13887:34;13867:18;;;13860:62;13939:18;;92297:75:0;13607:356:1;92297:75:0;-1:-1:-1;;;;;92383:21:0;;;;;;:10;:21;;;;;;;:28;;:38;;;92437:41;;;;;92414:7;345:25:1;;333:2;318:18;;199:177;92437:41:0;;;;;;;;92096:390;;:::o;110165:202::-;110230:32;27472:4;110230:12;:32::i;:::-;-1:-1:-1;;;;;110281:25:0;;110273:53;;;;-1:-1:-1;;;110273:53:0;;14170:2:1;110273:53:0;;;14152:21:1;14209:2;14189:18;;;14182:30;-1:-1:-1;;;14228:18:1;;;14221:45;14283:18;;110273:53:0;13968:339:1;110273:53:0;110337:8;:22;;-1:-1:-1;;;;;;110337:22:0;-1:-1:-1;;;;;110337:22:0;;;;;;;;;;110165:202::o;98957:107::-;99020:10;58896:7;58923:18;;;;;;;;;;;99000:56;;99020:10;99000:9;:56::i;48173:153::-;48263:7;48290:18;;;:12;:18;;;;;:28;;48312:5;48290:21;:28::i;28322:147::-;28408:4;28432:12;;;:6;:12;;;;;;;;-1:-1:-1;;;;;28432:29:0;;;;;;;;;;;;;;;28322:147::o;123224:256::-;123299:14;123335:19;123347:6;123335:11;:19::i;:::-;123326:28;;123446:26;123455:6;123463:8;123446;:26::i;:::-;;123224:256;;;;:::o;57750:104::-;57806:13;57839:7;57832:14;;;;;:::i;62108:436::-;62201:4;8681:10;62201:4;62284:25;8681:10;62301:7;62284:9;:25::i;:::-;62257:52;;62348:15;62328:16;:35;;62320:85;;;;-1:-1:-1;;;62320:85:0;;14514:2:1;62320:85:0;;;14496:21:1;14553:2;14533:18;;;14526:30;14592:34;14572:18;;;14565:62;-1:-1:-1;;;14643:18:1;;;14636:35;14688:19;;62320:85:0;14312:401:1;62320:85:0;62441:60;62450:5;62457:7;62485:15;62466:16;:34;62441:8;:60::i;:::-;-1:-1:-1;62532:4:0;;62108:436;-1:-1:-1;;;;62108:436:0:o;59155:193::-;59234:4;8681:10;59290:28;8681:10;59307:2;59311:6;59290:9;:28::i;95677:641::-;95762:19;-1:-1:-1;;;;;;;;;;;95762:12:0;:19::i;:::-;95814:16;95792:19;95856:16;;;95848:52;;;;-1:-1:-1;;;95848:52:0;;14920:2:1;95848:52:0;;;14902:21:1;14959:2;14939:18;;;14932:30;14998:25;14978:18;;;14971:53;15041:18;;95848:52:0;14718:347:1;95848:52:0;95913:22;95920:15;;95913:22;:::i;:::-;95951:9;95946:310;95970:11;95966:1;:15;95946:310;;;96020:16;96039;;96056:1;96039:19;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;96105:20:0;;96073:29;96105:20;;;:10;:20;;;;;96148:17;;96020:38;;-1:-1:-1;96105:20:0;96148:22;;96140:59;;;;-1:-1:-1;;;96140:59:0;;;;;;;:::i;:::-;-1:-1:-1;96214:15:0;:30;;;;;;;;-1:-1:-1;96214:30:0;;;;;;;;-1:-1:-1;;;;;;96214:30:0;-1:-1:-1;;;;;96214:30:0;;;;;;;;;;;1398:6;95946:310;;;;96271:39;96293:16;;96271:39;;;;;;;:::i;:::-;;;;;;;;95751:567;95677:641;;:::o;122304:207::-;122371:14;122402:13;58739:12;;;58651:108;122402:13;122419:1;122402:18;122398:37;;-1:-1:-1;122429:6:0;122304:207::o;122398:37::-;122455:48;122475:12;:10;:12::i;:::-;122466:21;;:6;:21;:::i;:::-;58739:12;;125502:10;:48::i;126491:424::-;126585:14;126621:23;126637:6;126621:15;:23::i;:::-;126612:32;-1:-1:-1;126743:10:0;-1:-1:-1;;;;;126743:19:0;;;126739:67;;126764:42;126780:5;126787:10;126799:6;126764:15;:42::i;:::-;126863:6;126825:34;126835:6;126843:8;126853:5;126825:9;:34::i;:::-;:44;126817:90;;;;-1:-1:-1;;;126817:90:0;;16114:2:1;126817:90:0;;;16096:21:1;16153:2;16133:18;;;16126:30;16192:34;16172:18;;;16165:62;-1:-1:-1;;;16243:18:1;;;16236:31;16284:19;;126817:90:0;15912:397:1;96550:101:0;96590:7;96629:14;;96617:9;;:26;;;;:::i;97853:91::-;97907:29;97916:7;97925:10;97907:8;:29::i;129807:465::-;-1:-1:-1;;;;;58923:18:0;;129899:14;58923:18;;;;;;;;;;;129899:14;;129987:10;:19;129983:67;;130008:42;130024:5;130031:10;130043:6;130008:15;:42::i;:::-;130070:34;130080:6;130088:8;130098:5;130070:9;:34::i;:::-;130061:43;;130115:25;130165:16;130175:5;-1:-1:-1;;;;;58923:18:0;58896:7;58923:18;;;;;;;;;;;;58822:127;130165:16;130143:38;;:19;:38;:::i;:::-;130115:66;;130221:6;130200:17;:27;130192:72;;;;-1:-1:-1;;;130192:72:0;;16516:2:1;130192:72:0;;;16498:21:1;;;16535:18;;;16528:30;16594:34;16574:18;;;16567:62;16646:18;;130192:72:0;16314:356:1;130192:72:0;129915:357;;129807:465;;;;;:::o;93593:381::-;93660:10;-1:-1:-1;;;;;93660:23:0;;;93656:78;;93700:22;-1:-1:-1;;;;;;;;;;;93700:12:0;:22::i;:::-;-1:-1:-1;;;;;93750:21:0;;;;;;:10;:21;;;;;:30;;;:35;;93746:74;;93593:381;:::o;93746:74::-;-1:-1:-1;;;;;93849:21:0;;;;;;:10;:21;;;;;:30;;;93832:13;:47;;93849:30;;93832:13;;:47;;93849:30;;93832:47;:::i;:::-;;;;-1:-1:-1;;;;;;;93890:21:0;;93923:1;93890:21;;;:10;:21;;;;;;:30;;:34;;;93940:26;;;93923:1;93940:26;93593:381;:::o;120956:271::-;121048:17;;121014;;121048;;;:40;;;121082:6;;121069:9;:7;:9::i;:::-;:19;;121048:40;121044:54;;;-1:-1:-1;121097:1:0;;120956:271;-1:-1:-1;120956:271:0:o;121044:54::-;-1:-1:-1;;121113:6:0;;:27;121109:57;;-1:-1:-1;;;121149:17:0;120956:271;-1:-1:-1;120956:271:0:o;121109:57::-;121184:35;121209:9;:7;:9::i;:::-;121200:6;;:18;;;;:::i;115895:221::-;115966:14;115997:13;58739:12;;;58651:108;115997:13;:18;;:39;;;116019:12;:10;:12::i;:::-;:17;115997:39;115993:58;;;-1:-1:-1;116045:6:0;115895:221::o;115993:58::-;116096:12;:10;:12::i;:::-;58739;;116079:13;58651:108;85907:32;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;85907:32:0;;-1:-1:-1;85907:32:0;:::o;48500:142::-;48580:7;48607:18;;;:12;:18;;;;;:27;;:25;:27::i;124039:146::-;-1:-1:-1;;;;;58923:18:0;;124107:17;58923:18;;;;;;;;;;;124144:33;;116905:200;:::i;30730:149::-;29923:7;29950:12;;;:6;:12;;;;;:22;;;27918:16;27929:4;27918:10;:16::i;:::-;30845:26:::1;30857:4;30863:7;30845:11;:26::i;127475:127::-:0;-1:-1:-1;;;;;58923:18:0;;127541:17;58923:18;;;;;;;;;;;127578:16;58822:127;59411:151;-1:-1:-1;;;;;59527:18:0;;;59500:7;59527:18;;;:11;:18;;;;;;;;:27;;;;;;;;;;;;;59411:151::o;97558:99::-;97609:27;;-1:-1:-1;;;97609:27:0;;97625:10;97609:27;;;4260:51:1;97600:49:0;;97609:5;-1:-1:-1;;;;;97609:15:0;;;;4233:18:1;;97609:27:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;97638:10;97600:8;:49::i;110516:428::-;110582:19;-1:-1:-1;;;;;;;;;;;110582:12:0;:19::i;:::-;110631:47;;-1:-1:-1;;;110631:47:0;;110672:4;110631:47;;;4260:51:1;110614:14:0;;-1:-1:-1;;;;;110631:32:0;;;;;4233:18:1;;110631:47:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;110614:64;;110711:5;-1:-1:-1;;;;;110693:24:0;:6;-1:-1:-1;;;;;110693:24:0;;110689:76;;110744:9;;110734:19;;;;:::i;:::-;;;110689:76;110783:6;110793:1;110783:11;110775:35;;;;-1:-1:-1;;;110775:35:0;;16877:2:1;110775:35:0;;;16859:21:1;16916:2;16896:18;;;16889:30;-1:-1:-1;;;16935:18:1;;;16928:41;16986:18;;110775:35:0;16675:335:1;110775:35:0;110823:55;-1:-1:-1;;;;;110823:35:0;;110859:10;110871:6;110823:35;:55::i;:::-;110894:42;;;-1:-1:-1;;;;;17207:32:1;;17189:51;;17271:2;17256:18;;17249:34;;;110894:42:0;;17162:18:1;110894:42:0;;;;;;;110571:373;110516:428;:::o;119223:137::-;119295:14;119329:23;119345:6;119329:15;:23::i;90722:1179::-;90818:32;27472:4;90818:12;:32::i;:::-;90870:17;;;;90869:18;90861:76;;;;-1:-1:-1;;;90861:76:0;;17496:2:1;90861:76:0;;;17478:21:1;17535:2;17515:18;;;17508:30;17574:34;17554:18;;;17547:62;-1:-1:-1;;;17625:18:1;;;17618:43;17678:19;;90861:76:0;17294:409:1;90861:76:0;-1:-1:-1;;;;;90956:23:0;;90948:60;;;;-1:-1:-1;;;90948:60:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;91027:21:0;;;;;;:10;:21;;;;;:32;:37;91019:72;;;;-1:-1:-1;;;91019:72:0;;17910:2:1;91019:72:0;;;17892:21:1;17949:2;17929:18;;;17922:30;-1:-1:-1;;;17968:18:1;;;17961:52;18030:18;;91019:72:0;17708:346:1;91019:72:0;91137:9;-1:-1:-1;;;;;91127:26:0;;:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;91110:45:0;91118:4;-1:-1:-1;;;;;91110:45:0;;91102:89;;;;-1:-1:-1;;;91102:89:0;;18517:2:1;91102:89:0;;;18499:21:1;18556:2;18536:18;;;18529:30;18595:33;18575:18;;;18568:61;18646:18;;91102:89:0;18315:355:1;91102:89:0;91238:9;-1:-1:-1;;;;;91228:25:0;;:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;91210:45:0;91218:5;-1:-1:-1;;;;;91210:45:0;;91202:88;;;;-1:-1:-1;;;91202:88:0;;18877:2:1;91202:88:0;;;18859:21:1;18916:2;18896:18;;;18889:30;18955:32;18935:18;;;18928:60;19005:18;;91202:88:0;18675:354:1;91202:88:0;91320:19;91338:1;86103:5;91320:19;:::i;:::-;91309:7;:30;;91301:75;;;;-1:-1:-1;;;91301:75:0;;13809:2:1;91301:75:0;;;13791:21:1;;;13828:18;;;13821:30;13887:34;13867:18;;;13860:62;13939:18;;91301:75:0;13607:356:1;91301:75:0;86103:5;91407:13;;91395:9;:25;;;;:::i;:::-;:44;;91387:79;;;;-1:-1:-1;;;91387:79:0;;19236:2:1;91387:79:0;;;19218:21:1;19275:2;19255:18;;;19248:30;-1:-1:-1;;;19294:18:1;;;19287:52;19356:18;;91387:79:0;19034:346:1;91387:79:0;91503:249;;;;;;;;91545:15;91503:249;;;;;;;;;;;;;;;;-1:-1:-1;91503:249:0;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;91479:21:0;;;;:10;:21;;;;;;:273;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;91765:13;:26;;91615:9;;-1:-1:-1;91765:26:0;;91615:9;;91765:26;:::i;:::-;;;;-1:-1:-1;;91802:15:0;:31;;;;;;;-1:-1:-1;91802:31:0;;;;;;;;-1:-1:-1;;;;;;91802:31:0;-1:-1:-1;;;;;91802:31:0;;;;;;;;91849:44;;;19559:25:1;;;19615:2;19600:18;;19593:34;;;91849:44:0;;19532:18:1;91849:44:0;19385:248:1;1289:134:0;1403:1;1398:6;;1289:134::o;33031:238::-;33115:22;33123:4;33129:7;33115;:22::i;:::-;33110:152;;33154:12;;;;:6;:12;;;;;;;;-1:-1:-1;;;;;33154:29:0;;;;;;;;;:36;;-1:-1:-1;;33154:36:0;33186:4;33154:36;;;33237:12;8681:10;;8601:98;33237:12;-1:-1:-1;;;;;33210:40:0;33228:7;-1:-1:-1;;;;;33210:40:0;33222:4;33210:40;;;;;;;;;;33031:238;;:::o;42180:152::-;42250:4;42274:50;42279:3;-1:-1:-1;;;;;42299:23:0;;42274:4;:50::i;2138:885::-;2200:37;2240:23;:21;:23::i;:::-;2293:27;;2200:63;;-1:-1:-1;2274:16:0;;;2567:360;2591:8;2587:1;:12;2567:360;;;2643:22;2642:23;:72;;;;;2669:45;2678:20;2699:1;2678:23;;;;;;;;:::i;:::-;;;;;;;2703:10;2669:8;:45::i;:::-;2638:142;;;2760:4;2735:29;;2638:142;2807:20;2828:1;2807:23;;;;;;;;:::i;:::-;;;;;;;2798:5;:32;2794:122;;2872:4;2851:25;;2895:5;;2794:122;1403:1;1398:6;2567:360;;;;2947:18;:44;;;;;2969:22;2947:44;2939:76;;;;-1:-1:-1;;;2939:76:0;;19840:2:1;2939:76:0;;;19822:21:1;19879:2;19859:18;;;19852:30;-1:-1:-1;;;19898:18:1;;;19891:49;19957:18;;2939:76:0;19638:343:1;2939:76:0;2189:834;;;;2138:885;:::o;28026:204::-;28111:4;-1:-1:-1;;;;;;28135:47:0;;-1:-1:-1;;;28135:47:0;;:87;;-1:-1:-1;;;;;;;;;;25568:40:0;;;28186:36;25459:157;96939:116;96984:7;97023:24;:22;:24::i;:::-;97011:9;:7;:9::i;:::-;:36;;;;:::i;66135:380::-;-1:-1:-1;;;;;66271:19:0;;66263:68;;;;-1:-1:-1;;;66263:68:0;;20188:2:1;66263:68:0;;;20170:21:1;20227:2;20207:18;;;20200:30;20266:34;20246:18;;;20239:62;-1:-1:-1;;;20317:18:1;;;20310:34;20361:19;;66263:68:0;19986:400:1;66263:68:0;-1:-1:-1;;;;;66350:21:0;;66342:68;;;;-1:-1:-1;;;66342:68:0;;20593:2:1;66342:68:0;;;20575:21:1;20632:2;20612:18;;;20605:30;20671:34;20651:18;;;20644:62;-1:-1:-1;;;20722:18:1;;;20715:32;20764:19;;66342:68:0;20391:398:1;66342:68:0;-1:-1:-1;;;;;66423:18:0;;;;;;;:11;:18;;;;;;;;:27;;;;;;;;;;;;;:36;;;66475:32;;345:25:1;;;66475:32:0;;318:18:1;66475:32:0;;;;;;;66135:380;;;:::o;130872:204::-;130937:7;130965:1;130970;130965:6;130957:32;;;;-1:-1:-1;;;130957:32:0;;20996:2:1;130957:32:0;;;20978:21:1;21035:2;21015:18;;;21008:30;-1:-1:-1;;;21054:18:1;;;21047:43;21107:18;;130957:32:0;20794:337:1;130957:32:0;131002:9;131014:5;131018:1;131014;:5;:::i;:::-;131002:17;-1:-1:-1;131034:5:0;131038:1;131034;:5;:::i;:::-;:10;131030:19;;131046:3;;;;:::i;:::-;;131067:1;-1:-1:-1;;;;;130872:204:0:o;102553:964::-;-1:-1:-1;;;;;102663:20:0;;102626:34;102663:20;;;:10;:20;;;;;102795:21;;;;102835:18;;;;102827:78;;;;-1:-1:-1;;;102827:78:0;;21595:2:1;102827:78:0;;;21577:21:1;21634:2;21614:18;;;21607:30;21673:34;21653:18;;;21646:62;-1:-1:-1;;;21724:18:1;;;21717:45;21779:19;;102827:78:0;21393:411:1;102827:78:0;102922:13;;:18;102918:414;;103018:17;103038:71;103072:14;;103055:13;;103048:4;:20;;;;:::i;:::-;103047:39;;;;:::i;:::-;103088:11;:20;;;103038:8;:71::i;:::-;103018:91;-1:-1:-1;103192:14:0;;103188:133;;103251:9;103227:11;:20;;;:33;;;;;;;:::i;:::-;;;;;;;;103296:9;103279:13;;:26;;;;;;;:::i;:::-;;;;-1:-1:-1;;103188:133:0;102942:390;102918:414;103432:4;103410:11;:18;;;:26;;;;;;;:::i;:::-;;;;;;;;103472:4;103447:11;:21;;;:29;;;;;;;:::i;:::-;;;;;;;;103505:4;103487:14;;:22;;;;;;;:::i;:::-;;;;-1:-1:-1;;;;;;102553:964:0:o;103871:443::-;-1:-1:-1;;;;;103995:20:0;;103942:7;103995:20;;;:10;:20;;;;;:27;;;103942:7;;86103:5;;103988:34;;:4;:34;:::i;:::-;103987:54;;;;:::i;:::-;103962:79;-1:-1:-1;104056:19:0;;104052:223;;104092:14;104109:13;58739:12;;;58651:108;104109:13;104092:30;-1:-1:-1;104137:14:0;104154:11;;:71;;104213:12;:10;:12::i;:::-;104186:23;104203:6;104186:14;:23;:::i;:::-;104185:40;;;;:::i;:::-;104154:71;;;104168:14;104154:71;104246:8;;104137:88;;-1:-1:-1;104240:23:0;;-1:-1:-1;;;;;104246:8:0;104137:88;104240:5;:23::i;:::-;104077:198;;104292:14;-1:-1:-1;103871:443:0;;;;:::o;9451:106::-;9509:7;9540:1;9536;:5;:13;;9548:1;9536:13;;;-1:-1:-1;9544:1:0;;9451:106;-1:-1:-1;9451:106:0:o;80953:211::-;81097:58;;-1:-1:-1;;;;;17207:32:1;;81097:58:0;;;17189:51:1;17256:18;;;17249:34;;;81070:86:0;;81090:5;;-1:-1:-1;;;81120:23:0;17162:18:1;;81097:58:0;;;;-1:-1:-1;;81097:58:0;;;;;;;;;;;;;;-1:-1:-1;;;;;81097:58:0;-1:-1:-1;;;;;;81097:58:0;;;;;;;;;;81070:19;:86::i;81172:248::-;81343:68;;-1:-1:-1;;;;;22067:15:1;;;81343:68:0;;;22049:34:1;22119:15;;22099:18;;;22092:43;22151:18;;;22144:34;;;81316:96:0;;81336:5;;-1:-1:-1;;;81366:27:0;21984:18:1;;81343:68:0;21809:375:1;81316:96:0;81172:248;;;;:::o;102002:357::-;102059:7;102079:24;102139:23;;102125:10;;102107:15;:28;;;;:::i;:::-;102106:56;;;;:::i;:::-;102079:83;;85998:8;102177:16;:42;102173:158;;;85998:8;102279:12;;102260:16;:31;;;;:::i;:::-;102259:59;;;;:::i;:::-;102243:12;;:76;;;;:::i;102173:158::-;102350:1;102343:8;;;102002:357;:::o;66806:453::-;66941:24;66968:25;66978:5;66985:7;66968:9;:25::i;:::-;66941:52;;-1:-1:-1;;67008:16:0;:37;67004:248;;67090:6;67070:16;:26;;67062:68;;;;-1:-1:-1;;;67062:68:0;;22391:2:1;67062:68:0;;;22373:21:1;22430:2;22410:18;;;22403:30;22469:31;22449:18;;;22442:59;22518:18;;67062:68:0;22189:353:1;67062:68:0;67174:51;67183:5;67190:7;67218:6;67199:16;:25;67174:8;:51::i;63014:840::-;-1:-1:-1;;;;;63145:18:0;;63137:68;;;;-1:-1:-1;;;63137:68:0;;22749:2:1;63137:68:0;;;22731:21:1;22788:2;22768:18;;;22761:30;22827:34;22807:18;;;22800:62;-1:-1:-1;;;22878:18:1;;;22871:35;22923:19;;63137:68:0;22547:401:1;63137:68:0;-1:-1:-1;;;;;63224:16:0;;63216:64;;;;-1:-1:-1;;;63216:64:0;;23155:2:1;63216:64:0;;;23137:21:1;23194:2;23174:18;;;23167:30;23233:34;23213:18;;;23206:62;-1:-1:-1;;;23284:18:1;;;23277:33;23327:19;;63216:64:0;22953:399:1;63216:64:0;-1:-1:-1;;;;;63366:15:0;;63344:19;63366:15;;;;;;;;;;;63400:21;;;;63392:72;;;;-1:-1:-1;;;63392:72:0;;23559:2:1;63392:72:0;;;23541:21:1;23598:2;23578:18;;;23571:30;23637:34;23617:18;;;23610:62;-1:-1:-1;;;23688:18:1;;;23681:36;23734:19;;63392:72:0;23357:402:1;63392:72:0;-1:-1:-1;;;;;63500:15:0;;;:9;:15;;;;;;;;;;;63518:20;;;63500:38;;63718:13;;;;;;;;;;:23;;;;;;63770:26;;345:25:1;;;63718:13:0;;63770:26;;318:18:1;63770:26:0;;;;;;;63809:37;30290:147;99666:2185;99795:13;51436:21;:19;:21::i;:::-;99834:7:::1;99845:1;99834:12:::0;99826:39:::1;;;::::0;-1:-1:-1;;;99826:39:0;;23966:2:1;99826:39:0::1;::::0;::::1;23948:21:1::0;24005:2;23985:18;;;23978:30;-1:-1:-1;;;24024:18:1;;;24017:44;24078:18;;99826:39:0::1;23764:338:1::0;99826:39:0::1;58739:12:::0;;99900:7:::1;99885:12;:10;:12::i;:::-;:22;;;;:::i;:::-;99884:40;;;;:::i;:::-;99960:9;::::0;99876:48;;-1:-1:-1;99984:20:0;;::::1;99980:1682;;;100079:15;:22:::0;100021:17:::1;::::0;;100116:1156:::1;100140:11;100136:1;:15;100116:1156;;;100207:12;100198:5;:21;100194:75:::0;100244:5:::1;100194:75;100289:17;100309:15;100325:1;100309:18;;;;;;;;:::i;:::-;;::::0;;;::::1;::::0;;;;;::::1;::::0;-1:-1:-1;;;;;100309:18:0::1;100368:21:::0;;;:10:::1;:21:::0;;;;;;:31:::1;;::::0;100309:18;;-1:-1:-1;100368:31:0;100422:16;;;100418:73:::1;;100463:8;;;;100418:73;100511:17;100531:20;100539:12:::0;100531:5;:20:::1;:::i;:::-;100595:30;::::0;-1:-1:-1;;;100595:30:0;;100619:4:::1;100595:30;::::0;::::1;4260:51:1::0;100511:40:0;;-1:-1:-1;100570:22:0::1;::::0;-1:-1:-1;;;;;100595:5:0::1;:15;::::0;::::1;::::0;4233:18:1;;100595:30:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;100570:55;;100644:12;100669:9;-1:-1:-1::0;;;;;100659:29:0::1;;100689:32;100698:9;100709:11;100689:8;:32::i;:::-;100659:63;;;;;;;;;;;;;345:25:1::0;;333:2;318:18;;199:177;100659:63:0::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;100767:30;::::0;-1:-1:-1;;;100767:30:0;;100791:4:::1;100767:30;::::0;::::1;4260:51:1::0;100644:78:0;;-1:-1:-1;100741:23:0::1;::::0;100800:14;;-1:-1:-1;;;;;100767:5:0::1;:15;::::0;::::1;::::0;4233:18:1;;100767:30:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:47;;;;:::i;:::-;100741:73:::0;-1:-1:-1;100833:31:0::1;100741:73:::0;100833:31;::::1;:::i;:::-;::::0;-1:-1:-1;100976:9:0;;100972:162:::1;;101010:13;101019:4:::0;101010:13;::::1;:::i;:::-;::::0;-1:-1:-1;101046:17:0::1;101059:4:::0;101046:17;::::1;:::i;:::-;;;101086:28;101098:9;101109:4;101086:11;:28::i;:::-;-1:-1:-1::0;;;;;101154:21:0;::::1;;::::0;;;:10:::1;:21;::::0;;;;:31:::1;;:50:::0;;101189:15;;101154:21;:50:::1;::::0;101189:15;;101154:50:::1;:::i;:::-;;;;;;;;101241:15;101223:14;;:33;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;;;;;;;;100116:1156:0::1;1403:1:::0;1398:6;100116:1156:::1;;;-1:-1:-1::0;101288:9:0::1;:24:::0;;;101331:20;;::::1;101327:162;;;101380:12;101372:20;;101461:12;:10;:12::i;:::-;58739::::0;;101423:17:::1;101431:9:::0;101423:5;:17:::1;:::i;:::-;101422:35;;;;:::i;:::-;101421:52;;;;:::i;:::-;101411:62;;101327:162;101567:15;::::0;86103:5:::1;::::0;101546:17:::1;101554:9:::0;101546:5;:17:::1;:::i;:::-;101545:37;;;;:::i;:::-;101544:57;;;;:::i;:::-;101531:9;:70;;101505:145;;;::::0;-1:-1:-1;;;101505:145:0;;24309:2:1;101505:145:0::1;::::0;::::1;24291:21:1::0;24348:2;24328:18;;;24321:30;24387:32;24367:18;;;24360:60;24437:18;;101505:145:0::1;24107:354:1::0;101505:145:0::1;100006:1656;;99980:1682;101674:22;101680:6;101688:7;101674:5;:22::i;:::-;101720:5;101707:9;;:18;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;101736:36:0::1;::::0;-1:-1:-1;;;;;;101736:5:0::1;:18;101755:9:::0;101766:5;101736:18:::1;:36::i;:::-;101788:55;::::0;;19559:25:1;;;19615:2;19600:18;;19593:34;;;-1:-1:-1;;;;;101788:55:0;;::::1;::::0;;;::::1;::::0;101797:10:::1;::::0;101788:55:::1;::::0;19532:18:1;101788:55:0::1;;;;;;;99815:2036;51480:20:::0;50874:1;52000:7;:22;51817:213;28773:105;28840:30;28851:4;8681:10;28840;:30::i;48735:169::-;48823:31;48840:4;48846:7;48823:16;:31::i;:::-;48865:18;;;;:12;:18;;;;;:31;;48888:7;48865:22;:31::i;48998:174::-;49087:32;49105:4;49111:7;49087:17;:32::i;:::-;49130:18;;;;:12;:18;;;;;:34;;49156:7;49130:25;:34::i;98117:735::-;98202:14;51436:21;:19;:21::i;:::-;98238:17:::1;::::0;::::1;;98237:18;98229:71;;;::::0;-1:-1:-1;;;98229:71:0;;24668:2:1;98229:71:0::1;::::0;::::1;24650:21:1::0;24707:2;24687:18;;;24680:30;24746:34;24726:18;;;24719:62;-1:-1:-1;;;24797:18:1;;;24790:38;24845:19;;98229:71:0::1;24466:404:1::0;98229:71:0::1;98319:7;98330:1;98319:12:::0;98311:39:::1;;;::::0;-1:-1:-1;;;98311:39:0;;23966:2:1;98311:39:0::1;::::0;::::1;23948:21:1::0;24005:2;23985:18;;;23978:30;-1:-1:-1;;;24024:18:1;;;24017:44;24078:18;;98311:39:0::1;23764:338:1::0;98311:39:0::1;98392:6;;98381:7;98369:9;:7;:9::i;:::-;:19;;;;:::i;:::-;:29;;98361:55;;;::::0;-1:-1:-1;;;98361:55:0;;25077:2:1;98361:55:0::1;::::0;::::1;25059:21:1::0;25116:2;25096:18;;;25089:30;-1:-1:-1;;;25135:18:1;;;25128:43;25188:18;;98361:55:0::1;24875:337:1::0;98361:55:0::1;98429:14;98446:13;58739:12:::0;;;58651:108;98446:13:::1;98429:30;;98474:6;98484:1;98474:11:::0;98470:175:::1;;98511:7;98502:16;;98470:175;;;98581:12;:10;:12::i;:::-;98561:16;98571:6:::0;98561:7;:16:::1;:::i;:::-;98560:33;;;;:::i;:::-;98551:42;;98470:175;98657:24;98663:9;98674:6;98657:5;:24::i;:::-;98705:7;98692:9;;:20;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;98723:58:0::1;::::0;-1:-1:-1;;;;;;98723:5:0::1;:22;98746:10;98766:4;98773:7:::0;98723:22:::1;:58::i;:::-;98797:47;::::0;;19559:25:1;;;19615:2;19600:18;;19593:34;;;-1:-1:-1;;;;;98797:47:0;::::1;::::0;98805:10:::1;::::0;98797:47:::1;::::0;19532:18:1;98797:47:0::1;;;;;;;98218:634;51480:20:::0;50874:1;52000:7;:22;51817:213;43476:158;43550:7;43601:22;43605:3;43617:5;43601:3;:22::i;43005:117::-;43068:7;43095:19;43103:3;38305:18;;38222:109;35911:414;35974:4;38104:19;;;:12;;;:19;;;;;;35991:327;;-1:-1:-1;36034:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;36217:18;;36195:19;;;:12;;;:19;;;;;;:40;;;;36250:11;;35991:327;-1:-1:-1;36301:5:0;36294:12;;111501:385;111635:16;;;111649:1;111635:16;;;;;;;;;111566;;111595:37;;111635:16;;;;;;;;;;;-1:-1:-1;111635:16:0;111595:56;;27472:4;111688:18;;111662:20;111683:1;111662:23;;;;;;;;:::i;:::-;;;;;;:44;;;;;-1:-1:-1;;;;;;;;;;;111717:20:0;111738:1;111717:23;;;;;;;;:::i;:::-;;;;;;:31;;;;;-1:-1:-1;;;;;;;;;;;111759:20:0;111780:1;111759:23;;;;;;;;:::i;:::-;;;;;;:34;;;;;-1:-1:-1;;;;;;;;;;;111804:20:0;111825:1;111804:23;;;;;;;;:::i;:::-;;;;;;;;;;:36;111858:20;111501:385;-1:-1:-1;111501:385:0:o;112073:139::-;112156:4;112180:24;112188:5;112195:8;112180:7;:24::i;64141:548::-;-1:-1:-1;;;;;64225:21:0;;64217:65;;;;-1:-1:-1;;;64217:65:0;;25551:2:1;64217:65:0;;;25533:21:1;25590:2;25570:18;;;25563:30;25629:33;25609:18;;;25602:61;25680:18;;64217:65:0;25349:355:1;64217:65:0;64373:6;64357:12;;:22;;;;;;;:::i;:::-;;;;-1:-1:-1;;;;;;;64528:18:0;;:9;:18;;;;;;;;;;;:28;;;;;;64583:37;345:25:1;;;64583:37:0;;318:18:1;64583:37:0;;;;;;;99414:42;99359:105;:::o;84020:716::-;84444:23;84470:69;84498:4;84470:69;;;;;;;;;;;;;;;;;84478:5;-1:-1:-1;;;;;84470:27:0;;;:69;;;;;:::i;:::-;84554:17;;84444:95;;-1:-1:-1;84554:21:0;84550:179;;84651:10;84640:30;;;;;;;;;;;;:::i;:::-;84632:85;;;;-1:-1:-1;;;84632:85:0;;26161:2:1;84632:85:0;;;26143:21:1;26200:2;26180:18;;;26173:30;26239:34;26219:18;;;26212:62;-1:-1:-1;;;26290:18:1;;;26283:40;26340:19;;84632:85:0;25959:406:1;51516:293:0;50918:1;51650:7;;:19;51642:63;;;;-1:-1:-1;;;51642:63:0;;26572:2:1;51642:63:0;;;26554:21:1;26611:2;26591:18;;;26584:30;26650:33;26630:18;;;26623:61;26701:18;;51642:63:0;26370:355:1;51642:63:0;50918:1;51783:7;:18;51516:293::o;65022:675::-;-1:-1:-1;;;;;65106:21:0;;65098:67;;;;-1:-1:-1;;;65098:67:0;;26932:2:1;65098:67:0;;;26914:21:1;26971:2;26951:18;;;26944:30;27010:34;26990:18;;;26983:62;-1:-1:-1;;;27061:18:1;;;27054:31;27102:19;;65098:67:0;26730:397:1;65098:67:0;-1:-1:-1;;;;;65265:18:0;;65240:22;65265:18;;;;;;;;;;;65302:24;;;;65294:71;;;;-1:-1:-1;;;65294:71:0;;27334:2:1;65294:71:0;;;27316:21:1;27373:2;27353:18;;;27346:30;27412:34;27392:18;;;27385:62;-1:-1:-1;;;27463:18:1;;;27456:32;27505:19;;65294:71:0;27132:398:1;65294:71:0;-1:-1:-1;;;;;65401:18:0;;:9;:18;;;;;;;;;;;65422:23;;;65401:44;;65540:12;:22;;;;;;;65591:37;345:25:1;;;65401:9:0;;:18;65591:37;;318:18:1;65591:37:0;;;;;;;30290:147;;;:::o;29168:492::-;29257:22;29265:4;29271:7;29257;:22::i;:::-;29252:401;;29445:28;29465:7;29445:19;:28::i;:::-;29546:38;29574:4;29581:2;29546:19;:38::i;:::-;29350:257;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;29350:257:0;;;;;;;;;;-1:-1:-1;;;29296:345:0;;;;;;;:::i;33449:239::-;33533:22;33541:4;33547:7;33533;:22::i;:::-;33529:152;;;33604:5;33572:12;;;:6;:12;;;;;;;;-1:-1:-1;;;;;33572:29:0;;;;;;;;;;:37;;-1:-1:-1;;33572:37:0;;;33629:40;8681:10;;33572:12;;33629:40;;33604:5;33629:40;33449:239;;:::o;42508:158::-;42581:4;42605:53;42613:3;-1:-1:-1;;;;;42633:23:0;;42605:7;:53::i;38685:120::-;38752:7;38779:3;:11;;38791:5;38779:18;;;;;;;;:::i;:::-;;;;;;;;;38772:25;;38685:120;;;;:::o;74987:229::-;75124:12;75156:52;75178:6;75186:4;75192:1;75195:12;75156:21;:52::i;:::-;75149:59;74987:229;-1:-1:-1;;;;74987:229:0:o;23700:151::-;23758:13;23791:52;-1:-1:-1;;;;;23803:22:0;;21855:2;23096:447;23171:13;23197:19;23229:10;23233:6;23229:1;:10;:::i;:::-;:14;;23242:1;23229:14;:::i;:::-;23219:25;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;23219:25:0;;23197:47;;-1:-1:-1;;;23255:6:0;23262:1;23255:9;;;;;;;;:::i;:::-;;;;:15;-1:-1:-1;;;;;23255:15:0;;;;;;;;;-1:-1:-1;;;23281:6:0;23288:1;23281:9;;;;;;;;:::i;:::-;;;;:15;-1:-1:-1;;;;;23281:15:0;;;;;;;;-1:-1:-1;23312:9:0;23324:10;23328:6;23324:1;:10;:::i;:::-;:14;;23337:1;23324:14;:::i;:::-;23312:26;;23307:131;23344:1;23340;:5;23307:131;;;-1:-1:-1;;;23388:5:0;23396:3;23388:11;23379:21;;;;;;;:::i;:::-;;;;23367:6;23374:1;23367:9;;;;;;;;:::i;:::-;;;;:33;-1:-1:-1;;;;;23367:33:0;;;;;;;;-1:-1:-1;23425:1:0;23415:11;;;;;23347:3;;;:::i;:::-;;;23307:131;;;-1:-1:-1;23456:10:0;;23448:55;;;;-1:-1:-1;;;23448:55:0;;28695:2:1;23448:55:0;;;28677:21:1;;;28714:18;;;28707:30;28773:34;28753:18;;;28746:62;28825:18;;23448:55:0;28493:356:1;36501:1420:0;36567:4;36706:19;;;:12;;;:19;;;;;;36742:15;;36738:1176;;37117:21;37141:14;37154:1;37141:10;:14;:::i;:::-;37190:18;;37117:38;;-1:-1:-1;37170:17:0;;37190:22;;37211:1;;37190:22;:::i;:::-;37170:42;;37246:13;37233:9;:26;37229:405;;37280:17;37300:3;:11;;37312:9;37300:22;;;;;;;;:::i;:::-;;;;;;;;;37280:42;;37454:9;37425:3;:11;;37437:13;37425:26;;;;;;;;:::i;:::-;;;;;;;;;;;;:38;;;;37539:23;;;:12;;;:23;;;;;:36;;;37229:405;37715:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;37810:3;:12;;:19;37823:5;37810:19;;;;;;;;;;;37803:26;;;37853:4;37846:11;;;;;;;36738:1176;37897:5;37890:12;;;;;76107:455;76277:12;76335:5;76310:21;:30;;76302:81;;;;-1:-1:-1;;;76302:81:0;;29188:2:1;76302:81:0;;;29170:21:1;29227:2;29207:18;;;29200:30;29266:34;29246:18;;;29239:62;-1:-1:-1;;;29317:18:1;;;29310:36;29363:19;;76302:81:0;28986:402:1;76302:81:0;76395:12;76409:23;76436:6;-1:-1:-1;;;;;76436:11:0;76455:5;76462:4;76436:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;76394:73;;;;76485:69;76512:6;76520:7;76529:10;76541:12;78865;78894:7;78890:427;;;78922:10;:17;78943:1;78922:22;78918:290;;-1:-1:-1;;;;;72525:19:0;;;79132:60;;;;-1:-1:-1;;;79132:60:0;;29887:2:1;79132:60:0;;;29869:21:1;29926:2;29906:18;;;29899:30;29965:31;29945:18;;;29938:59;30014:18;;79132:60:0;29685:353:1;79132:60:0;-1:-1:-1;79229:10:0;79222:17;;78890:427;79272:33;79280:10;79292:12;80027:17;;:21;80023:388;;80259:10;80253:17;80316:15;80303:10;80299:2;80295:19;80288:44;80023:388;80386:12;80379:20;;-1:-1:-1;;;80379:20:0;;;;;;;;:::i;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;14:180:1:-;73:6;126:2;114:9;105:7;101:23;97:32;94:52;;;142:1;139;132:12;94:52;-1:-1:-1;165:23:1;;14:180;-1:-1:-1;14:180:1:o;381:286::-;439:6;492:2;480:9;471:7;467:23;463:32;460:52;;;508:1;505;498:12;460:52;534:23;;-1:-1:-1;;;;;;586:32:1;;576:43;;566:71;;633:1;630;623:12;864:250;949:1;959:113;973:6;970:1;967:13;959:113;;;1049:11;;;1043:18;1030:11;;;1023:39;995:2;988:10;959:113;;;-1:-1:-1;;1106:1:1;1088:16;;1081:27;864:250::o;1119:396::-;1268:2;1257:9;1250:21;1231:4;1300:6;1294:13;1343:6;1338:2;1327:9;1323:18;1316:34;1359:79;1431:6;1426:2;1415:9;1411:18;1406:2;1398:6;1394:15;1359:79;:::i;:::-;1499:2;1478:15;-1:-1:-1;;1474:29:1;1459:45;;;;1506:2;1455:54;;1119:396;-1:-1:-1;;1119:396:1:o;1520:131::-;-1:-1:-1;;;;;1595:31:1;;1585:42;;1575:70;;1641:1;1638;1631:12;1656:315;1724:6;1732;1785:2;1773:9;1764:7;1760:23;1756:32;1753:52;;;1801:1;1798;1791:12;1753:52;1840:9;1827:23;1859:31;1884:5;1859:31;:::i;:::-;1909:5;1961:2;1946:18;;;;1933:32;;-1:-1:-1;;;1656:315:1:o;1976:247::-;2043:6;2051;2104:2;2092:9;2083:7;2079:23;2075:32;2072:52;;;2120:1;2117;2110:12;2072:52;-1:-1:-1;;2143:23:1;;;2213:2;2198:18;;;2185:32;;-1:-1:-1;1976:247:1:o;2228:118::-;2314:5;2307:13;2300:21;2293:5;2290:32;2280:60;;2336:1;2333;2326:12;2351:241;2407:6;2460:2;2448:9;2439:7;2435:23;2431:32;2428:52;;;2476:1;2473;2466:12;2428:52;2515:9;2502:23;2534:28;2556:5;2534:28;:::i;2777:456::-;2854:6;2862;2870;2923:2;2911:9;2902:7;2898:23;2894:32;2891:52;;;2939:1;2936;2929:12;2891:52;2978:9;2965:23;2997:31;3022:5;2997:31;:::i;:::-;3047:5;-1:-1:-1;3104:2:1;3089:18;;3076:32;3117:33;3076:32;3117:33;:::i;:::-;2777:456;;3169:7;;-1:-1:-1;;;3223:2:1;3208:18;;;;3195:32;;2777:456::o;3605:315::-;3673:6;3681;3734:2;3722:9;3713:7;3709:23;3705:32;3702:52;;;3750:1;3747;3740:12;3702:52;3786:9;3773:23;3763:33;;3846:2;3835:9;3831:18;3818:32;3859:31;3884:5;3859:31;:::i;:::-;3909:5;3899:15;;;3605:315;;;;;:::o;4322:247::-;4381:6;4434:2;4422:9;4413:7;4409:23;4405:32;4402:52;;;4450:1;4447;4440:12;4402:52;4489:9;4476:23;4508:31;4533:5;4508:31;:::i;5759:615::-;5845:6;5853;5906:2;5894:9;5885:7;5881:23;5877:32;5874:52;;;5922:1;5919;5912:12;5874:52;5962:9;5949:23;5991:18;6032:2;6024:6;6021:14;6018:34;;;6048:1;6045;6038:12;6018:34;6086:6;6075:9;6071:22;6061:32;;6131:7;6124:4;6120:2;6116:13;6112:27;6102:55;;6153:1;6150;6143:12;6102:55;6193:2;6180:16;6219:2;6211:6;6208:14;6205:34;;;6235:1;6232;6225:12;6205:34;6288:7;6283:2;6273:6;6270:1;6266:14;6262:2;6258:23;6254:32;6251:45;6248:65;;;6309:1;6306;6299:12;6248:65;6340:2;6332:11;;;;;6362:6;;-1:-1:-1;5759:615:1;;-1:-1:-1;;;;5759:615:1:o;6379:456::-;6456:6;6464;6472;6525:2;6513:9;6504:7;6500:23;6496:32;6493:52;;;6541:1;6538;6531:12;6493:52;6577:9;6564:23;6554:33;;6637:2;6626:9;6622:18;6609:32;6650:31;6675:5;6650:31;:::i;:::-;6700:5;-1:-1:-1;6757:2:1;6742:18;;6729:32;6770:33;6729:32;6770:33;:::i;:::-;6822:7;6812:17;;;6379:456;;;;;:::o;6840:388::-;6908:6;6916;6969:2;6957:9;6948:7;6944:23;6940:32;6937:52;;;6985:1;6982;6975:12;6937:52;7024:9;7011:23;7043:31;7068:5;7043:31;:::i;:::-;7093:5;-1:-1:-1;7150:2:1;7135:18;;7122:32;7163:33;7122:32;7163:33;:::i;7233:383::-;7310:6;7318;7326;7379:2;7367:9;7358:7;7354:23;7350:32;7347:52;;;7395:1;7392;7385:12;7347:52;7434:9;7421:23;7453:31;7478:5;7453:31;:::i;:::-;7503:5;7555:2;7540:18;;7527:32;;-1:-1:-1;7606:2:1;7591:18;;;7578:32;;7233:383;-1:-1:-1;;;7233:383:1:o;7852:380::-;7931:1;7927:12;;;;7974;;;7995:61;;8049:4;8041:6;8037:17;8027:27;;7995:61;8102:2;8094:6;8091:14;8071:18;8068:38;8065:161;;8148:10;8143:3;8139:20;8136:1;8129:31;8183:4;8180:1;8173:15;8211:4;8208:1;8201:15;8065:161;;7852:380;;;:::o;8237:127::-;8298:10;8293:3;8289:20;8286:1;8279:31;8329:4;8326:1;8319:15;8353:4;8350:1;8343:15;8369:168;8442:9;;;8473;;8490:15;;;8484:22;;8470:37;8460:71;;8511:18;;:::i;8542:127::-;8603:10;8598:3;8594:20;8591:1;8584:31;8634:4;8631:1;8624:15;8658:4;8655:1;8648:15;8674:120;8714:1;8740;8730:35;;8745:18;;:::i;:::-;-1:-1:-1;8779:9:1;;8674:120::o;9149:136::-;9184:3;-1:-1:-1;;;9205:22:1;;9202:48;;9230:18;;:::i;:::-;-1:-1:-1;9270:1:1;9266:13;;9149:136::o;9290:125::-;9355:9;;;9376:10;;;9373:36;;;9389:18;;:::i;9420:128::-;9487:9;;;9508:11;;;9505:37;;;9522:18;;:::i;10237:184::-;10307:6;10360:2;10348:9;10339:7;10335:23;10331:32;10328:52;;;10376:1;10373;10366:12;10328:52;-1:-1:-1;10399:16:1;;10237:184;-1:-1:-1;10237:184:1:o;10426:273::-;10494:6;10547:2;10535:9;10526:7;10522:23;10518:32;10515:52;;;10563:1;10560;10553:12;10515:52;10595:9;10589:16;10645:4;10638:5;10634:16;10627:5;10624:27;10614:55;;10665:1;10662;10655:12;11466:348;11668:2;11650:21;;;11707:2;11687:18;;;11680:30;11746:26;11741:2;11726:18;;11719:54;11805:2;11790:18;;11466:348::o;11819:422::-;11908:1;11951:5;11908:1;11965:270;11986:7;11976:8;11973:21;11965:270;;;12045:4;12041:1;12037:6;12033:17;12027:4;12024:27;12021:53;;;12054:18;;:::i;:::-;12104:7;12094:8;12090:22;12087:55;;;12124:16;;;;12087:55;12203:22;;;;12163:15;;;;11965:270;;;11969:3;11819:422;;;;;:::o;12246:806::-;12295:5;12325:8;12315:80;;-1:-1:-1;12366:1:1;12380:5;;12315:80;12414:4;12404:76;;-1:-1:-1;12451:1:1;12465:5;;12404:76;12496:4;12514:1;12509:59;;;;12582:1;12577:130;;;;12489:218;;12509:59;12539:1;12530:10;;12553:5;;;12577:130;12614:3;12604:8;12601:17;12598:43;;;12621:18;;:::i;:::-;-1:-1:-1;;12677:1:1;12663:16;;12692:5;;12489:218;;12791:2;12781:8;12778:16;12772:3;12766:4;12763:13;12759:36;12753:2;12743:8;12740:16;12735:2;12729:4;12726:12;12722:35;12719:77;12716:159;;;-1:-1:-1;12828:19:1;;;12860:5;;12716:159;12907:34;12932:8;12926:4;12907:34;:::i;:::-;12977:6;12973:1;12969:6;12965:19;12956:7;12953:32;12950:58;;;12988:18;;:::i;:::-;13026:20;;12246:806;-1:-1:-1;;;12246:806:1:o;13057:140::-;13115:5;13144:47;13185:4;13175:8;13171:19;13165:4;13144:47;:::i;15070:127::-;15131:10;15126:3;15122:20;15119:1;15112:31;15162:4;15159:1;15152:15;15186:4;15183:1;15176:15;15202:705;15383:2;15435:21;;;15408:18;;;15491:22;;;15354:4;;15570:6;15544:2;15529:18;;15354:4;15604:277;15618:6;15615:1;15612:13;15604:277;;;15693:6;15680:20;15713:31;15738:5;15713:31;:::i;:::-;-1:-1:-1;;;;;15769:31:1;15757:44;;15856:15;;;;15821:12;;;;15797:1;15633:9;15604:277;;;-1:-1:-1;15898:3:1;15202:705;-1:-1:-1;;;;;;15202:705:1:o;18059:251::-;18129:6;18182:2;18170:9;18161:7;18157:23;18153:32;18150:52;;;18198:1;18195;18188:12;18150:52;18230:9;18224:16;18249:31;18274:5;18249:31;:::i;21136:112::-;21168:1;21194;21184:35;;21199:18;;:::i;:::-;-1:-1:-1;21233:9:1;;21136:112::o;21253:135::-;21292:3;21313:17;;;21310:43;;21333:18;;:::i;:::-;-1:-1:-1;21380:1:1;21369:13;;21253:135::o;25217:127::-;25278:10;25273:3;25269:20;25266:1;25259:31;25309:4;25306:1;25299:15;25333:4;25330:1;25323:15;25709:245;25776:6;25829:2;25817:9;25808:7;25804:23;25800:32;25797:52;;;25845:1;25842;25835:12;25797:52;25877:9;25871:16;25896:28;25918:5;25896:28;:::i;27535:812::-;27946:25;27941:3;27934:38;27916:3;28001:6;27995:13;28017:75;28085:6;28080:2;28075:3;28071:12;28064:4;28056:6;28052:17;28017:75;:::i;:::-;-1:-1:-1;;;28151:2:1;28111:16;;;28143:11;;;28136:40;28201:13;;28223:76;28201:13;28285:2;28277:11;;28270:4;28258:17;;28223:76;:::i;:::-;28319:17;28338:2;28315:26;;27535:812;-1:-1:-1;;;;27535:812:1:o;28352:136::-;28391:3;28419:5;28409:39;;28428:18;;:::i;:::-;-1:-1:-1;;;28464:18:1;;28352:136::o;28854:127::-;28915:10;28910:3;28906:20;28903:1;28896:31;28946:4;28943:1;28936:15;28970:4;28967:1;28960:15;29393:287;29522:3;29560:6;29554:13;29576:66;29635:6;29630:3;29623:4;29615:6;29611:17;29576:66;:::i;:::-;29658:16;;;;;29393:287;-1:-1:-1;;29393:287:1:o

Swarm Source

ipfs://45bccccc4dd2ce219255c32cca105d63cc485c45dd094981e615928fee1f3c8c
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.