ETH Price: $3,978.65 (-1.05%)

Contract

0xDcF7Dbe6865e52409A0fa2b4B23433DB2Af3646f
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
NodeManager

Compiler Version
v0.8.18+commit.87f61d96

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, Unlicense license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2024-05-13
*/

// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.18;

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

// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)

/**
 * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
 * proxy whose upgrades are fully controlled by the current implementation.
 */
interface IERC1822ProxiableUpgradeable {
    /**
     * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
     * address.
     *
     * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
     * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
     * function revert if invoked through a proxy.
     */
    function proxiableUUID() external view returns (bytes32);
}

// OpenZeppelin Contracts (last updated v4.8.3) (proxy/ERC1967/ERC1967Upgrade.sol)

// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)

/**
 * @dev This is the interface that {BeaconProxy} expects of its beacon.
 */
interface IBeaconUpgradeable {
    /**
     * @dev Must return an address that can be used as a delegate call target.
     *
     * {BeaconProxy} will check that this address is a contract.
     */
    function implementation() external view returns (address);
}

// OpenZeppelin Contracts (last updated v4.8.3) (interfaces/IERC1967.sol)

/**
 * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
 *
 * _Available since v4.9._
 */
interface IERC1967Upgradeable {
    /**
     * @dev Emitted when the implementation is upgraded.
     */
    event Upgraded(address indexed implementation);

    /**
     * @dev Emitted when the admin account has changed.
     */
    event AdminChanged(address previousAdmin, address newAdmin);

    /**
     * @dev Emitted when the beacon is changed.
     */
    event BeaconUpgraded(address indexed beacon);
}

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

/**
 * @dev Collection of functions related to the address type
 */
library AddressUpgradeable {
    /**
     * @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 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);
        }
    }
}

// OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol)

/**
 * @dev Library for reading and writing primitive types to specific storage slots.
 *
 * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
 * This library helps with reading and writing to such slots without the need for inline assembly.
 *
 * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
 *
 * Example usage to set ERC1967 implementation slot:
 * ```
 * contract ERC1967 {
 *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
 *
 *     function _getImplementation() internal view returns (address) {
 *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
 *     }
 *
 *     function _setImplementation(address newImplementation) internal {
 *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
 *     }
 * }
 * ```
 *
 * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
 */
library StorageSlotUpgradeable {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 value;
    }

    /**
     * @dev Returns an `AddressSlot` with member `value` located at `slot`.
     */
    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
     */
    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
     */
    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
     */
    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }
}

// OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol)

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     * @custom:oz-retyped-from bool
     */
    uint8 private _initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint8 version);

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts.
     *
     * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
     * constructor.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        bool isTopLevelCall = !_initializing;
        require(
            (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
            "Initializable: contract is already initialized"
        );
        _initialized = 1;
        if (isTopLevelCall) {
            _initializing = true;
        }
        _;
        if (isTopLevelCall) {
            _initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * A reinitializer may be used after the original initialization step. This is essential to configure modules that
     * are added through upgrades and that require initialization.
     *
     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
     * cannot be nested. If one is invoked in the context of another, execution will revert.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     *
     * WARNING: setting the version to 255 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint8 version) {
        require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
        _initialized = version;
        _initializing = true;
        _;
        _initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        require(_initializing, "Initializable: contract is not initializing");
        _;
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     *
     * Emits an {Initialized} event the first time it is successfully executed.
     */
    function _disableInitializers() internal virtual {
        require(!_initializing, "Initializable: contract is initializing");
        if (_initialized < type(uint8).max) {
            _initialized = type(uint8).max;
            emit Initialized(type(uint8).max);
        }
    }

    /**
     * @dev Returns the highest version that has been initialized. See {reinitializer}.
     */
    function _getInitializedVersion() internal view returns (uint8) {
        return _initialized;
    }

    /**
     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
     */
    function _isInitializing() internal view returns (bool) {
        return _initializing;
    }
}

/**
 * @dev This abstract contract provides getters and event emitting update functions for
 * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
 *
 * _Available since v4.1._
 *
 * @custom:oz-upgrades-unsafe-allow delegatecall
 */
abstract contract ERC1967UpgradeUpgradeable is Initializable, IERC1967Upgradeable {
    function __ERC1967Upgrade_init() internal onlyInitializing {
    }

    function __ERC1967Upgrade_init_unchained() internal onlyInitializing {
    }
    // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
    bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;

    /**
     * @dev Storage slot with the address of the current implementation.
     * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
     * validated in the constructor.
     */
    bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;

    /**
     * @dev Returns the current implementation address.
     */
    function _getImplementation() internal view returns (address) {
        return StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value;
    }

    /**
     * @dev Stores a new address in the EIP1967 implementation slot.
     */
    function _setImplementation(address newImplementation) private {
        require(AddressUpgradeable.isContract(newImplementation), "ERC1967: new implementation is not a contract");
        StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
    }

    /**
     * @dev Perform implementation upgrade
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeTo(address newImplementation) internal {
        _setImplementation(newImplementation);
        emit Upgraded(newImplementation);
    }

    /**
     * @dev Perform implementation upgrade with additional setup call.
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeToAndCall(
        address newImplementation,
        bytes memory data,
        bool forceCall
    ) internal {
        _upgradeTo(newImplementation);
        if (data.length > 0 || forceCall) {
            _functionDelegateCall(newImplementation, data);
        }
    }

    /**
     * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeToAndCallUUPS(
        address newImplementation,
        bytes memory data,
        bool forceCall
    ) internal {
        // Upgrades from old implementations will perform a rollback test. This test requires the new
        // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
        // this special case will break upgrade paths from old UUPS implementation to new ones.
        if (StorageSlotUpgradeable.getBooleanSlot(_ROLLBACK_SLOT).value) {
            _setImplementation(newImplementation);
        } else {
            try IERC1822ProxiableUpgradeable(newImplementation).proxiableUUID() returns (bytes32 slot) {
                require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
            } catch {
                revert("ERC1967Upgrade: new implementation is not UUPS");
            }
            _upgradeToAndCall(newImplementation, data, forceCall);
        }
    }

    /**
     * @dev Storage slot with the admin of the contract.
     * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
     * validated in the constructor.
     */
    bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;

    /**
     * @dev Returns the current admin.
     */
    function _getAdmin() internal view returns (address) {
        return StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value;
    }

    /**
     * @dev Stores a new address in the EIP1967 admin slot.
     */
    function _setAdmin(address newAdmin) private {
        require(newAdmin != address(0), "ERC1967: new admin is the zero address");
        StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
    }

    /**
     * @dev Changes the admin of the proxy.
     *
     * Emits an {AdminChanged} event.
     */
    function _changeAdmin(address newAdmin) internal {
        emit AdminChanged(_getAdmin(), newAdmin);
        _setAdmin(newAdmin);
    }

    /**
     * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
     * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
     */
    bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;

    /**
     * @dev Returns the current beacon.
     */
    function _getBeacon() internal view returns (address) {
        return StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value;
    }

    /**
     * @dev Stores a new beacon in the EIP1967 beacon slot.
     */
    function _setBeacon(address newBeacon) private {
        require(AddressUpgradeable.isContract(newBeacon), "ERC1967: new beacon is not a contract");
        require(
            AddressUpgradeable.isContract(IBeaconUpgradeable(newBeacon).implementation()),
            "ERC1967: beacon implementation is not a contract"
        );
        StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value = newBeacon;
    }

    /**
     * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
     * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
     *
     * Emits a {BeaconUpgraded} event.
     */
    function _upgradeBeaconToAndCall(
        address newBeacon,
        bytes memory data,
        bool forceCall
    ) internal {
        _setBeacon(newBeacon);
        emit BeaconUpgraded(newBeacon);
        if (data.length > 0 || forceCall) {
            _functionDelegateCall(IBeaconUpgradeable(newBeacon).implementation(), data);
        }
    }

    /**
     * @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) private returns (bytes memory) {
        require(AddressUpgradeable.isContract(target), "Address: delegate call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return AddressUpgradeable.verifyCallResult(success, returndata, "Address: low-level delegate call failed");
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}

/**
 * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
 * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
 *
 * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
 * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
 * `UUPSUpgradeable` with a custom implementation of upgrades.
 *
 * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
 *
 * _Available since v4.1._
 */
abstract contract UUPSUpgradeable is Initializable, IERC1822ProxiableUpgradeable, ERC1967UpgradeUpgradeable {
    function __UUPSUpgradeable_init() internal onlyInitializing {
    }

    function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
    }
    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
    address private immutable __self = address(this);

    /**
     * @dev Check that the execution is being performed through a delegatecall call and that the execution context is
     * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
     * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
     * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
     * fail.
     */
    modifier onlyProxy() {
        require(address(this) != __self, "Function must be called through delegatecall");
        require(_getImplementation() == __self, "Function must be called through active proxy");
        _;
    }

    /**
     * @dev Check that the execution is not being performed through a delegate call. This allows a function to be
     * callable on the implementing contract but not through proxies.
     */
    modifier notDelegated() {
        require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall");
        _;
    }

    /**
     * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
     * implementation. It is used to validate the implementation's compatibility when performing an upgrade.
     *
     * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
     * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
     * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
     */
    function proxiableUUID() external view virtual override notDelegated returns (bytes32) {
        return _IMPLEMENTATION_SLOT;
    }

    /**
     * @dev Upgrade the implementation of the proxy to `newImplementation`.
     *
     * Calls {_authorizeUpgrade}.
     *
     * Emits an {Upgraded} event.
     */
    function upgradeTo(address newImplementation) external virtual onlyProxy {
        _authorizeUpgrade(newImplementation);
        _upgradeToAndCallUUPS(newImplementation, new bytes(0), false);
    }

    /**
     * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
     * encoded in `data`.
     *
     * Calls {_authorizeUpgrade}.
     *
     * Emits an {Upgraded} event.
     */
    function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual onlyProxy {
        _authorizeUpgrade(newImplementation);
        _upgradeToAndCallUUPS(newImplementation, data, true);
    }

    /**
     * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
     * {upgradeTo} and {upgradeToAndCall}.
     *
     * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
     *
     * ```solidity
     * function _authorizeUpgrade(address) internal override onlyOwner {}
     * ```
     */
    function _authorizeUpgrade(address newImplementation) internal virtual;

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}

// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.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 ContextUpgradeable is Initializable {
    function __Context_init() internal onlyInitializing {
    }

    function __Context_init_unchained() internal onlyInitializing {
    }
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

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

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    function __Pausable_init() internal onlyInitializing {
        __Pausable_init_unchained();
    }

    function __Pausable_init_unchained() internal onlyInitializing {
        _paused = false;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        _requireNotPaused();
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        _requirePaused();
        _;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Throws if the contract is paused.
     */
    function _requireNotPaused() internal view virtual {
        require(!paused(), "Pausable: paused");
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        require(paused(), "Pausable: not paused");
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}

// 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 ReentrancyGuardUpgradeable is Initializable {
    // 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;

    function __ReentrancyGuard_init() internal onlyInitializing {
        __ReentrancyGuard_init_unchained();
    }

    function __ReentrancyGuard_init_unchained() internal onlyInitializing {
        _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;
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}

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

// 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 MathUpgradeable {
    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 StringsUpgradeable {
    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 = MathUpgradeable.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, MathUpgradeable.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);
    }
}

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSAUpgradeable {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS,
        InvalidSignatureV // Deprecated in v4.8
    }

    function _throwError(RecoverError error) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert("ECDSA: invalid signature");
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert("ECDSA: invalid signature length");
        } else if (error == RecoverError.InvalidSignatureS) {
            revert("ECDSA: invalid signature 's' value");
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature` or error string. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     *
     * _Available since v4.3._
     */
    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            /// @solidity memory-safe-assembly
            assembly {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength);
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, signature);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
     *
     * _Available since v4.3._
     */
    function tryRecover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address, RecoverError) {
        bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
        uint8 v = uint8((uint256(vs) >> 255) + 27);
        return tryRecover(hash, v, r, s);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     *
     * _Available since v4.2._
     */
    function recover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, r, vs);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     *
     * _Available since v4.3._
     */
    function tryRecover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address, RecoverError) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature);
        }

        return (signer, RecoverError.NoError);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from a `hash`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
        // 32 is the length in bytes of hash,
        // enforced by the type signature above
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from `s`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", StringsUpgradeable.toString(s.length), s));
    }

    /**
     * @dev Returns an Ethereum Signed Typed Data, created from a
     * `domainSeparator` and a `structHash`. This produces hash corresponding
     * to the one signed with the
     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
     * JSON-RPC method as part of EIP-712.
     *
     * See {recover}.
     */
    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
    }
}

interface IRoleManager {
    /// @dev Returns a boolean value indicating whether `_account` has role `_roleName` or not.
    function checkRole(bytes32 _roleName, address _account) external view returns (bool);
}

interface INodeManager {
    /// @notice Event for Oracle reporting.
    /// @param reportBlockNumber : block number of report.
    /// @param amountRewards : Amounts of rewards.
    /// @param amountExited : Amounts exited on report.
    /// @param amountLiquid : Amounts liquid on report.
    event LogLiquidityTransfer(
        uint256 indexed reportBlockNumber,
        uint256 amountRewards,
        uint256 amountExited,
        uint256 amountLiquid
    );

    /// @notice Event for Oracle reporting.
    /// @param reportBlockNumber : block number of report.
    /// @param validatorsCount : Number of validators.
    /// @param validatorsBalance : Total balance of validators.
    /// @param validatorsExited : Number of validators exited.
    event LogOracleReport(
        uint256 reportBlockNumber,
        uint256 validatorsCount,
        uint256 validatorsBalance,
        uint256 validatorsExited
    );

    /// @notice Event for record of oracle participation
    /// @param reportBlockNumber : block number of report.
    /// @param oracle : Oracle address.
    event LogOracleVote(uint256 indexed reportBlockNumber, address indexed oracle);

    /// @notice Event for updating oracle whitelist.
    /// @param oracle : Oracle address.
    /// @param flag : boolean for addition or removal.
    event LogSetOracleWhitelist(address indexed oracle, bool indexed flag);

    /// @notice Event for updating autobalance registration whitelist.
    /// @param caller : autobalance caller address.
    /// @param flag : boolean for addition or removal.
    event LogSetAutoBalanceWhitelist(address indexed caller, bool indexed flag);

    /// @notice Event for validator deposit.
    /// @param validatorId : ID of the validator in Node Manager.
    /// @param publicKey : Public key of validator.
    /// @param validatorType : Type of validator.
    event LogDeposit(uint256 indexed validatorId, bytes indexed publicKey, uint256 validatorType);

    /// @notice Event for validator deposit.
    /// @param publicKey : Public key of validator.
    /// @param owner : Node operator address.
    event LogPreDeposit(bytes indexed publicKey, address indexed owner);

    /// @notice Event for validator deposit.
    /// @param validatorId : ID of the validator in Node Manager.
    /// @param publicKey : Public key of validator.
    /// @param owner : Node operator address.
    event LogPreDepositRefund(uint256 indexed validatorId, bytes indexed publicKey, address indexed owner);

    /// @notice Event for validator exit request.
    /// @param batchId : ID of the batch in Node Manager.
    /// @param withdrawCount : Number of validators exited.
    event LogWithdraw(uint256 indexed batchId, uint256 withdrawCount);

    /// @notice Event for new quorum.
    /// @param oldQuorum : Old oracle quorum.
    /// @param newQuorum : New oracle quorum.
    event LogSetOracleQuorum(uint256 oldQuorum, uint256 newQuorum);

    /// @notice Event for new node operator fee.
    /// @param oldFee : Old fee.
    /// @param newFee : New fee.
    event LogSetNodeOperatorFees(uint256 oldFee, uint256 newFee);

    /// @notice Event for setting claymain.
    /// @param newClaymain : Address of clayMain.
    event LogSetClayMain(address indexed newClaymain);

    /// @notice Event for setting nodeOperator.
    /// @param newNodeOperator : Address of nodeOperator.
    event LogSetNodeOperator(address indexed newNodeOperator);

    /// @notice Event for setting EigenLayer.
    /// @param eigenPodManager : Address of EigenPodManager.
    /// @param delayedWithdrawalRouter : Address of DelayedWithdrawalRouter.
    event LogSetEigenLayer(address indexed eigenPodManager, address indexed delayedWithdrawalRouter);

    /// @notice Event for unstaking from eigen layer.
    /// @param delayedWithdrawalIndex : Index of withdraw order.
    event LogWithdrawBeforeRestaking(uint256 indexed delayedWithdrawalIndex);

    /// @notice Event for claiming tokens from eigen layer.
    /// @param claimedAmount : Amount of tokens claimed.
    event LogClaimEigenLayer(uint256 claimedAmount);

    /// @notice Struct for validator data
    struct Validator {
        bytes publicKey;
        bytes signature;
        uint256 validatorType;
    }

    /// @notice Struct for validator view
    struct ValidatorView {
        uint256 id;
        bytes publicKey;
        uint256 validatorType;
    }

    /// @notice Deposits / Withdraws while registering validators with the specified parameters.
    /// @dev Anyone can call the function as long as no registration occurs ir order to close NetStaking batches.
    /// @param _publicKey The public key(s) of the validator.
    /// @param _signature The signature(s) of the validator.
    /// @param _deposit_data_root The deposit data root(s) of the validator.
    /// @param _validatorType The type of the validator code internally used.
    /// @return A boolean indicating whether the registration was successful.
    function autoBalance(
        bytes[] memory _publicKey,
        bytes[] memory _signature,
        bytes32[] memory _deposit_data_root,
        uint256[] memory _validatorType
    ) external returns (bool);

    /// @notice Returns the balance of the contract accounting for pending staking.
    function getBalance() external view returns (uint256);

    /// @notice Returns whether the address is a whitelisted autobalancer.
    function autobalanceWhitelist(address _caller) external view returns (bool);
}

interface ICSToken {
    /// @notice Returns the amount of tokens in existence.
    function totalSupply() external view returns (uint256);

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

    /// @notice Mints `_amount` of tokens `_to` user.
    function mint(address _to, uint256 _amount) external returns (bool);

    /// @notice Burns `_amount` of tokens `_from` user.
    function burn(address _from, uint256 _amount) external returns (bool);

    /// @notice Transfers `_amount` of tokens `_to` user.
    function transfer(address _to, uint256 _amount) external returns (bool);
}

interface IClayMain {
    /// @notice Supported fee types. Matches fees ordering.
    enum SetFee {
        DepositFee,
        WithdrawFee,
        InstantWithdrawFee
    }

    /// @notice Struct used on ClayMatic fees
    struct Fees {
        uint256 depositFee;
        uint256 withdrawFee;
        uint256 instantWithdrawFee;
    }

    /// @notice Struct used on ClayMatic for returning user withdraw order
    struct UserWithdrawOrderInfo {
        uint256 orderId;
        uint256 amount;
        uint256 fee;
        uint256 claimableAt;
        bool isClaimable;
    }

    /// @notice Struct to track internal funds accounting
    /// @param currentDeposit : Total user deposits backing csETH
    /// @param withdrawQueue :  Current amount of ETH waiting in the queue to be withdrawn by users
    /// @param stakedDeposit : Amount of ETH currently staked with validators without including exit requests
    /// @param unstakeExternal : Amount of ETH staked, yet in the process to be withdrawn due user withdraw requests
    /// @param unstakeInternal : Amount of ETH staked, yet in the process to be withdrawn due to protocol balancing
    /// @param withdrawQueueOpen : Amount of ETH to be claimed from withdrawals on open batches
    /// @param claimablePool : ETH balance reserved on contract for claims.
    struct Funds {
        uint256 currentDeposit;
        uint256 withdrawQueue;
        uint256 stakedDeposit;
        uint256 unstakeExternal;
        uint256 unstakeInternal;
        uint256 withdrawQueueOpen;
        uint256 claimablePool;
    }

    /// @notice WithdrawOrder struct
    /// @param amount : Total amount unstaked from from ethereum.
    /// @param fee : Fee percentage to be paid by the user at claim time.
    /// @param claimableAt timestamp when batch claims can be processed
    /// @param batchId : Id of the batch process to be sent to ethereum.
    struct WithdrawOrder {
        uint256 amount;
        uint256 fee;
        uint256 claimableAt;
        uint256 batchId;
    }

    /// @notice Information on batches for withdraws
    /// @param claimableAt timestamp when batch claims can be processed
    /// @param amount : Total amount unstaked from from ethereum.
    /// @param amountCs : Total amount of csToken burned on batch.
    /// @param multiplier : Multiplier for batch accounting for slashing
    struct BatchWithdraw {
        uint256 claimableAt;
        uint256 amount;
        uint256 amountCs;
        uint256 multiplier;
    }

    /// @notice Exchange rate allowed percentage deviation.
    /// @param exchangeDecreaseLimit - Max allowed rate decrease percentage based on last valid exchange rate
    /// @param exchangeIncreaseLimit - Max allowed rate increase percentage based on last valid exchange rate
    struct ExchangeDeviation {
        uint256 exchangeDecreaseLimit;
        uint256 exchangeIncreaseLimit;
    }

    /// @notice Event for new deposit.
    /// @param user : Address of depositor.
    /// @param amount : Amount of Token deposited.
    /// @param amountCs : Amount of csToken minted.
    /// @param fee : Fee paid by user on deposit in Token
    event LogDeposit(address indexed user, uint256 amount, uint256 amountCs, uint256 fee);

    /// @notice Event for new withdraw request.
    /// @param user : Address of user withdrawing.
    /// @param orderId : Withdraw order id.
    /// @param amountCs : Amount of csToken burned.
    /// @param amount : Amount of Token withdrawn.
    /// @param fee : Fee percentage to be paid by the user
    /// @param timestamp : Epoch at the moment of request
    event LogWithdraw(
        address indexed user,
        uint256 orderId,
        uint256 amountCs,
        uint256 amount,
        uint256 fee,
        uint256 timestamp
    );

    /// @notice Event for withdraw claims by user.
    /// @param user : Address of user.
    /// @param orderId : Withdraw order id.
    /// @param amount : Amount of Token unstaked in order.
    /// @param received : Amount of Token received in order.
    /// @param fee : Fee paid by user.
    event LogClaim(address indexed user, uint256 orderId, uint256 amount, uint256 received, uint256 fee);

    /// @notice Event for instant withdraw.
    /// @param user : Address of user.
    /// @param amountCs : Amount of csToken burned.
    /// @param amount : Amount of Token withdrawn.
    /// @param fee : Fee paid by user on instant withdraw in Token
    event LogInstantWithdraw(address indexed user, uint256 amountCs, uint256 amount, uint256 fee);

    /// @notice Event for new deposit.
    /// @param updatedBy : Address of Updating entity.
    /// @param feeType : Fee type being updated.
    /// @param oldFee : Existing fee percent for given fee type.
    /// @param newFee : New fee percent for given fee type.
    event LogFeeUpdate(address indexed updatedBy, SetFee feeType, uint256 oldFee, uint256 newFee);

    /// @notice Event emitted when AutoBalance is run.
    /// @param batchId : Id of the current processed batch.
    /// @param isNetStaking : Flag denoting net tx type of batch.
    /// @param amount : Amount of Token to be deposited or expected at claim.
    event LogAutoBalance(uint256 indexed batchId, bool indexed isNetStaking, uint256 amount);

    /// @notice Event for rewards recognized.
    /// @param rewards : Amount of rewards recognized.
    event LogRewards(uint256 rewards);

    /// @notice Event for Donations recognized.
    /// @param amount : Amount of donations recognized.
    event LogDonation(uint256 amount);

    /// @notice Event for batch closed.
    /// @param batchId : Id of the current processed batch.
    /// @param amount : Amount of Token to be deposited or expected at claim.
    /// @param amountCs : Amount of csToken burned on batch.
    /// @param multiplier : Multiplier for batch accounting for slashing
    event LogBatchClosed(uint256 indexed batchId, uint256 amount, uint256 amountCs, uint256 multiplier);

    /// @notice Event for imposed penalties.
    /// @param penaltiesToHolders : Amount of penalties to cs holders.
    /// @param penaltiesToClaims : Amount of penalties to be claimed.
    event LogPenalties(uint256 indexed penaltiesToHolders, uint256 indexed penaltiesToClaims);

    /// @notice Event for updated value of exchange rate
    /// @param rate : Updated rate value.
    /// @param time : Timestamp on which info is updated.
    event LogUpdateExchangeRate(uint256 rate, uint256 time);

    /// @notice Event for updating minimum claim delay.
    /// @param newMinClaimSeconds : New claim delay.
    event LogSetMinClaimTime(uint256 indexed newMinClaimSeconds);

    /// @notice Event for updating withdrawals.
    /// @param flag : bool for enabling/disabling withdrawals.
    event LogSetWithdrawalsDisabled(bool indexed flag);

    /// @notice Event for updating change update limits.
    /// @param newDecreaseLimit : New fx change limit floor.
    /// @param newIncreaseLimit : New fx change limit ceil.
    event LogSetExchangeDeviation(uint256 indexed newDecreaseLimit, uint256 indexed newIncreaseLimit);

    /// @notice Sends msg.value Token to ClayMain contract and mints csToken to msg.sender.
    function deposit() external payable returns (uint256);

    /// @notice Sends msg.value Token to ClayMain contract and mints csToken to `_delegatedTo`.
    function depositDelegate(address _delegatedTo) external payable returns (uint256);

    /// @notice Burns `_amountCs` csToken tokens from user and unstake respective amounts of Token tokens from node.
    function withdraw(uint256 _amountCs) external returns (uint256);

    /// @notice Allows user to claim unstaked tokens.
    function claim(uint256[] calldata _orderIds) external returns (bool);

    /// @notice Performs claiming of rewards & staking of Token tokens for ClayStack.
    function autoBalance(
        uint256 validatorCapacity
    ) external returns (uint256 currentBatchId, bool netStaking, uint256 validatorCount);

    /// @notice Exchange rate from csETH to ETH.
    function getExchangeRate() external view returns (uint256);

    /// @notice Returns amount of csTokens for given `_amountToken`.
    function exchangeToken(uint256 _amountToken) external view returns (uint256);

    /// @notice Returns amount of Tokens for given `_amountCsToken`.
    function exchangeCsToken(uint256 amountCsToken) external view returns (uint256);

    /// @notice Receives confirmation from NodeManager on batch finalization
    function closeBatches(uint256[] calldata _batchIds) external;

    /// @notice Receives liquidity from NodeManager for exits and rewards
    function receiveLiquidity(uint256 rewards, uint256 exited) external payable;

    /// @notice Returns instance of csToken
    function csToken() external returns (ICSToken);

    /// @notice enforceAndUpdateBalance public call
    function updateBalances() external;

    /// @notice Whether withdrawals & claims are disabled given slashing protection or other reasons
    function withdrawalsDisabled() external view returns (bool);

    /// @notice Disables withdrawals and claims
    function setWithdrawalsDisabled(bool _disabled) external;
}

// This interface is designed to be compatible with the Vyper version.
/// @notice This is the Ethereum 2.0 deposit contract interface.
/// For more information see the Phase 0 specification under https://github.com/ethereum/eth2.0-specs
interface IDepositContract {
    /// @notice A processed deposit event.
    event DepositEvent(bytes pubkey, bytes withdrawal_credentials, bytes amount, bytes signature, bytes index);

    /// @notice Submit a Phase 0 DepositData object.
    /// @param pubkey A BLS12-381 public key.
    /// @param withdrawal_credentials Commitment to a public key for withdrawals.
    /// @param signature A BLS12-381 signature.
    /// @param deposit_data_root The SHA-256 hash of the SSZ-encoded DepositData object.
    /// Used as a protection against malformed input.
    function deposit(
        bytes calldata pubkey,
        bytes calldata withdrawal_credentials,
        bytes calldata signature,
        bytes32 deposit_data_root
    ) external payable;

    /// @notice Query the current deposit root hash.
    /// @return The deposit root hash.
    function get_deposit_root() external view returns (bytes32);

    /// @notice Query the current deposit count.
    /// @return The deposit count encoded as a little endian 64-bit number.
    function get_deposit_count() external view returns (bytes memory);
}

// 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);
}

/**
 * @title Minimal interface for an `Strategy` contract.
 * @author Layr Labs, Inc.
 * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
 * @notice Custom `Strategy` implementations may expand extensively on this interface.
 */
interface IStrategy {
    /**
     * @notice Used to deposit tokens into this Strategy
     * @param token is the ERC20 token being deposited
     * @param amount is the amount of token being deposited
     * @dev This function is only callable by the strategyManager contract. It is invoked inside of the strategyManager's
     * `depositIntoStrategy` function, and individual share balances are recorded in the strategyManager as well.
     * @return newShares is the number of new shares issued at the current exchange ratio.
     */
    function deposit(IERC20 token, uint256 amount) external returns (uint256);

    /**
     * @notice Used to withdraw tokens from this Strategy, to the `depositor`'s address
     * @param depositor is the address to receive the withdrawn funds
     * @param token is the ERC20 token being transferred out
     * @param amountShares is the amount of shares being withdrawn
     * @dev This function is only callable by the strategyManager contract. It is invoked inside of the strategyManager's
     * other functions, and individual share balances are recorded in the strategyManager as well.
     */
    function withdraw(address depositor, IERC20 token, uint256 amountShares) external;

    /**
     * @notice Used to convert a number of shares to the equivalent amount of underlying tokens for this strategy.
     * @notice In contrast to `sharesToUnderlyingView`, this function **may** make state modifications
     * @param amountShares is the amount of shares to calculate its conversion into the underlying token
     * @return The amount of underlying tokens corresponding to the input `amountShares`
     * @dev Implementation for these functions in particular may vary significantly for different strategies
     */
    function sharesToUnderlying(uint256 amountShares) external returns (uint256);

    /**
     * @notice Used to convert an amount of underlying tokens to the equivalent amount of shares in this strategy.
     * @notice In contrast to `underlyingToSharesView`, this function **may** make state modifications
     * @param amountUnderlying is the amount of `underlyingToken` to calculate its conversion into strategy shares
     * @return The amount of underlying tokens corresponding to the input `amountShares`
     * @dev Implementation for these functions in particular may vary significantly for different strategies
     */
    function underlyingToShares(uint256 amountUnderlying) external returns (uint256);

    /**
     * @notice convenience function for fetching the current underlying value of all of the `user`'s shares in
     * this strategy. In contrast to `userUnderlyingView`, this function **may** make state modifications
     */
    function userUnderlying(address user) external returns (uint256);

    /**
     * @notice Used to convert a number of shares to the equivalent amount of underlying tokens for this strategy.
     * @notice In contrast to `sharesToUnderlying`, this function guarantees no state modifications
     * @param amountShares is the amount of shares to calculate its conversion into the underlying token
     * @return The amount of shares corresponding to the input `amountUnderlying`
     * @dev Implementation for these functions in particular may vary significantly for different strategies
     */
    function sharesToUnderlyingView(uint256 amountShares) external view returns (uint256);

    /**
     * @notice Used to convert an amount of underlying tokens to the equivalent amount of shares in this strategy.
     * @notice In contrast to `underlyingToShares`, this function guarantees no state modifications
     * @param amountUnderlying is the amount of `underlyingToken` to calculate its conversion into strategy shares
     * @return The amount of shares corresponding to the input `amountUnderlying`
     * @dev Implementation for these functions in particular may vary significantly for different strategies
     */
    function underlyingToSharesView(uint256 amountUnderlying) external view returns (uint256);

    /**
     * @notice convenience function for fetching the current underlying value of all of the `user`'s shares in
     * this strategy. In contrast to `userUnderlying`, this function guarantees no state modifications
     */
    function userUnderlyingView(address user) external view returns (uint256);

    /// @notice The underlying token for shares in this Strategy
    function underlyingToken() external view returns (IERC20);

    /// @notice The total number of extant shares in this Strategy
    function totalShares() external view returns (uint256);

    /// @notice Returns either a brief string explaining the strategy's goal & purpose, or a link to metadata that explains in more detail.
    function explanation() external view returns (string memory);
}

/**
 * @title Interface for the primary 'slashing' contract for EigenLayer.
 * @author Layr Labs, Inc.
 * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
 * @notice See the `Slasher` contract itself for implementation details.
 */
interface ISlasher {
    // struct used to store information about the current state of an operator's obligations to middlewares they are serving
    struct MiddlewareTimes {
        // The update block for the middleware whose most recent update was earliest, i.e. the 'stalest' update out of all middlewares the operator is serving
        uint32 stalestUpdateBlock;
        // The latest 'serveUntilBlock' from all of the middleware that the operator is serving
        uint32 latestServeUntilBlock;
    }

    // struct used to store details relevant to a single middleware that an operator has opted-in to serving
    struct MiddlewareDetails {
        // the block before which the contract is allowed to slash the user
        uint32 contractCanSlashOperatorUntilBlock;
        // the block at which the middleware's view of the operator's stake was most recently updated
        uint32 latestUpdateBlock;
    }

    /**
     * @notice Gives the `contractAddress` permission to slash the funds of the caller.
     * @dev Typically, this function must be called prior to registering for a middleware.
     */
    function optIntoSlashing(address contractAddress) external;

    /**
     * @notice Used for 'slashing' a certain operator.
     * @param toBeFrozen The operator to be frozen.
     * @dev Technically the operator is 'frozen' (hence the name of this function), and then subject to slashing pending a decision by a human-in-the-loop.
     * @dev The operator must have previously given the caller (which should be a contract) the ability to slash them, through a call to `optIntoSlashing`.
     */
    function freezeOperator(address toBeFrozen) external;

    /**
     * @notice Removes the 'frozen' status from each of the `frozenAddresses`
     * @dev Callable only by the contract owner (i.e. governance).
     */
    function resetFrozenStatus(address[] calldata frozenAddresses) external;

    /**
     * @notice this function is a called by middlewares during an operator's registration to make sure the operator's stake at registration
     *         is slashable until serveUntil
     * @param operator the operator whose stake update is being recorded
     * @param serveUntilBlock the block until which the operator's stake at the current block is slashable
     * @dev adds the middleware's slashing contract to the operator's linked list
     */
    function recordFirstStakeUpdate(address operator, uint32 serveUntilBlock) external;

    /**
     * @notice this function is a called by middlewares during a stake update for an operator (perhaps to free pending withdrawals)
     *         to make sure the operator's stake at updateBlock is slashable until serveUntil
     * @param operator the operator whose stake update is being recorded
     * @param updateBlock the block for which the stake update is being recorded
     * @param serveUntilBlock the block until which the operator's stake at updateBlock is slashable
     * @param insertAfter the element of the operators linked list that the currently updating middleware should be inserted after
     * @dev insertAfter should be calculated offchain before making the transaction that calls this. this is subject to race conditions,
     *      but it is anticipated to be rare and not detrimental.
     */
    function recordStakeUpdate(
        address operator,
        uint32 updateBlock,
        uint32 serveUntilBlock,
        uint256 insertAfter
    ) external;

    /**
     * @notice this function is a called by middlewares during an operator's deregistration to make sure the operator's stake at deregistration
     *         is slashable until serveUntil
     * @param operator the operator whose stake update is being recorded
     * @param serveUntilBlock the block until which the operator's stake at the current block is slashable
     * @dev removes the middleware's slashing contract to the operator's linked list and revokes the middleware's (i.e. caller's) ability to
     * slash `operator` once `serveUntil` is reached
     */
    function recordLastStakeUpdateAndRevokeSlashingAbility(address operator, uint32 serveUntilBlock) external;

    /**
     * @notice Used to determine whether `staker` is actively 'frozen'. If a staker is frozen, then they are potentially subject to
     * slashing of their funds, and cannot cannot deposit or withdraw from the strategyManager until the slashing process is completed
     * and the staker's status is reset (to 'unfrozen').
     * @param staker The staker of interest.
     * @return Returns 'true' if `staker` themselves has their status set to frozen, OR if the staker is delegated
     * to an operator who has their status set to frozen. Otherwise returns 'false'.
     */
    function isFrozen(address staker) external view returns (bool);

    /// @notice Returns true if `slashingContract` is currently allowed to slash `toBeSlashed`.
    function canSlash(address toBeSlashed, address slashingContract) external view returns (bool);

    /// @notice Returns the block until which `serviceContract` is allowed to slash the `operator`.
    function contractCanSlashOperatorUntilBlock(
        address operator,
        address serviceContract
    ) external view returns (uint32);

    /// @notice Returns the block at which the `serviceContract` last updated its view of the `operator`'s stake
    function latestUpdateBlock(address operator, address serviceContract) external view returns (uint32);

    /// @notice A search routine for finding the correct input value of `insertAfter` to `recordStakeUpdate` / `_updateMiddlewareList`.
    function getCorrectValueForInsertAfter(address operator, uint32 updateBlock) external view returns (uint256);

    /**
     * @notice Returns 'true' if `operator` can currently complete a withdrawal started at the `withdrawalStartBlock`, with `middlewareTimesIndex` used
     * to specify the index of a `MiddlewareTimes` struct in the operator's list (i.e. an index in `operatorToMiddlewareTimes[operator]`). The specified
     * struct is consulted as proof of the `operator`'s ability (or lack thereof) to complete the withdrawal.
     * This function will return 'false' if the operator cannot currently complete a withdrawal started at the `withdrawalStartBlock`, *or* in the event
     * that an incorrect `middlewareTimesIndex` is supplied, even if one or more correct inputs exist.
     * @param operator Either the operator who queued the withdrawal themselves, or if the withdrawing party is a staker who delegated to an operator,
     * this address is the operator *who the staker was delegated to* at the time of the `withdrawalStartBlock`.
     * @param withdrawalStartBlock The block number at which the withdrawal was initiated.
     * @param middlewareTimesIndex Indicates an index in `operatorToMiddlewareTimes[operator]` to consult as proof of the `operator`'s ability to withdraw
     * @dev The correct `middlewareTimesIndex` input should be computable off-chain.
     */
    function canWithdraw(
        address operator,
        uint32 withdrawalStartBlock,
        uint256 middlewareTimesIndex
    ) external returns (bool);

    /**
     * operator =>
     *  [
     *      (
     *          the least recent update block of all of the middlewares it's serving/served,
     *          latest time that the stake bonded at that update needed to serve until
     *      )
     *  ]
     */
    function operatorToMiddlewareTimes(
        address operator,
        uint256 arrayIndex
    ) external view returns (MiddlewareTimes memory);

    /// @notice Getter function for fetching `operatorToMiddlewareTimes[operator].length`
    function middlewareTimesLength(address operator) external view returns (uint256);

    /// @notice Getter function for fetching `operatorToMiddlewareTimes[operator][index].stalestUpdateBlock`.
    function getMiddlewareTimesIndexBlock(address operator, uint32 index) external view returns (uint32);

    /// @notice Getter function for fetching `operatorToMiddlewareTimes[operator][index].latestServeUntil`.
    function getMiddlewareTimesIndexServeUntilBlock(address operator, uint32 index) external view returns (uint32);

    /// @notice Getter function for fetching `_operatorToWhitelistedContractsByUpdate[operator].size`.
    function operatorWhitelistedContractsLinkedListSize(address operator) external view returns (uint256);

    /// @notice Getter function for fetching a single node in the operator's linked list (`_operatorToWhitelistedContractsByUpdate[operator]`).
    function operatorWhitelistedContractsLinkedListEntry(
        address operator,
        address node
    ) external view returns (bool, uint256, uint256);
}

/**
 * @title Abstract interface for a contract that helps structure the delegation relationship.
 * @author Layr Labs, Inc.
 * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
 * @notice The gas budget provided to this contract in calls from EigenLayer contracts is limited.
 */
interface IDelegationTerms {
    function payForService(IERC20 token, uint256 amount) external payable;

    function onDelegationWithdrawn(
        address delegator,
        IStrategy[] memory stakerStrategyList,
        uint256[] memory stakerShares
    ) external returns (bytes memory);

    function onDelegationReceived(
        address delegator,
        IStrategy[] memory stakerStrategyList,
        uint256[] memory stakerShares
    ) external returns (bytes memory);
}

/**
 * @title The interface for the primary delegation contract for EigenLayer.
 * @author Layr Labs, Inc.
 * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
 * @notice  This is the contract for delegation in EigenLayer. The main functionalities of this contract are
 * - enabling anyone to register as an operator in EigenLayer
 * - allowing new operators to provide a DelegationTerms-type contract, which may mediate their interactions with stakers who delegate to them
 * - enabling any staker to delegate its stake to the operator of its choice
 * - enabling a staker to undelegate its assets from an operator (performed as part of the withdrawal process, initiated through the StrategyManager)
 */
interface IDelegationManager {
    /**
     * @notice This will be called by an operator to register itself as an operator that stakers can choose to delegate to.
     * @param dt is the `DelegationTerms` contract that the operator has for those who delegate to them.
     * @dev An operator can set `dt` equal to their own address (or another EOA address), in the event that they want to split payments
     * in a more 'trustful' manner.
     * @dev In the present design, once set, there is no way for an operator to ever modify the address of their DelegationTerms contract.
     */
    function registerAsOperator(IDelegationTerms dt) external;

    /**
     *  @notice This will be called by a staker to delegate its assets to some operator.
     *  @param operator is the operator to whom staker (msg.sender) is delegating its assets
     */
    function delegateTo(address operator) external;

    /**
     * @notice Delegates from `staker` to `operator`.
     * @dev requires that:
     * 1) if `staker` is an EOA, then `signature` is valid ECDSA signature from `staker`, indicating their intention for this action
     * 2) if `staker` is a contract, then `signature` must will be checked according to EIP-1271
     */
    function delegateToBySignature(address staker, address operator, uint256 expiry, bytes memory signature) external;

    /**
     * @notice Undelegates `staker` from the operator who they are delegated to.
     * @notice Callable only by the StrategyManager
     * @dev Should only ever be called in the event that the `staker` has no active deposits in EigenLayer.
     */
    function undelegate(address staker) external;

    /// @notice returns the address of the operator that `staker` is delegated to.
    function delegatedTo(address staker) external view returns (address);

    /// @notice returns the DelegationTerms of the `operator`, which may mediate their interactions with stakers who delegate to them.
    function delegationTerms(address operator) external view returns (IDelegationTerms);

    /// @notice returns the total number of shares in `strategy` that are delegated to `operator`.
    function operatorShares(address operator, IStrategy strategy) external view returns (uint256);

    /**
     * @notice Increases the `staker`'s delegated shares in `strategy` by `shares, typically called when the staker has further deposits into EigenLayer
     * @dev Callable only by the StrategyManager
     */
    function increaseDelegatedShares(address staker, IStrategy strategy, uint256 shares) external;

    /**
     * @notice Decreases the `staker`'s delegated shares in each entry of `strategies` by its respective `shares[i]`, typically called when the staker withdraws from EigenLayer
     * @dev Callable only by the StrategyManager
     */
    function decreaseDelegatedShares(
        address staker,
        IStrategy[] calldata strategies,
        uint256[] calldata shares
    ) external;

    /// @notice Returns 'true' if `staker` *is* actively delegated, and 'false' otherwise.
    function isDelegated(address staker) external view returns (bool);

    /// @notice Returns 'true' if `staker` is *not* actively delegated, and 'false' otherwise.
    function isNotDelegated(address staker) external view returns (bool);

    /// @notice Returns if an operator can be delegated to, i.e. it has called `registerAsOperator`.
    function isOperator(address operator) external view returns (bool);
}

/**
 * @title Interface for the primary entrypoint for funds into EigenLayer.
 * @author Layr Labs, Inc.
 * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
 * @notice See the `StrategyManager` contract itself for implementation details.
 */
interface IStrategyManager {
    // packed struct for queued withdrawals; helps deal with stack-too-deep errors
    struct WithdrawerAndNonce {
        address withdrawer;
        uint96 nonce;
    }

    /**
     * Struct type used to specify an existing queued withdrawal. Rather than storing the entire struct, only a hash is stored.
     * In functions that operate on existing queued withdrawals -- e.g. `startQueuedWithdrawalWaitingPeriod` or `completeQueuedWithdrawal`,
     * the data is resubmitted and the hash of the submitted data is computed by `calculateWithdrawalRoot` and checked against the
     * stored hash in order to confirm the integrity of the submitted data.
     */
    struct QueuedWithdrawal {
        IStrategy[] strategies;
        uint256[] shares;
        address depositor;
        WithdrawerAndNonce withdrawerAndNonce;
        uint32 withdrawalStartBlock;
        address delegatedAddress;
    }

    /**
     * @notice Deposits `amount` of `token` into the specified `strategy`, with the resultant shares credited to `msg.sender`
     * @param strategy is the specified strategy where deposit is to be made,
     * @param token is the denomination in which the deposit is to be made,
     * @param amount is the amount of token to be deposited in the strategy by the depositor
     * @return shares The amount of new shares in the `strategy` created as part of the action.
     * @dev The `msg.sender` must have previously approved this contract to transfer at least `amount` of `token` on their behalf.
     * @dev Cannot be called by an address that is 'frozen' (this function will revert if the `msg.sender` is frozen).
     *
     * WARNING: Depositing tokens that allow reentrancy (eg. ERC-777) into a strategy is not recommended.  This can lead to attack vectors
     *          where the token balance and corresponding strategy shares are not in sync upon reentrancy.
     */
    function depositIntoStrategy(
        IStrategy strategy,
        IERC20 token,
        uint256 amount
    ) external returns (uint256 shares);

    /**
     * @notice Deposits `amount` of beaconchain ETH into this contract on behalf of `staker`
     * @param staker is the entity that is restaking in eigenlayer,
     * @param amount is the amount of beaconchain ETH being restaked,
     * @dev Only callable by EigenPodManager.
     */
    function depositBeaconChainETH(address staker, uint256 amount) external;

    /**
     * @notice Records an overcommitment event on behalf of a staker. The staker's beaconChainETH shares are decremented by `amount`.
     * @param overcommittedPodOwner is the pod owner to be slashed
     * @param beaconChainETHStrategyIndex is the index of the beaconChainETHStrategy in case it must be removed,
     * @param amount is the amount to decrement the slashedAddress's beaconChainETHStrategy shares
     * @dev Only callable by EigenPodManager.
     */
    function recordOvercommittedBeaconChainETH(
        address overcommittedPodOwner,
        uint256 beaconChainETHStrategyIndex,
        uint256 amount
    ) external;

    /**
     * @notice Used for depositing an asset into the specified strategy with the resultant shares credited to `staker`,
     * who must sign off on the action.
     * Note that the assets are transferred out/from the `msg.sender`, not from the `staker`; this function is explicitly designed
     * purely to help one address deposit 'for' another.
     * @param strategy is the specified strategy where deposit is to be made,
     * @param token is the denomination in which the deposit is to be made,
     * @param amount is the amount of token to be deposited in the strategy by the depositor
     * @param staker the staker that the deposited assets will be credited to
     * @param expiry the timestamp at which the signature expires
     * @param signature is a valid signature from the `staker`. either an ECDSA signature if the `staker` is an EOA, or data to forward
     * following EIP-1271 if the `staker` is a contract
     * @return shares The amount of new shares in the `strategy` created as part of the action.
     * @dev The `msg.sender` must have previously approved this contract to transfer at least `amount` of `token` on their behalf.
     * @dev A signature is required for this function to eliminate the possibility of griefing attacks, specifically those
     * targeting stakers who may be attempting to undelegate.
     * @dev Cannot be called on behalf of a staker that is 'frozen' (this function will revert if the `staker` is frozen).
     *
     *  WARNING: Depositing tokens that allow reentrancy (eg. ERC-777) into a strategy is not recommended.  This can lead to attack vectors
     *          where the token balance and corresponding strategy shares are not in sync upon reentrancy
     */
    function depositIntoStrategyWithSignature(
        IStrategy strategy,
        IERC20 token,
        uint256 amount,
        address staker,
        uint256 expiry,
        bytes memory signature
    ) external returns (uint256 shares);

    /// @notice Returns the current shares of `user` in `strategy`
    function stakerStrategyShares(address user, IStrategy strategy) external view returns (uint256 shares);

    /**
     * @notice Get all details on the depositor's deposits and corresponding shares
     * @return (depositor's strategies, shares in these strategies)
     */
    function getDeposits(address depositor) external view returns (IStrategy[] memory, uint256[] memory);

    /// @notice Simple getter function that returns `stakerStrategyList[staker].length`.
    function stakerStrategyListLength(address staker) external view returns (uint256);

    /**
     * @notice Called by a staker to queue a withdrawal of the given amount of `shares` from each of the respective given `strategies`.
     * @dev Stakers will complete their withdrawal by calling the 'completeQueuedWithdrawal' function.
     * User shares are decreased in this function, but the total number of shares in each strategy remains the same.
     * The total number of shares is decremented in the 'completeQueuedWithdrawal' function instead, which is where
     * the funds are actually sent to the user through use of the strategies' 'withdrawal' function. This ensures
     * that the value per share reported by each strategy will remain consistent, and that the shares will continue
     * to accrue gains during the enforced withdrawal waiting period.
     * @param strategyIndexes is a list of the indices in `stakerStrategyList[msg.sender]` that correspond to the strategies
     * for which `msg.sender` is withdrawing 100% of their shares
     * @param strategies The Strategies to withdraw from
     * @param shares The amount of shares to withdraw from each of the respective Strategies in the `strategies` array
     * @param withdrawer The address that can complete the withdrawal and will receive any withdrawn funds or shares upon completing the withdrawal
     * @param undelegateIfPossible If this param is marked as 'true' *and the withdrawal will result in `msg.sender` having no shares in any Strategy,*
     * then this function will also make an internal call to `undelegate(msg.sender)` to undelegate the `msg.sender`.
     * @return The 'withdrawalRoot' of the newly created Queued Withdrawal
     * @dev Strategies are removed from `stakerStrategyList` by swapping the last entry with the entry to be removed, then
     * popping off the last entry in `stakerStrategyList`. The simplest way to calculate the correct `strategyIndexes` to input
     * is to order the strategies *for which `msg.sender` is withdrawing 100% of their shares* from highest index in
     * `stakerStrategyList` to lowest index
     * @dev Note that if the withdrawal includes shares in the enshrined 'beaconChainETH' strategy, then it must *only* include shares in this strategy, and
     * `withdrawer` must match the caller's address. The first condition is because slashing of queued withdrawals cannot be guaranteed
     * for Beacon Chain ETH (since we cannot trigger a withdrawal from the beacon chain through a smart contract) and the second condition is because shares in
     * the enshrined 'beaconChainETH' strategy technically represent non-fungible positions (deposits to the Beacon Chain, each pointed at a specific EigenPod).
     */
    function queueWithdrawal(
        uint256[] calldata strategyIndexes,
        IStrategy[] calldata strategies,
        uint256[] calldata shares,
        address withdrawer,
        bool undelegateIfPossible
    ) external returns (bytes32);

    /**
     * @notice Used to complete the specified `queuedWithdrawal`. The function caller must match `queuedWithdrawal.withdrawer`
     * @param queuedWithdrawal The QueuedWithdrawal to complete.
     * @param tokens Array in which the i-th entry specifies the `token` input to the 'withdraw' function of the i-th Strategy in the `strategies` array
     * of the `queuedWithdrawal`. This input can be provided with zero length if `receiveAsTokens` is set to 'false' (since in that case, this input will be unused)
     * @param middlewareTimesIndex is the index in the operator that the staker who triggered the withdrawal was delegated to's middleware times array
     * @param receiveAsTokens If true, the shares specified in the queued withdrawal will be withdrawn from the specified strategies themselves
     * and sent to the caller, through calls to `queuedWithdrawal.strategies[i].withdraw`. If false, then the shares in the specified strategies
     * will simply be transferred to the caller directly.
     * @dev middlewareTimesIndex should be calculated off chain before calling this function by finding the first index that satisfies `slasher.canWithdraw`
     */
    function completeQueuedWithdrawal(
        QueuedWithdrawal calldata queuedWithdrawal,
        IERC20[] calldata tokens,
        uint256 middlewareTimesIndex,
        bool receiveAsTokens
    ) external;

    /**
     * @notice Used to complete the specified `queuedWithdrawals`. The function caller must match `queuedWithdrawals[...].withdrawer`
     * @param queuedWithdrawals The QueuedWithdrawals to complete.
     * @param tokens Array of tokens for each QueuedWithdrawal. See `completeQueuedWithdrawal` for the usage of a single array.
     * @param middlewareTimesIndexes One index to reference per QueuedWithdrawal. See `completeQueuedWithdrawal` for the usage of a single index.
     * @param receiveAsTokens If true, the shares specified in the queued withdrawal will be withdrawn from the specified strategies themselves
     * and sent to the caller, through calls to `queuedWithdrawal.strategies[i].withdraw`. If false, then the shares in the specified strategies
     * will simply be transferred to the caller directly.
     * @dev Array-ified version of `completeQueuedWithdrawal`
     * @dev middlewareTimesIndex should be calculated off chain before calling this function by finding the first index that satisfies `slasher.canWithdraw`
     */
    function completeQueuedWithdrawals(
        QueuedWithdrawal[] calldata queuedWithdrawals,
        IERC20[][] calldata tokens,
        uint256[] calldata middlewareTimesIndexes,
        bool[] calldata receiveAsTokens
    ) external;

    /**
     * @notice Slashes the shares of a 'frozen' operator (or a staker delegated to one)
     * @param slashedAddress is the frozen address that is having its shares slashed
     * @param recipient is the address that will receive the slashed funds, which could e.g. be a harmed party themself,
     * or a MerkleDistributor-type contract that further sub-divides the slashed funds.
     * @param strategies Strategies to slash
     * @param shareAmounts The amount of shares to slash in each of the provided `strategies`
     * @param tokens The tokens to use as input to the `withdraw` function of each of the provided `strategies`
     * @param strategyIndexes is a list of the indices in `stakerStrategyList[msg.sender]` that correspond to the strategies
     * for which `msg.sender` is withdrawing 100% of their shares
     * @param recipient The slashed funds are withdrawn as tokens to this address.
     * @dev strategies are removed from `stakerStrategyList` by swapping the last entry with the entry to be removed, then
     * popping off the last entry in `stakerStrategyList`. The simplest way to calculate the correct `strategyIndexes` to input
     * is to order the strategies *for which `msg.sender` is withdrawing 100% of their shares* from highest index in
     * `stakerStrategyList` to lowest index
     */
    function slashShares(
        address slashedAddress,
        address recipient,
        IStrategy[] calldata strategies,
        IERC20[] calldata tokens,
        uint256[] calldata strategyIndexes,
        uint256[] calldata shareAmounts
    ) external;

    /**
     * @notice Slashes an existing queued withdrawal that was created by a 'frozen' operator (or a staker delegated to one)
     * @param recipient The funds in the slashed withdrawal are withdrawn as tokens to this address.
     * @param queuedWithdrawal The previously queued withdrawal to be slashed
     * @param tokens Array in which the i-th entry specifies the `token` input to the 'withdraw' function of the i-th Strategy in the `strategies`
     * array of the `queuedWithdrawal`.
     * @param indicesToSkip Optional input parameter -- indices in the `strategies` array to skip (i.e. not call the 'withdraw' function on). This input exists
     * so that, e.g., if the slashed QueuedWithdrawal contains a malicious strategy in the `strategies` array which always reverts on calls to its 'withdraw' function,
     * then the malicious strategy can be skipped (with the shares in effect "burned"), while the non-malicious strategies are still called as normal.
     */
    function slashQueuedWithdrawal(
        address recipient,
        QueuedWithdrawal calldata queuedWithdrawal,
        IERC20[] calldata tokens,
        uint256[] calldata indicesToSkip
    ) external;

    /// @notice Returns the keccak256 hash of `queuedWithdrawal`.
    function calculateWithdrawalRoot(QueuedWithdrawal memory queuedWithdrawal) external pure returns (bytes32);

    /**
     * @notice Owner-only function that adds the provided Strategies to the 'whitelist' of strategies that stakers can deposit into
     * @param strategiesToWhitelist Strategies that will be added to the `strategyIsWhitelistedForDeposit` mapping (if they aren't in it already)
     */
    function addStrategiesToDepositWhitelist(IStrategy[] calldata strategiesToWhitelist) external;

    /**
     * @notice Owner-only function that removes the provided Strategies from the 'whitelist' of strategies that stakers can deposit into
     * @param strategiesToRemoveFromWhitelist Strategies that will be removed to the `strategyIsWhitelistedForDeposit` mapping (if they are in it)
     */
    function removeStrategiesFromDepositWhitelist(IStrategy[] calldata strategiesToRemoveFromWhitelist) external;

    /// @notice Returns the single, central Delegation contract of EigenLayer
    function delegation() external view returns (IDelegationManager);

    /// @notice Returns the single, central Slasher contract of EigenLayer
    function slasher() external view returns (ISlasher);

    /// @notice returns the enshrined, virtual 'beaconChainETH' Strategy
    function beaconChainETHStrategy() external view returns (IStrategy);

    /// @notice Returns the number of blocks that must pass between the time a withdrawal is queued and the time it can be completed
    function withdrawalDelayBlocks() external view returns (uint256);
}

// Adapted from OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/MerkleProof.sol)

/**
 * @dev These functions deal with verification of Merkle Tree proofs.
 *
 * The tree and the proofs can be generated using our
 * https://github.com/OpenZeppelin/merkle-tree[JavaScript library].
 * You will find a quickstart guide in the readme.
 *
 * WARNING: You should avoid using leaf values that are 64 bytes long prior to
 * hashing, or use a hash function other than keccak256 for hashing leaves.
 * This is because the concatenation of a sorted pair of internal nodes in
 * the merkle tree could be reinterpreted as a leaf value.
 * OpenZeppelin's JavaScript library generates merkle trees that are safe
 * against this attack out of the box.
 */
library Merkle {
    /**
     * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
     * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
     * hash matches the root of the tree. The tree is built assuming `leaf` is
     * the 0 indexed `index`'th leaf from the bottom left of the tree.
     *
     * Note this is for a Merkle tree using the keccak/sha3 hash function
     */
    function verifyInclusionKeccak(
        bytes memory proof,
        bytes32 root,
        bytes32 leaf,
        uint256 index
    ) internal pure returns (bool) {
        return processInclusionProofKeccak(proof, leaf, index) == root;
    }

    /**
     * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
     * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
     * hash matches the root of the tree. The tree is built assuming `leaf` is
     * the 0 indexed `index`'th leaf from the bottom left of the tree.
     *
     * _Available since v4.4._
     *
     * Note this is for a Merkle tree using the keccak/sha3 hash function
     */
    function processInclusionProofKeccak(
        bytes memory proof,
        bytes32 leaf,
        uint256 index
    ) internal pure returns (bytes32) {
        require(
            proof.length != 0 && proof.length % 32 == 0,
            "Merkle.processInclusionProofKeccak: proof length should be a non-zero multiple of 32"
        );
        bytes32 computedHash = leaf;
        for (uint256 i = 32; i <= proof.length; i += 32) {
            if (index % 2 == 0) {
                // if ith bit of index is 0, then computedHash is a left sibling
                assembly {
                    mstore(0x00, computedHash)
                    mstore(0x20, mload(add(proof, i)))
                    computedHash := keccak256(0x00, 0x40)
                    index := div(index, 2)
                }
            } else {
                // if ith bit of index is 1, then computedHash is a right sibling
                assembly {
                    mstore(0x00, mload(add(proof, i)))
                    mstore(0x20, computedHash)
                    computedHash := keccak256(0x00, 0x40)
                    index := div(index, 2)
                }
            }
        }
        return computedHash;
    }

    /**
     * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
     * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
     * hash matches the root of the tree. The tree is built assuming `leaf` is
     * the 0 indexed `index`'th leaf from the bottom left of the tree.
     *
     * Note this is for a Merkle tree using the sha256 hash function
     */
    function verifyInclusionSha256(
        bytes memory proof,
        bytes32 root,
        bytes32 leaf,
        uint256 index
    ) internal view returns (bool) {
        return processInclusionProofSha256(proof, leaf, index) == root;
    }

    /**
     * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
     * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
     * hash matches the root of the tree. The tree is built assuming `leaf` is
     * the 0 indexed `index`'th leaf from the bottom left of the tree.
     *
     * _Available since v4.4._
     *
     * Note this is for a Merkle tree using the sha256 hash function
     */
    function processInclusionProofSha256(
        bytes memory proof,
        bytes32 leaf,
        uint256 index
    ) internal view returns (bytes32) {
        require(
            proof.length != 0 && proof.length % 32 == 0,
            "Merkle.processInclusionProofSha256: proof length should be a non-zero multiple of 32"
        );
        bytes32[1] memory computedHash = [leaf];
        for (uint256 i = 32; i <= proof.length; i += 32) {
            if (index % 2 == 0) {
                // if ith bit of index is 0, then computedHash is a left sibling
                assembly {
                    mstore(0x00, mload(computedHash))
                    mstore(0x20, mload(add(proof, i)))
                    if iszero(staticcall(sub(gas(), 2000), 2, 0x00, 0x40, computedHash, 0x20)) {
                        revert(0, 0)
                    }
                    index := div(index, 2)
                }
            } else {
                // if ith bit of index is 1, then computedHash is a right sibling
                assembly {
                    mstore(0x00, mload(add(proof, i)))
                    mstore(0x20, mload(computedHash))
                    if iszero(staticcall(sub(gas(), 2000), 2, 0x00, 0x40, computedHash, 0x20)) {
                        revert(0, 0)
                    }
                    index := div(index, 2)
                }
            }
        }
        return computedHash[0];
    }

    /**
     @notice this function returns the merkle root of a tree created from a set of leaves using sha256 as its hash function
     @param leaves the leaves of the merkle tree
     @return The computed Merkle root of the tree.
     @dev A pre-condition to this function is that leaves.length is a power of two.  If not, the function will merkleize the inputs incorrectly.
     */
    function merkleizeSha256(bytes32[] memory leaves) internal pure returns (bytes32) {
        //there are half as many nodes in the layer above the leaves
        uint256 numNodesInLayer = leaves.length / 2;
        //create a layer to store the internal nodes
        bytes32[] memory layer = new bytes32[](numNodesInLayer);
        //fill the layer with the pairwise hashes of the leaves
        for (uint i = 0; i < numNodesInLayer; i++) {
            layer[i] = sha256(abi.encodePacked(leaves[2 * i], leaves[2 * i + 1]));
        }
        //the next layer above has half as many nodes
        numNodesInLayer /= 2;
        //while we haven't computed the root
        while (numNodesInLayer != 0) {
            //overwrite the first numNodesInLayer nodes in layer with the pairwise hashes of their children
            for (uint i = 0; i < numNodesInLayer; i++) {
                layer[i] = sha256(abi.encodePacked(layer[2 * i], layer[2 * i + 1]));
            }
            //the next layer above has half as many nodes
            numNodesInLayer /= 2;
        }
        //the first node in the layer is the root
        return layer[0];
    }
}

library Endian {
    /**
     * @notice Converts a little endian-formatted uint64 to a big endian-formatted uint64
     * @param lenum little endian-formatted uint64 input, provided as 'bytes32' type
     * @return n The big endian-formatted uint64
     * @dev Note that the input is formatted as a 'bytes32' type (i.e. 256 bits), but it is immediately truncated to a uint64 (i.e. 64 bits)
     * through a right-shift/shr operation.
     */
    function fromLittleEndianUint64(bytes32 lenum) internal pure returns (uint64 n) {
        // the number needs to be stored in little-endian encoding (ie in bytes 0-8)
        n = uint64(uint256(lenum >> 192));
        return
            (n >> 56) |
            ((0x00FF000000000000 & n) >> 40) |
            ((0x0000FF0000000000 & n) >> 24) |
            ((0x000000FF00000000 & n) >> 8) |
            ((0x00000000FF000000 & n) << 8) |
            ((0x0000000000FF0000 & n) << 24) |
            ((0x000000000000FF00 & n) << 40) |
            ((0x00000000000000FF & n) << 56);
    }
}

//Utility library for parsing and PHASE0 beacon chain block headers
//SSZ Spec: https://github.com/ethereum/consensus-specs/blob/dev/ssz/simple-serialize.md#merkleization
//BeaconBlockHeader Spec: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#beaconblockheader
//BeaconState Spec: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#beaconstate
library BeaconChainProofs {
    // constants are the number of fields and the heights of the different merkle trees used in merkleizing beacon chain containers
    uint256 internal constant NUM_BEACON_BLOCK_HEADER_FIELDS = 5;
    uint256 internal constant BEACON_BLOCK_HEADER_FIELD_TREE_HEIGHT = 3;

    uint256 internal constant NUM_BEACON_BLOCK_BODY_FIELDS = 11;
    uint256 internal constant BEACON_BLOCK_BODY_FIELD_TREE_HEIGHT = 4;

    uint256 internal constant NUM_BEACON_STATE_FIELDS = 21;
    uint256 internal constant BEACON_STATE_FIELD_TREE_HEIGHT = 5;

    uint256 internal constant NUM_ETH1_DATA_FIELDS = 3;
    uint256 internal constant ETH1_DATA_FIELD_TREE_HEIGHT = 2;

    uint256 internal constant NUM_VALIDATOR_FIELDS = 8;
    uint256 internal constant VALIDATOR_FIELD_TREE_HEIGHT = 3;

    uint256 internal constant NUM_EXECUTION_PAYLOAD_HEADER_FIELDS = 15;
    uint256 internal constant EXECUTION_PAYLOAD_HEADER_FIELD_TREE_HEIGHT = 4;

    uint256 internal constant NUM_EXECUTION_PAYLOAD_FIELDS = 15;
    uint256 internal constant EXECUTION_PAYLOAD_FIELD_TREE_HEIGHT = 4;

    // HISTORICAL_ROOTS_LIMIT	 = 2**24, so tree height is 24
    uint256 internal constant HISTORICAL_ROOTS_TREE_HEIGHT = 24;

    // HISTORICAL_BATCH is root of state_roots and block_root, so number of leaves =  2^1
    uint256 internal constant HISTORICAL_BATCH_TREE_HEIGHT = 1;

    // SLOTS_PER_HISTORICAL_ROOT = 2**13, so tree height is 13
    uint256 internal constant STATE_ROOTS_TREE_HEIGHT = 13;
    uint256 internal constant BLOCK_ROOTS_TREE_HEIGHT = 13;

    uint256 internal constant NUM_WITHDRAWAL_FIELDS = 4;
    // tree height for hash tree of an individual withdrawal container
    uint256 internal constant WITHDRAWAL_FIELD_TREE_HEIGHT = 2;

    uint256 internal constant VALIDATOR_TREE_HEIGHT = 40;
    //refer to the eigenlayer-cli proof library.  Despite being the same dimensions as the validator tree, the balance tree is merkleized differently
    uint256 internal constant BALANCE_TREE_HEIGHT = 38;

    // MAX_WITHDRAWALS_PER_PAYLOAD = 2**4, making tree height = 4
    uint256 internal constant WITHDRAWALS_TREE_HEIGHT = 4;

    //in beacon block body
    uint256 internal constant EXECUTION_PAYLOAD_INDEX = 9;

    // in beacon block header
    uint256 internal constant STATE_ROOT_INDEX = 3;
    uint256 internal constant PROPOSER_INDEX_INDEX = 1;
    uint256 internal constant SLOT_INDEX = 0;
    uint256 internal constant BODY_ROOT_INDEX = 4;
    // in beacon state
    uint256 internal constant STATE_ROOTS_INDEX = 6;
    uint256 internal constant BLOCK_ROOTS_INDEX = 5;
    uint256 internal constant HISTORICAL_ROOTS_INDEX = 7;
    uint256 internal constant ETH_1_ROOT_INDEX = 8;
    uint256 internal constant VALIDATOR_TREE_ROOT_INDEX = 11;
    uint256 internal constant BALANCE_INDEX = 12;
    uint256 internal constant EXECUTION_PAYLOAD_HEADER_INDEX = 24;
    uint256 internal constant HISTORICAL_BATCH_STATE_ROOT_INDEX = 1;

    // in validator
    uint256 internal constant VALIDATOR_WITHDRAWAL_CREDENTIALS_INDEX = 1;
    uint256 internal constant VALIDATOR_BALANCE_INDEX = 2;
    uint256 internal constant VALIDATOR_SLASHED_INDEX = 3;
    uint256 internal constant VALIDATOR_WITHDRAWABLE_EPOCH_INDEX = 7;

    // in execution payload header
    uint256 internal constant BLOCK_NUMBER_INDEX = 6;
    uint256 internal constant WITHDRAWALS_ROOT_INDEX = 14;

    //in execution payload
    uint256 internal constant WITHDRAWALS_INDEX = 14;

    // in withdrawal
    uint256 internal constant WITHDRAWAL_VALIDATOR_INDEX_INDEX = 1;
    uint256 internal constant WITHDRAWAL_VALIDATOR_AMOUNT_INDEX = 3;

    //In historicalBatch
    uint256 internal constant HISTORICALBATCH_STATEROOTS_INDEX = 1;

    //Misc Constants
    uint256 internal constant SLOTS_PER_EPOCH = 32;

    bytes8 internal constant UINT64_MASK = 0xffffffffffffffff;

    struct WithdrawalProofs {
        bytes blockHeaderProof;
        bytes withdrawalProof;
        bytes slotProof;
        bytes executionPayloadProof;
        bytes blockNumberProof;
        uint64 blockHeaderRootIndex;
        uint64 withdrawalIndex;
        bytes32 blockHeaderRoot;
        bytes32 blockBodyRoot;
        bytes32 slotRoot;
        bytes32 blockNumberRoot;
        bytes32 executionPayloadRoot;
    }

    struct ValidatorFieldsAndBalanceProofs {
        bytes validatorFieldsProof;
        bytes validatorBalanceProof;
        bytes32 balanceRoot;
    }

    struct ValidatorFieldsProof {
        bytes validatorProof;
        uint40 validatorIndex;
    }

    /**
     *
     * @notice This function is parses the balanceRoot to get the uint64 balance of a validator.  During merkleization of the
     * beacon state balance tree, four uint64 values (making 32 bytes) are grouped together and treated as a single leaf in the merkle tree. Thus the
     * validatorIndex mod 4 is used to determine which of the four uint64 values to extract from the balanceRoot.
     * @param validatorIndex is the index of the validator being proven for.
     * @param balanceRoot is the combination of 4 validator balances being proven for.
     * @return The validator's balance, in Gwei
     */
    function getBalanceFromBalanceRoot(uint40 validatorIndex, bytes32 balanceRoot) internal pure returns (uint64) {
        uint256 bitShiftAmount = (validatorIndex % 4) * 64;
        bytes32 validatorBalanceLittleEndian = bytes32((uint256(balanceRoot) << bitShiftAmount));
        uint64 validatorBalance = Endian.fromLittleEndianUint64(validatorBalanceLittleEndian);
        return validatorBalance;
    }

    /**
     * @notice This function verifies merkle proofs of the fields of a certain validator against a beacon chain state root
     * @param validatorIndex the index of the proven validator
     * @param beaconStateRoot is the beacon chain state root to be proven against.
     * @param proof is the data used in proving the validator's fields
     * @param validatorFields the claimed fields of the validator
     */
    function verifyValidatorFields(
        uint40 validatorIndex,
        bytes32 beaconStateRoot,
        bytes calldata proof,
        bytes32[] calldata validatorFields
    ) internal view {
        require(
            validatorFields.length == 2 ** VALIDATOR_FIELD_TREE_HEIGHT,
            "BeaconChainProofs.verifyValidatorFields: Validator fields has incorrect length"
        );

        /**
         * Note: the length of the validator merkle proof is BeaconChainProofs.VALIDATOR_TREE_HEIGHT + 1.
         * There is an additional layer added by hashing the root with the length of the validator list
         */
        require(
            proof.length == 32 * ((VALIDATOR_TREE_HEIGHT + 1) + BEACON_STATE_FIELD_TREE_HEIGHT),
            "BeaconChainProofs.verifyValidatorFields: Proof has incorrect length"
        );
        uint256 index = (VALIDATOR_TREE_ROOT_INDEX << (VALIDATOR_TREE_HEIGHT + 1)) | uint256(validatorIndex);
        // merkleize the validatorFields to get the leaf to prove
        bytes32 validatorRoot = Merkle.merkleizeSha256(validatorFields);

        // verify the proof of the validatorRoot against the beaconStateRoot
        require(
            Merkle.verifyInclusionSha256(proof, beaconStateRoot, validatorRoot, index),
            "BeaconChainProofs.verifyValidatorFields: Invalid merkle proof"
        );
    }

    /**
     * @notice This function verifies merkle proofs of the balance of a certain validator against a beacon chain state root
     * @param validatorIndex the index of the proven validator
     * @param beaconStateRoot is the beacon chain state root to be proven against.
     * @param proof is the proof of the balance against the beacon chain state root
     * @param balanceRoot is the serialized balance used to prove the balance of the validator (refer to `getBalanceFromBalanceRoot` above for detailed explanation)
     */
    function verifyValidatorBalance(
        uint40 validatorIndex,
        bytes32 beaconStateRoot,
        bytes calldata proof,
        bytes32 balanceRoot
    ) internal view {
        require(
            proof.length == 32 * ((BALANCE_TREE_HEIGHT + 1) + BEACON_STATE_FIELD_TREE_HEIGHT),
            "BeaconChainProofs.verifyValidatorBalance: Proof has incorrect length"
        );

        /**
         * the beacon state's balance list is a list of uint64 values, and these are grouped together in 4s when merkleized.
         * Therefore, the index of the balance of a validator is validatorIndex/4
         */
        uint256 balanceIndex = uint256(validatorIndex / 4);
        balanceIndex = (BALANCE_INDEX << (BALANCE_TREE_HEIGHT + 1)) | balanceIndex;

        require(
            Merkle.verifyInclusionSha256(proof, beaconStateRoot, balanceRoot, balanceIndex),
            "BeaconChainProofs.verifyValidatorBalance: Invalid merkle proof"
        );
    }

    /**
     * @notice This function verifies the slot and the withdrawal fields for a given withdrawal
     * @param beaconStateRoot is the beacon chain state root to be proven against.
     * @param proofs is the provided set of merkle proofs
     * @param withdrawalFields is the serialized withdrawal container to be proven
     */
    function verifyWithdrawalProofs(
        bytes32 beaconStateRoot,
        WithdrawalProofs calldata proofs,
        bytes32[] calldata withdrawalFields
    ) internal view {
        require(
            withdrawalFields.length == 2 ** WITHDRAWAL_FIELD_TREE_HEIGHT,
            "BeaconChainProofs.verifyWithdrawalProofs: withdrawalFields has incorrect length"
        );

        require(
            proofs.blockHeaderRootIndex < 2 ** BLOCK_ROOTS_TREE_HEIGHT,
            "BeaconChainProofs.verifyWithdrawalProofs: blockRootIndex is too large"
        );
        require(
            proofs.withdrawalIndex < 2 ** WITHDRAWALS_TREE_HEIGHT,
            "BeaconChainProofs.verifyWithdrawalProofs: withdrawalIndex is too large"
        );

        // verify the block header proof length
        require(
            proofs.blockHeaderProof.length == 32 * (BEACON_STATE_FIELD_TREE_HEIGHT + BLOCK_ROOTS_TREE_HEIGHT),
            "BeaconChainProofs.verifyWithdrawalProofs: blockHeaderProof has incorrect length"
        );
        require(
            proofs.withdrawalProof.length ==
                32 * (EXECUTION_PAYLOAD_HEADER_FIELD_TREE_HEIGHT + WITHDRAWALS_TREE_HEIGHT + 1),
            "BeaconChainProofs.verifyWithdrawalProofs: withdrawalProof has incorrect length"
        );
        require(
            proofs.executionPayloadProof.length ==
                32 * (BEACON_BLOCK_HEADER_FIELD_TREE_HEIGHT + BEACON_BLOCK_BODY_FIELD_TREE_HEIGHT),
            "BeaconChainProofs.verifyWithdrawalProofs: executionPayloadProof has incorrect length"
        );
        require(
            proofs.slotProof.length == 32 * (BEACON_BLOCK_HEADER_FIELD_TREE_HEIGHT),
            "BeaconChainProofs.verifyWithdrawalProofs: slotProof has incorrect length"
        );
        require(
            proofs.blockNumberProof.length == 32 * (EXECUTION_PAYLOAD_HEADER_FIELD_TREE_HEIGHT),
            "BeaconChainProofs.verifyWithdrawalProofs: blockNumberProof has incorrect length"
        );

        /**
         * Computes the block_header_index relative to the beaconStateRoot.  It concatenates the indexes of all the
         * intermediate root indexes from the bottom of the sub trees (the block header container) to the top of the tree
         */
        uint256 blockHeaderIndex = (BLOCK_ROOTS_INDEX << (BLOCK_ROOTS_TREE_HEIGHT)) |
            uint256(proofs.blockHeaderRootIndex);
        // Verify the blockHeaderRoot against the beaconStateRoot
        require(
            Merkle.verifyInclusionSha256(
                proofs.blockHeaderProof,
                beaconStateRoot,
                proofs.blockHeaderRoot,
                blockHeaderIndex
            ),
            "BeaconChainProofs.verifyWithdrawalProofs: Invalid block header merkle proof"
        );

        //Next we verify the slot against the blockHeaderRoot
        require(
            Merkle.verifyInclusionSha256(proofs.slotProof, proofs.blockHeaderRoot, proofs.slotRoot, SLOT_INDEX),
            "BeaconChainProofs.verifyWithdrawalProofs: Invalid slot merkle proof"
        );

        // Next we verify the executionPayloadRoot against the blockHeaderRoot
        uint256 executionPayloadIndex = (BODY_ROOT_INDEX << (BEACON_BLOCK_BODY_FIELD_TREE_HEIGHT)) |
            EXECUTION_PAYLOAD_INDEX;
        require(
            Merkle.verifyInclusionSha256(
                proofs.executionPayloadProof,
                proofs.blockHeaderRoot,
                proofs.executionPayloadRoot,
                executionPayloadIndex
            ),
            "BeaconChainProofs.verifyWithdrawalProofs: Invalid executionPayload merkle proof"
        );

        // Next we verify the blockNumberRoot against the executionPayload root
        require(
            Merkle.verifyInclusionSha256(
                proofs.blockNumberProof,
                proofs.executionPayloadRoot,
                proofs.blockNumberRoot,
                BLOCK_NUMBER_INDEX
            ),
            "BeaconChainProofs.verifyWithdrawalProofs: Invalid blockNumber merkle proof"
        );

        /**
         * Next we verify the withdrawal fields against the blockHeaderRoot:
         * First we compute the withdrawal_index relative to the blockHeaderRoot by concatenating the indexes of all the
         * intermediate root indexes from the bottom of the sub trees (the withdrawal container) to the top, the blockHeaderRoot.
         * Then we calculate merkleize the withdrawalFields container to calculate the the withdrawalRoot.
         * Finally we verify the withdrawalRoot against the executionPayloadRoot.
         */
        uint256 withdrawalIndex = (WITHDRAWALS_INDEX << (WITHDRAWALS_TREE_HEIGHT + 1)) |
            uint256(proofs.withdrawalIndex);
        bytes32 withdrawalRoot = Merkle.merkleizeSha256(withdrawalFields);
        require(
            Merkle.verifyInclusionSha256(
                proofs.withdrawalProof,
                proofs.executionPayloadRoot,
                withdrawalRoot,
                withdrawalIndex
            ),
            "BeaconChainProofs.verifyWithdrawalProofs: Invalid withdrawal merkle proof"
        );
    }
}

/**
 * @title Interface for the BeaconStateOracle contract.
 * @author Layr Labs, Inc.
 * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
 */
interface IBeaconChainOracle {
    /// @notice Largest blockNumber that has been confirmed by the oracle.
    function latestConfirmedOracleBlockNumber() external view returns (uint64);

    /// @notice Mapping: Beacon Chain blockNumber => the Beacon Chain state root at the specified blockNumber.
    /// @dev This will return `bytes32(0)` if the state root at the specified blockNumber is not yet confirmed.
    function beaconStateRootAtBlockNumber(uint64 blockNumber) external view returns (bytes32);

    /// @notice Mapping: address => whether or not the address is in the set of oracle signers.
    function isOracleSigner(address _oracleSigner) external view returns (bool);

    /// @notice Mapping: Beacon Chain blockNumber => oracle signer address => whether or not the oracle signer has voted on the state root at the blockNumber.
    function hasVoted(uint64 blockNumber, address oracleSigner) external view returns (bool);

    /// @notice Mapping: Beacon Chain blockNumber => state root => total number of oracle signer votes for the state root at the blockNumber.
    function stateRootVotes(uint64 blockNumber, bytes32 stateRoot) external view returns (uint256);

    /// @notice Total number of members of the set of oracle signers.
    function totalOracleSigners() external view returns (uint256);

    /**
     * @notice Number of oracle signers that must vote for a state root in order for the state root to be confirmed.
     * Adjustable by this contract's owner through use of the `setThreshold` function.
     * @dev We note that there is an edge case -- when the threshold is adjusted downward, if a state root already has enough votes to meet the *new* threshold,
     * the state root must still receive one additional vote from an oracle signer to be confirmed. This behavior is intended, to minimize unexpected root confirmations.
     */
    function threshold() external view returns (uint256);

    /**
     * @notice Owner-only function used to modify the value of the `threshold` variable.
     * @param _threshold Desired new value for the `threshold` variable. Function will revert if this is set to zero.
     */
    function setThreshold(uint256 _threshold) external;

    /**
     * @notice Owner-only function used to add a signer to the set of oracle signers.
     * @param _oracleSigners Array of address to be added to the set.
     * @dev Function will have no effect on the i-th input address if `_oracleSigners[i]`is already in the set of oracle signers.
     */
    function addOracleSigners(address[] memory _oracleSigners) external;

    /**
     * @notice Owner-only function used to remove a signer from the set of oracle signers.
     * @param _oracleSigners Array of address to be removed from the set.
     * @dev Function will have no effect on the i-th input address if `_oracleSigners[i]`is already not in the set of oracle signers.
     */
    function removeOracleSigners(address[] memory _oracleSigners) external;

    /**
     * @notice Called by a member of the set of oracle signers to assert that the Beacon Chain state root is `stateRoot` at `blockNumber`.
     * @dev The state root will be finalized once the total number of votes *for this exact state root at this exact blockNumber* meets the `threshold` value.
     * @param blockNumber The Beacon Chain blockNumber of interest.
     * @param stateRoot The Beacon Chain state root that the caller asserts was the correct root, at the specified `blockNumber`.
     */
    function voteForBeaconChainStateRoot(uint64 blockNumber, bytes32 stateRoot) external;
}

/**
 * @title The implementation contract used for restaking beacon chain ETH on EigenLayer
 * @author Layr Labs, Inc.
 * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
 * @notice The main functionalities are:
 * - creating new ETH validators with their withdrawal credentials pointed to this contract
 * - proving from beacon chain state roots that withdrawal credentials are pointed to this contract
 * - proving from beacon chain state roots the balances of ETH validators with their withdrawal credentials
 *   pointed to this contract
 * - updating aggregate balances in the EigenPodManager
 * - withdrawing eth when withdrawals are initiated
 * @dev Note that all beacon chain balances are stored as gwei within the beacon chain datastructures. We choose
 *   to account balances in terms of gwei in the EigenPod contract and convert to wei when making calls to other contracts
 */
interface IEigenPod {
    enum VALIDATOR_STATUS {
        INACTIVE, // doesnt exist
        ACTIVE, // staked on ethpos and withdrawal credentials are pointed to the EigenPod
        OVERCOMMITTED, // proven to be overcommitted to EigenLayer
        WITHDRAWN // withdrawn from the Beacon Chain
    }

    // this struct keeps track of PartialWithdrawalClaims
    struct PartialWithdrawalClaim {
        PARTIAL_WITHDRAWAL_CLAIM_STATUS status;
        // block at which the PartialWithdrawalClaim was created
        uint32 creationBlockNumber;
        // last block (inclusive) in which the PartialWithdrawalClaim can be fraudproofed
        uint32 fraudproofPeriodEndBlockNumber;
        // amount of ETH -- in Gwei -- to be withdrawn until completion of this claim
        uint64 partialWithdrawalAmountGwei;
    }

    enum PARTIAL_WITHDRAWAL_CLAIM_STATUS {
        REDEEMED,
        PENDING,
        FAILED
    }

    /// @notice The amount of eth, in gwei, that is restaked per validator
    function REQUIRED_BALANCE_GWEI() external view returns (uint64);

    /// @notice The amount of eth, in wei, that is restaked per validator
    function REQUIRED_BALANCE_WEI() external view returns (uint256);

    /// @notice this is a mapping of validator indices to a Validator struct containing pertinent info about the validator
    function validatorStatus(uint40 validatorIndex) external view returns (VALIDATOR_STATUS);

    /// @notice the amount of execution layer ETH in this contract that is staked in EigenLayer (i.e. withdrawn from beaconchain but not EigenLayer),
    function restakedExecutionLayerGwei() external view returns (uint64);

    /// @notice Used to initialize the pointers to contracts crucial to the pod's functionality, in beacon proxy construction from EigenPodManager
    function initialize(address owner) external;

    /// @notice Called by EigenPodManager when the owner wants to create another ETH validator.
    function stake(bytes calldata pubkey, bytes calldata signature, bytes32 depositDataRoot) external payable;

    /**
     * @notice Transfers `amountWei` in ether from this contract to the specified `recipient` address
     * @notice Called by EigenPodManager to withdrawBeaconChainETH that has been added to the EigenPod's balance due to a withdrawal from the beacon chain.
     * @dev Called during withdrawal or slashing.
     * @dev Note that this function is marked as non-reentrant to prevent the recipient calling back into it
     */
    function withdrawRestakedBeaconChainETH(address recipient, uint256 amount) external;

    /// @notice The single EigenPodManager for EigenLayer
    function eigenPodManager() external view returns (IEigenPodManager);

    /// @notice The owner of this EigenPod
    function podOwner() external view returns (address);

    /// @notice an indicator of whether or not the podOwner has ever "fully restaked" by successfully calling `verifyCorrectWithdrawalCredentials`.
    function hasRestaked() external view returns (bool);

    /// @notice block number of the most recent withdrawal
    function mostRecentWithdrawalBlockNumber() external view returns (uint64);

    ///@notice mapping that tracks proven partial withdrawals
    function provenPartialWithdrawal(uint40 validatorIndex, uint64 slot) external view returns (bool);

    /**
     * @notice This function verifies that the withdrawal credentials of the podOwner are pointed to
     * this contract. It also verifies the current (not effective) balance  of the validator.  It verifies the provided proof of the ETH validator against the beacon chain state
     * root, marks the validator as 'active' in EigenLayer, and credits the restaked ETH in Eigenlayer.
     * @param oracleBlockNumber is the Beacon Chain blockNumber whose state root the `proof` will be proven against.
     * @param validatorIndex is the index of the validator being proven, refer to consensus specs
     * @param proofs is the bytes that prove the ETH validator's balance and withdrawal credentials against a beacon chain state root
     * @param validatorFields are the fields of the "Validator Container", refer to consensus specs
     * for details: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#validator
     */
    function verifyWithdrawalCredentialsAndBalance(
        uint64 oracleBlockNumber,
        uint40 validatorIndex,
        BeaconChainProofs.ValidatorFieldsAndBalanceProofs memory proofs,
        bytes32[] calldata validatorFields
    ) external;

    /**
     * @notice This function records an overcommitment of stake to EigenLayer on behalf of a certain ETH validator.
     *         If successful, the overcommitted balance is penalized (available for withdrawal whenever the pod's balance allows).
     *         The ETH validator's shares in the enshrined beaconChainETH strategy are also removed from the StrategyManager and undelegated.
     * @param oracleBlockNumber The oracleBlockNumber whose state root the `proof` will be proven against.
     *        Must be within `VERIFY_OVERCOMMITTED_WINDOW_BLOCKS` of the current block.
     * @param validatorIndex is the index of the validator being proven, refer to consensus specs
     * @param proofs is the proof of the validator's balance and validatorFields in the balance tree and the balanceRoot to prove for
     * @param beaconChainETHStrategyIndex is the index of the beaconChainETHStrategy for the pod owner for the callback to
     *                                    the StrategyManager in case it must be removed from the list of the podOwners strategies
     * @param validatorFields are the fields of the "Validator Container", refer to consensus specs
     * @dev For more details on the Beacon Chain spec, see: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#validator
     */
    function verifyOvercommittedStake(
        uint40 validatorIndex,
        BeaconChainProofs.ValidatorFieldsAndBalanceProofs calldata proofs,
        bytes32[] calldata validatorFields,
        uint256 beaconChainETHStrategyIndex,
        uint64 oracleBlockNumber
    ) external;

    /**
     * @notice This function records a full withdrawal on behalf of one of the Ethereum validators for this EigenPod
     * @param withdrawalProofs is the information needed to check the veracity of the block number and withdrawal being proven
     * @param validatorFieldsProof is the proof of the validator's fields in the validator tree
     * @param withdrawalFields are the fields of the withdrawal being proven
     * @param validatorFields are the fields of the validator being proven
     * @param beaconChainETHStrategyIndex is the index of the beaconChainETHStrategy for the pod owner for the callback to
     *        the EigenPodManager to the StrategyManager in case it must be removed from the podOwner's list of strategies
     */
    function verifyAndProcessWithdrawal(
        BeaconChainProofs.WithdrawalProofs calldata withdrawalProofs,
        bytes calldata validatorFieldsProof,
        bytes32[] calldata validatorFields,
        bytes32[] calldata withdrawalFields,
        uint256 beaconChainETHStrategyIndex,
        uint64 oracleBlockNumber
    ) external;

    /// @notice Called by the pod owner to withdraw the balance of the pod when `hasRestaked` is set to false
    function withdrawBeforeRestaking() external;
}

/**
 * @title Interface for the `PauserRegistry` contract.
 * @author Layr Labs, Inc.
 * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
 */
interface IPauserRegistry {
    /// @notice Mapping of addresses to whether they hold the pauser role.
    function isPauser(address pauser) external view returns (bool);

    /// @notice Unique address that holds the unpauser role. Capable of changing *both* the pauser and unpauser addresses.
    function unpauser() external view returns (address);
}

/**
 * @title Adds pausability to a contract, with pausing & unpausing controlled by the `pauser` and `unpauser` of a PauserRegistry contract.
 * @author Layr Labs, Inc.
 * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
 * @notice Contracts that inherit from this contract may define their own `pause` and `unpause` (and/or related) functions.
 * These functions should be permissioned as "onlyPauser" which defers to a `PauserRegistry` for determining access control.
 * @dev Pausability is implemented using a uint256, which allows up to 256 different single bit-flags; each bit can potentially pause different functionality.
 * Inspiration for this was taken from the NearBridge design here https://etherscan.io/address/0x3FEFc5A4B1c02f21cBc8D3613643ba0635b9a873#code.
 * For the `pause` and `unpause` functions we've implemented, if you pause, you can only flip (any number of) switches to on/1 (aka "paused"), and if you unpause,
 * you can only flip (any number of) switches to off/0 (aka "paused").
 * If you want a pauseXYZ function that just flips a single bit / "pausing flag", it will:
 * 1) 'bit-wise and' (aka `&`) a flag with the current paused state (as a uint256)
 * 2) update the paused state to this new value
 * @dev We note as well that we have chosen to identify flags by their *bit index* as opposed to their numerical value, so, e.g. defining `DEPOSITS_PAUSED = 3`
 * indicates specifically that if the *third bit* of `_paused` is flipped -- i.e. it is a '1' -- then deposits should be paused
 */

interface IPausable {
    /// @notice Address of the `PauserRegistry` contract that this contract defers to for determining access control (for pausing).
    function pauserRegistry() external view returns (IPauserRegistry);

    /**
     * @notice This function is used to pause an EigenLayer contract's functionality.
     * It is permissioned to the `pauser` address, which is expected to be a low threshold multisig.
     * @param newPausedStatus represents the new value for `_paused` to take, which means it may flip several bits at once.
     * @dev This function can only pause functionality, and thus cannot 'unflip' any bit in `_paused` from 1 to 0.
     */
    function pause(uint256 newPausedStatus) external;

    /**
     * @notice Alias for `pause(type(uint256).max)`.
     */
    function pauseAll() external;

    /**
     * @notice This function is used to unpause an EigenLayer contract's functionality.
     * It is permissioned to the `unpauser` address, which is expected to be a high threshold multisig or governance contract.
     * @param newPausedStatus represents the new value for `_paused` to take, which means it may flip several bits at once.
     * @dev This function can only unpause functionality, and thus cannot 'flip' any bit in `_paused` from 0 to 1.
     */
    function unpause(uint256 newPausedStatus) external;

    /// @notice Returns the current paused status as a uint256.
    function paused() external view returns (uint256);

    /// @notice Returns 'true' if the `indexed`th bit of `_paused` is 1, and 'false' otherwise
    function paused(uint8 index) external view returns (bool);

    /// @notice Allows the unpauser to set a new pauser registry
    function setPauserRegistry(IPauserRegistry newPauserRegistry) external;
}

/**
 * @title Interface for factory that creates and manages solo staking pods that have their withdrawal credentials pointed to EigenLayer.
 * @author Layr Labs, Inc.
 * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
 */

interface IEigenPodManager is IPausable {
    /**
     * @notice Creates an EigenPod for the sender.
     * @dev Function will revert if the `msg.sender` already has an EigenPod.
     */
    function createPod() external;

    /**
     * @notice Stakes for a new beacon chain validator on the sender's EigenPod.
     * Also creates an EigenPod for the sender if they don't have one already.
     * @param pubkey The 48 bytes public key of the beacon chain validator.
     * @param signature The validator's signature of the deposit data.
     * @param depositDataRoot The root/hash of the deposit data for the validator's deposit.
     */
    function stake(bytes calldata pubkey, bytes calldata signature, bytes32 depositDataRoot) external payable;

    /**
     * @notice Deposits/Restakes beacon chain ETH in EigenLayer on behalf of the owner of an EigenPod.
     * @param podOwner The owner of the pod whose balance must be deposited.
     * @param amount The amount of ETH to 'deposit' (i.e. be credited to the podOwner).
     * @dev Callable only by the podOwner's EigenPod contract.
     */
    function restakeBeaconChainETH(address podOwner, uint256 amount) external;

    /**
     * @notice Removes beacon chain ETH from EigenLayer on behalf of the owner of an EigenPod, when the
     *         balance of a validator is lower than how much stake they have committed to EigenLayer
     * @param podOwner The owner of the pod whose balance must be removed.
     * @param beaconChainETHStrategyIndex is the index of the beaconChainETHStrategy for the pod owner for the callback to
     *                                    the StrategyManager in case it must be removed from the list of the podOwner's strategies
     * @param amount The amount of ETH to remove.
     * @dev Callable only by the podOwner's EigenPod contract.
     */
    function recordOvercommittedBeaconChainETH(
        address podOwner,
        uint256 beaconChainETHStrategyIndex,
        uint256 amount
    ) external;

    /**
     * @notice Withdraws ETH from an EigenPod. The ETH must have first been withdrawn from the beacon chain.
     * @param podOwner The owner of the pod whose balance must be withdrawn.
     * @param recipient The recipient of the withdrawn ETH.
     * @param amount The amount of ETH to withdraw.
     * @dev Callable only by the StrategyManager contract.
     */
    function withdrawRestakedBeaconChainETH(address podOwner, address recipient, uint256 amount) external;

    /**
     * @notice Updates the oracle contract that provides the beacon chain state root
     * @param newBeaconChainOracle is the new oracle contract being pointed to
     * @dev Callable only by the owner of this contract (i.e. governance)
     */
    function updateBeaconChainOracle(IBeaconChainOracle newBeaconChainOracle) external;

    /// @notice Returns the address of the `podOwner`'s EigenPod if it has been deployed.
    function ownerToPod(address podOwner) external view returns (IEigenPod);

    /// @notice Returns the address of the `podOwner`'s EigenPod (whether it is deployed yet or not).
    function getPod(address podOwner) external view returns (IEigenPod);

    /// @notice Oracle contract that provides updates to the beacon chain's state
    function beaconChainOracle() external view returns (IBeaconChainOracle);

    /// @notice Returns the Beacon Chain state root at `blockNumber`. Reverts if the Beacon Chain state root at `blockNumber` has not yet been finalized.
    function getBeaconChainStateRoot(uint64 blockNumber) external view returns (bytes32);

    /// @notice EigenLayer's StrategyManager contract
    function strategyManager() external view returns (IStrategyManager);

    /// @notice EigenLayer's Slasher contract
    function slasher() external view returns (ISlasher);

    function hasPod(address podOwner) external view returns (bool);
}

interface IDelayedWithdrawalRouter {
    // struct used to pack data into a single storage slot
    struct DelayedWithdrawal {
        uint224 amount;
        uint32 blockCreated;
    }

    // struct used to store a single users delayedWithdrawal data
    struct UserDelayedWithdrawals {
        uint256 delayedWithdrawalsCompleted;
        DelayedWithdrawal[] delayedWithdrawals;
    }

    /**
     * @notice Creates an delayed withdrawal for `msg.value` to the `recipient`.
     * @dev Only callable by the `podOwner`'s EigenPod contract.
     */
    function createDelayedWithdrawal(address podOwner, address recipient) external payable;

    /**
     * @notice Called in order to withdraw delayed withdrawals made to the `recipient` that have passed the `withdrawalDelayBlocks` period.
     * @param recipient The address to claim delayedWithdrawals for.
     * @param maxNumberOfWithdrawalsToClaim Used to limit the maximum number of withdrawals to loop through claiming.
     */
    function claimDelayedWithdrawals(address recipient, uint256 maxNumberOfWithdrawalsToClaim) external;

    /**
     * @notice Called in order to withdraw delayed withdrawals made to the caller that have passed the `withdrawalDelayBlocks` period.
     * @param maxNumberOfWithdrawalsToClaim Used to limit the maximum number of withdrawals to loop through claiming.
     */
    function claimDelayedWithdrawals(uint256 maxNumberOfWithdrawalsToClaim) external;

    /// @notice Owner-only function for modifying the value of the `withdrawalDelayBlocks` variable.
    function setWithdrawalDelayBlocks(uint256 newValue) external;

    /// @notice Getter function for the mapping `_userWithdrawals`
    function userWithdrawals(address user) external view returns (UserDelayedWithdrawals memory);

    /// @notice Getter function to get all delayedWithdrawals of the `user`
    function getUserDelayedWithdrawals(address user) external view returns (DelayedWithdrawal[] memory);

    /// @notice Getter function to get all delayedWithdrawals that are currently claimable by the `user`
    function getClaimableUserDelayedWithdrawals(address user) external view returns (DelayedWithdrawal[] memory);

    /// @notice Getter function for fetching the delayedWithdrawal at the `index`th entry from the `_userWithdrawals[user].delayedWithdrawals` array
    function userDelayedWithdrawalByIndex(address user, uint256 index) external view returns (DelayedWithdrawal memory);

    /// @notice Getter function for fetching the length of the delayedWithdrawals array of a specific user
    function userWithdrawalsLength(address user) external view returns (uint256);

    /// @notice Convenience function for checking whether or not the delayedWithdrawal at the `index`th entry from the `_userWithdrawals[user].delayedWithdrawals` array is currently claimable
    function canClaimDelayedWithdrawal(address user, uint256 index) external view returns (bool);

    /**
     * @notice Delay enforced by this contract for completing any delayedWithdrawal. Measured in blocks, and adjustable by this contract's owner,
     * up to a maximum of `MAX_WITHDRAWAL_DELAY_BLOCKS`. Minimum value is 0 (i.e. no delay enforced).
     */
    function withdrawalDelayBlocks() external view returns (uint256);
}

/// @title NodeManager contract.
/// @notice This contract is responsible for managing the validator nodes and their deposits.
/// @dev This contract is upgradeable.
/// @dev This contract is pausable.
/// @dev This contract is re-entrant guarded.
/**
    @dev Node Types by unique number
    0: Direct Staking
    1: SSV Node
    10: EigenLayer
**/

contract NodeManager is INodeManager, UUPSUpgradeable, PausableUpgradeable, ReentrancyGuardUpgradeable {
    using ECDSAUpgradeable for bytes32;

    /// @notice ClayStack's default list of access-control roles.
    bytes32 private constant TIMELOCK_ROLE = keccak256("TIMELOCK_ROLE");
    bytes32 private constant TIMELOCK_UPGRADES_ROLE = keccak256("TIMELOCK_UPGRADES_ROLE");
    bytes32 private constant CS_SERVICE_ROLE = keccak256("CS_SERVICE_ROLE");

    /// @notice Constants
    uint256 private constant DEPOSIT_SIZE = 32 ether;
    uint256 private constant PRE_DEPOSIT_SIZE = 1 ether;
    uint256 private constant PERCENTAGE_BASE = 10000;
    uint256 private constant MAX_NODE_OPERATOR_FEES = 2000;
    uint256 private constant NODE_TYPE_EIGENLAYER = 10;

    /// @notice RoleManager instance.
    IRoleManager private roleManager;

    /// @notice address of clayMain contract.
    IClayMain public clayMain;

    /// @notice Instance of deposit contract.
    IDepositContract private depositContract;

    /// @notice Mapping of node ids to validator data.
    mapping(uint256 => Validator) public validators;

    /// @notice Nonce of validators ids registered
    uint256 public validatorNonce;

    /// @notice Number of exit requests
    uint256 public exitRequestsCount;

    /// @notice Number of exited validators
    uint256 public exitedValidators;

    /// @notice Number of validators active in the Consensus Layer state
    uint256 public activeValidators;

    /// @notice Total balance on active validators in the Consensus Layer state
    uint256 public activeValidatorsBalance;

    /// @notice Rewards accrued not yet added to liquidity
    uint256 public rewardsAccrued;

    /// @notice Oracle report block number
    uint256 public oracleReportBlock;

    /// @notice Keeps track of registered publicKey for validators
    mapping(bytes => bool) public registeredValidator;

    /// @notice Batch id to exit count request
    mapping(uint256 => uint256) public batchExitRequests;

    /// @notice Circular buffer queue of batches ids to exit in sequential order
    uint256[] public batchExitQueue;

    /// @notice Front of the queue
    uint256 public batchExitQueueFront;

    /// @notice Mapping of whitelisted oracles
    mapping(address => bool) public oracleWhitelist;

    /// @notice Mapping of whitelisted autobalance callers
    mapping(address => bool) public autobalanceWhitelist;

    /// @notice Mapping of last block number voted on oracle report
    mapping(address => uint256) public oracleVotes;

    /// @notice Minimum number of votes required for oracle update
    uint256 public oracleQuorum;

    /// @notice address of node operator
    address public nodeOperator;

    /// @notice Node operator fees
    uint256 public nodeOperatorFees;

    /// @notice Accrued fees not yet paid to node operator
    uint256 public nodeOperatorAccruedFees;

    /// @notice PreDeposit information
    mapping(bytes => address) public preDepositOwner;

    /// @notice Total amount of pre-deposits
    uint256 public preDepositsAmount;

    /// @notice Instance of EigenPodManager contract.
    IEigenPodManager private eigenPodManager;

    /// @notice Instance of DelayedWithdrawalRouter
    IDelayedWithdrawalRouter private eigenDelayedWithdrawalRouter;

    /// @notice Amount in delayed withdrawals to be claimed
    uint256 public eigenLayerWithdraws;

    /// @notice Maps EigenLayer claim id with total EigenLayer exits
    mapping(uint256 => uint256) public eigenLayerExits;

    /// @notice Check if the msg.sender has permission.
    /// @param _roleName : bytes32 hash of the role.
    modifier onlyRole(bytes32 _roleName) {
        _onlyRole(_roleName);
        _;
    }

    /// @notice Initializes the contract's state vars.
    /// @param _roleManager : Address of ClayStack's role manager contract.
    /// @param _depositContract : Address of the deposit contract.
    function initialize(address _roleManager, address _depositContract) external initializer onlyProxy {
        require(_roleManager != address(0), "Invalid roleManager address");
        require(_depositContract != address(0), "Invalid depositContract address");

        __Pausable_init();
        __ReentrancyGuard_init();
        __UUPSUpgradeable_init();

        roleManager = IRoleManager(_roleManager);
        depositContract = IDepositContract(_depositContract);
        oracleQuorum = 1;
    }

    /** STAKING **/

    /// @notice preDeposit can be called by NodeOperator contract or directly by node operator.
    /// @dev Amount will be locked and refunded when oracle registration confirms validity of withdrawal address.
    /// @dev preDeposit nodes are not supported for EigenLayer type nodes
    /// @param _publicKey The public key(s) of the validator.
    /// @param _signature The signature(s) of the validator.
    /// @param _deposit_data_root The deposit data root(s) of the validator.
    function preDeposit(
        bytes[] memory _publicKey,
        bytes[] memory _signature,
        bytes32[] memory _deposit_data_root
    ) external payable whenNotPaused nonReentrant returns (bool) {
        require(
            _publicKey.length == _signature.length &&
                _publicKey.length == _deposit_data_root.length &&
                _publicKey.length > 0,
            "Invalid param lengths"
        );
        require(msg.value == PRE_DEPOSIT_SIZE * _publicKey.length, "preDeposit value must be 1 ether per validator");

        for (uint256 i = 0; i < _publicKey.length; i++) {
            require(!registeredValidator[_publicKey[i]], "publicKey already registered");
            require(preDepositOwner[_publicKey[i]] == address(0), "publicKey already pre-deposited");

            depositContract.deposit{value: PRE_DEPOSIT_SIZE}(
                _publicKey[i],
                abi.encodePacked(bytes1(0x01), bytes11(0x0), address(this)),
                _signature[i],
                _deposit_data_root[i]
            );

            preDepositOwner[_publicKey[i]] = msg.sender;
            emit LogPreDeposit(_publicKey[i], msg.sender);
        }

        preDepositsAmount += msg.value;

        return true;
    }

    /// @notice Deposits / Withdraws while registering validators with the specified parameters.
    /// @dev Anyone can call the function as long as no registration occurs ir order to close NetStaking batches.
    /// @param _publicKey The public key(s) of the validator.
    /// @param _signature The signature(s) of the validator.
    /// @param _deposit_data_root The deposit data root(s) of the validator.
    /// @param _validatorType The type of the validator code internally used.
    /// @return A boolean indicating whether the registration was successful.
    function autoBalance(
        bytes[] memory _publicKey,
        bytes[] memory _signature,
        bytes32[] memory _deposit_data_root,
        uint256[] memory _validatorType
    ) public whenNotPaused nonReentrant returns (bool) {
        require(
            _publicKey.length == _signature.length &&
                _publicKey.length == _deposit_data_root.length &&
                _publicKey.length == _validatorType.length,
            "Invalid param lengths"
        );
        require(address(clayMain) != address(0), "Claymain not set");

        if (_publicKey.length > 0) {
            require(
                roleManager.checkRole(CS_SERVICE_ROLE, msg.sender) || autobalanceWhitelist[msg.sender],
                "Auth Failed"
            );
        }

        // get action from ClayMain
        (uint256 currentBatchId, bool netStaking, uint256 validatorCount) = clayMain.autoBalance(_publicKey.length);

        if (netStaking && validatorCount > 0) {
            uint256 id = validatorNonce;
            for (uint256 i = 0; i < validatorCount; i++) {
                require(!registeredValidator[_publicKey[i]], "publicKey already registered");

                ++id;
                validators[id] = Validator(_publicKey[i], _signature[i], _validatorType[i]);
                registeredValidator[_publicKey[i]] = true;

                address preDepositOwnerAddress = preDepositOwner[_publicKey[i]];
                uint256 deposit = preDepositOwnerAddress == address(0) ? 0 : PRE_DEPOSIT_SIZE;
                if (_validatorType[i] == NODE_TYPE_EIGENLAYER) {
                    require(address(eigenPodManager) != address(0), "EigenPodManager not set");
                    require(deposit == 0, "EigenPod M1 Requires 32 ETH");
                    eigenPodManager.stake{value: DEPOSIT_SIZE}(_publicKey[i], _signature[i], _deposit_data_root[i]);
                } else {
                    depositContract.deposit{value: DEPOSIT_SIZE - deposit}(
                        _publicKey[i],
                        abi.encodePacked(bytes1(0x01), bytes11(0x0), address(this)),
                        _signature[i],
                        _deposit_data_root[i]
                    );
                }

                // Refund pre-deposit
                if (deposit > 0) {
                    (bool success, ) = preDepositOwnerAddress.call{value: deposit}("");
                    require(success, "Transfer of pre-deposit failed");
                    preDepositsAmount -= deposit;
                    emit LogPreDepositRefund(id, _publicKey[i], preDepositOwnerAddress);
                }

                emit LogDeposit(id, _publicKey[i], _validatorType[i]);
            }
            validatorNonce = id;
        } else if (!netStaking && validatorCount > 0) {
            require(batchExitRequests[currentBatchId] == 0, "Batch already requested");
            exitRequestsCount += validatorCount;
            batchExitRequests[currentBatchId] = validatorCount;
            batchExitQueue.push(currentBatchId);
            emit LogWithdraw(currentBatchId, validatorCount);
        }
        return true;
    }

    /// @notice Simplified public autoBalance function.
    function autoBalancePublic() external returns (bool) {
        return autoBalance(new bytes[](0), new bytes[](0), new bytes32[](0), new uint256[](0));
    }

    /** NODE MANAGEMENT **/

    /// @notice Returns validators and status
    /// @notice Returns list of validators.
    /// @dev Max 10 results starting at page 0
    /// @param _page : Page to query.
    /// @return info Array for struct of nodes view
    /// @return totalPages supported.
    function getValidators(uint256 _page) external view returns (ValidatorView[] memory, uint256) {
        ValidatorView[] memory info = new ValidatorView[](10);
        uint256 pageSize = 10;
        uint256 length = validatorNonce;
        uint256 totalPages = length / pageSize;
        if (length > 0 && length % pageSize == 0) {
            totalPages--;
        }
        if (_page <= totalPages && length != 0) {
            for (uint256 i = 0; i < pageSize; i++) {
                uint256 index = length - _page * pageSize - i;
                Validator memory validator = validators[index];
                info[i] = ValidatorView({
                    id: index,
                    publicKey: validator.publicKey,
                    validatorType: validator.validatorType
                });
                if (index == 1) break;
            }
        }
        return (info, totalPages);
    }

    /** NETWORK ORACLES **/

    /// @notice Consensus layer oracle report on validators and balances.
    /// Called by the oracle service that consolidates all the signatures and data posted by oracles for a decided block.
    /// The frequency of the updates is decided by the oracle service.
    /// @param _reportBlock : block number of the report.
    /// @param _validatorsCount : Number of validators on Consensus Layer.
    /// @param _validatorsBalance: Total balance of active validators on Consensus Layer.
    /// @param _validatorsExited: Number of validators exited.
    /// @param _eigenLayerValidatorsExited: Number of validators exited part of EigenLayer.
    /// @param _maxNumberOfWithdrawalsToClaim: Triggers claims from EigenLayer.
    /// @param _withdrawalsDisabled: Whether withdrawals are disabled based on slashing conditions.
    /// @param _signatures : Signatures of the report from trusted oracles.
    function oracleReport(
        uint256 _reportBlock,
        uint256 _validatorsCount,
        uint256 _validatorsBalance,
        uint256 _validatorsExited,
        uint256 _eigenLayerValidatorsExited,
        uint256 _maxNumberOfWithdrawalsToClaim,
        bool _withdrawalsDisabled,
        bytes[] calldata _signatures
    ) external whenNotPaused nonReentrant {
        require(_reportBlock > oracleReportBlock, "Invalid report block");
        require(_validatorsCount <= validatorNonce, "Invalid validatorsCount");
        require(
            _validatorsExited <= validatorNonce && _validatorsExited >= exitedValidators,
            "Invalid validatorsExited"
        );
        require(_signatures.length >= oracleQuorum, "Invalid signatures length");
        require(address(clayMain) != address(0), "Claymain not set");

        // Verify signatures and quorum
        bytes32 signedHash = keccak256(
            abi.encodePacked(
                _reportBlock,
                _validatorsCount,
                _validatorsBalance,
                _validatorsExited,
                _eigenLayerValidatorsExited,
                _withdrawalsDisabled
            )
        ).toEthSignedMessageHash();
        for (uint256 i = 0; i < _signatures.length; i++) {
            require(_validateSignature(_reportBlock, signedHash, _signatures[i]), "Invalid Signature");
        }

        _oracleReport(
            _reportBlock,
            _validatorsCount,
            _validatorsBalance,
            _validatorsExited,
            _eigenLayerValidatorsExited,
            _maxNumberOfWithdrawalsToClaim,
            _withdrawalsDisabled
        );
    }

    /// @notice Internal implementation and update of rate.
    function _oracleReport(
        uint256 _reportBlock,
        uint256 _validatorsCount,
        uint256 _validatorsBalance,
        uint256 _validatorsExited,
        uint256 _eigenLayerValidatorsExited,
        uint256 _maxNumberOfWithdrawalsToClaim,
        bool _withdrawalsDisabled
    ) internal {
        // EigenLayer adjustments
        if (address(eigenPodManager) != address(0)) {
            // Claim
            if (_maxNumberOfWithdrawalsToClaim > 0) {
                claimEigenLayer(_maxNumberOfWithdrawalsToClaim);
            }

            // Start any EigenLayer withdraws
            uint256 balanceEigenLayer = _withdrawBeforeRestaking(_eigenLayerValidatorsExited);

            IDelayedWithdrawalRouter.UserDelayedWithdrawals memory queue = eigenDelayedWithdrawalRouter.userWithdrawals(
                address(this)
            );
            uint256 eigenLayerClaimed = queue.delayedWithdrawalsCompleted > 0
                ? eigenLayerExits[queue.delayedWithdrawalsCompleted - 1]
                : 0;
            uint256 eigenLayerExitedPending = _eigenLayerValidatorsExited - eigenLayerClaimed;

            // Adds back exited, for accounting and rewards, doesn't consider EigenLayer fully exited until claimed
            _validatorsBalance += balanceEigenLayer;
            _validatorsCount += eigenLayerExitedPending;
            _validatorsExited = _validatorsExited - eigenLayerExitedPending;
        }

        uint256 amountRewards = _validatorsBalance > _validatorsCount * DEPOSIT_SIZE
            ? _validatorsBalance - _validatorsCount * DEPOSIT_SIZE
            : 0;
        uint256 previousRewardsAccrued = rewardsAccrued;
        uint256 newExits = _validatorsExited - exitedValidators;

        // Update report
        oracleReportBlock = _reportBlock;
        activeValidators = _validatorsCount;
        activeValidatorsBalance = _validatorsBalance;
        exitedValidators = _validatorsExited;
        rewardsAccrued = amountRewards;

        // execute withdrawals disabling
        if (clayMain.withdrawalsDisabled() != _withdrawalsDisabled) {
            clayMain.setWithdrawalsDisabled(_withdrawalsDisabled);
        }

        // Adjust accrued rewards based on rewards on beacon chain
        if (nodeOperator != address(0)) {
            nodeOperatorAccruedFees = (amountRewards * nodeOperatorFees) / PERCENTAGE_BASE;
        }

        // Transfer balance to ClayMain and update it's contract tracker
        uint256 amountLiquid = address(this).balance;
        if (amountLiquid != 0) {
            uint256 amountExited = _min(amountLiquid, newExits * DEPOSIT_SIZE);
            uint256 amountLiquidRewards = amountLiquid - amountExited;
            uint256 totalRewards = amountRewards + amountLiquidRewards;
            uint256 amountNewRewards = _positiveSub(totalRewards, previousRewardsAccrued);
            uint256 amountNewLiquidRewards = _min(amountLiquidRewards, amountNewRewards);

            // Calculate Nodes rewards & distribute
            if (amountLiquidRewards > 0 && nodeOperator != address(0)) {
                uint256 amountNodeRewards = (amountLiquidRewards * nodeOperatorFees) / PERCENTAGE_BASE;
                uint256 amountNodeNewRewards = (amountNewLiquidRewards * nodeOperatorFees) / PERCENTAGE_BASE;
                amountLiquidRewards -= amountNodeRewards;
                amountLiquid -= amountNodeRewards;
                amountNewLiquidRewards -= amountNodeNewRewards;
                (bool success, ) = nodeOperator.call{value: amountNodeRewards}("");
                require(success, "Transfer of node rewards failed");
            }

            clayMain.receiveLiquidity{value: amountLiquid}(amountNewLiquidRewards, amountExited);
            emit LogLiquidityTransfer(_reportBlock, amountNewLiquidRewards, amountExited, amountLiquid);
        } else {
            clayMain.updateBalances();
        }

        // Close batches
        if (newExits != 0) _closeBatches(newExits);

        emit LogOracleReport(_reportBlock, _validatorsCount, _validatorsBalance, _validatorsExited);
    }

    /// @notice Validates oracle signature and records block voted on.
    /// @param _reportBlock : block number of the report.
    /// @param _signedHash : Hash of the report.
    /// @param _signature : Signature of the report.
    /// @return A boolean indicating whether the signature is valid.
    function _validateSignature(
        uint256 _reportBlock,
        bytes32 _signedHash,
        bytes memory _signature
    ) internal returns (bool) {
        address signer = _signedHash.recover(_signature);

        // check it's in the list
        if (!oracleWhitelist[signer]) return false;

        // check single vote and mark block
        if (oracleVotes[signer] >= _reportBlock) return false;

        oracleVotes[signer] = _reportBlock;
        emit LogOracleVote(_reportBlock, signer);

        return true;
    }

    /// @notice Closes batch confirmation sent to ClayMain.
    /// @param _newExits : Number of new exits.
    function _closeBatches(uint256 _newExits) internal {
        // determine which batches can be closed
        uint256 fulfilledBatches = 0;
        for (uint256 i = batchExitQueueFront; i < batchExitQueue.length; i++) {
            uint256 batchId = batchExitQueue[i];
            uint256 requestCount = batchExitRequests[batchId];
            if (requestCount <= _newExits) {
                // close batch
                fulfilledBatches++;
                _newExits -= requestCount;
            } else {
                // partial fulfill, update and break
                batchExitRequests[batchId] = requestCount - _newExits;
                break;
            }
            // no more exits, end loop
            if (_newExits <= 0) break;
        }

        // create output
        uint256[] memory batches = new uint256[](fulfilledBatches);
        for (uint256 i = 0; i < fulfilledBatches; i++) {
            batches[i] = _deleteBatchFromQueue();
        }

        clayMain.closeBatches(batches);
    }

    /// @notice Deletes first element from the batch exit queue.
    /// @return batchId The deleted element.
    function _deleteBatchFromQueue() internal returns (uint256 batchId) {
        require(batchExitQueue.length > batchExitQueueFront, "Queue is empty");
        batchId = batchExitQueue[batchExitQueueFront];
        delete batchExitQueue[batchExitQueueFront];
        batchExitQueueFront += 1;
    }

    /** EIGENLAYER **/

    /// @notice Update EigenPodManager address.
    /// @param _eigenPodManager : EigenPodManager address.
    /// @param _delayedWithdrawalRouter: DelayedWithdrawalRouter address.
    function setEigenLayer(
        address _eigenPodManager,
        address _delayedWithdrawalRouter
    ) external onlyRole(TIMELOCK_ROLE) {
        require(_eigenPodManager != address(0), "Invalid EigenPodManager");
        require(_delayedWithdrawalRouter != address(0), "Invalid DelayedWithdrawalRouter");

        eigenPodManager = IEigenPodManager(_eigenPodManager);
        eigenDelayedWithdrawalRouter = IDelayedWithdrawalRouter(_delayedWithdrawalRouter);

        emit LogSetEigenLayer(_eigenPodManager, _delayedWithdrawalRouter);
    }

    /// @notice Starts the delayed withdrawal process at EigenLayer and tracks how much in the process
    function _withdrawBeforeRestaking(uint256 _eigenLayerValidatorsExited) internal returns (uint256) {
        IEigenPod pod = eigenPodManager.getPod(address(this));
        uint256 balance = address(pod).balance;
        if (balance > 0) {
            // NOTE: index for "PAUSED_DELAYED_WITHDRAWAL_CLAIMS" is "0"
            bool withdrawBeforeActive = (pod.hasRestaked() == false) &&
                (IPausable(address(eigenDelayedWithdrawalRouter)).paused(0) == false);

            if (withdrawBeforeActive) {
                eigenLayerWithdraws += balance;
                pod.withdrawBeforeRestaking();

                // Connects total exits to the latest withdrawal
                IDelayedWithdrawalRouter.UserDelayedWithdrawals memory queue = eigenDelayedWithdrawalRouter
                    .userWithdrawals(address(this));
                eigenLayerExits[queue.delayedWithdrawals.length - 1] = _eigenLayerValidatorsExited;

                emit LogWithdrawBeforeRestaking(queue.delayedWithdrawals.length - 1);
                return eigenLayerWithdraws;
            } else {
                return eigenLayerWithdraws + balance;
            }
        }
        return eigenLayerWithdraws;
    }

    // @notice Claims and tracks claimed value
    function claimEigenLayer(uint256 maxNumberOfWithdrawalsToClaim) public {
        eigenDelayedWithdrawalRouter.claimDelayedWithdrawals(maxNumberOfWithdrawalsToClaim);
    }

    /** OTHER **/

    /// @notice Used for receiving payments
    receive() external payable {
        // Eigenlayer Claim Accounting
        if(msg.sender == address(eigenDelayedWithdrawalRouter)) {
            eigenLayerWithdraws -= msg.value;
            emit LogClaimEigenLayer(msg.value);
        }
    }

    /** BALANCES **/

    /// @notice Returns the balance of the contract accounting for pending staking.
    function getBalance() external view returns (uint256) {
        return activeValidatorsBalance + getPendingStaking() - nodeOperatorAccruedFees;
    }

    /// @notice Returns the pending staking amount assuming fixed size.
    function getPendingStaking() public view returns (uint256) {
        return (validatorNonce - activeValidators - exitedValidators) * DEPOSIT_SIZE;
    }

    /** ADMIN **/

    /// @notice Set minimum number of votes required for reporting.
    /// @dev By design an acceptable range from 1 to 100
    /// @param _newQuorum: New quorum.
    function setOracleQuorum(uint256 _newQuorum) external onlyRole(TIMELOCK_ROLE) {
        require(_newQuorum > 0 && _newQuorum <= 100, "Invalid quorum");
        emit LogSetOracleQuorum(oracleQuorum, _newQuorum);
        oracleQuorum = _newQuorum;
    }

    /// @notice Update oracle whitelist. The whitelist is set by Claystack service and gets updated depending on the performance and reliability of the oracles.
    /// @param _list : list of Oracle addresses.
    /// @param _flag : boolean for addition or removal.
    function setOracleWhitelist(address[] calldata _list, bool _flag) external onlyRole(TIMELOCK_ROLE) {
        require(_list.length > 0, "Invalid list length");
        for (uint256 i = 0; i < _list.length; i++) {
            require(_list[i] != address(0), "Zero Address");
            oracleWhitelist[_list[i]] = _flag;
            emit LogSetOracleWhitelist(_list[i], _flag);
        }
    }

    /// @notice Update autobalance caller whitelist.
    /// @param _list : list of autobalance caller addresses.
    /// @param _flag : boolean for addition or removal.
    function setAutoBalanceWhitelist(address[] calldata _list, bool _flag) external onlyRole(TIMELOCK_ROLE) {
        require(_list.length > 0, "Invalid list length");
        for (uint256 i = 0; i < _list.length; i++) {
            require(_list[i] != address(0), "Zero Address");
            autobalanceWhitelist[_list[i]] = _flag;
            emit LogSetAutoBalanceWhitelist(_list[i], _flag);
        }
    }

    /// @notice Update node operator fees.
    /// @param _fees : new node operator fees.
    function setNodeOperatorFees(uint256 _fees) external onlyRole(TIMELOCK_ROLE) {
        require(_fees <= MAX_NODE_OPERATOR_FEES, "Invalid nodeOperatorFees");
        emit LogSetNodeOperatorFees(nodeOperatorFees, _fees);
        nodeOperatorFees = _fees;
    }

    /// @notice Sets `_clayMain` address.
    /// @dev ClayMain can be set only once.
    /// @param _clayMain : Address of new ClayMain contract.
    function setClayMain(address _clayMain) external onlyRole(TIMELOCK_UPGRADES_ROLE) {
        require(_clayMain != address(0), "Invalid ClayMain");
        clayMain = IClayMain(_clayMain);
        emit LogSetClayMain(_clayMain);
    }

    /// @notice Update node operator address.
    /// @param _nodeOperator : new node operator address.
    function setNodeOperator(address _nodeOperator) external onlyRole(TIMELOCK_ROLE) {
        require(_nodeOperator != address(0), "Invalid nodeOperator");
        nodeOperator = _nodeOperator;
        emit LogSetNodeOperator(_nodeOperator);
    }

    /** SUPPORT **/

    /// @dev returns the smaller number between a and b
    function _min(uint256 _a, uint256 _b) internal pure returns (uint256) {
        return _a > _b ? _b : _a;
    }

    /// @dev Returns the positive difference  between x & y
    function _positiveSub(uint256 x, uint256 y) internal pure returns (uint256) {
        if (x < y) {
            return 0;
        } else {
            return x - y;
        }
    }

    /// @notice Triggers stopped state.
    function pause() external onlyRole(CS_SERVICE_ROLE) whenNotPaused {
        _pause();
    }

    /// @notice Returns to normal state.
    function unpause() external onlyRole(CS_SERVICE_ROLE) whenPaused {
        _unpause();
    }

    /// @notice Checks caller has the given `_roleName` or not.
    /// @param _roleName supported by RoleManager
    function _onlyRole(bytes32 _roleName) internal view {
        require(roleManager.checkRole(_roleName, msg.sender), "Auth Failed");
    }

    /// @notice Upgrade the implementation of the proxy to `_newImplementation`.
    /// @param _newImplementation : Address of new implementation of the contract
    function upgradeTo(
        address _newImplementation
    ) external virtual override onlyRole(TIMELOCK_UPGRADES_ROLE) onlyProxy {
        _authorizeUpgrade(_newImplementation);
        _upgradeTo(_newImplementation);
    }

    /// @notice Function that should revert when `msg.sender` is not authorized to upgrade the contract or
    /// @param _newImplementation : Address of new implementation of the contract.
    function _authorizeUpgrade(address _newImplementation) internal virtual override onlyRole(TIMELOCK_UPGRADES_ROLE) {
        require(_newImplementation.code.length > 0, "!contract");
    }
}

Contract Security Audit

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beacon","type":"address"}],"name":"BeaconUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"claimedAmount","type":"uint256"}],"name":"LogClaimEigenLayer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"validatorId","type":"uint256"},{"indexed":true,"internalType":"bytes","name":"publicKey","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"validatorType","type":"uint256"}],"name":"LogDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"reportBlockNumber","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountRewards","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountExited","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountLiquid","type":"uint256"}],"name":"LogLiquidityTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"reportBlockNumber","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"validatorsCount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"validatorsBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"validatorsExited","type":"uint256"}],"name":"LogOracleReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"reportBlockNumber","type":"uint256"},{"indexed":true,"internalType":"address","name":"oracle","type":"address"}],"name":"LogOracleVote","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes","name":"publicKey","type":"bytes"},{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"LogPreDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"validatorId","type":"uint256"},{"indexed":true,"internalType":"bytes","name":"publicKey","type":"bytes"},{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"LogPreDepositRefund","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"bool","name":"flag","type":"bool"}],"name":"LogSetAutoBalanceWhitelist","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newClaymain","type":"address"}],"name":"LogSetClayMain","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"eigenPodManager","type":"address"},{"indexed":true,"internalType":"address","name":"delayedWithdrawalRouter","type":"address"}],"name":"LogSetEigenLayer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newNodeOperator","type":"address"}],"name":"LogSetNodeOperator","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFee","type":"uint256"}],"name":"LogSetNodeOperatorFees","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldQuorum","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newQuorum","type":"uint256"}],"name":"LogSetOracleQuorum","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oracle","type":"address"},{"indexed":true,"internalType":"bool","name":"flag","type":"bool"}],"name":"LogSetOracleWhitelist","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"batchId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"withdrawCount","type":"uint256"}],"name":"LogWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"delayedWithdrawalIndex","type":"uint256"}],"name":"LogWithdrawBeforeRestaking","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"activeValidators","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"activeValidatorsBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"_publicKey","type":"bytes[]"},{"internalType":"bytes[]","name":"_signature","type":"bytes[]"},{"internalType":"bytes32[]","name":"_deposit_data_root","type":"bytes32[]"},{"internalType":"uint256[]","name":"_validatorType","type":"uint256[]"}],"name":"autoBalance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"autoBalancePublic","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"autobalanceWhitelist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"batchExitQueue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"batchExitQueueFront","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"batchExitRequests","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxNumberOfWithdrawalsToClaim","type":"uint256"}],"name":"claimEigenLayer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"clayMain","outputs":[{"internalType":"contract IClayMain","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"eigenLayerExits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"eigenLayerWithdraws","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"exitRequestsCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"exitedValidators","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPendingStaking","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_page","type":"uint256"}],"name":"getValidators","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"publicKey","type":"bytes"},{"internalType":"uint256","name":"validatorType","type":"uint256"}],"internalType":"struct INodeManager.ValidatorView[]","name":"","type":"tuple[]"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_roleManager","type":"address"},{"internalType":"address","name":"_depositContract","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nodeOperator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nodeOperatorAccruedFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nodeOperatorFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oracleQuorum","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_reportBlock","type":"uint256"},{"internalType":"uint256","name":"_validatorsCount","type":"uint256"},{"internalType":"uint256","name":"_validatorsBalance","type":"uint256"},{"internalType":"uint256","name":"_validatorsExited","type":"uint256"},{"internalType":"uint256","name":"_eigenLayerValidatorsExited","type":"uint256"},{"internalType":"uint256","name":"_maxNumberOfWithdrawalsToClaim","type":"uint256"},{"internalType":"bool","name":"_withdrawalsDisabled","type":"bool"},{"internalType":"bytes[]","name":"_signatures","type":"bytes[]"}],"name":"oracleReport","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"oracleReportBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"oracleVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"oracleWhitelist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"_publicKey","type":"bytes[]"},{"internalType":"bytes[]","name":"_signature","type":"bytes[]"},{"internalType":"bytes32[]","name":"_deposit_data_root","type":"bytes32[]"}],"name":"preDeposit","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"}],"name":"preDepositOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"preDepositsAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"}],"name":"registeredValidator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsAccrued","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_list","type":"address[]"},{"internalType":"bool","name":"_flag","type":"bool"}],"name":"setAutoBalanceWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_clayMain","type":"address"}],"name":"setClayMain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_eigenPodManager","type":"address"},{"internalType":"address","name":"_delayedWithdrawalRouter","type":"address"}],"name":"setEigenLayer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_nodeOperator","type":"address"}],"name":"setNodeOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fees","type":"uint256"}],"name":"setNodeOperatorFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newQuorum","type":"uint256"}],"name":"setOracleQuorum","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_list","type":"address[]"},{"internalType":"bool","name":"_flag","type":"bool"}],"name":"setOracleWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newImplementation","type":"address"}],"name":"upgradeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"validatorNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"validators","outputs":[{"internalType":"bytes","name":"publicKey","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"validatorType","type":"uint256"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

60a06040523060805234801561001457600080fd5b50608051614e1961005a60003960008181610aca01528181610b13015281816113050152818161134501528181611e8f01528181611ecf0152611f470152614e196000f3fe6080604052600436106102815760003560e01c806365577c551161014f578063a33a7d53116100c1578063b20257791161007a578063b20257791461082e578063b5a561fc14610845578063b8c226071461085c578063d2d49c4b14610873578063e17a684f1461088a578063fce4deab146108a057600080fd5b8063a33a7d5314610758578063a465ff1214610778578063a55461be146107a9578063a8158f65146107d7578063aa4a0d39146107ee578063b1fe93101461080e57600080fd5b80638456cb59116101135780638456cb59146106b05780638e03ac8d146106c5578063907a587b146106dc5780639266799a146106f3578063956041971461070a578063974fb7b31461073857600080fd5b806365577c551461060d57806368a80b4314610624578063747c17171461063757806378ea2dd9146106795780638357ed421461069057600080fd5b806343981753116101f35780634f1ef286116101ac5780634f1ef28614610543578063523f49461461055657806352d1902d146105925780635347f96e146105a75780635c975abb146105d55780635d1e7a59146105ed57600080fd5b8063439817531461048957806343ebf50a1461049e578063471f40fb146104be578063478e61aa146104ec578063485cc955146105035780634aa3a34e1461052357600080fd5b806335aa2e441161024557806335aa2e44146103ce5780633659cfe6146103fd5780633882b1c91461041d5780633d1ebf35146104345780633f2cf0b1146104545780633f4ba83a1461047457600080fd5b8063023c5b08146102ec57806312065fe01461032a57806326517d901461034d57806331b46e671461036d578063323f34431461038d57600080fd5b366102e757610114546001600160a01b031633036102e5573461011560008282546102ac91906140d9565b90915550506040513481527f239494018d16a74ebf338493b53d9f2a6ad0992e071b7ace15ccd561981bf1dd9060200160405180910390a15b005b600080fd5b3480156102f857600080fd5b5061010e5461030d906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561033657600080fd5b5061033f6108b5565b604051908152602001610321565b34801561035957600080fd5b5061033f6103683660046140ec565b6108e0565b34801561037957600080fd5b506102e56103883660046140ec565b610902565b34801561039957600080fd5b506103be6103a836600461411a565b61010b6020526000908152604090205460ff1681565b6040519015158152602001610321565b3480156103da57600080fd5b506103ee6103e93660046140ec565b610964565b60405161032193929190614187565b34801561040957600080fd5b506102e561041836600461411a565b610a96565b34801561042957600080fd5b5061033f6101015481565b34801561044057600080fd5b506102e561044f3660046141bd565b610b7f565b34801561046057600080fd5b506102e561046f366004614248565b610ca4565b34801561048057600080fd5b506102e5610e3e565b34801561049557600080fd5b506103be610e7b565b3480156104aa57600080fd5b506102e56104b93660046140ec565b610ef3565b3480156104ca57600080fd5b506104de6104d93660046140ec565b610fa1565b60405161032192919061429e565b3480156104f857600080fd5b5061033f6101055481565b34801561050f57600080fd5b506102e561051e3660046141bd565b61123b565b34801561052f57600080fd5b506103be61053e36600461450f565b6114e0565b6102e561055136600461460e565b611e85565b34801561056257600080fd5b506103be61057136600461465d565b80516020818301810180516101068252928201919093012091525460ff1681565b34801561059e57600080fd5b5061033f611f3a565b3480156105b357600080fd5b5061033f6105c236600461411a565b61010c6020526000908152604090205481565b3480156105e157600080fd5b5060975460ff166103be565b3480156105f957600080fd5b506102e56106083660046140ec565b611fed565b34801561061957600080fd5b5061033f6101105481565b6103be610632366004614691565b612097565b34801561064357600080fd5b5061030d61065236600461465d565b8051602081830181018051610111825292820191909301209152546001600160a01b031681565b34801561068557600080fd5b5061033f61010d5481565b34801561069c57600080fd5b506102e56106ab366004614248565b6124a0565b3480156106bc57600080fd5b506102e561263a565b3480156106d157600080fd5b5061033f6101005481565b3480156106e857600080fd5b5061033f6101155481565b3480156106ff57600080fd5b5061033f6101125481565b34801561071657600080fd5b5061033f6107253660046140ec565b6101076020526000908152604090205481565b34801561074457600080fd5b506102e561075336600461411a565b612674565b34801561076457600080fd5b5060fc5461030d906001600160a01b031681565b34801561078457600080fd5b506103be61079336600461411a565b61010a6020526000908152604090205460ff1681565b3480156107b557600080fd5b5061033f6107c43660046140ec565b6101166020526000908152604090205481565b3480156107e357600080fd5b5061033f6101045481565b3480156107fa57600080fd5b506102e5610809366004614718565b612725565b34801561081a57600080fd5b506102e561082936600461411a565b612a44565b34801561083a57600080fd5b5061033f6101035481565b34801561085157600080fd5b5061033f6101095481565b34801561086857600080fd5b5061033f61010f5481565b34801561087f57600080fd5b5061033f6101025481565b34801561089657600080fd5b5061033f60ff5481565b3480156108ac57600080fd5b5061033f612b02565b6000610110546108c3612b02565b610103546108d191906147aa565b6108db91906140d9565b905090565b61010881815481106108f157600080fd5b600091825260209091200154905081565b61011454604051636a270dbb60e11b8152600481018390526001600160a01b039091169063d44e1b7690602401600060405180830381600087803b15801561094957600080fd5b505af115801561095d573d6000803e3d6000fd5b5050505050565b60fe6020526000908152604090208054819061097f906147bd565b80601f01602080910402602001604051908101604052809291908181526020018280546109ab906147bd565b80156109f85780601f106109cd576101008083540402835291602001916109f8565b820191906000526020600020905b8154815290600101906020018083116109db57829003601f168201915b505050505090806001018054610a0d906147bd565b80601f0160208091040260200160405190810160405280929190818152602001828054610a39906147bd565b8015610a865780601f10610a5b57610100808354040283529160200191610a86565b820191906000526020600020905b815481529060010190602001808311610a6957829003601f168201915b5050505050908060020154905083565b7fb8ea7c31de614c54f5b3938aa9732e87deb869a880ec52d4bb778c09789441b1610ac081612b37565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003610b115760405162461bcd60e51b8152600401610b08906147f1565b60405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610b43612be4565b6001600160a01b031614610b695760405162461bcd60e51b8152600401610b089061483d565b610b7282612c00565b610b7b82612c70565b5050565b600080516020614d7d833981519152610b9781612b37565b6001600160a01b038316610bed5760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420456967656e506f644d616e616765720000000000000000006044820152606401610b08565b6001600160a01b038216610c435760405162461bcd60e51b815260206004820152601f60248201527f496e76616c69642044656c617965645769746864726177616c526f75746572006044820152606401610b08565b61011380546001600160a01b03199081166001600160a01b0386811691821790935561011480549092169285169283179091556040517f02a8f2ee3a37fb50b19f6b965301f3d567f9d0d7001b4df74d926f2870bc355790600090a3505050565b600080516020614d7d833981519152610cbc81612b37565b82610cff5760405162461bcd60e51b8152602060048201526013602482015272092dcecc2d8d2c840d8d2e6e840d8cadccee8d606b1b6044820152606401610b08565b60005b8381101561095d576000858583818110610d1e57610d1e614889565b9050602002016020810190610d33919061411a565b6001600160a01b031603610d785760405162461bcd60e51b815260206004820152600c60248201526b5a65726f204164647265737360a01b6044820152606401610b08565b8261010b6000878785818110610d9057610d90614889565b9050602002016020810190610da5919061411a565b6001600160a01b031681526020810191909152604001600020805460ff1916911515919091179055821515858583818110610de257610de2614889565b9050602002016020810190610df7919061411a565b6001600160a01b03167f37db4d805bae1ff00af5ccce3625706c8bc4181c0f0577c5d3715765e71edd8360405160405180910390a380610e368161489f565b915050610d02565b7f70afc91226fba57efa6b459a2add00f29a9a7961e6eb3103074a44780ab8cdc8610e6881612b37565b610e70612cb0565b610e78612cfb565b50565b604080516000808252602082019092526108db9082610eaa565b6060815260200190600190039081610e955790505b506040805160008082526020820190925290610ed6565b6060815260200190600190039081610ec15790505b5060408051600080825260208201908152818301909252906114e0565b600080516020614d7d833981519152610f0b81612b37565b6107d0821115610f5d5760405162461bcd60e51b815260206004820152601860248201527f496e76616c6964206e6f64654f70657261746f724665657300000000000000006044820152606401610b08565b61010f5460408051918252602082018490527fb1e342ac4a9cc386141d1bbc96e62081e34d521bdd7671a2dfe9b07424babd4b910160405180910390a15061010f55565b60408051600a80825261016082019092526060916000918291816020015b610fe360405180606001604052806000815260200160608152602001600081525090565b815260200190600190039081610fbf57505060ff54909150600a90600061100a83836148ce565b9050600082118015611023575061102183836148e2565b155b156110365780611032816148f6565b9150505b80871115801561104557508115155b1561122e5760005b8381101561122c57600081611062868b61490d565b61106c90866140d9565b61107691906140d9565b9050600060fe60008381526020019081526020016000206040518060600160405290816000820180546110a8906147bd565b80601f01602080910402602001604051908101604052809291908181526020018280546110d4906147bd565b80156111215780601f106110f657610100808354040283529160200191611121565b820191906000526020600020905b81548152906001019060200180831161110457829003601f168201915b5050505050815260200160018201805461113a906147bd565b80601f0160208091040260200160405190810160405280929190818152602001828054611166906147bd565b80156111b35780601f10611188576101008083540402835291602001916111b3565b820191906000526020600020905b81548152906001019060200180831161119657829003601f168201915b50505050508152602001600282015481525050905060405180606001604052808381526020018260000151815260200182604001518152508784815181106111fd576111fd614889565b60200260200101819052508160010361121757505061122c565b505080806112249061489f565b91505061104d565b505b9296929550919350505050565b600054610100900460ff161580801561125b5750600054600160ff909116105b806112755750303b158015611275575060005460ff166001145b6112d85760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610b08565b6000805460ff1916600117905580156112fb576000805461ff0019166101001790555b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036113435760405162461bcd60e51b8152600401610b08906147f1565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316611375612be4565b6001600160a01b03161461139b5760405162461bcd60e51b8152600401610b089061483d565b6001600160a01b0383166113f15760405162461bcd60e51b815260206004820152601b60248201527f496e76616c696420726f6c654d616e61676572206164647265737300000000006044820152606401610b08565b6001600160a01b0382166114475760405162461bcd60e51b815260206004820152601f60248201527f496e76616c6964206465706f736974436f6e74726163742061646472657373006044820152606401610b08565b61144f612d4d565b611457612d7c565b61145f612dab565b60fb80546001600160a01b038086166001600160a01b03199283161790925560fd805492851692909116919091179055600161010d5580156114db576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b60006114ea612dd2565b6114f2612e18565b83518551148015611504575082518551145b8015611511575081518551145b6115555760405162461bcd60e51b8152602060048201526015602482015274496e76616c696420706172616d206c656e6774687360581b6044820152606401610b08565b60fc546001600160a01b03166115a05760405162461bcd60e51b815260206004820152601060248201526f10db185e5b585a5b881b9bdd081cd95d60821b6044820152606401610b08565b84511561168e5760fb546040516312d9a6ad60e01b81527f70afc91226fba57efa6b459a2add00f29a9a7961e6eb3103074a44780ab8cdc860048201523360248201526001600160a01b03909116906312d9a6ad90604401602060405180830381865afa158015611615573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116399190614924565b80611654575033600090815261010b602052604090205460ff165b61168e5760405162461bcd60e51b815260206004820152600b60248201526a105d5d1a0811985a5b195960aa1b6044820152606401610b08565b60fc548551604051637e70d9c560e01b81526004810191909152600091829182916001600160a01b031690637e70d9c5906024016060604051808303816000875af11580156116e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117059190614941565b9250925092508180156117185750600081115b15611d625760ff5460005b82811015611d59576101068a828151811061174057611740614889565b6020026020010151604051611755919061497a565b9081526040519081900360200190205460ff16156117b55760405162461bcd60e51b815260206004820152601c60248201527f7075626c69634b657920616c72656164792072656769737465726564000000006044820152606401610b08565b6117be8261489f565b915060405180606001604052808b83815181106117dd576117dd614889565b602002602001015181526020018a83815181106117fc576117fc614889565b6020026020010151815260200188838151811061181b5761181b614889565b602090810291909101810151909152600084815260fe909152604090208151819061184690826149e4565b506020820151600182019061185b90826149e4565b506040820151816002015590505060016101068b838151811061188057611880614889565b6020026020010151604051611895919061497a565b908152602001604051809103902060006101000a81548160ff02191690831515021790555060006101118b83815181106118d1576118d1614889565b60200260200101516040516118e6919061497a565b908152604051908190036020019020546001600160a01b031690506000811561191757670de0b6b3a764000061191a565b60005b9050600a89848151811061193057611930614889565b602002602001015103611aaa57610113546001600160a01b03166119965760405162461bcd60e51b815260206004820152601760248201527f456967656e506f644d616e61676572206e6f74207365740000000000000000006044820152606401610b08565b80156119e45760405162461bcd60e51b815260206004820152601b60248201527f456967656e506f64204d312052657175697265732033322045544800000000006044820152606401610b08565b610113548c516001600160a01b0390911690639b4e4634906801bc16d674ec800000908f9087908110611a1957611a19614889565b60200260200101518e8781518110611a3357611a33614889565b60200260200101518e8881518110611a4d57611a4d614889565b60200260200101516040518563ffffffff1660e01b8152600401611a7393929190614187565b6000604051808303818588803b158015611a8c57600080fd5b505af1158015611aa0573d6000803e3d6000fd5b5050505050611b9a565b60fd546001600160a01b03166322895118611ace836801bc16d674ec8000006140d9565b8e8681518110611ae057611ae0614889565b6020026020010151600160f81b600060a81b30604051602001611b0593929190614aa3565b6040516020818303038152906040528f8881518110611b2657611b26614889565b60200260200101518f8981518110611b4057611b40614889565b60200260200101516040518663ffffffff1660e01b8152600401611b679493929190614ae1565b6000604051808303818588803b158015611b8057600080fd5b505af1158015611b94573d6000803e3d6000fd5b50505050505b8015611cc2576000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114611bed576040519150601f19603f3d011682016040523d82523d6000602084013e611bf2565b606091505b5050905080611c435760405162461bcd60e51b815260206004820152601e60248201527f5472616e73666572206f66207072652d6465706f736974206661696c656400006044820152606401610b08565b816101126000828254611c5691906140d9565b92505081905550826001600160a01b03168d8581518110611c7957611c79614889565b6020026020010151604051611c8e919061497a565b6040519081900381209087907fa9600995f0aabc7cf77040d60ec36eb9ed073c47abfe0717fa47ca4c3df692a590600090a4505b8b8381518110611cd457611cd4614889565b6020026020010151604051611ce9919061497a565b6040518091039020847f3424df4338b4478ef58d99493e4ed96927ec2c63beec8d9de1d410a8b351acf18b8681518110611d2557611d25614889565b6020026020010151604051611d3c91815260200190565b60405180910390a350508080611d519061489f565b915050611723565b5060ff55611e6c565b81158015611d705750600081115b15611e6c576000838152610107602052604090205415611dd25760405162461bcd60e51b815260206004820152601760248201527f426174636820616c7265616479207265717565737465640000000000000000006044820152606401610b08565b806101006000828254611de591906147aa565b909155505060008381526101076020526040808220839055610108805460018101825592527f8543e9adbfbe1f62b7411fdf032fcfea758a7d6b332f64d971a1334c2ff364dd9091018490555183907f210405eb88ac7589aa9de0a6e36b9c9d3cd6e4061b74363d250a77afe3c6efb790611e639084815260200190565b60405180910390a25b60019350505050611e7d600160c955565b949350505050565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003611ecd5760405162461bcd60e51b8152600401610b08906147f1565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316611eff612be4565b6001600160a01b031614611f255760405162461bcd60e51b8152600401610b089061483d565b611f2e82612c00565b610b7b82826001612e78565b6000306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611fda5760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401610b08565b50600080516020614d9d83398151915290565b600080516020614d7d83398151915261200581612b37565b600082118015612016575060648211155b6120535760405162461bcd60e51b815260206004820152600e60248201526d496e76616c69642071756f72756d60901b6044820152606401610b08565b61010d5460408051918252602082018490527fd7916aef7cb7f069c87c44c871962132fdd6653e603c7180377b7226b1a5506d910160405180910390a15061010d55565b60006120a1612dd2565b6120a9612e18565b825184511480156120bb575081518451145b80156120c8575060008451115b61210c5760405162461bcd60e51b8152602060048201526015602482015274496e76616c696420706172616d206c656e6774687360581b6044820152606401610b08565b835161212090670de0b6b3a764000061490d565b34146121855760405162461bcd60e51b815260206004820152602e60248201527f7072654465706f7369742076616c7565206d757374206265203120657468657260448201526d103832b9103b30b634b230ba37b960911b6064820152608401610b08565b60005b8451811015612472576101068582815181106121a6576121a6614889565b60200260200101516040516121bb919061497a565b9081526040519081900360200190205460ff161561221b5760405162461bcd60e51b815260206004820152601c60248201527f7075626c69634b657920616c72656164792072656769737465726564000000006044820152606401610b08565b60006001600160a01b031661011186838151811061223b5761223b614889565b6020026020010151604051612250919061497a565b908152604051908190036020019020546001600160a01b0316146122b65760405162461bcd60e51b815260206004820152601f60248201527f7075626c69634b657920616c7265616479207072652d6465706f7369746564006044820152606401610b08565b60fd5485516001600160a01b0390911690632289511890670de0b6b3a7640000908890859081106122e9576122e9614889565b6020026020010151600160f81b600060a81b3060405160200161230e93929190614aa3565b60405160208183030381529060405288868151811061232f5761232f614889565b602002602001015188878151811061234957612349614889565b60200260200101516040518663ffffffff1660e01b81526004016123709493929190614ae1565b6000604051808303818588803b15801561238957600080fd5b505af115801561239d573d6000803e3d6000fd5b5050505050336101118683815181106123b8576123b8614889565b60200260200101516040516123cd919061497a565b908152602001604051809103902060006101000a8154816001600160a01b0302191690836001600160a01b03160217905550336001600160a01b031685828151811061241b5761241b614889565b6020026020010151604051612430919061497a565b604051908190038120907f306a11966d026aa41af5f696c416464d527e1b8539d6b1db76a5a3298703720e90600090a38061246a8161489f565b915050612188565b5034610112600082825461248691906147aa565b909155506001915050612499600160c955565b9392505050565b600080516020614d7d8339815191526124b881612b37565b826124fb5760405162461bcd60e51b8152602060048201526013602482015272092dcecc2d8d2c840d8d2e6e840d8cadccee8d606b1b6044820152606401610b08565b60005b8381101561095d57600085858381811061251a5761251a614889565b905060200201602081019061252f919061411a565b6001600160a01b0316036125745760405162461bcd60e51b815260206004820152600c60248201526b5a65726f204164647265737360a01b6044820152606401610b08565b8261010a600087878581811061258c5761258c614889565b90506020020160208101906125a1919061411a565b6001600160a01b031681526020810191909152604001600020805460ff19169115159190911790558215158585838181106125de576125de614889565b90506020020160208101906125f3919061411a565b6001600160a01b03167fdf67d94eba45581175e628d76b5e5058cf811bb243dfa6627fd46b8465234e6260405160405180910390a3806126328161489f565b9150506124fe565b7f70afc91226fba57efa6b459a2add00f29a9a7961e6eb3103074a44780ab8cdc861266481612b37565b61266c612dd2565b610e78612fe3565b600080516020614d7d83398151915261268c81612b37565b6001600160a01b0382166126d95760405162461bcd60e51b815260206004820152601460248201527324b73b30b634b2103737b232a7b832b930ba37b960611b6044820152606401610b08565b61010e80546001600160a01b0319166001600160a01b0384169081179091556040517f826392384452e326ae3357d613e8f331be7a57fc88379826286d982f1261b46d90600090a25050565b61272d612dd2565b612735612e18565b61010554891161277e5760405162461bcd60e51b8152602060048201526014602482015273496e76616c6964207265706f727420626c6f636b60601b6044820152606401610b08565b60ff548811156127d05760405162461bcd60e51b815260206004820152601760248201527f496e76616c69642076616c696461746f7273436f756e740000000000000000006044820152606401610b08565b60ff5486111580156127e55750610101548610155b6128315760405162461bcd60e51b815260206004820152601860248201527f496e76616c69642076616c696461746f727345786974656400000000000000006044820152606401610b08565b61010d548110156128845760405162461bcd60e51b815260206004820152601960248201527f496e76616c6964207369676e617475726573206c656e677468000000000000006044820152606401610b08565b60fc546001600160a01b03166128cf5760405162461bcd60e51b815260206004820152601060248201526f10db185e5b585a5b881b9bdd081cd95d60821b6044820152606401610b08565b6040805160208082018c90528183018b9052606082018a90526080820189905260a0820188905285151560f81b60c0830152825160a181840301815260c1830184528051908201207f19457468657265756d205369676e6564204d6573736167653a0a33320000000060e184015260fd808401919091528351808403909101815261011d909201909252805191012060005b82811015612a1e576129cc8b8386868581811061298057612980614889565b90506020028101906129929190614b2c565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061302092505050565b612a0c5760405162461bcd60e51b8152602060048201526011602482015270496e76616c6964205369676e617475726560781b6044820152606401610b08565b80612a168161489f565b915050612961565b50612a2e8a8a8a8a8a8a8a6130d2565b50612a39600160c955565b505050505050505050565b7fb8ea7c31de614c54f5b3938aa9732e87deb869a880ec52d4bb778c09789441b1612a6e81612b37565b6001600160a01b038216612ab75760405162461bcd60e51b815260206004820152601060248201526f24b73b30b634b21021b630bca6b0b4b760811b6044820152606401610b08565b60fc80546001600160a01b0319166001600160a01b0384169081179091556040517f104a66f1cbeb1a854e33542efdf4cab6dd7bd309067e996a7c9cd2bb5c082b8390600090a25050565b60006801bc16d674ec800000610101546101025460ff54612b2391906140d9565b612b2d91906140d9565b6108db919061490d565b60fb546040516312d9a6ad60e01b8152600481018390523360248201526001600160a01b03909116906312d9a6ad90604401602060405180830381865afa158015612b86573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612baa9190614924565b610e785760405162461bcd60e51b815260206004820152600b60248201526a105d5d1a0811985a5b195960aa1b6044820152606401610b08565b600080516020614d9d833981519152546001600160a01b031690565b7fb8ea7c31de614c54f5b3938aa9732e87deb869a880ec52d4bb778c09789441b1612c2a81612b37565b6000826001600160a01b03163b11610b7b5760405162461bcd60e51b81526020600482015260096024820152680858dbdb9d1c9858dd60ba1b6044820152606401610b08565b612c7981613688565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60975460ff16612cf95760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610b08565b565b612d03612cb0565b6097805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b600054610100900460ff16612d745760405162461bcd60e51b8152600401610b0890614b72565b612cf9613724565b600054610100900460ff16612da35760405162461bcd60e51b8152600401610b0890614b72565b612cf9613757565b600054610100900460ff16612cf95760405162461bcd60e51b8152600401610b0890614b72565b60975460ff1615612cf95760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610b08565b600260c95403612e6a5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610b08565b600260c955565b600160c955565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615612eab576114db83613688565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015612f05575060408051601f3d908101601f19168201909252612f0291810190614bbd565b60015b612f685760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610b08565b600080516020614d9d8339815191528114612fd75760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610b08565b506114db83838361377e565b612feb612dd2565b6097805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258612d303390565b60008061302d84846137a9565b6001600160a01b038116600090815261010a602052604090205490915060ff1661305b576000915050612499565b6001600160a01b038116600090815261010c60205260409020548511613085576000915050612499565b6001600160a01b038116600081815261010c60205260408082208890555187917e4a0156b3be77c48016f4bd6f1dcb3d729680a091d3889629370a973475d75d91a3506001949350505050565b610113546001600160a01b0316156131ea5781156130f3576130f382610902565b60006130fe846137cf565b6101145460405163ecb7cb1b60e01b81523060048201529192506000916001600160a01b039091169063ecb7cb1b90602401600060405180830381865afa15801561314d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526131759190810190614bd6565b905060008082600001511161318b5760006131b1565b6101166000600184600001516131a191906140d9565b8152602001908152602001600020545b905060006131bf82886140d9565b90506131cb848a6147aa565b98506131d7818b6147aa565b99506131e381896140d9565b9750505050505b60006131ff6801bc16d674ec8000008861490d565b861161320c576000613229565b61321f6801bc16d674ec8000008861490d565b61322990876140d9565b61010454610101549192509060009061324290886140d9565b6101058b90556101028a905561010389905561010188905561010484905560fc54604080516344573f9760e11b81529051929350861515926001600160a01b03909216916388ae7f2e916004818101926020929091908290030181865afa1580156132b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132d59190614924565b15151461333c5760fc54604051630a54644f60e21b815285151560048201526001600160a01b0390911690632951913c90602401600060405180830381600087803b15801561332357600080fd5b505af1158015613337573d6000803e3d6000fd5b505050505b61010e546001600160a01b03161561336f5761271061010f5484613360919061490d565b61336a91906148ce565b610110555b4780156135bb5760006133948261338f6801bc16d674ec8000008661490d565b613ab2565b905060006133a282846140d9565b905060006133b082886147aa565b905060006133be8288613ac7565b905060006133cc8483613ab2565b90506000841180156133e9575061010e546001600160a01b031615155b156134fd57600061271061010f5486613402919061490d565b61340c91906148ce565b9050600061271061010f5484613422919061490d565b61342c91906148ce565b905061343882876140d9565b955061344482896140d9565b975061345081846140d9565b61010e546040519194506000916001600160a01b039091169084908381818185875af1925050503d80600081146134a3576040519150601f19603f3d011682016040523d82523d6000602084013e6134a8565b606091505b50509050806134f95760405162461bcd60e51b815260206004820152601f60248201527f5472616e73666572206f66206e6f64652072657761726473206661696c6564006044820152606401610b08565b5050505b60fc5460405163070f0b8960e21b815260048101839052602481018790526001600160a01b0390911690631c3c2e249088906044016000604051808303818588803b15801561354b57600080fd5b505af115801561355f573d6000803e3d6000fd5b50505050508f7f1947dd35f2ad7cfad67d80241fe2f032f18b67bf60792d5f9132dac5817527cb8287896040516135a9939291909283526020830191909152604082015260600190565b60405180910390a25050505050613624565b60fc60009054906101000a90046001600160a01b03166001600160a01b0316636f3fe4046040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561360b57600080fd5b505af115801561361f573d6000803e3d6000fd5b505050505b81156136335761363382613aea565b604080518c8152602081018c90529081018a9052606081018990527f7a4a8ff550d096ae3e71e1c79680b17560ea3076ff95d4666ab60c0ef5308a569060800160405180910390a15050505050505050505050565b6001600160a01b0381163b6136f55760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610b08565b600080516020614d9d83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b600054610100900460ff1661374b5760405162461bcd60e51b8152600401610b0890614b72565b6097805460ff19169055565b600054610100900460ff16612e715760405162461bcd60e51b8152600401610b0890614b72565b61378783612c70565b6000825111806137945750805b156114db576137a38383613c92565b50505050565b60008060006137b88585613d7d565b915091506137c581613dc2565b5090505b92915050565b6101135460405163a38406a360e01b815230600482015260009182916001600160a01b039091169063a38406a390602401602060405180830381865afa15801561381d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138419190614cf2565b90506001600160a01b038116318015613aa6576000826001600160a01b0316633106ab536040518163ffffffff1660e01b8152600401602060405180830381865afa158015613894573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138b89190614924565b158015613930575061011454604051635ac86ab760e01b8152600060048201526001600160a01b0390911690635ac86ab790602401602060405180830381865afa15801561390a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061392e9190614924565b155b90508015613a8e5781610115600082825461394b91906147aa565b92505081905550826001600160a01b031663baa7145a6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561398d57600080fd5b505af11580156139a1573d6000803e3d6000fd5b50506101145460405163ecb7cb1b60e01b8152306004820152600093506001600160a01b03909116915063ecb7cb1b90602401600060405180830381865afa1580156139f1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613a199190810190614bd6565b90508561011660006001846020015151613a3391906140d9565b8152602001908152602001600020819055506001816020015151613a5791906140d9565b6040517f6ae853a67b9b71d5e6454259a07b6b7fcf4b2c78c0703a0ccc38834d66ed952990600090a2505061011554949350505050565b8161011554613a9d91906147aa565b95945050505050565b50506101155492915050565b6000818311613ac15782612499565b50919050565b600081831015613ad9575060006137c9565b613ae382846140d9565b90506137c9565b610109546000905b61010854811015613ba15760006101088281548110613b1357613b13614889565b6000918252602080832090910154808352610107909152604090912054909150848111613b595783613b448161489f565b9450613b52905081866140d9565b9450613b7d565b613b6385826140d9565b600092835261010760205260409092209190915550613ba1565b60008511613b8c575050613ba1565b50508080613b999061489f565b915050613af2565b506000816001600160401b03811115613bbc57613bbc614325565b604051908082528060200260200182016040528015613be5578160200160208202803683370190505b50905060005b82811015613c2a57613bfb613f0c565b828281518110613c0d57613c0d614889565b602090810291909101015280613c228161489f565b915050613beb565b5060fc546040516370e301fb60e11b81526001600160a01b039091169063e1c603f690613c5b908490600401614d0f565b600060405180830381600087803b158015613c7557600080fd5b505af1158015613c89573d6000803e3d6000fd5b50505050505050565b60606001600160a01b0383163b613cfa5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610b08565b600080846001600160a01b031684604051613d15919061497a565b600060405180830381855af49150503d8060008114613d50576040519150601f19603f3d011682016040523d82523d6000602084013e613d55565b606091505b5091509150613a9d8282604051806060016040528060278152602001614dbd60279139613fbc565b6000808251604103613db35760208301516040840151606085015160001a613da787828585613fd5565b94509450505050613dbb565b506000905060025b9250929050565b6000816004811115613dd657613dd6614d53565b03613dde5750565b6001816004811115613df257613df2614d53565b03613e3f5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610b08565b6002816004811115613e5357613e53614d53565b03613ea05760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610b08565b6003816004811115613eb457613eb4614d53565b03610e785760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610b08565b610109546101085460009110613f555760405162461bcd60e51b815260206004820152600e60248201526d517565756520697320656d70747960901b6044820152606401610b08565b6101086101095481548110613f6c57613f6c614889565b906000526020600020015490506101086101095481548110613f9057613f90614889565b906000526020600020016000905560016101096000828254613fb291906147aa565b9250508190555090565b60608315613fcb575081612499565b6124998383614099565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561400c5750600090506003614090565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015614060573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811661408957600060019250925050614090565b9150600090505b94509492505050565b8151156140a95781518083602001fd5b8060405162461bcd60e51b8152600401610b089190614d69565b634e487b7160e01b600052601160045260246000fd5b818103818111156137c9576137c96140c3565b6000602082840312156140fe57600080fd5b5035919050565b6001600160a01b0381168114610e7857600080fd5b60006020828403121561412c57600080fd5b813561249981614105565b60005b8381101561415257818101518382015260200161413a565b50506000910152565b60008151808452614173816020860160208601614137565b601f01601f19169290920160200192915050565b60608152600061419a606083018661415b565b82810360208401526141ac818661415b565b915050826040830152949350505050565b600080604083850312156141d057600080fd5b82356141db81614105565b915060208301356141eb81614105565b809150509250929050565b60008083601f84011261420857600080fd5b5081356001600160401b0381111561421f57600080fd5b6020830191508360208260051b8501011115613dbb57600080fd5b8015158114610e7857600080fd5b60008060006040848603121561425d57600080fd5b83356001600160401b0381111561427357600080fd5b61427f868287016141f6565b90945092505060208401356142938161423a565b809150509250925092565b60006040808301818452808651808352606092508286019150828160051b8701016020808a0160005b8481101561431057605f198a85030186528151805185528381015188858701526142f38987018261415b565b918a0151958a0195909552958301959350908201906001016142c7565b50509690960196909652509295945050505050565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b038111828210171561435d5761435d614325565b60405290565b604051601f8201601f191681016001600160401b038111828210171561438b5761438b614325565b604052919050565b60006001600160401b038211156143ac576143ac614325565b5060051b60200190565b600082601f8301126143c757600080fd5b81356001600160401b038111156143e0576143e0614325565b6143f3601f8201601f1916602001614363565b81815284602083860101111561440857600080fd5b816020850160208301376000918101602001919091529392505050565b600082601f83011261443657600080fd5b8135602061444b61444683614393565b614363565b82815260059290921b8401810191818101908684111561446a57600080fd5b8286015b848110156144a95780356001600160401b0381111561448d5760008081fd5b61449b8986838b01016143b6565b84525091830191830161446e565b509695505050505050565b600082601f8301126144c557600080fd5b813560206144d561444683614393565b82815260059290921b840181019181810190868411156144f457600080fd5b8286015b848110156144a957803583529183019183016144f8565b6000806000806080858703121561452557600080fd5b84356001600160401b038082111561453c57600080fd5b61454888838901614425565b955060209150818701358181111561455f57600080fd5b61456b89828a01614425565b95505060408701358181111561458057600080fd5b61458c89828a016144b4565b9450506060870135818111156145a157600080fd5b87019050601f810188136145b457600080fd5b80356145c261444682614393565b81815260059190911b8201830190838101908a8311156145e157600080fd5b928401925b828410156145ff578335825292840192908401906145e6565b979a9699509497505050505050565b6000806040838503121561462157600080fd5b823561462c81614105565b915060208301356001600160401b0381111561464757600080fd5b614653858286016143b6565b9150509250929050565b60006020828403121561466f57600080fd5b81356001600160401b0381111561468557600080fd5b611e7d848285016143b6565b6000806000606084860312156146a657600080fd5b83356001600160401b03808211156146bd57600080fd5b6146c987838801614425565b945060208601359150808211156146df57600080fd5b6146eb87838801614425565b9350604086013591508082111561470157600080fd5b5061470e868287016144b4565b9150509250925092565b60008060008060008060008060006101008a8c03121561473757600080fd5b8935985060208a0135975060408a0135965060608a0135955060808a0135945060a08a0135935060c08a013561476c8161423a565b925060e08a01356001600160401b0381111561478757600080fd5b6147938c828d016141f6565b915080935050809150509295985092959850929598565b808201808211156137c9576137c96140c3565b600181811c908216806147d157607f821691505b602082108103613ac157634e487b7160e01b600052602260045260246000fd5b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b6000600182016148b1576148b16140c3565b5060010190565b634e487b7160e01b600052601260045260246000fd5b6000826148dd576148dd6148b8565b500490565b6000826148f1576148f16148b8565b500690565b600081614905576149056140c3565b506000190190565b80820281158282048414176137c9576137c96140c3565b60006020828403121561493657600080fd5b81516124998161423a565b60008060006060848603121561495657600080fd5b8351925060208401516149688161423a565b80925050604084015190509250925092565b6000825161498c818460208701614137565b9190910192915050565b601f8211156114db57600081815260208120601f850160051c810160208610156149bd5750805b601f850160051c820191505b818110156149dc578281556001016149c9565b505050505050565b81516001600160401b038111156149fd576149fd614325565b614a1181614a0b84546147bd565b84614996565b602080601f831160018114614a465760008415614a2e5750858301515b600019600386901b1c1916600185901b1785556149dc565b600085815260208120601f198616915b82811015614a7557888601518255948401946001909101908401614a56565b5085821015614a935787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160f81b03199390931683526001600160a81b031991909116600183015260601b6bffffffffffffffffffffffff1916600c82015260200190565b608081526000614af4608083018761415b565b8281036020840152614b06818761415b565b90508281036040840152614b1a818661415b565b91505082606083015295945050505050565b6000808335601e19843603018112614b4357600080fd5b8301803591506001600160401b03821115614b5d57600080fd5b602001915036819003821315613dbb57600080fd5b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b600060208284031215614bcf57600080fd5b5051919050565b60006020808385031215614be957600080fd5b82516001600160401b0380821115614c0057600080fd5b81850191506040808388031215614c1657600080fd5b614c1e61433b565b835181528484015183811115614c3357600080fd5b80850194505087601f850112614c4857600080fd5b83519250614c5861444684614393565b83815260069390931b84018501928581019089851115614c7757600080fd5b948601945b84861015614ce05783868b031215614c945760008081fd5b614c9c61433b565b86516001600160e01b0381168114614cb45760008081fd5b81528688015163ffffffff81168114614ccd5760008081fd5b8189015282529483019490860190614c7c565b95820195909552979650505050505050565b600060208284031215614d0457600080fd5b815161249981614105565b6020808252825182820181905260009190848201906040850190845b81811015614d4757835183529284019291840191600101614d2b565b50909695505050505050565b634e487b7160e01b600052602160045260246000fd5b602081526000612499602083018461415b56fef66846415d2bf9eabda9e84793ff9c0ea96d87f50fc41e66aa16469c6a442f05360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212202d5aeadc3340defc038b9c71a09d61a2ccd715d6fd8efadaaeb86875e6ee919464736f6c63430008120033

Deployed Bytecode

0x6080604052600436106102815760003560e01c806365577c551161014f578063a33a7d53116100c1578063b20257791161007a578063b20257791461082e578063b5a561fc14610845578063b8c226071461085c578063d2d49c4b14610873578063e17a684f1461088a578063fce4deab146108a057600080fd5b8063a33a7d5314610758578063a465ff1214610778578063a55461be146107a9578063a8158f65146107d7578063aa4a0d39146107ee578063b1fe93101461080e57600080fd5b80638456cb59116101135780638456cb59146106b05780638e03ac8d146106c5578063907a587b146106dc5780639266799a146106f3578063956041971461070a578063974fb7b31461073857600080fd5b806365577c551461060d57806368a80b4314610624578063747c17171461063757806378ea2dd9146106795780638357ed421461069057600080fd5b806343981753116101f35780634f1ef286116101ac5780634f1ef28614610543578063523f49461461055657806352d1902d146105925780635347f96e146105a75780635c975abb146105d55780635d1e7a59146105ed57600080fd5b8063439817531461048957806343ebf50a1461049e578063471f40fb146104be578063478e61aa146104ec578063485cc955146105035780634aa3a34e1461052357600080fd5b806335aa2e441161024557806335aa2e44146103ce5780633659cfe6146103fd5780633882b1c91461041d5780633d1ebf35146104345780633f2cf0b1146104545780633f4ba83a1461047457600080fd5b8063023c5b08146102ec57806312065fe01461032a57806326517d901461034d57806331b46e671461036d578063323f34431461038d57600080fd5b366102e757610114546001600160a01b031633036102e5573461011560008282546102ac91906140d9565b90915550506040513481527f239494018d16a74ebf338493b53d9f2a6ad0992e071b7ace15ccd561981bf1dd9060200160405180910390a15b005b600080fd5b3480156102f857600080fd5b5061010e5461030d906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561033657600080fd5b5061033f6108b5565b604051908152602001610321565b34801561035957600080fd5b5061033f6103683660046140ec565b6108e0565b34801561037957600080fd5b506102e56103883660046140ec565b610902565b34801561039957600080fd5b506103be6103a836600461411a565b61010b6020526000908152604090205460ff1681565b6040519015158152602001610321565b3480156103da57600080fd5b506103ee6103e93660046140ec565b610964565b60405161032193929190614187565b34801561040957600080fd5b506102e561041836600461411a565b610a96565b34801561042957600080fd5b5061033f6101015481565b34801561044057600080fd5b506102e561044f3660046141bd565b610b7f565b34801561046057600080fd5b506102e561046f366004614248565b610ca4565b34801561048057600080fd5b506102e5610e3e565b34801561049557600080fd5b506103be610e7b565b3480156104aa57600080fd5b506102e56104b93660046140ec565b610ef3565b3480156104ca57600080fd5b506104de6104d93660046140ec565b610fa1565b60405161032192919061429e565b3480156104f857600080fd5b5061033f6101055481565b34801561050f57600080fd5b506102e561051e3660046141bd565b61123b565b34801561052f57600080fd5b506103be61053e36600461450f565b6114e0565b6102e561055136600461460e565b611e85565b34801561056257600080fd5b506103be61057136600461465d565b80516020818301810180516101068252928201919093012091525460ff1681565b34801561059e57600080fd5b5061033f611f3a565b3480156105b357600080fd5b5061033f6105c236600461411a565b61010c6020526000908152604090205481565b3480156105e157600080fd5b5060975460ff166103be565b3480156105f957600080fd5b506102e56106083660046140ec565b611fed565b34801561061957600080fd5b5061033f6101105481565b6103be610632366004614691565b612097565b34801561064357600080fd5b5061030d61065236600461465d565b8051602081830181018051610111825292820191909301209152546001600160a01b031681565b34801561068557600080fd5b5061033f61010d5481565b34801561069c57600080fd5b506102e56106ab366004614248565b6124a0565b3480156106bc57600080fd5b506102e561263a565b3480156106d157600080fd5b5061033f6101005481565b3480156106e857600080fd5b5061033f6101155481565b3480156106ff57600080fd5b5061033f6101125481565b34801561071657600080fd5b5061033f6107253660046140ec565b6101076020526000908152604090205481565b34801561074457600080fd5b506102e561075336600461411a565b612674565b34801561076457600080fd5b5060fc5461030d906001600160a01b031681565b34801561078457600080fd5b506103be61079336600461411a565b61010a6020526000908152604090205460ff1681565b3480156107b557600080fd5b5061033f6107c43660046140ec565b6101166020526000908152604090205481565b3480156107e357600080fd5b5061033f6101045481565b3480156107fa57600080fd5b506102e5610809366004614718565b612725565b34801561081a57600080fd5b506102e561082936600461411a565b612a44565b34801561083a57600080fd5b5061033f6101035481565b34801561085157600080fd5b5061033f6101095481565b34801561086857600080fd5b5061033f61010f5481565b34801561087f57600080fd5b5061033f6101025481565b34801561089657600080fd5b5061033f60ff5481565b3480156108ac57600080fd5b5061033f612b02565b6000610110546108c3612b02565b610103546108d191906147aa565b6108db91906140d9565b905090565b61010881815481106108f157600080fd5b600091825260209091200154905081565b61011454604051636a270dbb60e11b8152600481018390526001600160a01b039091169063d44e1b7690602401600060405180830381600087803b15801561094957600080fd5b505af115801561095d573d6000803e3d6000fd5b5050505050565b60fe6020526000908152604090208054819061097f906147bd565b80601f01602080910402602001604051908101604052809291908181526020018280546109ab906147bd565b80156109f85780601f106109cd576101008083540402835291602001916109f8565b820191906000526020600020905b8154815290600101906020018083116109db57829003601f168201915b505050505090806001018054610a0d906147bd565b80601f0160208091040260200160405190810160405280929190818152602001828054610a39906147bd565b8015610a865780601f10610a5b57610100808354040283529160200191610a86565b820191906000526020600020905b815481529060010190602001808311610a6957829003601f168201915b5050505050908060020154905083565b7fb8ea7c31de614c54f5b3938aa9732e87deb869a880ec52d4bb778c09789441b1610ac081612b37565b6001600160a01b037f000000000000000000000000dcf7dbe6865e52409a0fa2b4b23433db2af3646f163003610b115760405162461bcd60e51b8152600401610b08906147f1565b60405180910390fd5b7f000000000000000000000000dcf7dbe6865e52409a0fa2b4b23433db2af3646f6001600160a01b0316610b43612be4565b6001600160a01b031614610b695760405162461bcd60e51b8152600401610b089061483d565b610b7282612c00565b610b7b82612c70565b5050565b600080516020614d7d833981519152610b9781612b37565b6001600160a01b038316610bed5760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420456967656e506f644d616e616765720000000000000000006044820152606401610b08565b6001600160a01b038216610c435760405162461bcd60e51b815260206004820152601f60248201527f496e76616c69642044656c617965645769746864726177616c526f75746572006044820152606401610b08565b61011380546001600160a01b03199081166001600160a01b0386811691821790935561011480549092169285169283179091556040517f02a8f2ee3a37fb50b19f6b965301f3d567f9d0d7001b4df74d926f2870bc355790600090a3505050565b600080516020614d7d833981519152610cbc81612b37565b82610cff5760405162461bcd60e51b8152602060048201526013602482015272092dcecc2d8d2c840d8d2e6e840d8cadccee8d606b1b6044820152606401610b08565b60005b8381101561095d576000858583818110610d1e57610d1e614889565b9050602002016020810190610d33919061411a565b6001600160a01b031603610d785760405162461bcd60e51b815260206004820152600c60248201526b5a65726f204164647265737360a01b6044820152606401610b08565b8261010b6000878785818110610d9057610d90614889565b9050602002016020810190610da5919061411a565b6001600160a01b031681526020810191909152604001600020805460ff1916911515919091179055821515858583818110610de257610de2614889565b9050602002016020810190610df7919061411a565b6001600160a01b03167f37db4d805bae1ff00af5ccce3625706c8bc4181c0f0577c5d3715765e71edd8360405160405180910390a380610e368161489f565b915050610d02565b7f70afc91226fba57efa6b459a2add00f29a9a7961e6eb3103074a44780ab8cdc8610e6881612b37565b610e70612cb0565b610e78612cfb565b50565b604080516000808252602082019092526108db9082610eaa565b6060815260200190600190039081610e955790505b506040805160008082526020820190925290610ed6565b6060815260200190600190039081610ec15790505b5060408051600080825260208201908152818301909252906114e0565b600080516020614d7d833981519152610f0b81612b37565b6107d0821115610f5d5760405162461bcd60e51b815260206004820152601860248201527f496e76616c6964206e6f64654f70657261746f724665657300000000000000006044820152606401610b08565b61010f5460408051918252602082018490527fb1e342ac4a9cc386141d1bbc96e62081e34d521bdd7671a2dfe9b07424babd4b910160405180910390a15061010f55565b60408051600a80825261016082019092526060916000918291816020015b610fe360405180606001604052806000815260200160608152602001600081525090565b815260200190600190039081610fbf57505060ff54909150600a90600061100a83836148ce565b9050600082118015611023575061102183836148e2565b155b156110365780611032816148f6565b9150505b80871115801561104557508115155b1561122e5760005b8381101561122c57600081611062868b61490d565b61106c90866140d9565b61107691906140d9565b9050600060fe60008381526020019081526020016000206040518060600160405290816000820180546110a8906147bd565b80601f01602080910402602001604051908101604052809291908181526020018280546110d4906147bd565b80156111215780601f106110f657610100808354040283529160200191611121565b820191906000526020600020905b81548152906001019060200180831161110457829003601f168201915b5050505050815260200160018201805461113a906147bd565b80601f0160208091040260200160405190810160405280929190818152602001828054611166906147bd565b80156111b35780601f10611188576101008083540402835291602001916111b3565b820191906000526020600020905b81548152906001019060200180831161119657829003601f168201915b50505050508152602001600282015481525050905060405180606001604052808381526020018260000151815260200182604001518152508784815181106111fd576111fd614889565b60200260200101819052508160010361121757505061122c565b505080806112249061489f565b91505061104d565b505b9296929550919350505050565b600054610100900460ff161580801561125b5750600054600160ff909116105b806112755750303b158015611275575060005460ff166001145b6112d85760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610b08565b6000805460ff1916600117905580156112fb576000805461ff0019166101001790555b6001600160a01b037f000000000000000000000000dcf7dbe6865e52409a0fa2b4b23433db2af3646f1630036113435760405162461bcd60e51b8152600401610b08906147f1565b7f000000000000000000000000dcf7dbe6865e52409a0fa2b4b23433db2af3646f6001600160a01b0316611375612be4565b6001600160a01b03161461139b5760405162461bcd60e51b8152600401610b089061483d565b6001600160a01b0383166113f15760405162461bcd60e51b815260206004820152601b60248201527f496e76616c696420726f6c654d616e61676572206164647265737300000000006044820152606401610b08565b6001600160a01b0382166114475760405162461bcd60e51b815260206004820152601f60248201527f496e76616c6964206465706f736974436f6e74726163742061646472657373006044820152606401610b08565b61144f612d4d565b611457612d7c565b61145f612dab565b60fb80546001600160a01b038086166001600160a01b03199283161790925560fd805492851692909116919091179055600161010d5580156114db576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b60006114ea612dd2565b6114f2612e18565b83518551148015611504575082518551145b8015611511575081518551145b6115555760405162461bcd60e51b8152602060048201526015602482015274496e76616c696420706172616d206c656e6774687360581b6044820152606401610b08565b60fc546001600160a01b03166115a05760405162461bcd60e51b815260206004820152601060248201526f10db185e5b585a5b881b9bdd081cd95d60821b6044820152606401610b08565b84511561168e5760fb546040516312d9a6ad60e01b81527f70afc91226fba57efa6b459a2add00f29a9a7961e6eb3103074a44780ab8cdc860048201523360248201526001600160a01b03909116906312d9a6ad90604401602060405180830381865afa158015611615573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116399190614924565b80611654575033600090815261010b602052604090205460ff165b61168e5760405162461bcd60e51b815260206004820152600b60248201526a105d5d1a0811985a5b195960aa1b6044820152606401610b08565b60fc548551604051637e70d9c560e01b81526004810191909152600091829182916001600160a01b031690637e70d9c5906024016060604051808303816000875af11580156116e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117059190614941565b9250925092508180156117185750600081115b15611d625760ff5460005b82811015611d59576101068a828151811061174057611740614889565b6020026020010151604051611755919061497a565b9081526040519081900360200190205460ff16156117b55760405162461bcd60e51b815260206004820152601c60248201527f7075626c69634b657920616c72656164792072656769737465726564000000006044820152606401610b08565b6117be8261489f565b915060405180606001604052808b83815181106117dd576117dd614889565b602002602001015181526020018a83815181106117fc576117fc614889565b6020026020010151815260200188838151811061181b5761181b614889565b602090810291909101810151909152600084815260fe909152604090208151819061184690826149e4565b506020820151600182019061185b90826149e4565b506040820151816002015590505060016101068b838151811061188057611880614889565b6020026020010151604051611895919061497a565b908152602001604051809103902060006101000a81548160ff02191690831515021790555060006101118b83815181106118d1576118d1614889565b60200260200101516040516118e6919061497a565b908152604051908190036020019020546001600160a01b031690506000811561191757670de0b6b3a764000061191a565b60005b9050600a89848151811061193057611930614889565b602002602001015103611aaa57610113546001600160a01b03166119965760405162461bcd60e51b815260206004820152601760248201527f456967656e506f644d616e61676572206e6f74207365740000000000000000006044820152606401610b08565b80156119e45760405162461bcd60e51b815260206004820152601b60248201527f456967656e506f64204d312052657175697265732033322045544800000000006044820152606401610b08565b610113548c516001600160a01b0390911690639b4e4634906801bc16d674ec800000908f9087908110611a1957611a19614889565b60200260200101518e8781518110611a3357611a33614889565b60200260200101518e8881518110611a4d57611a4d614889565b60200260200101516040518563ffffffff1660e01b8152600401611a7393929190614187565b6000604051808303818588803b158015611a8c57600080fd5b505af1158015611aa0573d6000803e3d6000fd5b5050505050611b9a565b60fd546001600160a01b03166322895118611ace836801bc16d674ec8000006140d9565b8e8681518110611ae057611ae0614889565b6020026020010151600160f81b600060a81b30604051602001611b0593929190614aa3565b6040516020818303038152906040528f8881518110611b2657611b26614889565b60200260200101518f8981518110611b4057611b40614889565b60200260200101516040518663ffffffff1660e01b8152600401611b679493929190614ae1565b6000604051808303818588803b158015611b8057600080fd5b505af1158015611b94573d6000803e3d6000fd5b50505050505b8015611cc2576000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114611bed576040519150601f19603f3d011682016040523d82523d6000602084013e611bf2565b606091505b5050905080611c435760405162461bcd60e51b815260206004820152601e60248201527f5472616e73666572206f66207072652d6465706f736974206661696c656400006044820152606401610b08565b816101126000828254611c5691906140d9565b92505081905550826001600160a01b03168d8581518110611c7957611c79614889565b6020026020010151604051611c8e919061497a565b6040519081900381209087907fa9600995f0aabc7cf77040d60ec36eb9ed073c47abfe0717fa47ca4c3df692a590600090a4505b8b8381518110611cd457611cd4614889565b6020026020010151604051611ce9919061497a565b6040518091039020847f3424df4338b4478ef58d99493e4ed96927ec2c63beec8d9de1d410a8b351acf18b8681518110611d2557611d25614889565b6020026020010151604051611d3c91815260200190565b60405180910390a350508080611d519061489f565b915050611723565b5060ff55611e6c565b81158015611d705750600081115b15611e6c576000838152610107602052604090205415611dd25760405162461bcd60e51b815260206004820152601760248201527f426174636820616c7265616479207265717565737465640000000000000000006044820152606401610b08565b806101006000828254611de591906147aa565b909155505060008381526101076020526040808220839055610108805460018101825592527f8543e9adbfbe1f62b7411fdf032fcfea758a7d6b332f64d971a1334c2ff364dd9091018490555183907f210405eb88ac7589aa9de0a6e36b9c9d3cd6e4061b74363d250a77afe3c6efb790611e639084815260200190565b60405180910390a25b60019350505050611e7d600160c955565b949350505050565b6001600160a01b037f000000000000000000000000dcf7dbe6865e52409a0fa2b4b23433db2af3646f163003611ecd5760405162461bcd60e51b8152600401610b08906147f1565b7f000000000000000000000000dcf7dbe6865e52409a0fa2b4b23433db2af3646f6001600160a01b0316611eff612be4565b6001600160a01b031614611f255760405162461bcd60e51b8152600401610b089061483d565b611f2e82612c00565b610b7b82826001612e78565b6000306001600160a01b037f000000000000000000000000dcf7dbe6865e52409a0fa2b4b23433db2af3646f1614611fda5760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401610b08565b50600080516020614d9d83398151915290565b600080516020614d7d83398151915261200581612b37565b600082118015612016575060648211155b6120535760405162461bcd60e51b815260206004820152600e60248201526d496e76616c69642071756f72756d60901b6044820152606401610b08565b61010d5460408051918252602082018490527fd7916aef7cb7f069c87c44c871962132fdd6653e603c7180377b7226b1a5506d910160405180910390a15061010d55565b60006120a1612dd2565b6120a9612e18565b825184511480156120bb575081518451145b80156120c8575060008451115b61210c5760405162461bcd60e51b8152602060048201526015602482015274496e76616c696420706172616d206c656e6774687360581b6044820152606401610b08565b835161212090670de0b6b3a764000061490d565b34146121855760405162461bcd60e51b815260206004820152602e60248201527f7072654465706f7369742076616c7565206d757374206265203120657468657260448201526d103832b9103b30b634b230ba37b960911b6064820152608401610b08565b60005b8451811015612472576101068582815181106121a6576121a6614889565b60200260200101516040516121bb919061497a565b9081526040519081900360200190205460ff161561221b5760405162461bcd60e51b815260206004820152601c60248201527f7075626c69634b657920616c72656164792072656769737465726564000000006044820152606401610b08565b60006001600160a01b031661011186838151811061223b5761223b614889565b6020026020010151604051612250919061497a565b908152604051908190036020019020546001600160a01b0316146122b65760405162461bcd60e51b815260206004820152601f60248201527f7075626c69634b657920616c7265616479207072652d6465706f7369746564006044820152606401610b08565b60fd5485516001600160a01b0390911690632289511890670de0b6b3a7640000908890859081106122e9576122e9614889565b6020026020010151600160f81b600060a81b3060405160200161230e93929190614aa3565b60405160208183030381529060405288868151811061232f5761232f614889565b602002602001015188878151811061234957612349614889565b60200260200101516040518663ffffffff1660e01b81526004016123709493929190614ae1565b6000604051808303818588803b15801561238957600080fd5b505af115801561239d573d6000803e3d6000fd5b5050505050336101118683815181106123b8576123b8614889565b60200260200101516040516123cd919061497a565b908152602001604051809103902060006101000a8154816001600160a01b0302191690836001600160a01b03160217905550336001600160a01b031685828151811061241b5761241b614889565b6020026020010151604051612430919061497a565b604051908190038120907f306a11966d026aa41af5f696c416464d527e1b8539d6b1db76a5a3298703720e90600090a38061246a8161489f565b915050612188565b5034610112600082825461248691906147aa565b909155506001915050612499600160c955565b9392505050565b600080516020614d7d8339815191526124b881612b37565b826124fb5760405162461bcd60e51b8152602060048201526013602482015272092dcecc2d8d2c840d8d2e6e840d8cadccee8d606b1b6044820152606401610b08565b60005b8381101561095d57600085858381811061251a5761251a614889565b905060200201602081019061252f919061411a565b6001600160a01b0316036125745760405162461bcd60e51b815260206004820152600c60248201526b5a65726f204164647265737360a01b6044820152606401610b08565b8261010a600087878581811061258c5761258c614889565b90506020020160208101906125a1919061411a565b6001600160a01b031681526020810191909152604001600020805460ff19169115159190911790558215158585838181106125de576125de614889565b90506020020160208101906125f3919061411a565b6001600160a01b03167fdf67d94eba45581175e628d76b5e5058cf811bb243dfa6627fd46b8465234e6260405160405180910390a3806126328161489f565b9150506124fe565b7f70afc91226fba57efa6b459a2add00f29a9a7961e6eb3103074a44780ab8cdc861266481612b37565b61266c612dd2565b610e78612fe3565b600080516020614d7d83398151915261268c81612b37565b6001600160a01b0382166126d95760405162461bcd60e51b815260206004820152601460248201527324b73b30b634b2103737b232a7b832b930ba37b960611b6044820152606401610b08565b61010e80546001600160a01b0319166001600160a01b0384169081179091556040517f826392384452e326ae3357d613e8f331be7a57fc88379826286d982f1261b46d90600090a25050565b61272d612dd2565b612735612e18565b61010554891161277e5760405162461bcd60e51b8152602060048201526014602482015273496e76616c6964207265706f727420626c6f636b60601b6044820152606401610b08565b60ff548811156127d05760405162461bcd60e51b815260206004820152601760248201527f496e76616c69642076616c696461746f7273436f756e740000000000000000006044820152606401610b08565b60ff5486111580156127e55750610101548610155b6128315760405162461bcd60e51b815260206004820152601860248201527f496e76616c69642076616c696461746f727345786974656400000000000000006044820152606401610b08565b61010d548110156128845760405162461bcd60e51b815260206004820152601960248201527f496e76616c6964207369676e617475726573206c656e677468000000000000006044820152606401610b08565b60fc546001600160a01b03166128cf5760405162461bcd60e51b815260206004820152601060248201526f10db185e5b585a5b881b9bdd081cd95d60821b6044820152606401610b08565b6040805160208082018c90528183018b9052606082018a90526080820189905260a0820188905285151560f81b60c0830152825160a181840301815260c1830184528051908201207f19457468657265756d205369676e6564204d6573736167653a0a33320000000060e184015260fd808401919091528351808403909101815261011d909201909252805191012060005b82811015612a1e576129cc8b8386868581811061298057612980614889565b90506020028101906129929190614b2c565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061302092505050565b612a0c5760405162461bcd60e51b8152602060048201526011602482015270496e76616c6964205369676e617475726560781b6044820152606401610b08565b80612a168161489f565b915050612961565b50612a2e8a8a8a8a8a8a8a6130d2565b50612a39600160c955565b505050505050505050565b7fb8ea7c31de614c54f5b3938aa9732e87deb869a880ec52d4bb778c09789441b1612a6e81612b37565b6001600160a01b038216612ab75760405162461bcd60e51b815260206004820152601060248201526f24b73b30b634b21021b630bca6b0b4b760811b6044820152606401610b08565b60fc80546001600160a01b0319166001600160a01b0384169081179091556040517f104a66f1cbeb1a854e33542efdf4cab6dd7bd309067e996a7c9cd2bb5c082b8390600090a25050565b60006801bc16d674ec800000610101546101025460ff54612b2391906140d9565b612b2d91906140d9565b6108db919061490d565b60fb546040516312d9a6ad60e01b8152600481018390523360248201526001600160a01b03909116906312d9a6ad90604401602060405180830381865afa158015612b86573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612baa9190614924565b610e785760405162461bcd60e51b815260206004820152600b60248201526a105d5d1a0811985a5b195960aa1b6044820152606401610b08565b600080516020614d9d833981519152546001600160a01b031690565b7fb8ea7c31de614c54f5b3938aa9732e87deb869a880ec52d4bb778c09789441b1612c2a81612b37565b6000826001600160a01b03163b11610b7b5760405162461bcd60e51b81526020600482015260096024820152680858dbdb9d1c9858dd60ba1b6044820152606401610b08565b612c7981613688565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60975460ff16612cf95760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610b08565b565b612d03612cb0565b6097805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b600054610100900460ff16612d745760405162461bcd60e51b8152600401610b0890614b72565b612cf9613724565b600054610100900460ff16612da35760405162461bcd60e51b8152600401610b0890614b72565b612cf9613757565b600054610100900460ff16612cf95760405162461bcd60e51b8152600401610b0890614b72565b60975460ff1615612cf95760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610b08565b600260c95403612e6a5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610b08565b600260c955565b600160c955565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615612eab576114db83613688565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015612f05575060408051601f3d908101601f19168201909252612f0291810190614bbd565b60015b612f685760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610b08565b600080516020614d9d8339815191528114612fd75760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610b08565b506114db83838361377e565b612feb612dd2565b6097805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258612d303390565b60008061302d84846137a9565b6001600160a01b038116600090815261010a602052604090205490915060ff1661305b576000915050612499565b6001600160a01b038116600090815261010c60205260409020548511613085576000915050612499565b6001600160a01b038116600081815261010c60205260408082208890555187917e4a0156b3be77c48016f4bd6f1dcb3d729680a091d3889629370a973475d75d91a3506001949350505050565b610113546001600160a01b0316156131ea5781156130f3576130f382610902565b60006130fe846137cf565b6101145460405163ecb7cb1b60e01b81523060048201529192506000916001600160a01b039091169063ecb7cb1b90602401600060405180830381865afa15801561314d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526131759190810190614bd6565b905060008082600001511161318b5760006131b1565b6101166000600184600001516131a191906140d9565b8152602001908152602001600020545b905060006131bf82886140d9565b90506131cb848a6147aa565b98506131d7818b6147aa565b99506131e381896140d9565b9750505050505b60006131ff6801bc16d674ec8000008861490d565b861161320c576000613229565b61321f6801bc16d674ec8000008861490d565b61322990876140d9565b61010454610101549192509060009061324290886140d9565b6101058b90556101028a905561010389905561010188905561010484905560fc54604080516344573f9760e11b81529051929350861515926001600160a01b03909216916388ae7f2e916004818101926020929091908290030181865afa1580156132b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132d59190614924565b15151461333c5760fc54604051630a54644f60e21b815285151560048201526001600160a01b0390911690632951913c90602401600060405180830381600087803b15801561332357600080fd5b505af1158015613337573d6000803e3d6000fd5b505050505b61010e546001600160a01b03161561336f5761271061010f5484613360919061490d565b61336a91906148ce565b610110555b4780156135bb5760006133948261338f6801bc16d674ec8000008661490d565b613ab2565b905060006133a282846140d9565b905060006133b082886147aa565b905060006133be8288613ac7565b905060006133cc8483613ab2565b90506000841180156133e9575061010e546001600160a01b031615155b156134fd57600061271061010f5486613402919061490d565b61340c91906148ce565b9050600061271061010f5484613422919061490d565b61342c91906148ce565b905061343882876140d9565b955061344482896140d9565b975061345081846140d9565b61010e546040519194506000916001600160a01b039091169084908381818185875af1925050503d80600081146134a3576040519150601f19603f3d011682016040523d82523d6000602084013e6134a8565b606091505b50509050806134f95760405162461bcd60e51b815260206004820152601f60248201527f5472616e73666572206f66206e6f64652072657761726473206661696c6564006044820152606401610b08565b5050505b60fc5460405163070f0b8960e21b815260048101839052602481018790526001600160a01b0390911690631c3c2e249088906044016000604051808303818588803b15801561354b57600080fd5b505af115801561355f573d6000803e3d6000fd5b50505050508f7f1947dd35f2ad7cfad67d80241fe2f032f18b67bf60792d5f9132dac5817527cb8287896040516135a9939291909283526020830191909152604082015260600190565b60405180910390a25050505050613624565b60fc60009054906101000a90046001600160a01b03166001600160a01b0316636f3fe4046040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561360b57600080fd5b505af115801561361f573d6000803e3d6000fd5b505050505b81156136335761363382613aea565b604080518c8152602081018c90529081018a9052606081018990527f7a4a8ff550d096ae3e71e1c79680b17560ea3076ff95d4666ab60c0ef5308a569060800160405180910390a15050505050505050505050565b6001600160a01b0381163b6136f55760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610b08565b600080516020614d9d83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b600054610100900460ff1661374b5760405162461bcd60e51b8152600401610b0890614b72565b6097805460ff19169055565b600054610100900460ff16612e715760405162461bcd60e51b8152600401610b0890614b72565b61378783612c70565b6000825111806137945750805b156114db576137a38383613c92565b50505050565b60008060006137b88585613d7d565b915091506137c581613dc2565b5090505b92915050565b6101135460405163a38406a360e01b815230600482015260009182916001600160a01b039091169063a38406a390602401602060405180830381865afa15801561381d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138419190614cf2565b90506001600160a01b038116318015613aa6576000826001600160a01b0316633106ab536040518163ffffffff1660e01b8152600401602060405180830381865afa158015613894573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138b89190614924565b158015613930575061011454604051635ac86ab760e01b8152600060048201526001600160a01b0390911690635ac86ab790602401602060405180830381865afa15801561390a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061392e9190614924565b155b90508015613a8e5781610115600082825461394b91906147aa565b92505081905550826001600160a01b031663baa7145a6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561398d57600080fd5b505af11580156139a1573d6000803e3d6000fd5b50506101145460405163ecb7cb1b60e01b8152306004820152600093506001600160a01b03909116915063ecb7cb1b90602401600060405180830381865afa1580156139f1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613a199190810190614bd6565b90508561011660006001846020015151613a3391906140d9565b8152602001908152602001600020819055506001816020015151613a5791906140d9565b6040517f6ae853a67b9b71d5e6454259a07b6b7fcf4b2c78c0703a0ccc38834d66ed952990600090a2505061011554949350505050565b8161011554613a9d91906147aa565b95945050505050565b50506101155492915050565b6000818311613ac15782612499565b50919050565b600081831015613ad9575060006137c9565b613ae382846140d9565b90506137c9565b610109546000905b61010854811015613ba15760006101088281548110613b1357613b13614889565b6000918252602080832090910154808352610107909152604090912054909150848111613b595783613b448161489f565b9450613b52905081866140d9565b9450613b7d565b613b6385826140d9565b600092835261010760205260409092209190915550613ba1565b60008511613b8c575050613ba1565b50508080613b999061489f565b915050613af2565b506000816001600160401b03811115613bbc57613bbc614325565b604051908082528060200260200182016040528015613be5578160200160208202803683370190505b50905060005b82811015613c2a57613bfb613f0c565b828281518110613c0d57613c0d614889565b602090810291909101015280613c228161489f565b915050613beb565b5060fc546040516370e301fb60e11b81526001600160a01b039091169063e1c603f690613c5b908490600401614d0f565b600060405180830381600087803b158015613c7557600080fd5b505af1158015613c89573d6000803e3d6000fd5b50505050505050565b60606001600160a01b0383163b613cfa5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610b08565b600080846001600160a01b031684604051613d15919061497a565b600060405180830381855af49150503d8060008114613d50576040519150601f19603f3d011682016040523d82523d6000602084013e613d55565b606091505b5091509150613a9d8282604051806060016040528060278152602001614dbd60279139613fbc565b6000808251604103613db35760208301516040840151606085015160001a613da787828585613fd5565b94509450505050613dbb565b506000905060025b9250929050565b6000816004811115613dd657613dd6614d53565b03613dde5750565b6001816004811115613df257613df2614d53565b03613e3f5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610b08565b6002816004811115613e5357613e53614d53565b03613ea05760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610b08565b6003816004811115613eb457613eb4614d53565b03610e785760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610b08565b610109546101085460009110613f555760405162461bcd60e51b815260206004820152600e60248201526d517565756520697320656d70747960901b6044820152606401610b08565b6101086101095481548110613f6c57613f6c614889565b906000526020600020015490506101086101095481548110613f9057613f90614889565b906000526020600020016000905560016101096000828254613fb291906147aa565b9250508190555090565b60608315613fcb575081612499565b6124998383614099565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561400c5750600090506003614090565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015614060573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811661408957600060019250925050614090565b9150600090505b94509492505050565b8151156140a95781518083602001fd5b8060405162461bcd60e51b8152600401610b089190614d69565b634e487b7160e01b600052601160045260246000fd5b818103818111156137c9576137c96140c3565b6000602082840312156140fe57600080fd5b5035919050565b6001600160a01b0381168114610e7857600080fd5b60006020828403121561412c57600080fd5b813561249981614105565b60005b8381101561415257818101518382015260200161413a565b50506000910152565b60008151808452614173816020860160208601614137565b601f01601f19169290920160200192915050565b60608152600061419a606083018661415b565b82810360208401526141ac818661415b565b915050826040830152949350505050565b600080604083850312156141d057600080fd5b82356141db81614105565b915060208301356141eb81614105565b809150509250929050565b60008083601f84011261420857600080fd5b5081356001600160401b0381111561421f57600080fd5b6020830191508360208260051b8501011115613dbb57600080fd5b8015158114610e7857600080fd5b60008060006040848603121561425d57600080fd5b83356001600160401b0381111561427357600080fd5b61427f868287016141f6565b90945092505060208401356142938161423a565b809150509250925092565b60006040808301818452808651808352606092508286019150828160051b8701016020808a0160005b8481101561431057605f198a85030186528151805185528381015188858701526142f38987018261415b565b918a0151958a0195909552958301959350908201906001016142c7565b50509690960196909652509295945050505050565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b038111828210171561435d5761435d614325565b60405290565b604051601f8201601f191681016001600160401b038111828210171561438b5761438b614325565b604052919050565b60006001600160401b038211156143ac576143ac614325565b5060051b60200190565b600082601f8301126143c757600080fd5b81356001600160401b038111156143e0576143e0614325565b6143f3601f8201601f1916602001614363565b81815284602083860101111561440857600080fd5b816020850160208301376000918101602001919091529392505050565b600082601f83011261443657600080fd5b8135602061444b61444683614393565b614363565b82815260059290921b8401810191818101908684111561446a57600080fd5b8286015b848110156144a95780356001600160401b0381111561448d5760008081fd5b61449b8986838b01016143b6565b84525091830191830161446e565b509695505050505050565b600082601f8301126144c557600080fd5b813560206144d561444683614393565b82815260059290921b840181019181810190868411156144f457600080fd5b8286015b848110156144a957803583529183019183016144f8565b6000806000806080858703121561452557600080fd5b84356001600160401b038082111561453c57600080fd5b61454888838901614425565b955060209150818701358181111561455f57600080fd5b61456b89828a01614425565b95505060408701358181111561458057600080fd5b61458c89828a016144b4565b9450506060870135818111156145a157600080fd5b87019050601f810188136145b457600080fd5b80356145c261444682614393565b81815260059190911b8201830190838101908a8311156145e157600080fd5b928401925b828410156145ff578335825292840192908401906145e6565b979a9699509497505050505050565b6000806040838503121561462157600080fd5b823561462c81614105565b915060208301356001600160401b0381111561464757600080fd5b614653858286016143b6565b9150509250929050565b60006020828403121561466f57600080fd5b81356001600160401b0381111561468557600080fd5b611e7d848285016143b6565b6000806000606084860312156146a657600080fd5b83356001600160401b03808211156146bd57600080fd5b6146c987838801614425565b945060208601359150808211156146df57600080fd5b6146eb87838801614425565b9350604086013591508082111561470157600080fd5b5061470e868287016144b4565b9150509250925092565b60008060008060008060008060006101008a8c03121561473757600080fd5b8935985060208a0135975060408a0135965060608a0135955060808a0135945060a08a0135935060c08a013561476c8161423a565b925060e08a01356001600160401b0381111561478757600080fd5b6147938c828d016141f6565b915080935050809150509295985092959850929598565b808201808211156137c9576137c96140c3565b600181811c908216806147d157607f821691505b602082108103613ac157634e487b7160e01b600052602260045260246000fd5b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b6000600182016148b1576148b16140c3565b5060010190565b634e487b7160e01b600052601260045260246000fd5b6000826148dd576148dd6148b8565b500490565b6000826148f1576148f16148b8565b500690565b600081614905576149056140c3565b506000190190565b80820281158282048414176137c9576137c96140c3565b60006020828403121561493657600080fd5b81516124998161423a565b60008060006060848603121561495657600080fd5b8351925060208401516149688161423a565b80925050604084015190509250925092565b6000825161498c818460208701614137565b9190910192915050565b601f8211156114db57600081815260208120601f850160051c810160208610156149bd5750805b601f850160051c820191505b818110156149dc578281556001016149c9565b505050505050565b81516001600160401b038111156149fd576149fd614325565b614a1181614a0b84546147bd565b84614996565b602080601f831160018114614a465760008415614a2e5750858301515b600019600386901b1c1916600185901b1785556149dc565b600085815260208120601f198616915b82811015614a7557888601518255948401946001909101908401614a56565b5085821015614a935787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160f81b03199390931683526001600160a81b031991909116600183015260601b6bffffffffffffffffffffffff1916600c82015260200190565b608081526000614af4608083018761415b565b8281036020840152614b06818761415b565b90508281036040840152614b1a818661415b565b91505082606083015295945050505050565b6000808335601e19843603018112614b4357600080fd5b8301803591506001600160401b03821115614b5d57600080fd5b602001915036819003821315613dbb57600080fd5b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b600060208284031215614bcf57600080fd5b5051919050565b60006020808385031215614be957600080fd5b82516001600160401b0380821115614c0057600080fd5b81850191506040808388031215614c1657600080fd5b614c1e61433b565b835181528484015183811115614c3357600080fd5b80850194505087601f850112614c4857600080fd5b83519250614c5861444684614393565b83815260069390931b84018501928581019089851115614c7757600080fd5b948601945b84861015614ce05783868b031215614c945760008081fd5b614c9c61433b565b86516001600160e01b0381168114614cb45760008081fd5b81528688015163ffffffff81168114614ccd5760008081fd5b8189015282529483019490860190614c7c565b95820195909552979650505050505050565b600060208284031215614d0457600080fd5b815161249981614105565b6020808252825182820181905260009190848201906040850190845b81811015614d4757835183529284019291840191600101614d2b565b50909695505050505050565b634e487b7160e01b600052602160045260246000fd5b602081526000612499602083018461415b56fef66846415d2bf9eabda9e84793ff9c0ea96d87f50fc41e66aa16469c6a442f05360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212202d5aeadc3340defc038b9c71a09d61a2ccd715d6fd8efadaaeb86875e6ee919464736f6c63430008120033

Deployed Bytecode Sourcemap

166497:28711:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;189921:28;;-1:-1:-1;;;;;189921:28:0;189899:10;:51;189896:164;;189990:9;189967:19;;:32;;;;;;;:::i;:::-;;;;-1:-1:-1;;190019:29:0;;190038:9;425:25:1;;190019:29:0;;413:2:1;398:18;190019:29:0;;;;;;;189896:164;166497:28711;;;;;169260:27;;;;;;;;;;-1:-1:-1;169260:27:0;;;;-1:-1:-1;;;;;169260:27:0;;;;;;-1:-1:-1;;;;;625:32:1;;;607:51;;595:2;580:18;169260:27:0;;;;;;;;190184:151;;;;;;;;;;;;;:::i;:::-;;;425:25:1;;;413:2;398:18;190184:151:0;279:177:1;168646:31:0;;;;;;;;;;-1:-1:-1;168646:31:0;;;;;:::i;:::-;;:::i;189571:173::-;;;;;;;;;;-1:-1:-1;189571:173:0;;;;;:::i;:::-;;:::i;168929:52::-;;;;;;;;;;-1:-1:-1;168929:52:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;1407:14:1;;1400:22;1382:41;;1370:2;1355:18;168929:52:0;1242:187:1;167591:47:0;;;;;;;;;;-1:-1:-1;167591:47:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;;;:::i;194587:229::-;;;;;;;;;;-1:-1:-1;194587:229:0;;;;;:::i;:::-;;:::i;167864:31::-;;;;;;;;;;;;;;;;187621:554;;;;;;;;;;-1:-1:-1;187621:554:0;;;;;:::i;:::-;;:::i;191878:414::-;;;;;;;;;;-1:-1:-1;191878:414:0;;;;;:::i;:::-;;:::i;194057:94::-;;;;;;;;;;;;;:::i;176685:158::-;;;;;;;;;;;;;:::i;192392:262::-;;;;;;;;;;-1:-1:-1;192392:262:0;;;;;:::i;:::-;;:::i;177153:925::-;;;;;;;;;;-1:-1:-1;177153:925:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;;:::i;168288:32::-;;;;;;;;;;;;;;;;170531:512;;;;;;;;;;-1:-1:-1;170531:512:0;;;;;:::i;:::-;;:::i;173421:3199::-;;;;;;;;;;-1:-1:-1;173421:3199:0;;;;;:::i;:::-;;:::i;30848:225::-;;;;;;:::i;:::-;;:::i;168397:49::-;;;;;;;;;;-1:-1:-1;168397:49:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30067:133;;;;;;;;;;;;;:::i;169059:46::-;;;;;;;;;;-1:-1:-1;169059:46:0;;;;;:::i;:::-;;;;;;;;;;;;;;34926:86;;;;;;;;;;-1:-1:-1;34997:7:0;;;;34926:86;;190766:255;;;;;;;;;;-1:-1:-1;190766:255:0;;;;;:::i;:::-;;:::i;169432:38::-;;;;;;;;;;;;;;;;171564:1275;;;;;;:::i;:::-;;:::i;169519:48::-;;;;;;;;;;-1:-1:-1;169519:48:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;169519:48:0;;;169182:27;;;;;;;;;;;;;;;;191298:399;;;;;;;;;;-1:-1:-1;191298:399:0;;;;;:::i;:::-;;:::i;193914:93::-;;;;;;;;;;;;;:::i;167778:32::-;;;;;;;;;;;;;;;;169951:34;;;;;;;;;;;;;;;;169622:32;;;;;;;;;;;;;;;;168503:52;;;;;;;;;;-1:-1:-1;168503:52:0;;;;;:::i;:::-;;;;;;;;;;;;;;193162:248;;;;;;;;;;-1:-1:-1;193162:248:0;;;;;:::i;:::-;;:::i;167405:25::-;;;;;;;;;;-1:-1:-1;167405:25:0;;;;-1:-1:-1;;;;;167405:25:0;;;168813:47;;;;;;;;;;-1:-1:-1;168813:47:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;170064:50;;;;;;;;;;-1:-1:-1;170064:50:0;;;;;:::i;:::-;;;;;;;;;;;;;;168206:29;;;;;;;;;;;;;;;;179029:1702;;;;;;;;;;-1:-1:-1;179029:1702:0;;;;;:::i;:::-;;:::i;192812:236::-;;;;;;;;;;-1:-1:-1;192812:236:0;;;;;:::i;:::-;;:::i;168099:38::-;;;;;;;;;;;;;;;;168722:34;;;;;;;;;;;;;;;;169332:31;;;;;;;;;;;;;;;;167978;;;;;;;;;;;;;;;;167699:29;;;;;;;;;;;;;;;;190416:154;;;;;;;;;;;;;:::i;190184:151::-;190229:7;190304:23;;190282:19;:17;:19::i;:::-;190256:23;;:45;;;;:::i;:::-;:71;;;;:::i;:::-;190249:78;;190184:151;:::o;168646:31::-;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;168646:31:0;:::o;189571:173::-;189653:28;;:83;;-1:-1:-1;;;189653:83:0;;;;;425:25:1;;;-1:-1:-1;;;;;189653:28:0;;;;:52;;398:18:1;;189653:83:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;189571:173;:::o;167591:47::-;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;194587:229::-;166841:35;170282:20;170292:9;170282;:20::i;:::-;-1:-1:-1;;;;;28937:6:0::1;28920:23;28928:4;28920:23:::0;28912:80:::1;;;;-1:-1:-1::0;;;28912:80:0::1;;;;;;;:::i;:::-;;;;;;;;;29035:6;-1:-1:-1::0;;;;;29011:30:0::1;:20;:18;:20::i;:::-;-1:-1:-1::0;;;;;29011:30:0::1;;29003:87;;;;-1:-1:-1::0;;;29003:87:0::1;;;;;;;:::i;:::-;194730:37:::2;194748:18;194730:17;:37::i;:::-;194778:30;194789:18;194778:10;:30::i;:::-;194587:229:::0;;:::o;187621:554::-;-1:-1:-1;;;;;;;;;;;170282:20:0;170292:9;170282;:20::i;:::-;-1:-1:-1;;;;;187781:30:0;::::1;187773:66;;;::::0;-1:-1:-1;;;187773:66:0;;14230:2:1;187773:66:0::1;::::0;::::1;14212:21:1::0;14269:2;14249:18;;;14242:30;14308:25;14288:18;;;14281:53;14351:18;;187773:66:0::1;14028:347:1::0;187773:66:0::1;-1:-1:-1::0;;;;;187858:38:0;::::1;187850:82;;;::::0;-1:-1:-1;;;187850:82:0;;14582:2:1;187850:82:0::1;::::0;::::1;14564:21:1::0;14621:2;14601:18;;;14594:30;14660:33;14640:18;;;14633:61;14711:18;;187850:82:0::1;14380:355:1::0;187850:82:0::1;187945:15;:52:::0;;-1:-1:-1;;;;;;187945:52:0;;::::1;-1:-1:-1::0;;;;;187945:52:0;;::::1;::::0;;::::1;::::0;;;188008:28:::1;:81:::0;;;;::::1;::::0;;::::1;::::0;;::::1;::::0;;;188107:60:::1;::::0;::::1;::::0;-1:-1:-1;;188107:60:0::1;187621:554:::0;;;:::o;191878:414::-;-1:-1:-1;;;;;;;;;;;170282:20:0;170292:9;170282;:20::i;:::-;192001:16;191993:48:::1;;;::::0;-1:-1:-1;;;191993:48:0;;14942:2:1;191993:48:0::1;::::0;::::1;14924:21:1::0;14981:2;14961:18;;;14954:30;-1:-1:-1;;;15000:18:1;;;14993:49;15059:18;;191993:48:0::1;14740:343:1::0;191993:48:0::1;192057:9;192052:233;192072:16:::0;;::::1;192052:233;;;192138:1;192118:5:::0;;192124:1;192118:8;;::::1;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;192118:22:0::1;::::0;192110:47:::1;;;::::0;-1:-1:-1;;;192110:47:0;;15422:2:1;192110:47:0::1;::::0;::::1;15404:21:1::0;15461:2;15441:18;;;15434:30;-1:-1:-1;;;15480:18:1;;;15473:42;15532:18;;192110:47:0::1;15220:336:1::0;192110:47:0::1;192205:5;192172:20;:30;192193:5;;192199:1;192193:8;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;192172:30:0::1;::::0;;::::1;::::0;::::1;::::0;;;;;;-1:-1:-1;192172:30:0;:38;;-1:-1:-1;;192172:38:0::1;::::0;::::1;;::::0;;;::::1;::::0;;192230:43;::::1;;192257:5:::0;;192263:1;192257:8;;::::1;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;192230:43:0::1;;;;;;;;;;;192090:3:::0;::::1;::::0;::::1;:::i;:::-;;;;192052:233;;194057:94:::0;166926:28;170282:20;170292:9;170282;:20::i;:::-;34790:16:::1;:14;:16::i;:::-;194133:10:::2;:8;:10::i;:::-;194057:94:::0;:::o;176685:158::-;176768:14;;;176732:4;176768:14;;;;;;;;;176756:79;;176732:4;176768:14;;;;;;;;;;;;;;;;;;;-1:-1:-1;176784:14:0;;;176796:1;176784:14;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;176800:16:0;;;176814:1;176800:16;;;;;;176818;;;;;;;;;176800;176756:11;:79::i;192392:262::-;-1:-1:-1;;;;;;;;;;;170282:20:0;170292:9;170282;:20::i;:::-;167208:4:::1;192488:5;:31;;192480:68;;;::::0;-1:-1:-1;;;192480:68:0;;15903:2:1;192480:68:0::1;::::0;::::1;15885:21:1::0;15942:2;15922:18;;;15915:30;15981:26;15961:18;;;15954:54;16025:18;;192480:68:0::1;15701:348:1::0;192480:68:0::1;192587:16;::::0;192564:47:::1;::::0;;16228:25:1;;;16284:2;16269:18;;16262:34;;;192564:47:0::1;::::0;16201:18:1;192564:47:0::1;;;;;;;-1:-1:-1::0;192622:16:0::1;:24:::0;192392:262::o;177153:925::-;177288:23;;;177308:2;177288:23;;;;;;;;;177214:22;;177238:7;;;;177288:23;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;177288:23:0;;;;;;;;;;;;;-1:-1:-1;;177371:14:0;;177258:53;;-1:-1:-1;177341:2:0;;177322:16;177417:17;177341:2;177371:14;177417:17;:::i;:::-;177396:38;;177458:1;177449:6;:10;:36;;;;-1:-1:-1;177463:17:0;177472:8;177463:6;:17;:::i;:::-;:22;177449:36;177445:81;;;177502:12;;;;:::i;:::-;;;;177445:81;177549:10;177540:5;:19;;:34;;;;-1:-1:-1;177563:11:0;;;177540:34;177536:499;;;177596:9;177591:433;177615:8;177611:1;:12;177591:433;;;177649:13;177693:1;177674:16;177682:8;177674:5;:16;:::i;:::-;177665:25;;:6;:25;:::i;:::-;:29;;;;:::i;:::-;177649:45;;177713:26;177742:10;:17;177753:5;177742:17;;;;;;;;;;;177713:46;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;177788:180;;;;;;;;177829:5;177788:180;;;;177868:9;:19;;;177788:180;;;;177925:9;:23;;;177788:180;;;177778:4;177783:1;177778:7;;;;;;;;:::i;:::-;;;;;;:190;;;;177991:5;178000:1;177991:10;177987:21;;178003:5;;;;177987:21;177630:394;;177625:3;;;;;:::i;:::-;;;;177591:433;;;;177536:499;178053:4;;178059:10;;-1:-1:-1;177153:925:0;;-1:-1:-1;;;;177153:925:0:o;170531:512::-;16551:19;16574:13;;;;;;16573:14;;16621:34;;;;-1:-1:-1;16639:12:0;;16654:1;16639:12;;;;:16;16621:34;16620:108;;;-1:-1:-1;16700:4:0;3609:19;:23;;;16661:66;;-1:-1:-1;16710:12:0;;;;;:17;16661:66;16598:204;;;;-1:-1:-1;;;16598:204:0;;17197:2:1;16598:204:0;;;17179:21:1;17236:2;17216:18;;;17209:30;17275:34;17255:18;;;17248:62;-1:-1:-1;;;17326:18:1;;;17319:44;17380:19;;16598:204:0;16995:410:1;16598:204:0;16813:12;:16;;-1:-1:-1;;16813:16:0;16828:1;16813:16;;;16840:67;;;;16875:13;:20;;-1:-1:-1;;16875:20:0;;;;;16840:67;-1:-1:-1;;;;;28937:6:0::1;28920:23;28928:4;28920:23:::0;28912:80:::1;;;;-1:-1:-1::0;;;28912:80:0::1;;;;;;;:::i;:::-;29035:6;-1:-1:-1::0;;;;;29011:30:0::1;:20;:18;:20::i;:::-;-1:-1:-1::0;;;;;29011:30:0::1;;29003:87;;;;-1:-1:-1::0;;;29003:87:0::1;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;170649:26:0;::::2;170641:66;;;::::0;-1:-1:-1;;;170641:66:0;;17612:2:1;170641:66:0::2;::::0;::::2;17594:21:1::0;17651:2;17631:18;;;17624:30;17690:29;17670:18;;;17663:57;17737:18;;170641:66:0::2;17410:351:1::0;170641:66:0::2;-1:-1:-1::0;;;;;170726:30:0;::::2;170718:74;;;::::0;-1:-1:-1;;;170718:74:0;;17968:2:1;170718:74:0::2;::::0;::::2;17950:21:1::0;18007:2;17987:18;;;17980:30;18046:33;18026:18;;;18019:61;18097:18;;170718:74:0::2;17766:355:1::0;170718:74:0::2;170805:17;:15;:17::i;:::-;170833:24;:22;:24::i;:::-;170868;:22;:24::i;:::-;170905:11;:40:::0;;-1:-1:-1;;;;;170905:40:0;;::::2;-1:-1:-1::0;;;;;;170905:40:0;;::::2;;::::0;;;170956:15:::2;:52:::0;;;;::::2;::::0;;;::::2;::::0;;;::::2;::::0;;170905:40;171019:12:::2;:16:::0;16929:102;;;;16980:5;16964:21;;-1:-1:-1;;16964:21:0;;;17005:14;;-1:-1:-1;18278:36:1;;17005:14:0;;18266:2:1;18251:18;17005:14:0;;;;;;;16929:102;16540:498;170531:512;;:::o;173421:3199::-;173652:4;34531:19;:17;:19::i;:::-;38662:21:::1;:19;:21::i;:::-;173712:10:::2;:17;173691:10;:17;:38;:105;;;;;173771:18;:25;173750:10;:17;:46;173691:105;:168;;;;;173838:14;:21;173817:10;:17;:42;173691:168;173669:239;;;::::0;-1:-1:-1;;;173669:239:0;;18527:2:1;173669:239:0::2;::::0;::::2;18509:21:1::0;18566:2;18546:18;;;18539:30;-1:-1:-1;;;18585:18:1;;;18578:51;18646:18;;173669:239:0::2;18325:345:1::0;173669:239:0::2;173935:8;::::0;-1:-1:-1;;;;;173935:8:0::2;173919:60;;;::::0;-1:-1:-1;;;173919:60:0;;18877:2:1;173919:60:0::2;::::0;::::2;18859:21:1::0;18916:2;18896:18;;;18889:30;-1:-1:-1;;;18935:18:1;;;18928:46;18991:18;;173919:60:0::2;18675:340:1::0;173919:60:0::2;173996:17:::0;;:21;173992:213:::2;;174060:11;::::0;:50:::2;::::0;-1:-1:-1;;;174060:50:0;;166926:28:::2;174060:50;::::0;::::2;19194:25:1::0;174099:10:0::2;19235:18:1::0;;;19228:60;-1:-1:-1;;;;;174060:11:0;;::::2;::::0;:21:::2;::::0;19167:18:1;;174060:50:0::2;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:86;;;-1:-1:-1::0;174135:10:0::2;174114:32;::::0;;;:20:::2;:32;::::0;;;;;::::2;;174060:86;174034:159;;;::::0;-1:-1:-1;;;174034:159:0;;19751:2:1;174034:159:0::2;::::0;::::2;19733:21:1::0;19790:2;19770:18;;;19763:30;-1:-1:-1;;;19809:18:1;;;19802:41;19860:18;;174034:159:0::2;19549:335:1::0;174034:159:0::2;174322:8;::::0;174343:17;;174322:39:::2;::::0;-1:-1:-1;;;174322:39:0;;::::2;::::0;::::2;425:25:1::0;;;;174255:22:0::2;::::0;;;;;-1:-1:-1;;;;;174322:8:0::2;::::0;:20:::2;::::0;398:18:1;;174322:39:0::2;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;174254:107;;;;;;174378:10;:32;;;;;174409:1;174392:14;:18;174378:32;174374:2217;;;174440:14;::::0;174427:10:::2;174469:1703;174493:14;174489:1;:18;174469:1703;;;174542:19;174562:10;174573:1;174562:13;;;;;;;;:::i;:::-;;;;;;;174542:34;;;;;;:::i;:::-;::::0;;;::::2;::::0;;;;;::::2;::::0;;;;::::2;;174541:35;174533:76;;;::::0;-1:-1:-1;;;174533:76:0;;20755:2:1;174533:76:0::2;::::0;::::2;20737:21:1::0;20794:2;20774:18;;;20767:30;20833;20813:18;;;20806:58;20881:18;;174533:76:0::2;20553:352:1::0;174533:76:0::2;174630:4;::::0;::::2;:::i;:::-;;;174670:58;;;;;;;;174680:10;174691:1;174680:13;;;;;;;;:::i;:::-;;;;;;;174670:58;;;;174695:10;174706:1;174695:13;;;;;;;;:::i;:::-;;;;;;;174670:58;;;;174710:14;174725:1;174710:17;;;;;;;;:::i;:::-;;::::0;;::::2;::::0;;;;;;;174670:58;;;174653:14:::2;::::0;;;:10:::2;:14:::0;;;;;;:75;;:14;;:75:::2;::::0;:14;:75:::2;:::i;:::-;-1:-1:-1::0;174653:75:0::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;::::2;::::0;;::::2;:::i;:::-;;;;;;;;;;;;;174784:4;174747:19;174767:10;174778:1;174767:13;;;;;;;;:::i;:::-;;;;;;;174747:34;;;;;;:::i;:::-;;;;;;;;;;;;;;:41;;;;;;;;;;;;;;;;;;174809:30;174842:15;174858:10;174869:1;174858:13;;;;;;;;:::i;:::-;;;;;;;174842:30;;;;;;:::i;:::-;::::0;;;::::2;::::0;;;;;::::2;::::0;;;;-1:-1:-1;;;;;174842:30:0::2;::::0;-1:-1:-1;174842:30:0::2;174909:36:::0;;:59:::2;;167089:7;174909:59;;;174948:1;174909:59;174891:77;;167267:2;174991:14;175006:1;174991:17;;;;;;;;:::i;:::-;;;;;;;:41:::0;174987:697:::2;;175073:15;::::0;-1:-1:-1;;;;;175073:15:0::2;175057:74;;;::::0;-1:-1:-1;;;175057:74:0;;23310:2:1;175057:74:0::2;::::0;::::2;23292:21:1::0;23349:2;23329:18;;;23322:30;23388:25;23368:18;;;23361:53;23431:18;;175057:74:0::2;23108:347:1::0;175057:74:0::2;175162:12:::0;;175154:52:::2;;;::::0;-1:-1:-1;;;175154:52:0;;23662:2:1;175154:52:0::2;::::0;::::2;23644:21:1::0;23701:2;23681:18;;;23674:30;23740:29;23720:18;;;23713:57;23787:18;;175154:52:0::2;23460:351:1::0;175154:52:0::2;175229:15;::::0;175272:13;;-1:-1:-1;;;;;175229:15:0;;::::2;::::0;:21:::2;::::0;167030:8:::2;::::0;175272:10;;175283:1;;175272:13;::::2;;;;;:::i;:::-;;;;;;;175287:10;175298:1;175287:13;;;;;;;;:::i;:::-;;;;;;;175302:18;175321:1;175302:21;;;;;;;;:::i;:::-;;;;;;;175229:95;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;174987:697;;;175373:15;::::0;-1:-1:-1;;;;;175373:15:0::2;:23;175404:22;175419:7:::0;167030:8:::2;175404:22;:::i;:::-;175454:10;175465:1;175454:13;;;;;;;;:::i;:::-;;;;;;;175518:4;175511:12;;175533:3;175525:12;;175547:4;175494:59;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;175580:10;175591:1;175580:13;;;;;;;;:::i;:::-;;;;;;;175620:18;175639:1;175620:21;;;;;;;;:::i;:::-;;;;;;;175373:291;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;174987:697;175747:11:::0;;175743:340:::2;;175784:12;175802:22;-1:-1:-1::0;;;;;175802:27:0::2;175837:7;175802:47;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;175783:66;;;175880:7;175872:50;;;::::0;-1:-1:-1;;;175872:50:0;;25718:2:1;175872:50:0::2;::::0;::::2;25700:21:1::0;25757:2;25737:18;;;25730:30;25796:32;25776:18;;;25769:60;25846:18;;175872:50:0::2;25516:354:1::0;175872:50:0::2;175966:7;175945:17;;:28;;;;;;;:::i;:::-;;;;;;;;176040:22;-1:-1:-1::0;;;;;176001:62:0::2;176025:10;176036:1;176025:13;;;;;;;;:::i;:::-;;;;;;;176001:62;;;;;;:::i;:::-;;::::0;;;;::::2;::::0;;;176021:2;;176001:62:::2;::::0;;;::::2;175760:323;175743:340;176123:10;176134:1;176123:13;;;;;;;;:::i;:::-;;;;;;;176108:48;;;;;;:::i;:::-;;;;;;;;176119:2;176108:48;176138:14;176153:1;176138:17;;;;;;;;:::i;:::-;;;;;;;176108:48;;;;425:25:1::0;;413:2;398:18;;279:177;176108:48:0::2;;;;;;;;174514:1658;;174509:3;;;;;:::i;:::-;;;;174469:1703;;;-1:-1:-1::0;176186:14:0::2;:19:::0;174374:2217:::2;;;176228:10;176227:11;:33;;;;;176259:1;176242:14;:18;176227:33;176223:368;;;176285:33;::::0;;;:17:::2;:33;::::0;;;;;:38;176277:74:::2;;;::::0;-1:-1:-1;;;176277:74:0;;26077:2:1;176277:74:0::2;::::0;::::2;26059:21:1::0;26116:2;26096:18;;;26089:30;26155:25;26135:18;;;26128:53;26198:18;;176277:74:0::2;25875:347:1::0;176277:74:0::2;176387:14;176366:17;;:35;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;;176416:33:0::2;::::0;;;:17:::2;:33;::::0;;;;;:50;;;176481:14:::2;:35:::0;;::::2;::::0;::::2;::::0;;;;;;;::::2;::::0;;;176536:43;176434:14;;176536:43:::2;::::0;::::2;::::0;176452:14;425:25:1;;413:2;398:18;;279:177;176536:43:0::2;;;;;;;;176223:368;176608:4;176601:11;;;;;38706:20:::1;37923:1:::0;39226:7;:22;39043:213;38706:20:::1;173421:3199:::0;;;;;;:::o;30848:225::-;-1:-1:-1;;;;;28937:6:0;28920:23;28928:4;28920:23;28912:80;;;;-1:-1:-1;;;28912:80:0;;;;;;;:::i;:::-;29035:6;-1:-1:-1;;;;;29011:30:0;:20;:18;:20::i;:::-;-1:-1:-1;;;;;29011:30:0;;29003:87;;;;-1:-1:-1;;;29003:87:0;;;;;;;:::i;:::-;30966:36:::1;30984:17;30966;:36::i;:::-;31013:52;31035:17;31054:4;31060;31013:21;:52::i;30067:133::-:0;30145:7;29373:4;-1:-1:-1;;;;;29382:6:0;29365:23;;29357:92;;;;-1:-1:-1;;;29357:92:0;;26429:2:1;29357:92:0;;;26411:21:1;26468:2;26448:18;;;26441:30;26507:34;26487:18;;;26480:62;26578:26;26558:18;;;26551:54;26622:19;;29357:92:0;26227:420:1;29357:92:0;-1:-1:-1;;;;;;;;;;;;30067:133:0;:::o;190766:255::-;-1:-1:-1;;;;;;;;;;;170282:20:0;170292:9;170282;:20::i;:::-;190876:1:::1;190863:10;:14;:35;;;;;190895:3;190881:10;:17;;190863:35;190855:62;;;::::0;-1:-1:-1;;;190855:62:0;;26854:2:1;190855:62:0::1;::::0;::::1;26836:21:1::0;26893:2;26873:18;;;26866:30;-1:-1:-1;;;26912:18:1;;;26905:44;26966:18;;190855:62:0::1;26652:338:1::0;190855:62:0::1;190952:12;::::0;190933:44:::1;::::0;;16228:25:1;;;16284:2;16269:18;;16262:34;;;190933:44:0::1;::::0;16201:18:1;190933:44:0::1;;;;;;;-1:-1:-1::0;190988:12:0::1;:25:::0;190766:255::o;171564:1275::-;171762:4;34531:19;:17;:19::i;:::-;38662:21:::1;:19;:21::i;:::-;171822:10:::2;:17;171801:10;:17;:38;:105;;;;;171881:18;:25;171860:10;:17;:46;171801:105;:147;;;;;171947:1;171927:10;:17;:21;171801:147;171779:218;;;::::0;-1:-1:-1;;;171779:218:0;;18527:2:1;171779:218:0::2;::::0;::::2;18509:21:1::0;18566:2;18546:18;;;18539:30;-1:-1:-1;;;18585:18:1;;;18578:51;18646:18;;171779:218:0::2;18325:345:1::0;171779:218:0::2;172048:17:::0;;172029:36:::2;::::0;167089:7:::2;172029:36;:::i;:::-;172016:9;:49;172008:108;;;::::0;-1:-1:-1;;;172008:108:0;;27197:2:1;172008:108:0::2;::::0;::::2;27179:21:1::0;27236:2;27216:18;;;27209:30;27275:34;27255:18;;;27248:62;-1:-1:-1;;;27326:18:1;;;27319:44;27380:19;;172008:108:0::2;26995:410:1::0;172008:108:0::2;172134:9;172129:636;172153:10;:17;172149:1;:21;172129:636;;;172201:19;172221:10;172232:1;172221:13;;;;;;;;:::i;:::-;;;;;;;172201:34;;;;;;:::i;:::-;::::0;;;::::2;::::0;;;;;::::2;::::0;;;;::::2;;172200:35;172192:76;;;::::0;-1:-1:-1;;;172192:76:0;;20755:2:1;172192:76:0::2;::::0;::::2;20737:21:1::0;20794:2;20774:18;;;20767:30;20833;20813:18;;;20806:58;20881:18;;172192:76:0::2;20553:352:1::0;172192:76:0::2;172333:1;-1:-1:-1::0;;;;;172291:44:0::2;:15;172307:10;172318:1;172307:13;;;;;;;;:::i;:::-;;;;;;;172291:30;;;;;;:::i;:::-;::::0;;;::::2;::::0;;;;;::::2;::::0;;;;-1:-1:-1;;;;;172291:30:0::2;:44;172283:88;;;::::0;-1:-1:-1;;;172283:88:0;;27612:2:1;172283:88:0::2;::::0;::::2;27594:21:1::0;27651:2;27631:18;;;27624:30;27690:33;27670:18;;;27663:61;27741:18;;172283:88:0::2;27410:355:1::0;172283:88:0::2;172388:15;::::0;172455:13;;-1:-1:-1;;;;;172388:15:0;;::::2;::::0;:23:::2;::::0;167089:7:::2;::::0;172455:10;;172466:1;;172455:13;::::2;;;;;:::i;:::-;;;;;;;172511:4;172504:12;;172526:3;172518:12;;172540:4;172487:59;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;172565:10;172576:1;172565:13;;;;;;;;:::i;:::-;;;;;;;172597:18;172616:1;172597:21;;;;;;;;:::i;:::-;;;;;;;172388:245;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;;172683:10;172650:15;172666:10;172677:1;172666:13;;;;;;;;:::i;:::-;;;;;;;172650:30;;;;;;:::i;:::-;;;;;;;;;;;;;;:43;;;;;-1:-1:-1::0;;;;;172650:43:0::2;;;;;-1:-1:-1::0;;;;;172650:43:0::2;;;;;;172742:10;-1:-1:-1::0;;;;;172713:40:0::2;172727:10;172738:1;172727:13;;;;;;;;:::i;:::-;;;;;;;172713:40;;;;;;:::i;:::-;;::::0;;;;::::2;::::0;;;::::2;::::0;;;::::2;172172:3:::0;::::2;::::0;::::2;:::i;:::-;;;;172129:636;;;;172798:9;172777:17;;:30;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;172827:4:0::2;::::0;-1:-1:-1;;38706:20:0::1;37923:1:::0;39226:7;:22;39043:213;38706:20:::1;171564:1275:::0;;;;;:::o;191298:399::-;-1:-1:-1;;;;;;;;;;;170282:20:0;170292:9;170282;:20::i;:::-;191416:16;191408:48:::1;;;::::0;-1:-1:-1;;;191408:48:0;;14942:2:1;191408:48:0::1;::::0;::::1;14924:21:1::0;14981:2;14961:18;;;14954:30;-1:-1:-1;;;15000:18:1;;;14993:49;15059:18;;191408:48:0::1;14740:343:1::0;191408:48:0::1;191472:9;191467:223;191487:16:::0;;::::1;191467:223;;;191553:1;191533:5:::0;;191539:1;191533:8;;::::1;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;191533:22:0::1;::::0;191525:47:::1;;;::::0;-1:-1:-1;;;191525:47:0;;15422:2:1;191525:47:0::1;::::0;::::1;15404:21:1::0;15461:2;15441:18;;;15434:30;-1:-1:-1;;;15480:18:1;;;15473:42;15532:18;;191525:47:0::1;15220:336:1::0;191525:47:0::1;191615:5;191587:15;:25;191603:5;;191609:1;191603:8;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;191587:25:0::1;::::0;;::::1;::::0;::::1;::::0;;;;;;-1:-1:-1;191587:25:0;:33;;-1:-1:-1;;191587:33:0::1;::::0;::::1;;::::0;;;::::1;::::0;;191640:38;::::1;;191662:5:::0;;191668:1;191662:8;;::::1;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;191640:38:0::1;;;;;;;;;;;191505:3:::0;::::1;::::0;::::1;:::i;:::-;;;;191467:223;;193914:93:::0;166926:28;170282:20;170292:9;170282;:20::i;:::-;34531:19:::1;:17;:19::i;:::-;193991:8:::2;:6;:8::i;193162:248::-:0;-1:-1:-1;;;;;;;;;;;170282:20:0;170292:9;170282;:20::i;:::-;-1:-1:-1;;;;;193262:27:0;::::1;193254:60;;;::::0;-1:-1:-1;;;193254:60:0;;27972:2:1;193254:60:0::1;::::0;::::1;27954:21:1::0;28011:2;27991:18;;;27984:30;-1:-1:-1;;;28030:18:1;;;28023:50;28090:18;;193254:60:0::1;27770:344:1::0;193254:60:0::1;193325:12;:28:::0;;-1:-1:-1;;;;;;193325:28:0::1;-1:-1:-1::0;;;;;193325:28:0;::::1;::::0;;::::1;::::0;;;193369:33:::1;::::0;::::1;::::0;-1:-1:-1;;193369:33:0::1;193162:248:::0;;:::o;179029:1702::-;34531:19;:17;:19::i;:::-;38662:21:::1;:19;:21::i;:::-;179437:17:::2;;179422:12;:32;179414:65;;;::::0;-1:-1:-1;;;179414:65:0;;28321:2:1;179414:65:0::2;::::0;::::2;28303:21:1::0;28360:2;28340:18;;;28333:30;-1:-1:-1;;;28379:18:1;;;28372:50;28439:18;;179414:65:0::2;28119:344:1::0;179414:65:0::2;179518:14;;179498:16;:34;;179490:70;;;::::0;-1:-1:-1;;;179490:70:0;;28670:2:1;179490:70:0::2;::::0;::::2;28652:21:1::0;28709:2;28689:18;;;28682:30;28748:25;28728:18;;;28721:53;28791:18;;179490:70:0::2;28468:347:1::0;179490:70:0::2;179614:14;;179593:17;:35;;:76;;;;;179653:16;;179632:17;:37;;179593:76;179571:150;;;::::0;-1:-1:-1;;;179571:150:0;;29022:2:1;179571:150:0::2;::::0;::::2;29004:21:1::0;29061:2;29041:18;;;29034:30;29100:26;29080:18;;;29073:54;29144:18;;179571:150:0::2;28820:348:1::0;179571:150:0::2;179762:12;::::0;179740:34;::::2;;179732:72;;;::::0;-1:-1:-1;;;179732:72:0;;29375:2:1;179732:72:0::2;::::0;::::2;29357:21:1::0;29414:2;29394:18;;;29387:30;29453:27;29433:18;;;29426:55;29498:18;;179732:72:0::2;29173:349:1::0;179732:72:0::2;179831:8;::::0;-1:-1:-1;;;;;179831:8:0::2;179815:60;;;::::0;-1:-1:-1;;;179815:60:0;;18877:2:1;179815:60:0::2;::::0;::::2;18859:21:1::0;18916:2;18896:18;;;18889:30;-1:-1:-1;;;18935:18:1;;;18928:46;18991:18;;179815:60:0::2;18675:340:1::0;179815:60:0::2;179974:255;::::0;;::::2;::::0;;::::2;29790:19:1::0;;;29825:12;;;29818:28;;;29862:12;;;29855:28;;;29899:12;;;29892:28;;;29936:13;;;29929:29;;;30005:14;;29998:22;29993:3;29989:32;29974:13;;;29967:55;179974:255:0;;;;;;;;;30038:13:1;;;179974:255:0;;179950:290;;;;::::2;::::0;34338:66:1;62197:58:0;;;34326:79:1;34421:12;;;;34414:28;;;;62197:58:0;;;;;;;;;;34458:12:1;;;;62197:58:0;;;62187:69;;;;;180281:9:::2;180276:166;180296:22:::0;;::::2;180276:166;;;180348:60;180367:12;180381:10;180393:11;;180405:1;180393:14;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;180348:60;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::2;::::0;;;;-1:-1:-1;180348:18:0::2;::::0;-1:-1:-1;;;180348:60:0:i:2;:::-;180340:90;;;::::0;-1:-1:-1;;;180340:90:0;;30790:2:1;180340:90:0::2;::::0;::::2;30772:21:1::0;30829:2;30809:18;;;30802:30;-1:-1:-1;;;30848:18:1;;;30841:47;30905:18;;180340:90:0::2;30588:341:1::0;180340:90:0::2;180320:3:::0;::::2;::::0;::::2;:::i;:::-;;;;180276:166;;;;180454:269;180482:12;180509:16;180540:18;180573:17;180605:27;180647:30;180692:20;180454:13;:269::i;:::-;179403:1328;38706:20:::1;37923:1:::0;39226:7;:22;39043:213;38706:20:::1;179029:1702:::0;;;;;;;;;:::o;192812:236::-;166841:35;170282:20;170292:9;170282;:20::i;:::-;-1:-1:-1;;;;;192913:23:0;::::1;192905:52;;;::::0;-1:-1:-1;;;192905:52:0;;31136:2:1;192905:52:0::1;::::0;::::1;31118:21:1::0;31175:2;31155:18;;;31148:30;-1:-1:-1;;;31194:18:1;;;31187:46;31250:18;;192905:52:0::1;30934:340:1::0;192905:52:0::1;192968:8;:31:::0;;-1:-1:-1;;;;;;192968:31:0::1;-1:-1:-1::0;;;;;192968:31:0;::::1;::::0;;::::1;::::0;;;193015:25:::1;::::0;::::1;::::0;-1:-1:-1;;193015:25:0::1;192812:236:::0;;:::o;190416:154::-;190466:7;167030:8;190530:16;;190511;;190494:14;;:33;;;;:::i;:::-;:52;;;;:::i;:::-;190493:69;;;;:::i;194275:139::-;194346:11;;:44;;-1:-1:-1;;;194346:44:0;;;;;19194:25:1;;;194379:10:0;19235:18:1;;;19228:60;-1:-1:-1;;;;;194346:11:0;;;;:21;;19167:18:1;;194346:44:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;194338:68;;;;-1:-1:-1;;;194338:68:0;;19751:2:1;194338:68:0;;;19733:21:1;19790:2;19770:18;;;19763:30;-1:-1:-1;;;19809:18:1;;;19802:41;19860:18;;194338:68:0;19549:335:1;21108:153:0;-1:-1:-1;;;;;;;;;;;21188:65:0;-1:-1:-1;;;;;21188:65:0;;21108:153::o;195016:189::-;166841:35;170282:20;170292:9;170282;:20::i;:::-;195182:1:::1;195149:18;-1:-1:-1::0;;;;;195149:30:0::1;;:34;195141:56;;;::::0;-1:-1:-1;;;195141:56:0;;31481:2:1;195141:56:0::1;::::0;::::1;31463:21:1::0;31520:1;31500:18;;;31493:29;-1:-1:-1;;;31538:18:1;;;31531:39;31587:18;;195141:56:0::1;31279:332:1::0;21754:155:0;21821:37;21840:17;21821:18;:37::i;:::-;21874:27;;-1:-1:-1;;;;;21874:27:0;;;;;;;;21754:155;:::o;35270:108::-;34997:7;;;;35329:41;;;;-1:-1:-1;;;35329:41:0;;31818:2:1;35329:41:0;;;31800:21:1;31857:2;31837:18;;;31830:30;-1:-1:-1;;;31876:18:1;;;31869:50;31936:18;;35329:41:0;31616:344:1;35329:41:0;35270:108::o;35781:120::-;34790:16;:14;:16::i;:::-;35840:7:::1;:15:::0;;-1:-1:-1;;35840:15:0::1;::::0;;35871:22:::1;32792:10:::0;35880:12:::1;35871:22;::::0;-1:-1:-1;;;;;625:32:1;;;607:51;;595:2;580:18;35871:22:0::1;;;;;;;35781:120::o:0;34096:99::-;18694:13;;;;;;;18686:69;;;;-1:-1:-1;;;18686:69:0;;;;;;;:::i;:::-;34160:27:::1;:25;:27::i;38009:113::-:0;18694:13;;;;;;;18686:69;;;;-1:-1:-1;;;18686:69:0;;;;;;;:::i;:::-;38080:34:::1;:32;:34::i;28065:68::-:0;18694:13;;;;;;;18686:69;;;;-1:-1:-1;;;18686:69:0;;;;;;;:::i;35085:108::-;34997:7;;;;35155:9;35147:38;;;;-1:-1:-1;;;35147:38:0;;32579:2:1;35147:38:0;;;32561:21:1;32618:2;32598:18;;;32591:30;-1:-1:-1;;;32637:18:1;;;32630:46;32693:18;;35147:38:0;32377:340:1;38742:293:0;37967:1;38876:7;;:19;38868:63;;;;-1:-1:-1;;;38868:63:0;;32924:2:1;38868:63:0;;;32906:21:1;32963:2;32943:18;;;32936:30;33002:33;32982:18;;;32975:61;33053:18;;38868:63:0;32722:355:1;38868:63:0;37967:1;39009:7;:18;38742:293::o;39043:213::-;37923:1;39226:7;:22;39043:213::o;22526:992::-;20610:66;22980:59;;;22976:535;;;23056:37;23075:17;23056:18;:37::i;22976:535::-;23159:17;-1:-1:-1;;;;;23130:61:0;;:63;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;23130:63:0;;;;;;;;-1:-1:-1;;23130:63:0;;;;;;;;;;;;:::i;:::-;;;23126:306;;23360:56;;-1:-1:-1;;;23360:56:0;;33473:2:1;23360:56:0;;;33455:21:1;33512:2;33492:18;;;33485:30;33551:34;33531:18;;;33524:62;-1:-1:-1;;;33602:18:1;;;33595:44;33656:19;;23360:56:0;33271:410:1;23126:306:0;-1:-1:-1;;;;;;;;;;;23244:28:0;;23236:82;;;;-1:-1:-1;;;23236:82:0;;33888:2:1;23236:82:0;;;33870:21:1;33927:2;33907:18;;;33900:30;33966:34;33946:18;;;33939:62;-1:-1:-1;;;34017:18:1;;;34010:39;34066:19;;23236:82:0;33686:405:1;23236:82:0;23194:140;23446:53;23464:17;23483:4;23489:9;23446:17;:53::i;35522:118::-;34531:19;:17;:19::i;:::-;35582:7:::1;:14:::0;;-1:-1:-1;;35582:14:0::1;35592:4;35582:14;::::0;;35612:20:::1;35619:12;32792:10:::0;;32712:98;185280:544;185428:4;;185462:31;:11;185482:10;185462:19;:31::i;:::-;-1:-1:-1;;;;;185546:23:0;;;;;;:15;:23;;;;;;185445:48;;-1:-1:-1;185546:23:0;;185541:42;;185578:5;185571:12;;;;;185541:42;-1:-1:-1;;;;;185645:19:0;;;;;;:11;:19;;;;;;:35;-1:-1:-1;185641:53:0;;185689:5;185682:12;;;;;185641:53;-1:-1:-1;;;;;185707:19:0;;;;;;:11;:19;;;;;;:34;;;185757:35;185729:12;;185757:35;;;-1:-1:-1;185812:4:0;;185280:544;-1:-1:-1;;;;185280:544:0:o;180800:4167::-;181167:15;;-1:-1:-1;;;;;181167:15:0;181159:38;181155:1110;;181240:34;;181236:122;;181295:47;181311:30;181295:15;:47::i;:::-;181421:25;181449:53;181474:27;181449:24;:53::i;:::-;181582:28;;:91;;-1:-1:-1;;;181582:91:0;;181653:4;181582:91;;;607:51:1;181421:81:0;;-1:-1:-1;181519:60:0;;-1:-1:-1;;;;;181582:28:0;;;;:44;;580:18:1;;181582:91:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;181582:91:0;;;;;;;;;;;;:::i;:::-;181519:154;;181688:25;181752:1;181716:5;:33;;;:37;:132;;181847:1;181716:132;;;181773:15;:54;181825:1;181789:5;:33;;;:37;;;;:::i;:::-;181773:54;;;;;;;;;;;;181716:132;181688:160;-1:-1:-1;181863:31:0;181897:47;181688:160;181897:27;:47;:::i;:::-;181863:81;-1:-1:-1;182078:39:0;182100:17;182078:39;;:::i;:::-;;-1:-1:-1;182132:43:0;182152:23;182132:43;;:::i;:::-;;-1:-1:-1;182210:43:0;182230:23;182210:17;:43;:::i;:::-;182190:63;;181199:1066;;;;181155:1110;182277:21;182322:31;167030:8;182322:16;:31;:::i;:::-;182301:18;:52;:137;;182437:1;182301:137;;;182390:31;167030:8;182390:16;:31;:::i;:::-;182369:52;;:18;:52;:::i;:::-;182482:14;;182546:16;;182277:161;;-1:-1:-1;182482:14:0;182449:30;;182526:36;;:17;:36;:::i;:::-;182601:17;:32;;;182644:16;:35;;;182690:23;:44;;;182745:16;:36;;;182792:14;:30;;;182881:8;;:30;;;-1:-1:-1;;;182881:30:0;;;;182507:55;;-1:-1:-1;182881:54:0;;;;-1:-1:-1;;;;;182881:8:0;;;;:28;;-1:-1:-1;182881:30:0;;;;;;;;;;;;;;:8;:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:54;;;182877:140;;182952:8;;:53;;-1:-1:-1;;;182952:53:0;;1407:14:1;;1400:22;182952:53:0;;;1382:41:1;-1:-1:-1;;;;;182952:8:0;;;;:31;;1355:18:1;;182952:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;182877:140;183101:12;;-1:-1:-1;;;;;183101:12:0;:26;183097:137;;167146:5;183187:16;;183171:13;:32;;;;:::i;:::-;183170:52;;;;:::i;:::-;183144:23;:78;183097:137;183343:21;183379:17;;183375:1400;;183413:20;183436:43;183441:12;183455:23;167030:8;183455;:23;:::i;:::-;183436:4;:43::i;:::-;183413:66;-1:-1:-1;183494:27:0;183524;183413:66;183524:12;:27;:::i;:::-;183494:57;-1:-1:-1;183566:20:0;183589:35;183494:57;183589:13;:35;:::i;:::-;183566:58;;183639:24;183666:50;183679:12;183693:22;183666:12;:50::i;:::-;183639:77;;183731:30;183764:43;183769:19;183790:16;183764:4;:43::i;:::-;183731:76;;183903:1;183881:19;:23;:53;;;;-1:-1:-1;183908:12:0;;-1:-1:-1;;;;;183908:12:0;:26;;183881:53;183877:622;;;183955:25;167146:5;184006:16;;183984:19;:38;;;;:::i;:::-;183983:58;;;;:::i;:::-;183955:86;;184060:28;167146:5;184117:16;;184092:22;:41;;;;:::i;:::-;184091:61;;;;:::i;:::-;184060:92;-1:-1:-1;184171:40:0;184194:17;184171:40;;:::i;:::-;;-1:-1:-1;184230:33:0;184246:17;184230:33;;:::i;:::-;;-1:-1:-1;184282:46:0;184308:20;184282:46;;:::i;:::-;184366:12;;:47;;184282:46;;-1:-1:-1;184348:12:0;;-1:-1:-1;;;;;184366:12:0;;;;184391:17;;184348:12;184366:47;184348:12;184366:47;184391:17;184366:12;:47;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;184347:66;;;184440:7;184432:51;;;;-1:-1:-1;;;184432:51:0;;36568:2:1;184432:51:0;;;36550:21:1;36607:2;36587:18;;;36580:30;36646:33;36626:18;;;36619:61;36697:18;;184432:51:0;36366:355:1;184432:51:0;183936:563;;;183877:622;184515:8;;:84;;-1:-1:-1;;;184515:84:0;;;;;16228:25:1;;;16269:18;;;16262:34;;;-1:-1:-1;;;;;184515:8:0;;;;:25;;184548:12;;16201:18:1;;184515:84:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;184640:12;184619:86;184654:22;184678:12;184692;184619:86;;;;;;;36928:25:1;;;36984:2;36969:18;;36962:34;;;;37027:2;37012:18;;37005:34;36916:2;36901:18;;36726:319;184619:86:0;;;;;;;;183398:1319;;;;;183375:1400;;;184738:8;;;;;;;;;-1:-1:-1;;;;;184738:8:0;-1:-1:-1;;;;;184738:23:0;;:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;183375:1400;184817:13;;184813:42;;184832:23;184846:8;184832:13;:23::i;:::-;184873:86;;;37281:25:1;;;37337:2;37322:18;;37315:34;;;37365:18;;;37358:34;;;37423:2;37408:18;;37401:34;;;184873:86:0;;37268:3:1;37253:19;184873:86:0;;;;;;;181109:3858;;;;180800:4167;;;;;;;:::o;21357:284::-;-1:-1:-1;;;;;3609:19:0;;;21431:106;;;;-1:-1:-1;;;21431:106:0;;37648:2:1;21431:106:0;;;37630:21:1;37687:2;37667:18;;;37660:30;37726:34;37706:18;;;37699:62;-1:-1:-1;;;37777:18:1;;;37770:43;37830:19;;21431:106:0;37446:409:1;21431:106:0;-1:-1:-1;;;;;;;;;;;21548:85:0;;-1:-1:-1;;;;;;21548:85:0;-1:-1:-1;;;;;21548:85:0;;;;;;;;;;21357:284::o;34203:97::-;18694:13;;;;;;;18686:69;;;;-1:-1:-1;;;18686:69:0;;;;;;;:::i;:::-;34277:7:::1;:15:::0;;-1:-1:-1;;34277:15:0::1;::::0;;34203:97::o;38130:111::-;18694:13;;;;;;;18686:69;;;;-1:-1:-1;;;18686:69:0;;;;;;;:::i;22050:297::-;22193:29;22204:17;22193:10;:29::i;:::-;22251:1;22237:4;:11;:15;:28;;;;22256:9;22237:28;22233:107;;;22282:46;22304:17;22323:4;22282:21;:46::i;:::-;;22050:297;;;:::o;58305:231::-;58383:7;58404:17;58423:18;58445:27;58456:4;58462:9;58445:10;:27::i;:::-;58403:69;;;;58483:18;58495:5;58483:11;:18::i;:::-;-1:-1:-1;58519:9:0;-1:-1:-1;58305:231:0;;;;;:::o;188287:1228::-;188412:15;;:37;;-1:-1:-1;;;188412:37:0;;188443:4;188412:37;;;607:51:1;188376:7:0;;;;-1:-1:-1;;;;;188412:15:0;;;;:22;;580:18:1;;188412:37:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;188396:53;-1:-1:-1;;;;;;188478:20:0;;;188513:11;;188509:962;;188615:25;188644:3;-1:-1:-1;;;;;188644:15:0;;:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:26;;;188643:118;;-1:-1:-1;188711:28:0;;188693:58;;-1:-1:-1;;;188693:58:0;;188711:28;188693:58;;;18278:36:1;-1:-1:-1;;;;;188711:28:0;;;;188693:55;;18251:18:1;;188693:58:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:67;188643:118;188615:146;;188782:20;188778:682;;;188846:7;188823:19;;:30;;;;;;;:::i;:::-;;;;;;;;188872:3;-1:-1:-1;;;;;188872:27:0;;:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;189051:28:0;;:81;;-1:-1:-1;;;189051:81:0;;189126:4;189051:81;;;607:51:1;188988:60:0;;-1:-1:-1;;;;;;189051:28:0;;;;-1:-1:-1;189051:66:0;;580:18:1;;189051:81:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;189051:81:0;;;;;;;;;;;;:::i;:::-;188988:144;;189206:27;189151:15;:52;189201:1;189167:5;:24;;;:31;:35;;;;:::i;:::-;189151:52;;;;;;;;;;;:82;;;;189320:1;189286:5;:24;;;:31;:35;;;;:::i;:::-;189259:63;;;;;;;-1:-1:-1;;189348:19:0;;;188287:1228;-1:-1:-1;;;;188287:1228:0:o;188778:682::-;189437:7;189415:19;;:29;;;;:::i;:::-;189408:36;188287:1228;-1:-1:-1;;;;;188287:1228:0:o;188509:962::-;-1:-1:-1;;189488:19:0;;;188287:1228;-1:-1:-1;;188287:1228:0:o;193498:113::-;193559:7;193591:2;193586;:7;:17;;193601:2;193586:17;;;-1:-1:-1;193596:2:0;193579:24;-1:-1:-1;193498:113:0:o;193680:185::-;193747:7;193775:1;193771;:5;193767:91;;;-1:-1:-1;193800:1:0;193793:8;;193767:91;193841:5;193845:1;193841;:5;:::i;:::-;193834:12;;;;185942:1040;186110:19;;186054:24;;186093:622;186135:14;:21;186131:25;;186093:622;;;186178:15;186196:14;186211:1;186196:17;;;;;;;;:::i;:::-;;;;;;;;;;;;;186251:26;;;:17;:26;;;;;;;;186196:17;;-1:-1:-1;186296:25:0;;;186292:332;;186374:18;;;;:::i;:::-;;-1:-1:-1;186411:25:0;;-1:-1:-1;186424:12:0;186411:25;;:::i;:::-;;;186292:332;;;186560:24;186575:9;186560:12;:24;:::i;:::-;186531:26;;;;:17;:26;;;;;;:53;;;;-1:-1:-1;186603:5:0;;186292:332;186695:1;186682:9;:14;186678:25;;186698:5;;;;186678:25;186163:552;;186158:3;;;;;:::i;:::-;;;;186093:622;;;;186753:24;186794:16;-1:-1:-1;;;;;186780:31:0;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;186780:31:0;;186753:58;;186827:9;186822:110;186846:16;186842:1;:20;186822:110;;;186897:23;:21;:23::i;:::-;186884:7;186892:1;186884:10;;;;;;;;:::i;:::-;;;;;;;;;;:36;186864:3;;;;:::i;:::-;;;;186822:110;;;-1:-1:-1;186944:8:0;;:30;;-1:-1:-1;;;186944:30:0;;-1:-1:-1;;;;;186944:8:0;;;;:21;;:30;;186966:7;;186944:30;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;185993:989;;185942:1040;:::o;26523:461::-;26606:12;-1:-1:-1;;;;;3609:19:0;;;26631:88;;;;-1:-1:-1;;;26631:88:0;;39172:2:1;26631:88:0;;;39154:21:1;39211:2;39191:18;;;39184:30;39250:34;39230:18;;;39223:62;-1:-1:-1;;;39301:18:1;;;39294:36;39347:19;;26631:88:0;38970:402:1;26631:88:0;26793:12;26807:23;26834:6;-1:-1:-1;;;;;26834:19:0;26854:4;26834:25;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;26792:67;;;;26877:99;26913:7;26922:10;26877:99;;;;;;;;;;;;;;;;;:35;:99::i;56756:747::-;56837:7;56846:12;56875:9;:16;56895:2;56875:22;56871:625;;57219:4;57204:20;;57198:27;57269:4;57254:20;;57248:27;57327:4;57312:20;;57306:27;56914:9;57298:36;57370:25;57381:4;57298:36;57198:27;57248;57370:10;:25::i;:::-;57363:32;;;;;;;;;56871:625;-1:-1:-1;57444:1:0;;-1:-1:-1;57448:35:0;56871:625;56756:747;;;;;:::o;55149:521::-;55227:20;55218:5;:29;;;;;;;;:::i;:::-;;55214:449;;55149:521;:::o;55214:449::-;55325:29;55316:5;:38;;;;;;;;:::i;:::-;;55312:351;;55371:34;;-1:-1:-1;;;55371:34:0;;39711:2:1;55371:34:0;;;39693:21:1;39750:2;39730:18;;;39723:30;39789:26;39769:18;;;39762:54;39833:18;;55371:34:0;39509:348:1;55312:351:0;55436:35;55427:5;:44;;;;;;;;:::i;:::-;;55423:240;;55488:41;;-1:-1:-1;;;55488:41:0;;40064:2:1;55488:41:0;;;40046:21:1;40103:2;40083:18;;;40076:30;40142:33;40122:18;;;40115:61;40193:18;;55488:41:0;39862:355:1;55423:240:0;55560:30;55551:5;:39;;;;;;;;:::i;:::-;;55547:116;;55607:44;;-1:-1:-1;;;55607:44:0;;40424:2:1;55607:44:0;;;40406:21:1;40463:2;40443:18;;;40436:30;40502:34;40482:18;;;40475:62;-1:-1:-1;;;40553:18:1;;;40546:32;40595:19;;55607:44:0;40222:398:1;187102:301:0;187213:19;;187189:14;:21;187153:15;;-1:-1:-1;187181:70:0;;;;-1:-1:-1;;;187181:70:0;;40827:2:1;187181:70:0;;;40809:21:1;40866:2;40846:18;;;40839:30;-1:-1:-1;;;40885:18:1;;;40878:44;40939:18;;187181:70:0;40625:338:1;187181:70:0;187272:14;187287:19;;187272:35;;;;;;;;:::i;:::-;;;;;;;;;187262:45;;187325:14;187340:19;;187325:35;;;;;;;;:::i;:::-;;;;;;;;187318:42;;;187394:1;187371:19;;:24;;;;;;;:::i;:::-;;;;;;;;187102:301;:::o;9724:305::-;9874:12;9903:7;9899:123;;;-1:-1:-1;9934:10:0;9927:17;;9899:123;9977:33;9985:10;9997:12;9977:7;:33::i;59757:1520::-;59888:7;;60822:66;60809:79;;60805:163;;;-1:-1:-1;60921:1:0;;-1:-1:-1;60925:30:0;60905:51;;60805:163;61082:24;;;61065:14;61082:24;;;;;;;;;41195:25:1;;;41268:4;41256:17;;41236:18;;;41229:45;;;;41290:18;;;41283:34;;;41333:18;;;41326:34;;;61082:24:0;;41167:19:1;;61082:24:0;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;61082:24:0;;-1:-1:-1;;61082:24:0;;;-1:-1:-1;;;;;;;61121:20:0;;61117:103;;61174:1;61178:29;61158:50;;;;;;;61117:103;61240:6;-1:-1:-1;61248:20:0;;-1:-1:-1;59757:1520:0;;;;;;;;:::o;10037:552::-;10198:17;;:21;10194:388;;10430:10;10424:17;10487:15;10474:10;10470:2;10466:19;10459:44;10194:388;10557:12;10550:20;;-1:-1:-1;;;10550:20:0;;;;;;;;:::i;14:127:1:-;75:10;70:3;66:20;63:1;56:31;106:4;103:1;96:15;130:4;127:1;120:15;146:128;213:9;;;234:11;;;231:37;;;248:18;;:::i;669:180::-;728:6;781:2;769:9;760:7;756:23;752:32;749:52;;;797:1;794;787:12;749:52;-1:-1:-1;820:23:1;;669:180;-1:-1:-1;669:180:1:o;854:131::-;-1:-1:-1;;;;;929:31:1;;919:42;;909:70;;975:1;972;965:12;990:247;1049:6;1102:2;1090:9;1081:7;1077:23;1073:32;1070:52;;;1118:1;1115;1108:12;1070:52;1157:9;1144:23;1176:31;1201:5;1176:31;:::i;1434:250::-;1519:1;1529:113;1543:6;1540:1;1537:13;1529:113;;;1619:11;;;1613:18;1600:11;;;1593:39;1565:2;1558:10;1529:113;;;-1:-1:-1;;1676:1:1;1658:16;;1651:27;1434:250::o;1689:270::-;1730:3;1768:5;1762:12;1795:6;1790:3;1783:19;1811:76;1880:6;1873:4;1868:3;1864:14;1857:4;1850:5;1846:16;1811:76;:::i;:::-;1941:2;1920:15;-1:-1:-1;;1916:29:1;1907:39;;;;1948:4;1903:50;;1689:270;-1:-1:-1;;1689:270:1:o;1964:448::-;2185:2;2174:9;2167:21;2148:4;2211:44;2251:2;2240:9;2236:18;2228:6;2211:44;:::i;:::-;2303:9;2295:6;2291:22;2286:2;2275:9;2271:18;2264:50;2331:32;2356:6;2348;2331:32;:::i;:::-;2323:40;;;2399:6;2394:2;2383:9;2379:18;2372:34;1964:448;;;;;;:::o;2417:388::-;2485:6;2493;2546:2;2534:9;2525:7;2521:23;2517:32;2514:52;;;2562:1;2559;2552:12;2514:52;2601:9;2588:23;2620:31;2645:5;2620:31;:::i;:::-;2670:5;-1:-1:-1;2727:2:1;2712:18;;2699:32;2740:33;2699:32;2740:33;:::i;:::-;2792:7;2782:17;;;2417:388;;;;;:::o;2810:367::-;2873:8;2883:6;2937:3;2930:4;2922:6;2918:17;2914:27;2904:55;;2955:1;2952;2945:12;2904:55;-1:-1:-1;2978:20:1;;-1:-1:-1;;;;;3010:30:1;;3007:50;;;3053:1;3050;3043:12;3007:50;3090:4;3082:6;3078:17;3066:29;;3150:3;3143:4;3133:6;3130:1;3126:14;3118:6;3114:27;3110:38;3107:47;3104:67;;;3167:1;3164;3157:12;3182:118;3268:5;3261:13;3254:21;3247:5;3244:32;3234:60;;3290:1;3287;3280:12;3305:566;3397:6;3405;3413;3466:2;3454:9;3445:7;3441:23;3437:32;3434:52;;;3482:1;3479;3472:12;3434:52;3522:9;3509:23;-1:-1:-1;;;;;3547:6:1;3544:30;3541:50;;;3587:1;3584;3577:12;3541:50;3626:70;3688:7;3679:6;3668:9;3664:22;3626:70;:::i;:::-;3715:8;;-1:-1:-1;3600:96:1;-1:-1:-1;;3800:2:1;3785:18;;3772:32;3813:28;3772:32;3813:28;:::i;:::-;3860:5;3850:15;;;3305:566;;;;;:::o;3876:1221::-;4108:4;4137:2;4177;4166:9;4162:18;4207:2;4196:9;4189:21;4230:6;4265;4259:13;4296:6;4288;4281:22;4322:2;4312:12;;4355:2;4344:9;4340:18;4333:25;;4417:2;4407:6;4404:1;4400:14;4389:9;4385:30;4381:39;4439:4;4478:2;4470:6;4466:15;4499:1;4509:516;4523:6;4520:1;4517:13;4509:516;;;4616:2;4612:7;4600:9;4592:6;4588:22;4584:36;4579:3;4572:49;4650:6;4644:13;4691:2;4685:9;4677:6;4670:25;4742:2;4738;4734:11;4728:18;4783:2;4778;4770:6;4766:15;4759:27;4813:47;4856:2;4848:6;4844:15;4830:12;4813:47;:::i;:::-;4903:11;;;4897:18;4880:15;;;4873:43;;;;5003:12;;;;4799:61;-1:-1:-1;4968:15:1;;;;4545:1;4538:9;4509:516;;;-1:-1:-1;;5064:18:1;;;;5057:34;;;;-1:-1:-1;5042:6:1;;3876:1221;-1:-1:-1;;;;;3876:1221:1:o;5102:127::-;5163:10;5158:3;5154:20;5151:1;5144:31;5194:4;5191:1;5184:15;5218:4;5215:1;5208:15;5234:257;5306:4;5300:11;;;5338:17;;-1:-1:-1;;;;;5370:34:1;;5406:22;;;5367:62;5364:88;;;5432:18;;:::i;:::-;5468:4;5461:24;5234:257;:::o;5496:275::-;5567:2;5561:9;5632:2;5613:13;;-1:-1:-1;;5609:27:1;5597:40;;-1:-1:-1;;;;;5652:34:1;;5688:22;;;5649:62;5646:88;;;5714:18;;:::i;:::-;5750:2;5743:22;5496:275;;-1:-1:-1;5496:275:1:o;5776:181::-;5834:4;-1:-1:-1;;;;;5859:6:1;5856:30;5853:56;;;5889:18;;:::i;:::-;-1:-1:-1;5934:1:1;5930:14;5946:4;5926:25;;5776:181::o;5962:530::-;6004:5;6057:3;6050:4;6042:6;6038:17;6034:27;6024:55;;6075:1;6072;6065:12;6024:55;6111:6;6098:20;-1:-1:-1;;;;;6133:2:1;6130:26;6127:52;;;6159:18;;:::i;:::-;6203:55;6246:2;6227:13;;-1:-1:-1;;6223:27:1;6252:4;6219:38;6203:55;:::i;:::-;6283:2;6274:7;6267:19;6329:3;6322:4;6317:2;6309:6;6305:15;6301:26;6298:35;6295:55;;;6346:1;6343;6336:12;6295:55;6411:2;6404:4;6396:6;6392:17;6385:4;6376:7;6372:18;6359:55;6459:1;6434:16;;;6452:4;6430:27;6423:38;;;;6438:7;5962:530;-1:-1:-1;;;5962:530:1:o;6497:884::-;6549:5;6602:3;6595:4;6587:6;6583:17;6579:27;6569:55;;6620:1;6617;6610:12;6569:55;6656:6;6643:20;6682:4;6706:58;6722:41;6760:2;6722:41;:::i;:::-;6706:58;:::i;:::-;6798:15;;;6884:1;6880:10;;;;6868:23;;6864:32;;;6829:12;;;;6908:15;;;6905:35;;;6936:1;6933;6926:12;6905:35;6972:2;6964:6;6960:15;6984:368;7000:6;6995:3;6992:15;6984:368;;;7086:3;7073:17;-1:-1:-1;;;;;7109:11:1;7106:35;7103:125;;;7182:1;7211:2;7207;7200:14;7103:125;7253:56;7305:3;7300:2;7286:11;7278:6;7274:24;7270:33;7253:56;:::i;:::-;7241:69;;-1:-1:-1;7330:12:1;;;;7017;;6984:368;;;-1:-1:-1;7370:5:1;6497:884;-1:-1:-1;;;;;;6497:884:1:o;7386:660::-;7440:5;7493:3;7486:4;7478:6;7474:17;7470:27;7460:55;;7511:1;7508;7501:12;7460:55;7547:6;7534:20;7573:4;7597:58;7613:41;7651:2;7613:41;:::i;7597:58::-;7689:15;;;7775:1;7771:10;;;;7759:23;;7755:32;;;7720:12;;;;7799:15;;;7796:35;;;7827:1;7824;7817:12;7796:35;7863:2;7855:6;7851:15;7875:142;7891:6;7886:3;7883:15;7875:142;;;7957:17;;7945:30;;7995:12;;;;7908;;7875:142;;8051:1603;8255:6;8263;8271;8279;8332:3;8320:9;8311:7;8307:23;8303:33;8300:53;;;8349:1;8346;8339:12;8300:53;8389:9;8376:23;-1:-1:-1;;;;;8459:2:1;8451:6;8448:14;8445:34;;;8475:1;8472;8465:12;8445:34;8498:59;8549:7;8540:6;8529:9;8525:22;8498:59;:::i;:::-;8488:69;;8576:2;8566:12;;8631:2;8620:9;8616:18;8603:32;8660:2;8650:8;8647:16;8644:36;;;8676:1;8673;8666:12;8644:36;8699:61;8752:7;8741:8;8730:9;8726:24;8699:61;:::i;:::-;8689:71;;;8813:2;8802:9;8798:18;8785:32;8842:2;8832:8;8829:16;8826:36;;;8858:1;8855;8848:12;8826:36;8881:63;8936:7;8925:8;8914:9;8910:24;8881:63;:::i;:::-;8871:73;;;8997:2;8986:9;8982:18;8969:32;9026:2;9016:8;9013:16;9010:36;;;9042:1;9039;9032:12;9010:36;9065:24;;;-1:-1:-1;9120:4:1;9112:13;;9108:27;-1:-1:-1;9098:55:1;;9149:1;9146;9139:12;9098:55;9185:2;9172:16;9208:58;9224:41;9262:2;9224:41;:::i;9208:58::-;9300:15;;;9382:1;9378:10;;;;9370:19;;9366:28;;;9331:12;;;;9406:19;;;9403:39;;;9438:1;9435;9428:12;9403:39;9462:11;;;;9482:142;9498:6;9493:3;9490:15;9482:142;;;9564:17;;9552:30;;9515:12;;;;9602;;;;9482:142;;;8051:1603;;;;-1:-1:-1;8051:1603:1;;-1:-1:-1;;;;;;8051:1603:1:o;9659:455::-;9736:6;9744;9797:2;9785:9;9776:7;9772:23;9768:32;9765:52;;;9813:1;9810;9803:12;9765:52;9852:9;9839:23;9871:31;9896:5;9871:31;:::i;:::-;9921:5;-1:-1:-1;9977:2:1;9962:18;;9949:32;-1:-1:-1;;;;;9993:30:1;;9990:50;;;10036:1;10033;10026:12;9990:50;10059:49;10100:7;10091:6;10080:9;10076:22;10059:49;:::i;:::-;10049:59;;;9659:455;;;;;:::o;10119:320::-;10187:6;10240:2;10228:9;10219:7;10215:23;10211:32;10208:52;;;10256:1;10253;10246:12;10208:52;10296:9;10283:23;-1:-1:-1;;;;;10321:6:1;10318:30;10315:50;;;10361:1;10358;10351:12;10315:50;10384:49;10425:7;10416:6;10405:9;10401:22;10384:49;:::i;10626:835::-;10796:6;10804;10812;10865:2;10853:9;10844:7;10840:23;10836:32;10833:52;;;10881:1;10878;10871:12;10833:52;10921:9;10908:23;-1:-1:-1;;;;;10991:2:1;10983:6;10980:14;10977:34;;;11007:1;11004;10997:12;10977:34;11030:59;11081:7;11072:6;11061:9;11057:22;11030:59;:::i;:::-;11020:69;;11142:2;11131:9;11127:18;11114:32;11098:48;;11171:2;11161:8;11158:16;11155:36;;;11187:1;11184;11177:12;11155:36;11210:61;11263:7;11252:8;11241:9;11237:24;11210:61;:::i;:::-;11200:71;;11324:2;11313:9;11309:18;11296:32;11280:48;;11353:2;11343:8;11340:16;11337:36;;;11369:1;11366;11359:12;11337:36;;11392:63;11447:7;11436:8;11425:9;11421:24;11392:63;:::i;:::-;11382:73;;;10626:835;;;;;:::o;11692:990::-;11849:6;11857;11865;11873;11881;11889;11897;11905;11913;11966:3;11954:9;11945:7;11941:23;11937:33;11934:53;;;11983:1;11980;11973:12;11934:53;12019:9;12006:23;11996:33;;12076:2;12065:9;12061:18;12048:32;12038:42;;12127:2;12116:9;12112:18;12099:32;12089:42;;12178:2;12167:9;12163:18;12150:32;12140:42;;12229:3;12218:9;12214:19;12201:33;12191:43;;12281:3;12270:9;12266:19;12253:33;12243:43;;12336:3;12325:9;12321:19;12308:33;12350:28;12372:5;12350:28;:::i;:::-;12397:5;-1:-1:-1;12453:3:1;12438:19;;12425:33;-1:-1:-1;;;;;12470:30:1;;12467:50;;;12513:1;12510;12503:12;12467:50;12552:70;12614:7;12605:6;12594:9;12590:22;12552:70;:::i;:::-;12526:96;;12641:8;12631:18;;;12668:8;12658:18;;;11692:990;;;;;;;;;;;:::o;12687:125::-;12752:9;;;12773:10;;;12770:36;;;12786:18;;:::i;12817:380::-;12896:1;12892:12;;;;12939;;;12960:61;;13014:4;13006:6;13002:17;12992:27;;12960:61;13067:2;13059:6;13056:14;13036:18;13033:38;13030:161;;13113:10;13108:3;13104:20;13101:1;13094:31;13148:4;13145:1;13138:15;13176:4;13173:1;13166:15;13202:408;13404:2;13386:21;;;13443:2;13423:18;;;13416:30;13482:34;13477:2;13462:18;;13455:62;-1:-1:-1;;;13548:2:1;13533:18;;13526:42;13600:3;13585:19;;13202:408::o;13615:::-;13817:2;13799:21;;;13856:2;13836:18;;;13829:30;13895:34;13890:2;13875:18;;13868:62;-1:-1:-1;;;13961:2:1;13946:18;;13939:42;14013:3;13998:19;;13615:408::o;15088:127::-;15149:10;15144:3;15140:20;15137:1;15130:31;15180:4;15177:1;15170:15;15204:4;15201:1;15194:15;15561:135;15600:3;15621:17;;;15618:43;;15641:18;;:::i;:::-;-1:-1:-1;15688:1:1;15677:13;;15561:135::o;16307:127::-;16368:10;16363:3;16359:20;16356:1;16349:31;16399:4;16396:1;16389:15;16423:4;16420:1;16413:15;16439:120;16479:1;16505;16495:35;;16510:18;;:::i;:::-;-1:-1:-1;16544:9:1;;16439:120::o;16564:112::-;16596:1;16622;16612:35;;16627:18;;:::i;:::-;-1:-1:-1;16661:9:1;;16564:112::o;16681:136::-;16720:3;16748:5;16738:39;;16757:18;;:::i;:::-;-1:-1:-1;;;16793:18:1;;16681:136::o;16822:168::-;16895:9;;;16926;;16943:15;;;16937:22;;16923:37;16913:71;;16964:18;;:::i;19299:245::-;19366:6;19419:2;19407:9;19398:7;19394:23;19390:32;19387:52;;;19435:1;19432;19425:12;19387:52;19467:9;19461:16;19486:28;19508:5;19486:28;:::i;19889:367::-;19974:6;19982;19990;20043:2;20031:9;20022:7;20018:23;20014:32;20011:52;;;20059:1;20056;20049:12;20011:52;20088:9;20082:16;20072:26;;20141:2;20130:9;20126:18;20120:25;20154:28;20176:5;20154:28;:::i;:::-;20201:5;20191:15;;;20246:2;20235:9;20231:18;20225:25;20215:35;;19889:367;;;;;:::o;20261:287::-;20390:3;20428:6;20422:13;20444:66;20503:6;20498:3;20491:4;20483:6;20479:17;20444:66;:::i;:::-;20526:16;;;;;20261:287;-1:-1:-1;;20261:287:1:o;21035:544::-;21136:2;21131:3;21128:11;21125:448;;;21172:1;21197:5;21193:2;21186:17;21242:4;21238:2;21228:19;21312:2;21300:10;21296:19;21293:1;21289:27;21283:4;21279:38;21348:4;21336:10;21333:20;21330:47;;;-1:-1:-1;21371:4:1;21330:47;21426:2;21421:3;21417:12;21414:1;21410:20;21404:4;21400:31;21390:41;;21481:82;21499:2;21492:5;21489:13;21481:82;;;21544:17;;;21525:1;21514:13;21481:82;;;21485:3;;;21035:544;;;:::o;21755:1348::-;21879:3;21873:10;-1:-1:-1;;;;;21898:6:1;21895:30;21892:56;;;21928:18;;:::i;:::-;21957:96;22046:6;22006:38;22038:4;22032:11;22006:38;:::i;:::-;22000:4;21957:96;:::i;:::-;22108:4;;22172:2;22161:14;;22189:1;22184:662;;;;22890:1;22907:6;22904:89;;;-1:-1:-1;22959:19:1;;;22953:26;22904:89;-1:-1:-1;;21712:1:1;21708:11;;;21704:24;21700:29;21690:40;21736:1;21732:11;;;21687:57;23006:81;;22154:943;;22184:662;20982:1;20975:14;;;21019:4;21006:18;;-1:-1:-1;;22220:20:1;;;22337:236;22351:7;22348:1;22345:14;22337:236;;;22440:19;;;22434:26;22419:42;;22532:27;;;;22500:1;22488:14;;;;22367:19;;22337:236;;;22341:3;22601:6;22592:7;22589:19;22586:201;;;22662:19;;;22656:26;-1:-1:-1;;22745:1:1;22741:14;;;22757:3;22737:24;22733:37;22729:42;22714:58;22699:74;;22586:201;-1:-1:-1;;;;;22833:1:1;22817:14;;;22813:22;22800:36;;-1:-1:-1;21755:1348:1:o;24269:417::-;-1:-1:-1;;;;;;24464:26:1;;;;24452:39;;-1:-1:-1;;;;;;24520:47:1;;;;24516:1;24507:11;;24500:68;24606:2;24602:15;-1:-1:-1;;24598:53:1;24593:2;24584:12;;24577:75;24677:2;24668:12;;24269:417::o;24691:610::-;24958:3;24947:9;24940:22;24921:4;24985:45;25025:3;25014:9;25010:19;25002:6;24985:45;:::i;:::-;25078:9;25070:6;25066:22;25061:2;25050:9;25046:18;25039:50;25112:32;25137:6;25129;25112:32;:::i;:::-;25098:46;;25192:9;25184:6;25180:22;25175:2;25164:9;25160:18;25153:50;25220:32;25245:6;25237;25220:32;:::i;:::-;25212:40;;;25288:6;25283:2;25272:9;25268:18;25261:34;24691:610;;;;;;;:::o;30062:521::-;30139:4;30145:6;30205:11;30192:25;30299:2;30295:7;30284:8;30268:14;30264:29;30260:43;30240:18;30236:68;30226:96;;30318:1;30315;30308:12;30226:96;30345:33;;30397:20;;;-1:-1:-1;;;;;;30429:30:1;;30426:50;;;30472:1;30469;30462:12;30426:50;30505:4;30493:17;;-1:-1:-1;30536:14:1;30532:27;;;30522:38;;30519:58;;;30573:1;30570;30563:12;31965:407;32167:2;32149:21;;;32206:2;32186:18;;;32179:30;32245:34;32240:2;32225:18;;32218:62;-1:-1:-1;;;32311:2:1;32296:18;;32289:41;32362:3;32347:19;;31965:407::o;33082:184::-;33152:6;33205:2;33193:9;33184:7;33180:23;33176:32;33173:52;;;33221:1;33218;33211:12;33173:52;-1:-1:-1;33244:16:1;;33082:184;-1:-1:-1;33082:184:1:o;34481:1880::-;34591:6;34622:2;34665;34653:9;34644:7;34640:23;34636:32;34633:52;;;34681:1;34678;34671:12;34633:52;34714:9;34708:16;-1:-1:-1;;;;;34784:2:1;34776:6;34773:14;34770:34;;;34800:1;34797;34790:12;34770:34;34838:6;34827:9;34823:22;34813:32;;34864:4;34902:2;34897;34888:7;34884:16;34880:25;34877:45;;;34918:1;34915;34908:12;34877:45;34944:22;;:::i;:::-;34995:2;34989:9;34982:5;34975:24;35038:2;35034;35030:11;35024:18;35067:2;35057:8;35054:16;35051:36;;;35083:1;35080;35073:12;35051:36;35114:8;35110:2;35106:17;35096:27;;;35161:7;35154:4;35150:2;35146:13;35142:27;35132:55;;35183:1;35180;35173:12;35132:55;35212:2;35206:9;35196:19;;35235:58;35251:41;35289:2;35251:41;:::i;35235:58::-;35327:15;;;35409:1;35405:10;;;;35397:19;;35393:28;;;35358:12;;;;35433:19;;;35430:39;;;35465:1;35462;35455:12;35430:39;35489:11;;;;35509:784;35525:6;35520:3;35517:15;35509:784;;;35605:2;35599:3;35590:7;35586:17;35582:26;35579:116;;;35649:1;35678:2;35674;35667:14;35579:116;35723:22;;:::i;:::-;35773:10;;-1:-1:-1;;;;;35818:33:1;;35806:46;;35796:144;;35894:1;35923:2;35919;35912:14;35796:144;35953:24;;36011:12;;;36005:19;36072:10;36059:24;;36047:37;;36037:135;;36126:1;36155:2;36151;36144:14;36037:135;36192:16;;;36185:33;36231:20;;35542:12;;;;36271;;;;35509:784;;;36309:14;;;36302:29;;;;36313:5;34481:1880;-1:-1:-1;;;;;;;34481:1880:1:o;37860:269::-;37948:6;38001:2;37989:9;37980:7;37976:23;37972:32;37969:52;;;38017:1;38014;38007:12;37969:52;38049:9;38043:16;38068:31;38093:5;38068:31;:::i;38333:632::-;38504:2;38556:21;;;38626:13;;38529:18;;;38648:22;;;38475:4;;38504:2;38727:15;;;;38701:2;38686:18;;;38475:4;38770:169;38784:6;38781:1;38778:13;38770:169;;;38845:13;;38833:26;;38914:15;;;;38879:12;;;;38806:1;38799:9;38770:169;;;-1:-1:-1;38956:3:1;;38333:632;-1:-1:-1;;;;;;38333:632:1:o;39377:127::-;39438:10;39433:3;39429:20;39426:1;39419:31;39469:4;39466:1;39459:15;39493:4;39490:1;39483:15;41371:219;41520:2;41509:9;41502:21;41483:4;41540:44;41580:2;41569:9;41565:18;41557:6;41540:44;:::i

Swarm Source

ipfs://2d5aeadc3340defc038b9c71a09d61a2ccd715d6fd8efadaaeb86875e6ee9194

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

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