ETH Price: $2,406.70 (+2.88%)

Contract

0x1bc8FC30c499f30e85E37F2AE544DdEEAe52C44c
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Complete Exit203321452024-07-18 8:14:4757 days ago1721290487IN
0x1bc8FC30...EAe52C44c
0 ETH0.000982229.60152364
Exit202895612024-07-12 9:35:2363 days ago1720776923IN
0x1bc8FC30...EAe52C44c
0 ETH0.000605373.73322807
Complete Exit202654512024-07-09 0:47:2366 days ago1720486043IN
0x1bc8FC30...EAe52C44c
0 ETH0.000219291.76567866
Complete Exit202654372024-07-09 0:44:3566 days ago1720485875IN
0x1bc8FC30...EAe52C44c
0 ETH0.000188311.75832393
Complete Exit202425482024-07-05 19:58:5969 days ago1720209539IN
0x1bc8FC30...EAe52C44c
0 ETH0.000288082.68989404
Exit202355662024-07-04 20:35:2370 days ago1720125323IN
0x1bc8FC30...EAe52C44c
0 ETH0.001174597.52471038
Exit202212992024-07-02 20:45:4772 days ago1719953147IN
0x1bc8FC30...EAe52C44c
0 ETH0.000693754.53447472
Exit202212852024-07-02 20:42:5972 days ago1719952979IN
0x1bc8FC30...EAe52C44c
0 ETH0.000717824.59856435
Complete Exit201638522024-06-24 20:13:1180 days ago1719259991IN
0x1bc8FC30...EAe52C44c
0 ETH0.001025139.57186651
Exit201497072024-06-22 20:44:3582 days ago1719089075IN
0x1bc8FC30...EAe52C44c
0 ETH0.000332672.1588512
Complete Exit201103262024-06-17 8:30:4788 days ago1718613047IN
0x1bc8FC30...EAe52C44c
0 ETH0.000286573.18418723
Complete Exit201039262024-06-16 11:02:2389 days ago1718535743IN
0x1bc8FC30...EAe52C44c
0 ETH0.00044583.58942311
Complete Exit200909982024-06-14 15:39:3591 days ago1718379575IN
0x1bc8FC30...EAe52C44c
0 ETH0.0015426412.42079211
Complete Exit200837982024-06-13 15:28:4792 days ago1718292527IN
0x1bc8FC30...EAe52C44c
0 ETH0.0018269217.05827797
Exit200810852024-06-13 6:22:1192 days ago1718259731IN
0x1bc8FC30...EAe52C44c
0 ETH0.0016413510.72808532
Exit200785632024-06-12 21:54:3592 days ago1718229275IN
0x1bc8FC30...EAe52C44c
0 ETH0.0023530313.83359276
Exit200766952024-06-12 15:38:5993 days ago1718206739IN
0x1bc8FC30...EAe52C44c
0 ETH0.0034563622.81717954
Exit200764522024-06-12 14:49:5993 days ago1718203799IN
0x1bc8FC30...EAe52C44c
0 ETH0.0041824523.04690326
Stake198633092024-05-13 19:53:35122 days ago1715630015IN
0x1bc8FC30...EAe52C44c
0 ETH0.0014980711.16383384
Stake198630502024-05-13 19:01:23122 days ago1715626883IN
0x1bc8FC30...EAe52C44c
0 ETH0.0024274712.11319762
Stake198627662024-05-13 18:03:47122 days ago1715623427IN
0x1bc8FC30...EAe52C44c
0 ETH0.0024493412.22379812
Stake198625902024-05-13 17:28:35122 days ago1715621315IN
0x1bc8FC30...EAe52C44c
0 ETH0.0040132720.02884084
Stake198622412024-05-13 16:18:35122 days ago1715617115IN
0x1bc8FC30...EAe52C44c
0 ETH0.0024126618.67534142
Stake198622322024-05-13 16:16:47122 days ago1715617007IN
0x1bc8FC30...EAe52C44c
0 ETH0.0040095619.56469165
Stake198619192024-05-13 15:13:59123 days ago1715613239IN
0x1bc8FC30...EAe52C44c
0 ETH0.0040398519.70902777
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0x5aaf14f3...485354BF9
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
NonCompoundingRewardsPool

Compiler Version
v0.8.9+commit.e5eed63a

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, MIT license

Contract Source Code (Solidity)

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

// Sources flattened with hardhat v2.8.3 https://hardhat.org

// File @openzeppelin/contracts/token/ERC20/[email protected]

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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


// File @openzeppelin/contracts/utils/[email protected]


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

pragma solidity ^0.8.0;

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

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


// File @openzeppelin/contracts/access/[email protected]


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

pragma solidity ^0.8.0;

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

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

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

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

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

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

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

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


// File @openzeppelin/contracts/utils/[email protected]


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

pragma solidity ^0.8.0;

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

        uint256 size;
        assembly {
            size := extcodesize(account)
        }
        return size > 0;
    }

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

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

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

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

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

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

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

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

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

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

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

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

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason 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 {
            // 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

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}


// File @openzeppelin/contracts/token/ERC20/utils/[email protected]


// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;


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

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

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

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

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

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

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

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


// File contracts/RewardsPoolBase.sol


pragma solidity 0.8.9;



/** @dev Base pool contract used in all other pools. 
Users can stake tokens and get rewards based on the percentage of total staked tokens.
After deployment, owner can send funds and then start the pool. 
When it's started a check is done to verify enough rewards are available. 
Users can claim their rewards at any point, as well as withdraw their stake.
The owner can extend the pool by setting a new end time and sending more rewards if needed.

Rewards are kept track of using the accumulatedRewardMultiplier.
This variable represents the accumulated reward per token staked from the start until now.
Based on the difference between the accumulatedRewardMultiplier at the time of your stake and withdrawal, 
we calculate the amount of tokens you can claim.

For example, you enter when the accumulatedRewardMultiplier is 5 and exit at 20. You staked 100 tokens.
Your reward is (20 - 5) * 100 = 1500 tokens.
*/
contract RewardsPoolBase is Ownable {
    using SafeERC20 for IERC20;

    uint256 internal constant PRECISION = 1 ether;

    uint256 public totalStaked;
    uint256[] internal totalClaimed;
    uint256[] private totalSpentRewards;

    uint256[] public rewardPerSecond;
    address[] public rewardsTokens;

    IERC20 public immutable stakingToken;

    uint256 public startTimestamp;
    uint256 public endTimestamp;
    uint256 private lastRewardTimestamp;

    uint256 public extensionDuration;
    uint256[] public extensionRewardPerSecond;

    uint256[] public accumulatedRewardMultiplier;

    uint256 public immutable stakeLimit;
    uint256 public immutable contractStakeLimit;

    string public name;

    struct UserInfo {
        uint256 firstStakedTimestamp;
        uint256 amountStaked; // How many tokens the user has staked.
        uint256[] rewardDebt; //
        uint256[] tokensOwed; // How many tokens the contract owes to the user.
    }

    mapping(address => UserInfo) public userInfo;

    struct Campaign {
        uint256 startTimestamp;
        uint256 endTimestamp;
        uint256[] rewardPerSecond;
    }

    Campaign[] public previousCampaigns;

    event Started(uint256 startTimestamp, uint256 endTimestamp, uint256[] rewardsPerSecond);
    event Staked(address indexed user, uint256 amount);
    event Claimed(address indexed user, uint256 amount, address token);
    event Withdrawn(address indexed user, uint256 amount);
    event Exited(address indexed user, uint256 amount);
    event Extended(uint256 newStartTimestamp, uint256 newEndTimestamp, uint256[] newRewardsPerSecond);

    /** @param _stakingToken The token to stake
     * @param _rewardsTokens The reward tokens
     * @param _stakeLimit Maximum amount of tokens that can be staked per user
     * @param _contractStakeLimit Maximum amount of tokens that can be staked in total
     * @param _name Name of the pool
     */
    constructor(
        IERC20 _stakingToken,
        address[] memory _rewardsTokens,
        uint256 _stakeLimit,
        uint256 _contractStakeLimit,
        string memory _name
    ) {
        require(address(_stakingToken) != address(0), 'RewardsPoolBase: invalid staking token');

        require(_stakeLimit != 0 && _contractStakeLimit != 0, 'RewardsPoolBase: invalid stake limit');

        require(_rewardsTokens.length > 0, 'RewardsPoolBase: empty rewardsTokens');

        for (uint256 i = 0; i < _rewardsTokens.length; i++) {
            for (uint256 j = i + 1; j < _rewardsTokens.length; j++) {
                require(
                    address(_rewardsTokens[i]) != address(_rewardsTokens[j]),
                    'RewardsPoolBase: duplicate rewards token'
                );
            }
        }

        stakingToken = _stakingToken;
        rewardsTokens = _rewardsTokens;
        stakeLimit = _stakeLimit;
        contractStakeLimit = _contractStakeLimit;

        uint256[] memory empty = new uint256[](rewardsTokens.length);
        accumulatedRewardMultiplier = empty;
        totalClaimed = empty;
        totalSpentRewards = empty;

        name = _name;
    }

    /** @dev Start the pool. Funds for rewards will be checked and staking will be opened.
     * @param _startTimestamp The start time of the pool
     * @param _endTimestamp The end time of the pool
     * @param _rewardPerSecond Amount of rewards given per second
     */
    function start(
        uint256 _startTimestamp,
        uint256 _endTimestamp,
        uint256[] calldata _rewardPerSecond
    ) external virtual onlyOwner {
        _start(_startTimestamp, _endTimestamp, _rewardPerSecond);
    }

    function _start(
        uint256 _startTimestamp,
        uint256 _endTimestamp,
        uint256[] calldata _rewardPerSecond
    ) internal {
        require(startTimestamp == 0, 'RewardsPoolBase: already started');
        require(
            _startTimestamp >= block.timestamp && _endTimestamp > _startTimestamp,
            'RewardsPoolBase: invalid start or end'
        );

        require(_rewardPerSecond.length == rewardsTokens.length, 'RewardsPoolBase: invalid rewardPerSecond');
        rewardPerSecond = _rewardPerSecond;

        uint256 rewardsTokensLength = rewardsTokens.length;

        for (uint256 i = 0; i < rewardsTokensLength; i++) {
            uint256 rewardsAmount = calculateRewardsAmount(_startTimestamp, _endTimestamp, rewardPerSecond[i]);

            uint256 balance = IERC20(rewardsTokens[i]).balanceOf(address(this));

            require(balance >= rewardsAmount, 'RewardsPoolBase: not enough rewards');
        }

        startTimestamp = _startTimestamp;
        endTimestamp = _endTimestamp;
        lastRewardTimestamp = _startTimestamp;

        emit Started(startTimestamp, endTimestamp, rewardPerSecond);
    }

    /** @dev Cancels the scheduled start. Can only be done before the start.
     */
    function cancel() external onlyOwner {
        require(block.timestamp < startTimestamp, 'RewardsPoolBase: No start scheduled or already started');

        rewardPerSecond = new uint256[](0);
        startTimestamp = 0;
        endTimestamp = 0;
        lastRewardTimestamp = 0;
    }

    /** @dev Stake an amount of tokens
     * @param _tokenAmount The amount to be staked
     */
    function stake(uint256 _tokenAmount) public virtual {
        _stake(_tokenAmount, msg.sender, true);
    }

    function _stake(
        uint256 _tokenAmount,
        address _staker,
        bool _chargeStaker
    ) internal {
        uint256 currentTimestamp = block.timestamp;
        require(
            (startTimestamp > 0 && currentTimestamp > startTimestamp) &&
                (currentTimestamp <= endTimestamp + extensionDuration),
            'RewardsPoolBase: staking is not started or is finished or no extension taking in place'
        );

        UserInfo storage user = userInfo[_staker];
        require(
            (user.amountStaked + _tokenAmount <= stakeLimit) && (totalStaked + _tokenAmount <= contractStakeLimit),
            'RewardsPoolBase: stake limit reached'
        );

        require(_tokenAmount > 0, 'RewardsPoolBase: cannot stake 0');

        // if no amount has been staked this is considered the initial stake
        if (user.amountStaked == 0) {
            user.firstStakedTimestamp = currentTimestamp;
        }

        updateRewardMultipliers(); // Update the accumulated multipliers for everyone
        _updateUserAccruedReward(_staker); // Update the accrued reward for this specific user

        user.amountStaked = user.amountStaked + _tokenAmount;
        totalStaked = totalStaked + _tokenAmount;

        uint256 rewardsTokensLength = rewardsTokens.length;

        for (uint256 i = 0; i < rewardsTokensLength; i++) {
            user.rewardDebt[i] = (user.amountStaked * accumulatedRewardMultiplier[i]) / PRECISION; // Update user reward debt for each token
        }

        emit Staked(_staker, _tokenAmount);

        stakingToken.safeTransferFrom(address(_chargeStaker ? _staker : msg.sender), address(this), _tokenAmount);
    }

    /** @dev Claim all your rewards, this will not remove your stake
     */
    function claim() public virtual {
        _claim(msg.sender);
    }

    function _claim(address _claimer) internal {
        UserInfo storage user = userInfo[_claimer];
        updateRewardMultipliers();
        _updateUserAccruedReward(_claimer);

        uint256 rewardsTokensLength = rewardsTokens.length;

        for (uint256 i = 0; i < rewardsTokensLength; i++) {
            uint256 reward = user.tokensOwed[i];
            user.tokensOwed[i] = 0;
            totalClaimed[i] = totalClaimed[i] + reward;

            emit Claimed(_claimer, reward, rewardsTokens[i]);

            IERC20(rewardsTokens[i]).safeTransfer(_claimer, reward);
        }
    }

    /** @dev Withdrawing a portion or all of staked tokens. This will not claim your rewards
     * @param _tokenAmount The amount to be withdrawn
     */
    function withdraw(uint256 _tokenAmount) public virtual {
        _withdraw(_tokenAmount, msg.sender);
    }

    function _withdraw(uint256 _tokenAmount, address _withdrawer) internal {
        require(_tokenAmount > 0, 'RewardsPoolBase: cannot withdraw 0');

        UserInfo storage user = userInfo[_withdrawer];

        updateRewardMultipliers(); // Update the accumulated multipliers for everyone
        _updateUserAccruedReward(_withdrawer); // Update the accrued reward for this specific user

        user.amountStaked = user.amountStaked - _tokenAmount;
        totalStaked = totalStaked - _tokenAmount;

        uint256 rewardsTokensLength = rewardsTokens.length;

        for (uint256 i = 0; i < rewardsTokensLength; i++) {
            uint256 totalDebt = (user.amountStaked * accumulatedRewardMultiplier[i]) / PRECISION; // Update user reward debt for each token
            user.rewardDebt[i] = totalDebt;
        }

        emit Withdrawn(_withdrawer, _tokenAmount);

        stakingToken.safeTransfer(address(_withdrawer), _tokenAmount);
    }

    /** @dev Claim all rewards and withdraw all staked tokens. Exits from the rewards pool
     */
    function exit() public virtual {
        _exit(msg.sender);
    }

    function _exit(address exiter) internal {
        UserInfo storage user = userInfo[exiter];

        emit Exited(exiter, user.amountStaked);

        _claim(exiter);
        _withdraw(user.amountStaked, exiter);
    }

    /** @dev Returns the amount of tokens the user has staked
     * @param _userAddress The user to get the balance of
     */
    function balanceOf(address _userAddress) external view returns (uint256) {
        UserInfo storage user = userInfo[_userAddress];
        return user.amountStaked;
    }

    /**
		@dev Updates the accumulated reward multipliers for everyone and each token
	 */
    function updateRewardMultipliers() public {
        uint256 currentTimestamp = block.timestamp;

        if (currentTimestamp > endTimestamp && extensionDuration > 0) {
            _updateRewardMultipliers(endTimestamp);
            _extend(endTimestamp, endTimestamp + extensionDuration, extensionRewardPerSecond);
            _updateRewardMultipliers(currentTimestamp);
        } else {
            _updateRewardMultipliers(currentTimestamp);
        }
    }

    /**
     * @dev updates the accumulated reward multipliers for everyone and each token
     */
    function _updateRewardMultipliers(uint256 _currentTimestamp) internal {
        if (_currentTimestamp <= lastRewardTimestamp) {
            return;
        }

        uint256 applicableTimestamp = (_currentTimestamp < endTimestamp) ? _currentTimestamp : endTimestamp;

        uint256 secondsSinceLastReward = applicableTimestamp - lastRewardTimestamp;

        if (secondsSinceLastReward == 0) {
            return;
        }

        if (totalStaked == 0) {
            lastRewardTimestamp = applicableTimestamp;
            return;
        }

        uint256 rewardsTokensLength = rewardsTokens.length;

        for (uint256 i = 0; i < rewardsTokensLength; i++) {
            uint256 newReward = secondsSinceLastReward * rewardPerSecond[i]; // Get newly accumulated reward
            uint256 rewardMultiplierIncrease = (newReward * PRECISION) / totalStaked; // Calculate the multiplier increase
            accumulatedRewardMultiplier[i] = accumulatedRewardMultiplier[i] + rewardMultiplierIncrease; // Add the multiplier increase to the accumulated multiplier
        }

        lastRewardTimestamp = applicableTimestamp;
    }

    /** @dev Updates the accumulated reward for the user
     * @param _userAddress the address of the updated user
     */
    function _updateUserAccruedReward(address _userAddress) internal {
        UserInfo storage user = userInfo[_userAddress];

        uint256 rewardsTokensLength = rewardsTokens.length;

        if (user.rewardDebt.length == 0) {
            // Initialize user struct

            uint256[] memory empty = new uint256[](rewardsTokensLength);
            user.rewardDebt = empty;
            user.tokensOwed = empty;
        }

        if (user.amountStaked == 0) {
            return;
        }

        for (uint256 tokenIndex = 0; tokenIndex < rewardsTokensLength; tokenIndex++) {
            uint256 totalDebt = (user.amountStaked * accumulatedRewardMultiplier[tokenIndex]) / PRECISION;
            uint256 pendingDebt = totalDebt - user.rewardDebt[tokenIndex];

            if (pendingDebt > 0) {
                user.tokensOwed[tokenIndex] = user.tokensOwed[tokenIndex] + pendingDebt;
                user.rewardDebt[tokenIndex] = totalDebt;
            }
        }
    }

    /**
		@dev Checks if the staking has started
	 */
    function hasStakingStarted() external view returns (bool) {
        return (startTimestamp > 0 && block.timestamp >= startTimestamp);
    }

    /** @dev Returns the amount of reward debt of a specific token and user
     * @param _userAddress the address of the updated user
     * @param _index index of the reward token to check
     */
    function getUserRewardDebt(address _userAddress, uint256 _index) external view returns (uint256) {
        UserInfo storage user = userInfo[_userAddress];
        return user.rewardDebt[_index];
    }

    /** @dev Returns the amount of reward owed of a specific token and user
     * @param _userAddress the address of the updated user
     * @param _index index of the reward token to check
     */
    function getUserOwedTokens(address _userAddress, uint256 _index) external view returns (uint256) {
        UserInfo storage user = userInfo[_userAddress];
        return user.tokensOwed[_index];
    }

    /** @dev Calculates the reward at a specific time
     * @param _userAddress the address of the user
     * @param _tokenIndex the index of the reward token you are interested
     * @param _time the time to check the reward at
     */
    function getUserAccumulatedReward(
        address _userAddress,
        uint256 _tokenIndex,
        uint256 _time
    ) external view returns (uint256) {
        uint256 applicableTimestamp = (_time < endTimestamp) ? _time : endTimestamp;
        uint256 secondsSinceLastReward = applicableTimestamp - lastRewardTimestamp;

        uint256 newReward = secondsSinceLastReward * rewardPerSecond[_tokenIndex]; // Get newly accumulated reward
        uint256 rewardMultiplierIncrease = (newReward * PRECISION) / totalStaked; // Calculate the multiplier increase
        uint256 currentMultiplier = accumulatedRewardMultiplier[_tokenIndex] + rewardMultiplierIncrease; // Simulate the multiplier increase to the accumulated multiplier

        UserInfo storage user = userInfo[_userAddress];

        uint256 totalDebt = (user.amountStaked * currentMultiplier) / PRECISION; // Simulate the current debt
        uint256 pendingDebt = totalDebt - user.rewardDebt[_tokenIndex]; // Simulate the pending debt
        return user.tokensOwed[_tokenIndex] + pendingDebt;
    }

    /** @dev Returns the length of the owed tokens in the user info
     */
    function getUserTokensOwedLength(address _userAddress) external view returns (uint256) {
        UserInfo storage user = userInfo[_userAddress];
        return user.tokensOwed.length;
    }

    /** @dev Returns the length of the reward debt in the user info
     */
    function getUserRewardDebtLength(address _userAddress) external view returns (uint256) {
        UserInfo storage user = userInfo[_userAddress];
        return user.rewardDebt.length;
    }

    /** @dev Returns the amount of reward tokens
     */
    function getRewardTokensCount() external view returns (uint256) {
        return rewardsTokens.length;
    }

    /** @dev Returns the amount of previous campaigns
     */
    function getPreviousCampaignsCount() external view returns (uint256) {
        return previousCampaigns.length;
    }

    /**
     * @dev Extends the rewards period and updates the rates. 
     When the current campaign is still going on, the extension will be scheduled and started when the campaign ends.
     The extension can be cancelled until it starts. After it starts, the rewards are locked in and cannot be withdraw.
     * @param _durationTime duration of the campaign (how many seconds the campaign will have)
     * @param _rewardPerSecond array with new rewards per second for each token
     */
    function extend(uint256 _durationTime, uint256[] calldata _rewardPerSecond) external virtual onlyOwner {
        require(extensionDuration == 0, 'RewardsPoolBase: there is already an extension');

        require(_durationTime > 0, 'RewardsPoolBase: duration must be greater than 0');

        uint256 rewardPerSecondLength = _rewardPerSecond.length;
        require(rewardPerSecondLength == rewardsTokens.length, 'RewardsPoolBase: invalid rewardPerSecond');

        uint256 currentTimestamp = block.timestamp;
        bool ended = currentTimestamp > endTimestamp;

        uint256 newStartTimestamp = ended ? currentTimestamp : endTimestamp;
        uint256 newEndTimestamp = newStartTimestamp + _durationTime;

        for (uint256 i = 0; i < rewardPerSecondLength; i++) {
            uint256 newRewards = calculateRewardsAmount(newStartTimestamp, newEndTimestamp, _rewardPerSecond[i]);

            // We need to check if we have enough balance available in the contract to pay for the extension
            uint256 availableBalance = getAvailableBalance(i);

            require(availableBalance >= newRewards, 'RewardsPoolBase: not enough rewards to extend');
        }

        if (ended) {
            _updateRewardMultipliers(endTimestamp);
            _extend(newStartTimestamp, newEndTimestamp, _rewardPerSecond);
        } else {
            extensionDuration = _durationTime;
            extensionRewardPerSecond = _rewardPerSecond;
        }
    }

    function _extend(
        uint256 _startTimestamp,
        uint256 _endTimestamp,
        uint256[] memory _rewardPerSecond
    ) internal {
        uint256 rewardPerSecondLength = rewardPerSecond.length;
        for (uint256 i = 0; i < rewardPerSecondLength; i++) {
            uint256 spentRewards = calculateRewardsAmount(startTimestamp, endTimestamp, rewardPerSecond[i]);
            totalSpentRewards[i] = totalSpentRewards[i] + spentRewards;
        }

        previousCampaigns.push(Campaign(startTimestamp, endTimestamp, rewardPerSecond));

        rewardPerSecond = _rewardPerSecond;
        startTimestamp = _startTimestamp;
        endTimestamp = _endTimestamp;
        lastRewardTimestamp = _startTimestamp;

        extensionDuration = 0;
        delete extensionRewardPerSecond;

        emit Extended(_startTimestamp, _endTimestamp, _rewardPerSecond);
    }

    /**
     * @dev Cancels the schedules extension
     */
    function cancelExtension() external onlyOwner {
        require(extensionDuration > 0, 'RewardsPoolBase: there is no extension scheduled');
        require(block.timestamp < endTimestamp, 'RewardsPoolBase: cannot cancel extension after it has started');

        extensionDuration = 0;
        delete extensionRewardPerSecond;
    }

    /**
     *@dev Calculates the available amount of reward tokens that are not locked
     *@param _rewardTokenIndex the index of the reward token to check
     */
    function getAvailableBalance(uint256 _rewardTokenIndex) public view returns (uint256) {
        address rewardToken = rewardsTokens[_rewardTokenIndex];
        uint256 balance = IERC20(rewardToken).balanceOf(address(this));

        if (startTimestamp == 0) {
            return balance;
        }

        uint256 spentRewards = calculateRewardsAmount(startTimestamp, endTimestamp, rewardPerSecond[_rewardTokenIndex]);

        if (extensionDuration > 0) {
            uint256 spentExtensionRewards = calculateRewardsAmount(
                endTimestamp,
                endTimestamp + extensionDuration,
                extensionRewardPerSecond[_rewardTokenIndex]
            );

            spentRewards = spentRewards + spentExtensionRewards;
        }

        uint256 availableBalance = balance -
            (totalSpentRewards[_rewardTokenIndex] + spentRewards - totalClaimed[_rewardTokenIndex]);

        if (rewardToken == address(stakingToken)) {
            availableBalance = availableBalance - totalStaked;
        }

        return availableBalance;
    }

    /** @dev Withdraw tokens other than the staking and reward token, for example rewards from liquidity mining
     * @param _recipient The address to whom the rewards will be transferred
     * @param _token The address of the rewards contract
     */
    function withdrawTokens(address _recipient, address _token) external onlyOwner {
        uint256 currentReward = IERC20(_token).balanceOf(address(this));
        require(currentReward > 0, 'RewardsPoolBase: no rewards');

        require(_token != address(stakingToken), 'RewardsPoolBase: cannot withdraw staking token');

        uint256 rewardsTokensLength = rewardsTokens.length;

        for (uint256 i = 0; i < rewardsTokensLength; i++) {
            require(_token != rewardsTokens[i], 'RewardsPoolBase: cannot withdraw reward token');
        }

        IERC20(_token).safeTransfer(_recipient, currentReward);
    }

    /** @dev Withdraw excess staking tokens not needed for current campaign and extension
     * @param _recipient The address to whom the rewards will be transferred
     */
    function withdrawExcessStake(address _recipient) external onlyOwner {
        // Check if staking token is not also a reward token
        for (uint256 i = 0; i < rewardsTokens.length; i++) {
            require(address(stakingToken) != rewardsTokens[i], 'RewardsPoolBase: cannot withdraw staking token');
        }

        uint256 balance = stakingToken.balanceOf(address(this));

        if (balance > totalStaked) {
            stakingToken.safeTransfer(_recipient, balance - totalStaked);
        }
    }

    /** @dev Withdraw excess rewards not needed for current campaign and extension
     * @param _recipient The address to whom the rewards will be transferred
     */
    function withdrawExcessRewards(address _recipient) external onlyOwner {
        uint256 rewardsTokensLength = rewardsTokens.length;

        for (uint256 i = 0; i < rewardsTokensLength; i++) {
            uint256 balance = getAvailableBalance(i);

            if (balance > 0) {
                IERC20(rewardsTokens[i]).safeTransfer(_recipient, balance);
            }
        }
    }

    /** @dev Calculates the amount of rewards given in a specific period
     * @param _startTimestamp The start time of the period
     * @param _endTimestamp The end time of the period
     * @param _rewardPerSecond The reward per second
     */
    function calculateRewardsAmount(
        uint256 _startTimestamp,
        uint256 _endTimestamp,
        uint256 _rewardPerSecond
    ) internal pure returns (uint256) {
        uint256 rewardsPeriodSeconds = _endTimestamp - _startTimestamp;
        return _rewardPerSecond * rewardsPeriodSeconds;
    }
}


// File contracts/pool-features/OnlyExitFeature.sol



pragma solidity 0.8.9;

/** @dev Only allows exits, no claims or withdrawals.
 */
abstract contract OnlyExitFeature is RewardsPoolBase {
    //Without the passed argument the function is not overriden
    function withdraw(uint256) public virtual override {
        revert('OnlyExitFeature::cannot withdraw from this contract. Only exit.');
    }

    function claim() public virtual override {
        revert('OnlyExitFeature::cannot claim from this contract. Only exit.');
    }
}


// File contracts/StakeLock.sol



pragma solidity 0.8.9;

/** @dev Provides a time lock and onlyUnlocked modifier that allows locking a staking pool
    for a certain period of time.
*/
abstract contract StakeLock {
    uint256 public lockEndTimestamp;

    function lock(uint256 _lockEndTimestamp) internal {
        require(_lockEndTimestamp > block.timestamp, 'lock::Lock end needs to be in the future');
        lockEndTimestamp = _lockEndTimestamp;
    }

    modifier onlyUnlocked() {
        require(
            block.timestamp > lockEndTimestamp,
            'onlyUnlocked::cannot perform this action until the end of the lock'
        );
        _;
    }
}


// File contracts/pool-features/StakeLockingFeature.sol



pragma solidity 0.8.9;



/** @dev Locks the pool for a certain period of time, only after the lock period
    has passed can the pool be exited.
*/
abstract contract StakeLockingFeature is OnlyExitFeature, StakeLock {
    function exit() public virtual override(RewardsPoolBase) onlyUnlocked {
        RewardsPoolBase.exit();
    }
}


// File contracts/ThrottledExit.sol



pragma solidity 0.8.9;


/** @dev Provides a throttling mechanism for staking pools. Instead of allowing
    everyone to withdraw their stake at once at the end of the pool, this forces
    the exits to go in rounds. Every round has a limit of how many tokens can be exited
    and a certain amount of time has to pass before the next round can start. When the 
    round is full, users that want to exit are put into the next round. Exit happens
    in two stages, 'initiate exit' gives the user the time when they can exit. 
    'Finalize exit' actually withdraws the users stake and rewards.
*/
abstract contract ThrottledExit {
    using SafeERC20 for IERC20;

    uint256 public nextAvailableExitTimestamp;
    uint256 public nextAvailableRoundExitVolume;
    uint256 public throttleRoundSeconds;
    uint256 public throttleRoundCap;
    uint256 public campaignEndTimestamp;

    struct ExitInfo {
        uint256 exitTimestamp;
        uint256 exitStake;
        uint256[] rewards;
    }

    mapping(address => ExitInfo) public exitInfo;

    event ExitRequested(address user, uint256 exitTimestamp);
    event ExitCompleted(address user, uint256 stake);

    function setThrottleParams(uint256 _throttleRoundSeconds, uint256 _throttleRoundCap) internal {
        require(_throttleRoundSeconds > 0, 'setThrottle::throttle round seconds must be more than 0');
        require(_throttleRoundCap > 0, 'setThrottle::throttle round cap must be more than 0');
        require(
            throttleRoundSeconds == 0 && throttleRoundCap == 0,
            'setThrottle::throttle parameters were already set'
        );
        throttleRoundSeconds = _throttleRoundSeconds;
        throttleRoundCap = _throttleRoundCap;
    }

    function startThrottle(uint256 _throttleStart) internal {
        campaignEndTimestamp = _throttleStart;
        nextAvailableExitTimestamp = campaignEndTimestamp + throttleRoundSeconds;
    }

    function initiateExit(uint256 amountStaked, uint256[] memory _tokensOwed) internal virtual {
        uint256 rewardsTokensLength = _tokensOwed.length;

        initialiseExitInfo(msg.sender, rewardsTokensLength);

        ExitInfo storage info = exitInfo[msg.sender];
        info.exitTimestamp = getAvailableExitTime(amountStaked);
        info.exitStake = info.exitStake + amountStaked;

        for (uint256 i = 0; i < rewardsTokensLength; i++) {
            info.rewards[i] = info.rewards[i] + _tokensOwed[i];
        }

        emit ExitRequested(msg.sender, info.exitTimestamp);
    }

    function finalizeExit(address _stakingToken, address[] memory _rewardsTokens) internal virtual {
        ExitInfo storage info = exitInfo[msg.sender];
        require(block.timestamp > info.exitTimestamp, 'finalizeExit::Trying to exit too early');

        uint256 infoExitStake = info.exitStake;
        require(infoExitStake > 0, 'finalizeExit::No stake to exit');
        info.exitStake = 0;

        IERC20(_stakingToken).safeTransfer(address(msg.sender), infoExitStake);

        for (uint256 i = 0; i < _rewardsTokens.length; i++) {
            uint256 infoRewards = info.rewards[i];
            info.rewards[i] = 0;

            IERC20(_rewardsTokens[i]).safeTransfer(msg.sender, infoRewards);
        }

        emit ExitCompleted(msg.sender, infoExitStake);
    }

    function getAvailableExitTime(uint256 exitAmount) internal returns (uint256 exitTimestamp) {
        uint256 currentTimestamp = block.timestamp;

        if (currentTimestamp > nextAvailableExitTimestamp) {
            // We've passed the next available timestamp and need to readjust
            uint256 secondsFromCurrentRound = (currentTimestamp - nextAvailableExitTimestamp) % throttleRoundSeconds; // Find how many seconds have passed since last round should have started
            nextAvailableExitTimestamp = currentTimestamp - secondsFromCurrentRound + throttleRoundSeconds; // Find where the lst round should have started and add one round to find the next one
            nextAvailableRoundExitVolume = exitAmount; // Reset volume
            return nextAvailableExitTimestamp;
        } else {
            // We are still before the next available timestamp
            nextAvailableRoundExitVolume = nextAvailableRoundExitVolume + exitAmount; // Add volume
        }

        exitTimestamp = nextAvailableExitTimestamp;

        if (nextAvailableRoundExitVolume >= throttleRoundCap) {
            // If cap reached
            nextAvailableExitTimestamp = nextAvailableExitTimestamp + throttleRoundSeconds; // update next exit timestamp.
            // Note we know that this behaviour will lead to people exiting a bit more than the cap when the last user does not hit perfectly the cap. This is OK
            nextAvailableRoundExitVolume = 0; // Reset volume
        }
    }

    /** @dev Returns the amount of reward tokens that are pending for exit for this user
     * @param _tokenIndex The index of the reward to check
     */
    function getPendingReward(uint256 _tokenIndex) external view returns (uint256) {
        ExitInfo storage info = exitInfo[msg.sender];
        return info.rewards[_tokenIndex];
    }

    function initialiseExitInfo(address _userAddress, uint256 tokensLength) private {
        ExitInfo storage info = exitInfo[_userAddress];

        if (info.rewards.length == tokensLength) {
            // Already initialised
            return;
        }

        uint256[] memory empty = new uint256[](tokensLength);
        info.rewards = empty;
    }
}


// File contracts/pool-features/ThrottledExitFeature.sol



pragma solidity 0.8.9;



/** @dev Throttles the exit in rounds of a given duration and limit
 */
abstract contract ThrottledExitFeature is StakeLockingFeature, ThrottledExit {
    function exit() public virtual override onlyUnlocked {
        UserInfo storage user = userInfo[msg.sender];

        updateRewardMultipliers(); // Update the accumulated multipliers for everyone

        if (user.amountStaked == 0) {
            return;
        }

        _updateUserAccruedReward(msg.sender); // Update the accrued reward for this specific user

        uint256 amountStaked = user.amountStaked;
        uint256[] memory tokensOwed = user.tokensOwed;

        totalStaked = totalStaked - amountStaked;
        user.amountStaked = 0;

        for (uint256 i = 0; i < rewardsTokens.length; i++) {
            user.tokensOwed[i] = 0;
            user.rewardDebt[i] = 0;
        }

        initiateExit(amountStaked, tokensOwed);
    }

    function completeExit() public virtual onlyUnlocked {
        finalizeExit(address(stakingToken), rewardsTokens);
    }
}


// File contracts/StakeTransferer.sol



pragma solidity 0.8.9;

/** @dev Interface to transfer staking tokens to another whitelisted pool
 */
abstract contract StakeTransferer {
    mapping(address => bool) public receiversWhitelist;

    /** @dev Change whitelist status of a receiver pool to receive transfers.
     * @param _receiver The pool address to whitelist
     * @param _whitelisted If it should be whitelisted or not
     */
    function setReceiverWhitelisted(address _receiver, bool _whitelisted) public virtual {
        receiversWhitelist[_receiver] = _whitelisted;
    }

    modifier onlyWhitelistedReceiver(address _receiver) {
        require(receiversWhitelist[_receiver], 'exitAndTransfer::receiver is not whitelisted');
        _;
    }

    function exitAndTransfer(address transferTo) public virtual;
}


// File contracts/StakeReceiver.sol



pragma solidity 0.8.9;

/** @dev Interface to receive stake transfers from other staking pools
 */
abstract contract StakeReceiver {
    function delegateStake(address staker, uint256 stake) public virtual;
}


// File contracts/pool-features/StakeTransfererFeature.sol



pragma solidity 0.8.9;





/** @dev Transfer staked tokens to another whitelisted staking pool
 */
abstract contract StakeTransfererFeature is RewardsPoolBase, StakeTransferer {
    using SafeERC20 for IERC20;

    /** @dev Change whitelist status of a receiver pool to receive transfers.
     * @param _receiver The pool address to whitelist
     * @param _whitelisted If it should be whitelisted or not
     */
    function setReceiverWhitelisted(address _receiver, bool _whitelisted) public override(StakeTransferer) onlyOwner {
        StakeTransferer.setReceiverWhitelisted(_receiver, _whitelisted);
    }

    /** @dev exits the current campaign and trasnfers the stake to another whitelisted campaign
		@param transferTo address of the receiver to transfer the stake to
	 */
    function exitAndTransfer(address transferTo) public virtual override onlyWhitelistedReceiver(transferTo) {
        UserInfo storage user = userInfo[msg.sender];

        if (user.amountStaked == 0) {
            return;
        }
        updateRewardMultipliers(); // Update the accumulated multipliers for everyone

        uint256 userStakedAmount = user.amountStaked;

        _updateUserAccruedReward(msg.sender); // Update the accrued reward for this specific user

        _claim(msg.sender);

        //If this is before the claim, the will never be able to claim his rewards.
        user.amountStaked = 0;
        totalStaked = totalStaked - userStakedAmount;

        for (uint256 i = 0; i < rewardsTokens.length; i++) {
            user.rewardDebt[i] = 0;
        }

        stakingToken.approve(transferTo, userStakedAmount);
        StakeReceiver(transferTo).delegateStake(msg.sender, userStakedAmount);
    }
}


// File contracts/pool-features/StakeReceiverFeature.sol



pragma solidity 0.8.9;


/** @dev Receive a stake from another pool
 */
abstract contract StakeReceiverFeature is RewardsPoolBase, StakeReceiver {
    /** @dev Receives a stake from another pool
     * @param _staker The address who will own the stake
     * @param _amount The amount to stake
     */
    function delegateStake(address _staker, uint256 _amount) public virtual override {
        require(_amount > 0, 'StakeReceiverFeature: No stake sent');
        require(_staker != address(0x0), 'StakeReceiverFeature: Invalid staker');
        _stake(_amount, _staker, false);
    }
}


// File contracts/V2/NonCompoundingRewardsPool.sol



pragma solidity 0.8.9;






/** @dev Staking pool with a time lock and throttled exit. 
    Inherits all staking logic from RewardsPoolBase.
    Only allows exit at the end of the time lock and via the throttling mechanism.
*/
contract NonCompoundingRewardsPool is
    RewardsPoolBase,
    OnlyExitFeature,
    ThrottledExitFeature,
    StakeTransfererFeature,
    StakeReceiverFeature
{
    /** @param _stakingToken The token to stake
     * @param _rewardsTokens The reward tokens
     * @param _stakeLimit Maximum amount of tokens that can be staked per user
     * @param _throttleRoundSeconds Seconds per throttle round
     * @param _throttleRoundCap Maximum tokens withdrawn per throttle round
     * @param _contractStakeLimit Maximum amount of tokens that can be staked in total
     * @param _name Name of the pool
     */
    constructor(
        IERC20 _stakingToken,
        address[] memory _rewardsTokens,
        uint256 _stakeLimit,
        uint256 _throttleRoundSeconds,
        uint256 _throttleRoundCap,
        uint256 _contractStakeLimit,
        string memory _name
    ) RewardsPoolBase(_stakingToken, _rewardsTokens, _stakeLimit, _contractStakeLimit, _name) {
        setThrottleParams(_throttleRoundSeconds, _throttleRoundCap);
    }

    /** @dev Start the pool and set locking and throttling parameters.
     * @param _startTimestamp The start time of the pool
     * @param _endTimestamp The end time of the pool
     * @param _rewardPerSecond Amount of rewards given per second
     */
    function start(
        uint256 _startTimestamp,
        uint256 _endTimestamp,
        uint256[] calldata _rewardPerSecond
    ) external override onlyOwner {
        startThrottle(_endTimestamp);
        lock(_endTimestamp);
        _start(_startTimestamp, _endTimestamp, _rewardPerSecond);
    }

    /// @dev Not allowed
    function withdraw(uint256 _tokenAmount) public override(OnlyExitFeature, RewardsPoolBase) {
        OnlyExitFeature.withdraw(_tokenAmount);
    }

    /// @dev Not allowed
    function claim() public override(OnlyExitFeature, RewardsPoolBase) {
        OnlyExitFeature.claim();
    }

    /// @dev Requests a throttled exit from the pool and gives you a time from which you can withdraw your stake and rewards.
    function exit() public override(ThrottledExitFeature, RewardsPoolBase) {
        ThrottledExitFeature.exit();
    }

    /// @dev Completes the throttled exit from the pool.
    function completeExit() public virtual override(ThrottledExitFeature) {
        ThrottledExitFeature.completeExit();
    }

    /** @dev Exits the pool and tranfer to another pool
     * @param transferTo The new pool to tranfer to
     */
    function exitAndTransfer(address transferTo) public virtual override(StakeTransfererFeature) onlyUnlocked {
        StakeTransfererFeature.exitAndTransfer(transferTo);
    }

    /// @dev Not allowed
    function extend(uint256, uint256[] calldata) external virtual override(RewardsPoolBase) {
        revert('NonCompoundingRewardsPool: cannot extend this pool.');
    }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"contract IERC20","name":"_stakingToken","type":"address"},{"internalType":"address[]","name":"_rewardsTokens","type":"address[]"},{"internalType":"uint256","name":"_stakeLimit","type":"uint256"},{"internalType":"uint256","name":"_throttleRoundSeconds","type":"uint256"},{"internalType":"uint256","name":"_throttleRoundCap","type":"uint256"},{"internalType":"uint256","name":"_contractStakeLimit","type":"uint256"},{"internalType":"string","name":"_name","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"token","type":"address"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"stake","type":"uint256"}],"name":"ExitCompleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"exitTimestamp","type":"uint256"}],"name":"ExitRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Exited","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newStartTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newEndTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"newRewardsPerSecond","type":"uint256[]"}],"name":"Extended","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"startTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"rewardsPerSecond","type":"uint256[]"}],"name":"Started","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdrawn","type":"event"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"accumulatedRewardMultiplier","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_userAddress","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"campaignEndTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelExtension","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"completeExit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"contractStakeLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_staker","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"delegateStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"endTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"exit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"transferTo","type":"address"}],"name":"exitAndTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"exitInfo","outputs":[{"internalType":"uint256","name":"exitTimestamp","type":"uint256"},{"internalType":"uint256","name":"exitStake","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"name":"extend","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"extensionDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"extensionRewardPerSecond","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_rewardTokenIndex","type":"uint256"}],"name":"getAvailableBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenIndex","type":"uint256"}],"name":"getPendingReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPreviousCampaignsCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRewardTokensCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_userAddress","type":"address"},{"internalType":"uint256","name":"_tokenIndex","type":"uint256"},{"internalType":"uint256","name":"_time","type":"uint256"}],"name":"getUserAccumulatedReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_userAddress","type":"address"},{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getUserOwedTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_userAddress","type":"address"},{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getUserRewardDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_userAddress","type":"address"}],"name":"getUserRewardDebtLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_userAddress","type":"address"}],"name":"getUserTokensOwedLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"hasStakingStarted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lockEndTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextAvailableExitTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextAvailableRoundExitVolume","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"previousCampaigns","outputs":[{"internalType":"uint256","name":"startTimestamp","type":"uint256"},{"internalType":"uint256","name":"endTimestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"receiversWhitelist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewardPerSecond","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewardsTokens","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"bool","name":"_whitelisted","type":"bool"}],"name":"setReceiverWhitelisted","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenAmount","type":"uint256"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakeLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakingToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_startTimestamp","type":"uint256"},{"internalType":"uint256","name":"_endTimestamp","type":"uint256"},{"internalType":"uint256[]","name":"_rewardPerSecond","type":"uint256[]"}],"name":"start","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"throttleRoundCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"throttleRoundSeconds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalStaked","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updateRewardMultipliers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userInfo","outputs":[{"internalType":"uint256","name":"firstStakedTimestamp","type":"uint256"},{"internalType":"uint256","name":"amountStaked","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenAmount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"}],"name":"withdrawExcessRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"}],"name":"withdrawExcessStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"address","name":"_token","type":"address"}],"name":"withdrawTokens","outputs":[],"stateMutability":"nonpayable","type":"function"}]

Deployed Bytecode

0x608060405234801561001057600080fd5b506004361061030b5760003560e01c80638285d0451161019d578063b6d0dcd8116100e9578063e9fad8ee116100a2578063f27d02641161007c578063f27d0264146106df578063f2fde38b146106f2578063fb58cad114610705578063fd67fd7c1461071857600080fd5b8063e9fad8ee146106c6578063ea8a1af0146106ce578063ee483cdf146106d657600080fd5b8063b6d0dcd814610669578063b92290b81461067c578063c97559ce1461068f578063ce415302146106a2578063dd2da220146106b5578063e6fd48bc146106bd57600080fd5b8063a1292aea11610156578063a85adeab11610130578063a85adeab14610632578063a861a7a31461063b578063aabef0db1461064e578063b01eb6601461066157600080fd5b8063a1292aea146105e0578063a522ad251461060c578063a694fc3a1461061f57600080fd5b80638285d04514610571578063869d8ead146105795780638da5cb5b1461058c57806394f664171461059d57806398cda7f8146105c45780639d662b99146105cd57600080fd5b80633c323a1b1161025c578063652053d911610215578063715018a6116101ef578063715018a61461050e5780637211bbc91461051657806372f702f314610529578063817b1cd21461056857600080fd5b8063652053d9146104c65780636c32bf69146104cf57806370a08231146104e257600080fd5b80633c323a1b1461046057806345ef79af146104735780634e71d92d1461049a5780634ff3306f146104a257806357b4f01f146104ab578063602e007a146104b357600080fd5b80632240e63c116102c95780632c3f455c116102a35780632c3f455c146103ff5780632d9e88e1146104125780632e1a7d4d1461041a578063363291dc1461042d57600080fd5b80632240e63c146103d95780632711f727146103ee5780632af9b070146103f757600080fd5b806284c9271461031057806303d1dae01461034f57806306fdde03146103765780631959a0021461038b5780631aa85060146103c75780632037424b146103d0575b600080fd5b61033c61031e366004612f2d565b6001600160a01b03166000908152600d602052604090206002015490565b6040519081526020015b60405180910390f35b61033c7f00000000000000000000000000000000000000000001a784379d99db4200000081565b61037e61072b565b6040516103469190612f74565b6103b2610399366004612f2d565b600d602052600090815260409020805460019091015482565b60408051928352602083019190915201610346565b61033c600f5481565b61033c60095481565b6103ec6103e7366004612f2d565b6107b9565b005b61033c60145481565b6103ec6107ef565b6103ec61040d366004612f2d565b610910565b60055461033c565b6103ec610428366004612fa7565b6109a7565b61045061043b366004612f2d565b60166020526000908152604090205460ff1681565b6040519015158152602001610346565b6103ec61046e366004612fc0565b6109b0565b61033c7f00000000000000000000000000000000000000000001a784379d99db4200000081565b6103ec610a7e565b61033c60135481565b610450610a86565b61033c6104c1366004612fa7565b610aa0565b61033c60125481565b6103ec6104dd366004613036565b610ac1565b61033c6104f0366004612f2d565b6001600160a01b03166000908152600d602052604090206001015490565b6103ec610b25565b61033c610524366004612fa7565b610b59565b6105507f0000000000000000000000005ac34c53a04b9aaa0bf047e7291fb4e8a48f2a1881565b6040516001600160a01b039091168152602001610346565b61033c60015481565b600e5461033c565b6103ec610587366004613082565b610b91565b6000546001600160a01b0316610550565b6103b26105ab366004612f2d565b6015602052600090815260409020805460019091015482565b61033c60105481565b6103b26105db366004612fa7565b610bdf565b61033c6105ee366004612f2d565b6001600160a01b03166000908152600d602052604090206003015490565b6103ec61061a3660046130d5565b610c0d565b6103ec61062d366004612fa7565b610e1a565b61033c60075481565b6103ec610649366004613116565b610e26565b61033c61065c366004612fa7565b610e78565b6103ec61104e565b610550610677366004612fa7565b611056565b6103ec61068a366004612f2d565b611080565b61033c61069d36600461314d565b61121e565b61033c6106b0366004612fc0565b611373565b6103ec6113b5565b61033c60065481565b6103ec61144f565b6103ec611457565b61033c60115481565b61033c6106ed366004612fc0565b611520565b6103ec610700366004612f2d565b61154e565b61033c610713366004612fa7565b6115e6565b61033c610726366004612fa7565b6115f6565b600c805461073890613180565b80601f016020809104026020016040519081016040528092919081815260200182805461076490613180565b80156107b15780601f10610786576101008083540402835291602001916107b1565b820191906000526020600020905b81548152906001019060200180831161079457829003601f168201915b505050505081565b600f5442116107e35760405162461bcd60e51b81526004016107da906131b5565b60405180910390fd5b6107ec81611606565b50565b6000546001600160a01b031633146108195760405162461bcd60e51b81526004016107da9061321d565b6000600954116108845760405162461bcd60e51b815260206004820152603060248201527f52657761726473506f6f6c426173653a207468657265206973206e6f2065787460448201526f195b9cda5bdb881cd8da19591d5b195960821b60648201526084016107da565b60075442106108fb5760405162461bcd60e51b815260206004820152603d60248201527f52657761726473506f6f6c426173653a2063616e6e6f742063616e63656c206560448201527f7874656e73696f6e20616674657220697420686173207374617274656400000060648201526084016107da565b6000600981905561090e90600a90612e58565b565b6000546001600160a01b0316331461093a5760405162461bcd60e51b81526004016107da9061321d565b60055460005b818110156109a257600061095382610e78565b9050801561098f5761098f84826005858154811061097357610973613252565b6000918252602090912001546001600160a01b03169190611828565b508061099a8161327e565b915050610940565b505050565b6107ec8161188b565b60008111610a0c5760405162461bcd60e51b815260206004820152602360248201527f5374616b655265636569766572466561747572653a204e6f207374616b652073604482015262195b9d60ea1b60648201526084016107da565b6001600160a01b038216610a6e5760405162461bcd60e51b8152602060048201526024808201527f5374616b655265636569766572466561747572653a20496e76616c696420737460448201526330b5b2b960e11b60648201526084016107da565b610a7a818360006118f9565b5050565b61090e611c3c565b600080600654118015610a9b57506006544210155b905090565b600a8181548110610ab057600080fd5b600091825260209091200154905081565b60405162461bcd60e51b815260206004820152603360248201527f4e6f6e436f6d706f756e64696e6752657761726473506f6f6c3a2063616e6e6f6044820152723a1032bc3a32b732103a3434b9903837b7b61760691b60648201526084016107da565b6000546001600160a01b03163314610b4f5760405162461bcd60e51b81526004016107da9061321d565b61090e6000611caa565b33600090815260156020526040812060028101805484908110610b7e57610b7e613252565b9060005260206000200154915050919050565b6000546001600160a01b03163314610bbb5760405162461bcd60e51b81526004016107da9061321d565b610bc483611cfa565b610bcd83611d12565b610bd984848484611d77565b50505050565b600e8181548110610bef57600080fd5b60009182526020909120600390910201805460019091015490915082565b6000546001600160a01b03163314610c375760405162461bcd60e51b81526004016107da9061321d565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a082319060240160206040518083038186803b158015610c7957600080fd5b505afa158015610c8d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cb19190613299565b905060008111610d035760405162461bcd60e51b815260206004820152601b60248201527f52657761726473506f6f6c426173653a206e6f2072657761726473000000000060448201526064016107da565b7f0000000000000000000000005ac34c53a04b9aaa0bf047e7291fb4e8a48f2a186001600160a01b0316826001600160a01b03161415610d555760405162461bcd60e51b81526004016107da906132b2565b60055460005b81811015610e055760058181548110610d7657610d76613252565b6000918252602090912001546001600160a01b0385811691161415610df35760405162461bcd60e51b815260206004820152602d60248201527f52657761726473506f6f6c426173653a2063616e6e6f7420776974686472617760448201526c103932bbb0b932103a37b5b2b760991b60648201526084016107da565b80610dfd8161327e565b915050610d5b565b50610bd96001600160a01b0384168584611828565b6107ec813360016118f9565b6000546001600160a01b03163314610e505760405162461bcd60e51b81526004016107da9061321d565b6001600160a01b0382166000908152601660205260409020805460ff19168215151790555050565b60008060058381548110610e8e57610e8e613252565b60009182526020822001546040516370a0823160e01b81523060048201526001600160a01b03909116925082906370a082319060240160206040518083038186803b158015610edc57600080fd5b505afa158015610ef0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f149190613299565b905060065460001415610f28579392505050565b6000610f5660065460075460048881548110610f4657610f46613252565b9060005260206000200154612029565b60095490915015610f9c576000610f8c600754600954600754610f799190613300565b600a8981548110610f4657610f46613252565b9050610f988183613300565b9150505b600060028681548110610fb157610fb1613252565b90600052602060002001548260038881548110610fd057610fd0613252565b9060005260206000200154610fe59190613300565b610fef9190613318565b610ff99084613318565b90507f0000000000000000000000005ac34c53a04b9aaa0bf047e7291fb4e8a48f2a186001600160a01b0316846001600160a01b03161415611045576001546110429082613318565b90505b95945050505050565b61090e612042565b6005818154811061106657600080fd5b6000918252602090912001546001600160a01b0316905081565b6000546001600160a01b031633146110aa5760405162461bcd60e51b81526004016107da9061321d565b60005b60055481101561113457600581815481106110ca576110ca613252565b6000918252602090912001547f0000000000000000000000005ac34c53a04b9aaa0bf047e7291fb4e8a48f2a186001600160a01b03908116911614156111225760405162461bcd60e51b81526004016107da906132b2565b8061112c8161327e565b9150506110ad565b506040516370a0823160e01b81523060048201526000907f0000000000000000000000005ac34c53a04b9aaa0bf047e7291fb4e8a48f2a186001600160a01b0316906370a082319060240160206040518083038186803b15801561119757600080fd5b505afa1580156111ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111cf9190613299565b9050600154811115610a7a57610a7a82600154836111ed9190613318565b6001600160a01b037f0000000000000000000000005ac34c53a04b9aaa0bf047e7291fb4e8a48f2a18169190611828565b600080600754831061123257600754611234565b825b90506000600854826112469190613318565b905060006004868154811061125d5761125d613252565b906000526020600020015482611273919061332f565b90506000600154670de0b6b3a76400008361128e919061332f565b6112989190613364565b9050600081600b89815481106112b0576112b0613252565b90600052602060002001546112c59190613300565b6001600160a01b038a166000908152600d60205260408120600181015492935091670de0b6b3a7640000906112fb90859061332f565b6113059190613364565b90506000826002018b8154811061131e5761131e613252565b9060005260206000200154826113349190613318565b905080836003018c8154811061134c5761134c613252565b90600052602060002001546113619190613300565b985050505050505050505b9392505050565b6001600160a01b0382166000908152600d60205260408120600381018054849081106113a1576113a1613252565b906000526020600020015491505092915050565b6007544290811180156113ca57506000600954115b15611446576113da6007546120e7565b6114466007546009546007546113f09190613300565b600a80548060200260200160405190810160405280929190818152602001828054801561143c57602002820191906000526020600020905b815481526020019060010190808311611428575b50505050506121fa565b6107ec816120e7565b61090e6123b2565b6000546001600160a01b031633146114815760405162461bcd60e51b81526004016107da9061321d565b60065442106114f15760405162461bcd60e51b815260206004820152603660248201527f52657761726473506f6f6c426173653a204e6f207374617274207363686564756044820152751b1959081bdc88185b1c9958591e481cdd185c9d195960521b60648201526084016107da565b604080516000815260208101918290525161150e91600491612e76565b50600060068190556007819055600855565b6001600160a01b0382166000908152600d60205260408120600281018054849081106113a1576113a1613252565b6000546001600160a01b031633146115785760405162461bcd60e51b81526004016107da9061321d565b6001600160a01b0381166115dd5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016107da565b6107ec81611caa565b600b8181548110610ab057600080fd5b60048181548110610ab057600080fd5b6001600160a01b038116600090815260166020526040902054819060ff166116855760405162461bcd60e51b815260206004820152602c60248201527f65786974416e645472616e736665723a3a7265636569766572206973206e6f7460448201526b081dda1a5d195b1a5cdd195960a21b60648201526084016107da565b336000908152600d6020526040902060018101546116a257505050565b6116aa6113b5565b60018101546116b8336124e5565b6116c133612697565b60008260010181905550806001546116d99190613318565b60015560005b60055481101561171e57600083600201828154811061170057611700613252565b600091825260209091200155806117168161327e565b9150506116df565b5060405163095ea7b360e01b81526001600160a01b038581166004830152602482018390527f0000000000000000000000005ac34c53a04b9aaa0bf047e7291fb4e8a48f2a18169063095ea7b390604401602060405180830381600087803b15801561178957600080fd5b505af115801561179d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117c1919061338e565b50604051633c323a1b60e01b8152336004820152602481018290526001600160a01b03851690633c323a1b90604401600060405180830381600087803b15801561180a57600080fd5b505af115801561181e573d6000803e3d6000fd5b5050505050505050565b6040516001600160a01b0383166024820152604481018290526109a290849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612808565b60405162461bcd60e51b815260206004820152603f60248201527f4f6e6c7945786974466561747572653a3a63616e6e6f7420776974686472617760448201527f2066726f6d207468697320636f6e74726163742e204f6e6c7920657869742e0060648201526084016107da565b60065442901580159061190d575060065481115b801561192857506009546007546119249190613300565b8111155b6119b95760405162461bcd60e51b815260206004820152605660248201527f52657761726473506f6f6c426173653a207374616b696e67206973206e6f742060448201527f73746172746564206f722069732066696e6973686564206f72206e6f20657874606482015275656e73696f6e2074616b696e6720696e20706c61636560501b608482015260a4016107da565b6001600160a01b0383166000908152600d6020526040902060018101547f00000000000000000000000000000000000000000001a784379d99db4200000090611a03908790613300565b11158015611a3e57507f00000000000000000000000000000000000000000001a784379d99db4200000085600154611a3b9190613300565b11155b611a965760405162461bcd60e51b8152602060048201526024808201527f52657761726473506f6f6c426173653a207374616b65206c696d69742072656160448201526318da195960e21b60648201526084016107da565b60008511611ae65760405162461bcd60e51b815260206004820152601f60248201527f52657761726473506f6f6c426173653a2063616e6e6f74207374616b6520300060448201526064016107da565b6001810154611af3578181555b611afb6113b5565b611b04846124e5565b848160010154611b149190613300565b816001018190555084600154611b2a9190613300565b60015560055460005b81811015611bae57670de0b6b3a7640000600b8281548110611b5757611b57613252565b90600052602060002001548460010154611b71919061332f565b611b7b9190613364565b836002018281548110611b9057611b90613252565b60009182526020909120015580611ba68161327e565b915050611b33565b50846001600160a01b03167f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d87604051611bea91815260200190565b60405180910390a2611c3484611c005733611c02565b855b6001600160a01b037f0000000000000000000000005ac34c53a04b9aaa0bf047e7291fb4e8a48f2a18169030896128da565b505050505050565b60405162461bcd60e51b815260206004820152603c60248201527f4f6e6c7945786974466561747572653a3a63616e6e6f7420636c61696d20667260448201527f6f6d207468697320636f6e74726163742e204f6e6c7920657869742e0000000060648201526084016107da565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6014819055601254611d0c9082613300565b60105550565b428111611d725760405162461bcd60e51b815260206004820152602860248201527f6c6f636b3a3a4c6f636b20656e64206e6565647320746f20626520696e207468604482015267652066757475726560c01b60648201526084016107da565b600f55565b60065415611dc75760405162461bcd60e51b815260206004820181905260248201527f52657761726473506f6f6c426173653a20616c7265616479207374617274656460448201526064016107da565b428410158015611dd657508383115b611e305760405162461bcd60e51b815260206004820152602560248201527f52657761726473506f6f6c426173653a20696e76616c6964207374617274206f6044820152641c88195b9960da1b60648201526084016107da565b6005548114611e925760405162461bcd60e51b815260206004820152602860248201527f52657761726473506f6f6c426173653a20696e76616c69642072657761726450604482015267195c94d958dbdb9960c21b60648201526084016107da565b611e9e60048383612ec1565b5060055460005b81811015611fd5576000611ec7878760048581548110610f4657610f46613252565b9050600060058381548110611ede57611ede613252565b6000918252602090912001546040516370a0823160e01b81523060048201526001600160a01b03909116906370a082319060240160206040518083038186803b158015611f2a57600080fd5b505afa158015611f3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f629190613299565b905081811015611fc05760405162461bcd60e51b815260206004820152602360248201527f52657761726473506f6f6c426173653a206e6f7420656e6f756768207265776160448201526272647360e81b60648201526084016107da565b50508080611fcd9061327e565b915050611ea5565b506006859055600784905560088590556040517f74e89788dfd5b96dd5e9c38139638937b89fc0d4863da5644783b5d7f876b87a9061201a90879087906004906133ab565b60405180910390a15050505050565b6000806120368585613318565b9050611045818461332f565b600f5442116120635760405162461bcd60e51b81526004016107da906131b5565b61090e7f0000000000000000000000005ac34c53a04b9aaa0bf047e7291fb4e8a48f2a1860058054806020026020016040519081016040528092919081815260200182805480156120dd57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116120bf575b5050505050612912565b60085481116120f35750565b6000600754821061210657600754612108565b815b905060006008548261211a9190613318565b90508061212657505050565b600154612134575060085550565b60055460005b818110156121f15760006004828154811061215757612157613252565b90600052602060002001548461216d919061332f565b90506000600154670de0b6b3a764000083612188919061332f565b6121929190613364565b905080600b84815481106121a8576121a8613252565b90600052602060002001546121bd9190613300565b600b84815481106121d0576121d0613252565b600091825260209091200155508190506121e98161327e565b91505061213a565b50505060085550565b60045460005b8181101561228357600061222660065460075460048581548110610f4657610f46613252565b9050806003838154811061223c5761223c613252565b90600052602060002001546122519190613300565b6003838154811061226457612264613252565b600091825260209091200155508061227b8161327e565b915050612200565b50600e60405180606001604052806006548152602001600754815260200160048054806020026020016040519081016040528092919081815260200182805480156122ed57602002820191906000526020600020905b8154815260200190600101908083116122d9575b50505091909252505081546001818101845560009384526020938490208351600390930201918255838301519082015560408201518051929391926123389260028501920190612e76565b5050825161234e91506004906020850190612e76565b506006849055600783905560088490556000600981905561237190600a90612e58565b7fd363ac13638f68e7284bc244076ff171a95616bfe30c8c7629980906a9db03638484846040516123a493929190613405565b60405180910390a150505050565b600f5442116123d35760405162461bcd60e51b81526004016107da906131b5565b336000908152600d602052604090206123ea6113b5565b60018101546123f65750565b6123ff336124e5565b6001810154600382018054604080516020808402820181019092528281526000939092909183018282801561245357602002820191906000526020600020905b81548152602001906001019080831161243f575b50505050509050816001546124689190613318565b600190815560009084018190555b6005548110156124da57600084600301828154811061249757612497613252565b906000526020600020018190555060008460020182815481106124bc576124bc613252565b600091825260209091200155806124d28161327e565b915050612476565b506109a28282612ac3565b6001600160a01b0381166000908152600d60205260409020600554600282015461257f5760008167ffffffffffffffff81111561252457612524613378565b60405190808252806020026020018201604052801561254d578160200160208202803683370190505b5080519091506125669060028501906020840190612e76565b50805161257c9060038501906020840190612e76565b50505b600182015461258d57505050565b60005b81811015610bd9576000670de0b6b3a7640000600b83815481106125b6576125b6613252565b906000526020600020015485600101546125d0919061332f565b6125da9190613364565b905060008460020183815481106125f3576125f3613252565b9060005260206000200154826126099190613318565b90508015612682578085600301848154811061262757612627613252565b906000526020600020015461263c9190613300565b85600301848154811061265157612651613252565b90600052602060002001819055508185600201848154811061267557612675613252565b6000918252602090912001555b5050808061268f9061327e565b915050612590565b6001600160a01b0381166000908152600d602052604090206126b76113b5565b6126c0826124e5565b60055460005b81811015610bd95760008360030182815481106126e5576126e5613252565b90600052602060002001549050600084600301838154811061270957612709613252565b9060005260206000200181905550806002838154811061272b5761272b613252565b90600052602060002001546127409190613300565b6002838154811061275357612753613252565b9060005260206000200181905550846001600160a01b03167f7e6632ca16a0ac6cf28448500b1a17d96c8b8163ad4c4a9b44ef5386cc02779e82600585815481106127a0576127a0613252565b6000918252602090912001546040516127d592916001600160a01b0316909182526001600160a01b0316602082015260400190565b60405180910390a26127f585826005858154811061097357610973613252565b50806128008161327e565b9150506126c6565b600061285d826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612bba9092919063ffffffff16565b8051909150156109a2578080602001905181019061287b919061338e565b6109a25760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016107da565b6040516001600160a01b0380851660248301528316604482015260648101829052610bd99085906323b872dd60e01b90608401611854565b336000908152601560205260409020805442116129805760405162461bcd60e51b815260206004820152602660248201527f66696e616c697a65457869743a3a547279696e6720746f206578697420746f6f604482015265206561726c7960d01b60648201526084016107da565b6001810154806129d25760405162461bcd60e51b815260206004820152601e60248201527f66696e616c697a65457869743a3a4e6f207374616b6520746f2065786974000060448201526064016107da565b600060018301556129ed6001600160a01b0385163383611828565b60005b8351811015612a8c576000836002018281548110612a1057612a10613252565b906000526020600020015490506000846002018381548110612a3457612a34613252565b9060005260206000200181905550612a793382878581518110612a5957612a59613252565b60200260200101516001600160a01b03166118289092919063ffffffff16565b5080612a848161327e565b9150506129f0565b5060408051338152602081018390527f548aea05c5e3b6ba34acdf7b3ad06c7bb667ed71d1761e2c177167be0a9eb05991016123a4565b8051612acf3382612bd1565b336000908152601560205260409020612ae784612c5e565b81556001810154612af9908590613300565b600182015560005b82811015612b8057838181518110612b1b57612b1b613252565b6020026020010151826002018281548110612b3857612b38613252565b9060005260206000200154612b4d9190613300565b826002018281548110612b6257612b62613252565b60009182526020909120015580612b788161327e565b915050612b01565b5080546040805133815260208101929092527fd9217a461a0f7f84171a8866118c3d92e943ba7c1ba89b819371f729b5cabcbc91016123a4565b6060612bc98484600085612cf7565b949350505050565b6001600160a01b03821660009081526015602052604090206002810154821415612bfa57505050565b60008267ffffffffffffffff811115612c1557612c15613378565b604051908082528060200260200182016040528015612c3e578160200160208202803683370190505b508051909150612c579060028401906020840190612e76565b5050505050565b6010546000904290811115612cb757600060125460105483612c809190613318565b612c8a919061344c565b601254909150612c9a8284613318565b612ca49190613300565b6010819055601194909455509192915050565b82601154612cc59190613300565b601155601054915060135460115410612cf157601254601054612ce89190613300565b60105560006011555b50919050565b606082471015612d585760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016107da565b843b612da65760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107da565b600080866001600160a01b03168587604051612dc29190613460565b60006040518083038185875af1925050503d8060008114612dff576040519150601f19603f3d011682016040523d82523d6000602084013e612e04565b606091505b5091509150612e14828286612e1f565b979650505050505050565b60608315612e2e57508161136c565b825115612e3e5782518084602001fd5b8160405162461bcd60e51b81526004016107da9190612f74565b50805460008255906000526020600020908101906107ec9190612efc565b828054828255906000526020600020908101928215612eb1579160200282015b82811115612eb1578251825591602001919060010190612e96565b50612ebd929150612efc565b5090565b828054828255906000526020600020908101928215612eb1579160200282015b82811115612eb1578235825591602001919060010190612ee1565b5b80821115612ebd5760008155600101612efd565b80356001600160a01b0381168114612f2857600080fd5b919050565b600060208284031215612f3f57600080fd5b61136c82612f11565b60005b83811015612f63578181015183820152602001612f4b565b83811115610bd95750506000910152565b6020815260008251806020840152612f93816040850160208701612f48565b601f01601f19169190910160400192915050565b600060208284031215612fb957600080fd5b5035919050565b60008060408385031215612fd357600080fd5b612fdc83612f11565b946020939093013593505050565b60008083601f840112612ffc57600080fd5b50813567ffffffffffffffff81111561301457600080fd5b6020830191508360208260051b850101111561302f57600080fd5b9250929050565b60008060006040848603121561304b57600080fd5b83359250602084013567ffffffffffffffff81111561306957600080fd5b61307586828701612fea565b9497909650939450505050565b6000806000806060858703121561309857600080fd5b8435935060208501359250604085013567ffffffffffffffff8111156130bd57600080fd5b6130c987828801612fea565b95989497509550505050565b600080604083850312156130e857600080fd5b6130f183612f11565b91506130ff60208401612f11565b90509250929050565b80151581146107ec57600080fd5b6000806040838503121561312957600080fd5b61313283612f11565b9150602083013561314281613108565b809150509250929050565b60008060006060848603121561316257600080fd5b61316b84612f11565b95602085013595506040909401359392505050565b600181811c9082168061319457607f821691505b60208210811415612cf157634e487b7160e01b600052602260045260246000fd5b60208082526042908201527f6f6e6c79556e6c6f636b65643a3a63616e6e6f7420706572666f726d2074686960408201527f7320616374696f6e20756e74696c2074686520656e64206f6620746865206c6f606082015261636b60f01b608082015260a00190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060001982141561329257613292613268565b5060010190565b6000602082840312156132ab57600080fd5b5051919050565b6020808252602e908201527f52657761726473506f6f6c426173653a2063616e6e6f7420776974686472617760408201526d1039ba30b5b4b733903a37b5b2b760911b606082015260800190565b6000821982111561331357613313613268565b500190565b60008282101561332a5761332a613268565b500390565b600081600019048311821515161561334957613349613268565b500290565b634e487b7160e01b600052601260045260246000fd5b6000826133735761337361334e565b500490565b634e487b7160e01b600052604160045260246000fd5b6000602082840312156133a057600080fd5b815161136c81613108565b60006060820185835260208581850152606060408501528185548084526080860191508660005282600020935060005b818110156133f7578454835260019485019492840192016133db565b509098975050505050505050565b6000606082018583526020858185015260606040850152818551808452608086019150828701935060005b818110156133f757845183529383019391830191600101613430565b60008261345b5761345b61334e565b500690565b60008251613472818460208701612f48565b919091019291505056fea26469706673582212207d784b3f6b055f07674adbfd25309dc364490bca96fee7dbd150f72e563448e864736f6c63430008090033

Deployed Bytecode Sourcemap

55626:2904:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;35295:192;;;;;;:::i;:::-;-1:-1:-1;;;;;35417:22:0;35373:7;35417:22;;;:8;:22;;;;;35457:15;;:22;;35295:192;;;;529:25:1;;;517:2;502:18;35295:192:0;;;;;;;;20266:43;;;;;20318:18;;;:::i;:::-;;;;;;;:::i;20602:44::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;1390:25:1;;;1446:2;1431:18;;1424:34;;;;1363:18;20602:44:0;1216:248:1;43990:31:0;;;;;;20082:32;;;;;;58150:175;;;;;;:::i;:::-;;:::i;:::-;;45774:35;;;;;;38826:338;;;:::i;42225:394::-;;;;;;:::i;:::-;;:::i;35554:110::-;35636:13;:20;35554:110;;57291:147;;;;;;:::i;:::-;;:::i;51896:50::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;1819:14:1;;1812:22;1794:41;;1782:2;1767:18;51896:50:0;1654:187:1;55036:284:0;;;;;;:::i;:::-;;:::i;20224:35::-;;;;;57472:109;;;:::i;45736:31::-;;;;;;32628:141;;;:::i;20121:41::-;;;;;;:::i;:::-;;:::i;45694:35::-;;;;;;58359:168;;;;;;:::i;:::-;;:::i;29415:173::-;;;;;;:::i;:::-;-1:-1:-1;;;;;29523:22:0;29479:7;29523:22;;;:8;:22;;;;;29563:17;;;;29415:173;5617:103;;;:::i;49976:185::-;;;;;;:::i;:::-;;:::i;19923:36::-;;;;;;;;-1:-1:-1;;;;;3164:32:1;;;3146:51;;3134:2;3119:18;19923:36:0;2987:216:1;19730:26:0;;;;;;35736:119;35823:17;:24;35736:119;;56951:306;;;;;;:::i;:::-;;:::i;4966:87::-;5012:7;5039:6;-1:-1:-1;;;;;5039:6:0;4966:87;;45938:44;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;45596:41;;;;;;20787:35;;;;;;:::i;:::-;;:::i;35017:192::-;;;;;;:::i;:::-;-1:-1:-1;;;;;35139:22:0;35095:7;35139:22;;;:8;:22;;;;;35179:15;;:22;;35017:192;40705:635;;;;;;:::i;:::-;;:::i;25016:109::-;;;;;;:::i;:::-;;:::i;20004:27::-;;;;;;53325:195;;;;;;:::i;:::-;;:::i;39342:1097::-;;;;;;:::i;:::-;;:::i;57899:124::-;;;:::i;19884:30::-;;;;;;:::i;:::-;;:::i;41526:520::-;;;;;;:::i;:::-;;:::i;33850:1081::-;;;;;;:::i;:::-;;:::i;33394:203::-;;;;;;:::i;:::-;;:::i;29690:470::-;;;:::i;19968:29::-;;;;;;57716:117;;;:::i;24615:292::-;;;:::i;45644:43::-;;;;;;32980:203;;;;;;:::i;:::-;;:::i;5875:201::-;;;;;;:::i;:::-;;:::i;20171:44::-;;;;;;:::i;:::-;;:::i;19845:32::-;;;;;;:::i;:::-;;:::i;20318:18::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;58150:175::-;44317:16;;44299:15;:34;44277:150;;;;-1:-1:-1;;;44277:150:0;;;;;;;:::i;:::-;;;;;;;;;58267:50:::1;58306:10;58267:38;:50::i;:::-;58150:175:::0;:::o;38826:338::-;5012:7;5039:6;-1:-1:-1;;;;;5039:6:0;3764:10;5186:23;5178:68;;;;-1:-1:-1;;;5178:68:0;;;;;;;:::i;:::-;38911:1:::1;38891:17;;:21;38883:82;;;::::0;-1:-1:-1;;;38883:82:0;;6452:2:1;38883:82:0::1;::::0;::::1;6434:21:1::0;6491:2;6471:18;;;6464:30;6530:34;6510:18;;;6503:62;-1:-1:-1;;;6581:18:1;;;6574:46;6637:19;;38883:82:0::1;6250:412:1::0;38883:82:0::1;39002:12;;38984:15;:30;38976:104;;;::::0;-1:-1:-1;;;38976:104:0;;6869:2:1;38976:104:0::1;::::0;::::1;6851:21:1::0;6908:2;6888:18;;;6881:30;6947:34;6927:18;;;6920:62;7018:31;6998:18;;;6991:59;7067:19;;38976:104:0::1;6667:425:1::0;38976:104:0::1;39113:1;39093:17;:21:::0;;;39125:31:::1;::::0;39132:24:::1;::::0;39125:31:::1;:::i;:::-;38826:338::o:0;42225:394::-;5012:7;5039:6;-1:-1:-1;;;;;5039:6:0;3764:10;5186:23;5178:68;;;;-1:-1:-1;;;5178:68:0;;;;;;;:::i;:::-;42336:13:::1;:20:::0;42306:27:::1;42369:243;42393:19;42389:1;:23;42369:243;;;42434:15;42452:22;42472:1;42452:19;:22::i;:::-;42434:40:::0;-1:-1:-1;42495:11:0;;42491:110:::1;;42527:58;42565:10;42577:7;42534:13;42548:1;42534:16;;;;;;;;:::i;:::-;;::::0;;;::::1;::::0;;;::::1;::::0;-1:-1:-1;;;;;42534:16:0::1;::::0;42527:58;:37:::1;:58::i;:::-;-1:-1:-1::0;42414:3:0;::::1;::::0;::::1;:::i;:::-;;;;42369:243;;;;42295:324;42225:394:::0;:::o;57291:147::-;57392:38;57417:12;57392:24;:38::i;55036:284::-;55146:1;55136:7;:11;55128:59;;;;-1:-1:-1;;;55128:59:0;;7703:2:1;55128:59:0;;;7685:21:1;7742:2;7722:18;;;7715:30;7781:34;7761:18;;;7754:62;-1:-1:-1;;;7832:18:1;;;7825:33;7875:19;;55128:59:0;7501:399:1;55128:59:0;-1:-1:-1;;;;;55206:23:0;;55198:72;;;;-1:-1:-1;;;55198:72:0;;8107:2:1;55198:72:0;;;8089:21:1;8146:2;8126:18;;;8119:30;8185:34;8165:18;;;8158:62;-1:-1:-1;;;8236:18:1;;;8229:34;8280:19;;55198:72:0;7905:400:1;55198:72:0;55281:31;55288:7;55297;55306:5;55281:6;:31::i;:::-;55036:284;;:::o;57472:109::-;57550:23;:21;:23::i;32628:141::-;32680:4;32722:1;32705:14;;:18;:55;;;;;32746:14;;32727:15;:33;;32705:55;32697:64;;32628:141;:::o;20121:41::-;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;20121:41:0;:::o;58359:168::-;58458:61;;-1:-1:-1;;;58458:61:0;;8512:2:1;58458:61:0;;;8494:21:1;8551:2;8531:18;;;8524:30;8590:34;8570:18;;;8563:62;-1:-1:-1;;;8641:18:1;;;8634:49;8700:19;;58458:61:0;8310:415:1;5617:103:0;5012:7;5039:6;-1:-1:-1;;;;;5039:6:0;3764:10;5186:23;5178:68;;;;-1:-1:-1;;;5178:68:0;;;;;;;:::i;:::-;5682:30:::1;5709:1;5682:18;:30::i;49976:185::-:0;50099:10;50046:7;50090:20;;;:8;:20;;;;;50128:12;;;:25;;50141:11;;50128:25;;;;;;:::i;:::-;;;;;;;;;50121:32;;;49976:185;;;:::o;56951:306::-;5012:7;5039:6;-1:-1:-1;;;;;5039:6:0;3764:10;5186:23;5178:68;;;;-1:-1:-1;;;5178:68:0;;;;;;;:::i;:::-;57124:28:::1;57138:13;57124;:28::i;:::-;57163:19;57168:13;57163:4;:19::i;:::-;57193:56;57200:15;57217:13;57232:16;;57193:6;:56::i;:::-;56951:306:::0;;;;:::o;20787:35::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;20787:35:0;:::o;40705:635::-;5012:7;5039:6;-1:-1:-1;;;;;5039:6:0;3764:10;5186:23;5178:68;;;;-1:-1:-1;;;5178:68:0;;;;;;;:::i;:::-;40819:39:::1;::::0;-1:-1:-1;;;40819:39:0;;40852:4:::1;40819:39;::::0;::::1;3146:51:1::0;40795:21:0::1;::::0;-1:-1:-1;;;;;40819:24:0;::::1;::::0;::::1;::::0;3119:18:1;;40819:39:0::1;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;40795:63;;40893:1;40877:13;:17;40869:57;;;::::0;-1:-1:-1;;;40869:57:0;;9121:2:1;40869:57:0::1;::::0;::::1;9103:21:1::0;9160:2;9140:18;;;9133:30;9199:29;9179:18;;;9172:57;9246:18;;40869:57:0::1;8919:351:1::0;40869:57:0::1;40965:12;-1:-1:-1::0;;;;;40947:31:0::1;:6;-1:-1:-1::0;;;;;40947:31:0::1;;;40939:90;;;;-1:-1:-1::0;;;40939:90:0::1;;;;;;;:::i;:::-;41072:13;:20:::0;41042:27:::1;41105:161;41129:19;41125:1;:23;41105:161;;;41188:13;41202:1;41188:16;;;;;;;;:::i;:::-;;::::0;;;::::1;::::0;;;::::1;::::0;-1:-1:-1;;;;;41178:26:0;;::::1;41188:16:::0;::::1;41178:26;;41170:84;;;::::0;-1:-1:-1;;;41170:84:0;;9892:2:1;41170:84:0::1;::::0;::::1;9874:21:1::0;9931:2;9911:18;;;9904:30;9970:34;9950:18;;;9943:62;-1:-1:-1;;;10021:18:1;;;10014:43;10074:19;;41170:84:0::1;9690:409:1::0;41170:84:0::1;41150:3:::0;::::1;::::0;::::1;:::i;:::-;;;;41105:161;;;-1:-1:-1::0;41278:54:0::1;-1:-1:-1::0;;;;;41278:27:0;::::1;41306:10:::0;41318:13;41278:27:::1;:54::i;25016:109::-:0;25079:38;25086:12;25100:10;25112:4;25079:6;:38::i;53325:195::-;5012:7;5039:6;-1:-1:-1;;;;;5039:6:0;3764:10;5186:23;5178:68;;;;-1:-1:-1;;;5178:68:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;52257:29:0;;;;;;:18;:29;;;;;:44;;-1:-1:-1;;52257:44:0;;;;;;;55036:284;;:::o;39342:1097::-;39419:7;39439:19;39461:13;39475:17;39461:32;;;;;;;;:::i;:::-;;;;;;;;;;39522:44;;-1:-1:-1;;;39522:44:0;;39560:4;39522:44;;;3146:51:1;-1:-1:-1;;;;;39461:32:0;;;;-1:-1:-1;39461:32:0;;39522:29;;3119:18:1;;39522:44:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;39504:62;;39583:14;;39601:1;39583:19;39579:66;;;39626:7;39342:1097;-1:-1:-1;;;39342:1097:0:o;39579:66::-;39657:20;39680:88;39703:14;;39719:12;;39733:15;39749:17;39733:34;;;;;;;;:::i;:::-;;;;;;;;;39680:22;:88::i;:::-;39785:17;;39657:111;;-1:-1:-1;39785:21:0;39781:335;;39823:29;39855:181;39896:12;;39942:17;;39927:12;;:32;;;;:::i;:::-;39978:24;40003:17;39978:43;;;;;;;;:::i;39855:181::-;39823:213;-1:-1:-1;40068:36:0;39823:213;40068:12;:36;:::i;:::-;40053:51;;39808:308;39781:335;40128:24;40233:12;40246:17;40233:31;;;;;;;;:::i;:::-;;;;;;;;;40218:12;40179:17;40197;40179:36;;;;;;;;:::i;:::-;;;;;;;;;:51;;;;:::i;:::-;:85;;;;:::i;:::-;40155:110;;:7;:110;:::i;:::-;40128:137;;40305:12;-1:-1:-1;;;;;40282:36:0;:11;-1:-1:-1;;;;;40282:36:0;;40278:118;;;40373:11;;40354:30;;:16;:30;:::i;:::-;40335:49;;40278:118;40415:16;39342:1097;-1:-1:-1;;;;;39342:1097:0:o;57899:124::-;57980:35;:33;:35::i;19884:30::-;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;19884:30:0;;-1:-1:-1;19884:30:0;:::o;41526:520::-;5012:7;5039:6;-1:-1:-1;;;;;5039:6:0;3764:10;5186:23;5178:68;;;;-1:-1:-1;;;5178:68:0;;;;;;;:::i;:::-;41672:9:::1;41667:178;41691:13;:20:::0;41687:24;::::1;41667:178;;;41766:13;41780:1;41766:16;;;;;;;;:::i;:::-;;::::0;;;::::1;::::0;;;::::1;::::0;41749:12:::1;-1:-1:-1::0;;;;;41741:41:0;;::::1;41766:16:::0;::::1;41741:41;;41733:100;;;;-1:-1:-1::0;;;41733:100:0::1;;;;;;;:::i;:::-;41713:3:::0;::::1;::::0;::::1;:::i;:::-;;;;41667:178;;;-1:-1:-1::0;41875:37:0::1;::::0;-1:-1:-1;;;41875:37:0;;41906:4:::1;41875:37;::::0;::::1;3146:51:1::0;41857:15:0::1;::::0;41875:12:::1;-1:-1:-1::0;;;;;41875:22:0::1;::::0;::::1;::::0;3119:18:1;;41875:37:0::1;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;41857:55;;41939:11;;41929:7;:21;41925:114;;;41967:60;41993:10;42015:11;;42005:7;:21;;;;:::i;:::-;-1:-1:-1::0;;;;;41967:12:0::1;:25;::::0;:60;:25:::1;:60::i;33850:1081::-:0;33999:7;34019:27;34058:12;;34050:5;:20;34049:45;;34082:12;;34049:45;;;34074:5;34049:45;34019:75;;34105:30;34160:19;;34138;:41;;;;:::i;:::-;34105:74;;34192:17;34237:15;34253:11;34237:28;;;;;;;;:::i;:::-;;;;;;;;;34212:22;:53;;;;:::i;:::-;34192:73;;34308:32;34369:11;;19714:7;34344:9;:21;;;;:::i;:::-;34343:37;;;;:::i;:::-;34308:72;;34428:25;34499:24;34456:27;34484:11;34456:40;;;;;;;;:::i;:::-;;;;;;;;;:67;;;;:::i;:::-;-1:-1:-1;;;;;34626:22:0;;34602:21;34626:22;;;:8;:22;;;;;34682:17;;;;34428:95;;-1:-1:-1;34626:22:0;19714:7;;34682:37;;34428:95;;34682:37;:::i;:::-;34681:51;;;;:::i;:::-;34661:71;;34772:19;34806:4;:15;;34822:11;34806:28;;;;;;;;:::i;:::-;;;;;;;;;34794:9;:40;;;;:::i;:::-;34772:62;;34912:11;34881:4;:15;;34897:11;34881:28;;;;;;;;:::i;:::-;;;;;;;;;:42;;;;:::i;:::-;34874:49;;;;;;;;;;33850:1081;;;;;;:::o;33394:203::-;-1:-1:-1;;;;;33526:22:0;;33482:7;33526:22;;;:8;:22;;;;;33566:15;;;:23;;33582:6;;33566:23;;;;;;:::i;:::-;;;;;;;;;33559:30;;;33394:203;;;;:::o;29690:470::-;29821:12;;29770:15;;29802:31;;:56;;;;;29857:1;29837:17;;:21;29802:56;29798:355;;;29875:38;29900:12;;29875:24;:38::i;:::-;29928:81;29936:12;;29965:17;;29950:12;;:32;;;;:::i;:::-;29984:24;29928:81;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:7;:81::i;:::-;30024:42;30049:16;30024:24;:42::i;57716:117::-;57798:27;:25;:27::i;24615:292::-;5012:7;5039:6;-1:-1:-1;;;;;5039:6:0;3764:10;5186:23;5178:68;;;;-1:-1:-1;;;5178:68:0;;;;;;;:::i;:::-;24689:14:::1;;24671:15;:32;24663:99;;;::::0;-1:-1:-1;;;24663:99:0;;10999:2:1;24663:99:0::1;::::0;::::1;10981:21:1::0;11038:2;11018:18;;;11011:30;11077:34;11057:18;;;11050:62;-1:-1:-1;;;11128:18:1;;;11121:52;11190:19;;24663:99:0::1;10797:418:1::0;24663:99:0::1;24793:16;::::0;;24807:1:::1;24793:16:::0;;::::1;::::0;::::1;::::0;;;;24775:34;::::1;::::0;:15:::1;::::0;:34:::1;:::i;:::-;-1:-1:-1::0;24837:1:0::1;24820:14;:18:::0;;;24849:12:::1;:16:::0;;;24876:19:::1;:23:::0;24615:292::o;32980:203::-;-1:-1:-1;;;;;33112:22:0;;33068:7;33112:22;;;:8;:22;;;;;33152:15;;;:23;;33168:6;;33152:23;;;;;;:::i;5875:201::-;5012:7;5039:6;-1:-1:-1;;;;;5039:6:0;3764:10;5186:23;5178:68;;;;-1:-1:-1;;;5178:68:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;5964:22:0;::::1;5956:73;;;::::0;-1:-1:-1;;;5956:73:0;;11554:2:1;5956:73:0::1;::::0;::::1;11536:21:1::0;11593:2;11573:18;;;11566:30;11632:34;11612:18;;;11605:62;-1:-1:-1;;;11683:18:1;;;11676:36;11729:19;;5956:73:0::1;11352:402:1::0;5956:73:0::1;6040:28;6059:8;6040:18;:28::i;20171:44::-:0;;;;;;;;;;;;19845:32;;;;;;;;;;;;53701:946;-1:-1:-1;;;;;52388:29:0;;;;;;:18;:29;;;;;;53794:10;;52388:29;;52380:86;;;;-1:-1:-1;;;52380:86:0;;11961:2:1;52380:86:0;;;11943:21:1;12000:2;11980:18;;;11973:30;12039:34;12019:18;;;12012:62;-1:-1:-1;;;12090:18:1;;;12083:42;12142:19;;52380:86:0;11759:408:1;52380:86:0;53850:10:::1;53817:21;53841:20:::0;;;:8:::1;:20;::::0;;;;53878:17:::1;::::0;::::1;::::0;53874:61:::1;;53917:7;55036:284:::0;;:::o;53874:61::-:1;53945:25;:23;:25::i;:::-;54061:17;::::0;::::1;::::0;54091:36:::1;54116:10;54091:24;:36::i;:::-;54192:18;54199:10;54192:6;:18::i;:::-;54328:1;54308:4;:17;;:21;;;;54368:16;54354:11;;:30;;;;:::i;:::-;54340:11;:44:::0;54402:9:::1;54397:100;54421:13;:20:::0;54417:24;::::1;54397:100;;;54484:1;54463:4;:15;;54479:1;54463:18;;;;;;;;:::i;:::-;;::::0;;;::::1;::::0;;;::::1;:22:::0;54443:3;::::1;::::0;::::1;:::i;:::-;;;;54397:100;;;-1:-1:-1::0;54509:50:0::1;::::0;-1:-1:-1;;;54509:50:0;;-1:-1:-1;;;;;12364:32:1;;;54509:50:0::1;::::0;::::1;12346:51:1::0;12413:18;;;12406:34;;;54509:12:0::1;:20;::::0;::::1;::::0;12319:18:1;;54509:50:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;54570:69:0::1;::::0;-1:-1:-1;;;54570:69:0;;54610:10:::1;54570:69;::::0;::::1;12346:51:1::0;12413:18;;;12406:34;;;-1:-1:-1;;;;;54570:39:0;::::1;::::0;::::1;::::0;12319:18:1;;54570:69:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;53806:841;;53701:946:::0;;:::o;15296:211::-;15440:58;;-1:-1:-1;;;;;12364:32:1;;15440:58:0;;;12346:51:1;12413:18;;;12406:34;;;15413:86:0;;15433:5;;-1:-1:-1;;;15463:23:0;12319:18:1;;15440:58:0;;;;-1:-1:-1;;15440:58:0;;;;;;;;;;;;;;-1:-1:-1;;;;;15440:58:0;-1:-1:-1;;;;;;15440:58:0;;;;;;;;;;15413:19;:86::i;43469:143::-;43531:73;;-1:-1:-1;;;43531:73:0;;12903:2:1;43531:73:0;;;12885:21:1;12942:2;12922:18;;;12915:30;12981:34;12961:18;;;12954:62;13052:33;13032:18;;;13025:61;13103:19;;43531:73:0;12701:427:1;25133:1718:0;25338:14;;25289:15;;25338:18;;;;:55;;;25379:14;;25360:16;:33;25338:55;25337:132;;;;;25451:17;;25436:12;;:32;;;;:::i;:::-;25416:16;:52;;25337:132;25315:268;;;;-1:-1:-1;;;25315:268:0;;13335:2:1;25315:268:0;;;13317:21:1;13374:2;13354:18;;;13347:30;13413:34;13393:18;;;13386:62;13484:34;13464:18;;;13457:62;-1:-1:-1;;;13535:19:1;;;13528:53;13598:19;;25315:268:0;13133:490:1;25315:268:0;-1:-1:-1;;;;;25620:17:0;;25596:21;25620:17;;;:8;:17;;;;;25671;;;;25707:10;;25671:32;;25691:12;;25671:32;:::i;:::-;:46;;25670:102;;;;;25753:18;25737:12;25723:11;;:26;;;;:::i;:::-;:48;;25670:102;25648:188;;;;-1:-1:-1;;;25648:188:0;;13830:2:1;25648:188:0;;;13812:21:1;13869:2;13849:18;;;13842:30;13908:34;13888:18;;;13881:62;-1:-1:-1;;;13959:18:1;;;13952:34;14003:19;;25648:188:0;13628:400:1;25648:188:0;25872:1;25857:12;:16;25849:60;;;;-1:-1:-1;;;25849:60:0;;14235:2:1;25849:60:0;;;14217:21:1;14274:2;14254:18;;;14247:30;14313:33;14293:18;;;14286:61;14364:18;;25849:60:0;14033:355:1;25849:60:0;26004:17;;;;26000:99;;26043:44;;;26000:99;26111:25;:23;:25::i;:::-;26198:33;26223:7;26198:24;:33::i;:::-;26336:12;26316:4;:17;;;:32;;;;:::i;:::-;26296:4;:17;;:52;;;;26387:12;26373:11;;:26;;;;:::i;:::-;26359:11;:40;26442:13;:20;26412:27;26475:204;26499:19;26495:1;:23;26475:204;;;19714:7;26582:27;26610:1;26582:30;;;;;;;;:::i;:::-;;;;;;;;;26562:4;:17;;;:50;;;;:::i;:::-;26561:64;;;;:::i;:::-;26540:4;:15;;26556:1;26540:18;;;;;;;;:::i;:::-;;;;;;;;;;:85;26520:3;;;;:::i;:::-;;;;26475:204;;;;26703:7;-1:-1:-1;;;;;26696:29:0;;26712:12;26696:29;;;;529:25:1;;517:2;502:18;;383:177;26696:29:0;;;;;;;;26738:105;26776:13;:36;;26802:10;26776:36;;;26792:7;26776:36;-1:-1:-1;;;;;26738:12:0;:29;;26823:4;26830:12;26738:29;:105::i;:::-;25251:1600;;;25133:1718;;;:::o;43620:130::-;43672:70;;-1:-1:-1;;;43672:70:0;;14595:2:1;43672:70:0;;;14577:21:1;14634:2;14614:18;;;14607:30;14673:34;14653:18;;;14646:62;14744:30;14724:18;;;14717:58;14792:19;;43672:70:0;14393:424:1;6236:191:0;6310:16;6329:6;;-1:-1:-1;;;;;6346:17:0;;;-1:-1:-1;;;;;;6346:17:0;;;;;;6379:40;;6329:6;;;;;;;6379:40;;6310:16;6379:40;6299:128;6236:191;:::o;46683:195::-;46750:20;:37;;;46850:20;;46827:43;;46773:14;46827:43;:::i;:::-;46798:26;:72;-1:-1:-1;46683:195:0:o;44030:204::-;44119:15;44099:17;:35;44091:88;;;;-1:-1:-1;;;44091:88:0;;15024:2:1;44091:88:0;;;15006:21:1;15063:2;15043:18;;;15036:30;15102:34;15082:18;;;15075:62;-1:-1:-1;;;15153:18:1;;;15146:38;15201:19;;44091:88:0;14822:404:1;44091:88:0;44190:16;:36;44030:204::o;23341:1179::-;23504:14;;:19;23496:64;;;;-1:-1:-1;;;23496:64:0;;15433:2:1;23496:64:0;;;15415:21:1;;;15452:18;;;15445:30;15511:34;15491:18;;;15484:62;15563:18;;23496:64:0;15231:356:1;23496:64:0;23612:15;23593;:34;;:69;;;;;23647:15;23631:13;:31;23593:69;23571:156;;;;-1:-1:-1;;;23571:156:0;;15794:2:1;23571:156:0;;;15776:21:1;15833:2;15813:18;;;15806:30;15872:34;15852:18;;;15845:62;-1:-1:-1;;;15923:18:1;;;15916:35;15968:19;;23571:156:0;15592:401:1;23571:156:0;23775:13;:20;23748:47;;23740:100;;;;-1:-1:-1;;;23740:100:0;;16200:2:1;23740:100:0;;;16182:21:1;16239:2;16219:18;;;16212:30;16278:34;16258:18;;;16251:62;-1:-1:-1;;;16329:18:1;;;16322:38;16377:19;;23740:100:0;15998:404:1;23740:100:0;23851:34;:15;23869:16;;23851:34;:::i;:::-;-1:-1:-1;23928:13:0;:20;23898:27;23961:348;23985:19;23981:1;:23;23961:348;;;24026:21;24050:74;24073:15;24090:13;24105:15;24121:1;24105:18;;;;;;;;:::i;24050:74::-;24026:98;;24141:15;24166:13;24180:1;24166:16;;;;;;;;:::i;:::-;;;;;;;;;;;24159:49;;-1:-1:-1;;;24159:49:0;;24202:4;24159:49;;;3146:51:1;-1:-1:-1;;;;;24166:16:0;;;;24159:34;;3119:18:1;;24159:49:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;24141:67;;24244:13;24233:7;:24;;24225:72;;;;-1:-1:-1;;;24225:72:0;;16609:2:1;24225:72:0;;;16591:21:1;16648:2;16628:18;;;16621:30;16687:34;16667:18;;;16660:62;-1:-1:-1;;;16738:18:1;;;16731:33;16781:19;;24225:72:0;16407:399:1;24225:72:0;24011:298;;24006:3;;;;;:::i;:::-;;;;23961:348;;;-1:-1:-1;24321:14:0;:32;;;24364:12;:28;;;24403:19;:37;;;24458:54;;;;;;24338:15;;24379:13;;24496:15;;24458:54;:::i;:::-;;;;;;;;23485:1035;23341:1179;;;;:::o;42880:310::-;43043:7;;43094:31;43110:15;43094:13;:31;:::i;:::-;43063:62;-1:-1:-1;43143:39:0;43063:62;43143:16;:39;:::i;51574:121::-;44317:16;;44299:15;:34;44277:150;;;;-1:-1:-1;;;44277:150:0;;;;;;;:::i;:::-;51637:50:::1;51658:12;51673:13;51637:50;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;;-1:-1:-1;;;;;51637:50:0::1;::::0;;;;;::::1;::::0;::::1;;::::0;;::::1;;;;;;;;;:12;:50::i;30270:1158::-:0;30376:19;;30355:17;:40;30351:79;;30270:1158;:::o;30351:79::-;30442:27;30493:12;;30473:17;:32;30472:69;;30529:12;;30472:69;;;30509:17;30472:69;30442:99;;30554:30;30609:19;;30587;:41;;;;:::i;:::-;30554:74;-1:-1:-1;30645:27:0;30641:66;;30689:7;;30270:1158;:::o;30641:66::-;30723:11;;30719:111;;-1:-1:-1;30756:19:0;:41;-1:-1:-1;30270:1158:0:o;30719:111::-;30872:13;:20;30842:27;30905:462;30929:19;30925:1;:23;30905:462;;;30970:17;31015:15;31031:1;31015:18;;;;;;;;:::i;:::-;;;;;;;;;30990:22;:43;;;;:::i;:::-;30970:63;;31080:32;31141:11;;19714:7;31116:9;:21;;;;:::i;:::-;31115:37;;;;:::i;:::-;31080:72;;31270:24;31237:27;31265:1;31237:30;;;;;;;;:::i;:::-;;;;;;;;;:57;;;;:::i;:::-;31204:27;31232:1;31204:30;;;;;;;;:::i;:::-;;;;;;;;;;:90;-1:-1:-1;30950:3:0;;-1:-1:-1;30950:3:0;;;:::i;:::-;;;;30905:462;;;-1:-1:-1;;;31379:19:0;:41;-1:-1:-1;30270:1158:0:o;37861:894::-;38047:15;:22;38015:29;38080:247;38104:21;38100:1;:25;38080:247;;;38147:20;38170:72;38193:14;;38209:12;;38223:15;38239:1;38223:18;;;;;;;;:::i;38170:72::-;38147:95;;38303:12;38280:17;38298:1;38280:20;;;;;;;;:::i;:::-;;;;;;;;;:35;;;;:::i;:::-;38257:17;38275:1;38257:20;;;;;;;;:::i;:::-;;;;;;;;;;:58;-1:-1:-1;38127:3:0;;;;:::i;:::-;;;;38080:247;;;;38339:17;38362:55;;;;;;;;38371:14;;38362:55;;;;38387:12;;38362:55;;;;38401:15;38362:55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;38362:55:0;;;;-1:-1:-1;;38339:79:0;;;;;;;;-1:-1:-1;38339:79:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;38431:34:0;;;;-1:-1:-1;38431:15:0;;:34;;;;;:::i;:::-;-1:-1:-1;38476:14:0;:32;;;38519:12;:28;;;38558:19;:37;;;-1:-1:-1;38608:17:0;:21;;;38640:31;;38647:24;;38640:31;:::i;:::-;38689:58;38698:15;38715:13;38730:16;38689:58;;;;;;;;:::i;:::-;;;;;;;;38004:751;37861:894;;;:::o;50793:773::-;44317:16;;44299:15;:34;44277:150;;;;-1:-1:-1;;;44277:150:0;;;;;;;:::i;:::-;50890:10:::1;50857:21;50881:20:::0;;;:8:::1;:20;::::0;;;;50914:25:::1;:23;:25::i;:::-;51007:17;::::0;::::1;::::0;51003:61:::1;;51046:7;38826:338::o:0;51003:61::-:1;51076:36;51101:10;51076:24;:36::i;:::-;51200:17;::::0;::::1;::::0;51258:15:::1;::::0;::::1;51228:45:::0;;::::1;::::0;;::::1;::::0;;::::1;::::0;;;;;;;;;;51177:20:::1;::::0;51228:45;;51258:15;;51228:45;::::1;51258:15:::0;51228:45;;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;51314:12;51300:11;;:26;;;;:::i;:::-;51286:11;:40:::0;;;51357:1:::1;51337:17:::0;;::::1;:21:::0;;;51371:137:::1;51395:13;:20:::0;51391:24;::::1;51371:137;;;51458:1;51437:4;:15;;51453:1;51437:18;;;;;;;;:::i;:::-;;;;;;;;:22;;;;51495:1;51474:4;:15;;51490:1;51474:18;;;;;;;;:::i;:::-;;::::0;;;::::1;::::0;;;::::1;:22:::0;51417:3;::::1;::::0;::::1;:::i;:::-;;;;51371:137;;;;51520:38;51533:12;51547:10;51520:12;:38::i;31563:1000::-:0;-1:-1:-1;;;;;31663:22:0;;31639:21;31663:22;;;:8;:22;;;;;31728:13;:20;31765:15;;;:22;31761:236;;31850:22;31889:19;31875:34;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;31875:34:0;-1:-1:-1;31924:23:0;;31850:59;;-1:-1:-1;31924:23:0;;:15;;;;:23;;;;;:::i;:::-;-1:-1:-1;31962:23:0;;;;:15;;;;:23;;;;;:::i;:::-;;31794:203;31761:236;32013:17;;;;32009:61;;32052:7;;31563:1000;:::o;32009:61::-;32087:18;32082:474;32124:19;32111:10;:32;32082:474;;;32174:17;19714:7;32215:27;32243:10;32215:39;;;;;;;;:::i;:::-;;;;;;;;;32195:4;:17;;;:59;;;;:::i;:::-;32194:73;;;;:::i;:::-;32174:93;;32282:19;32316:4;:15;;32332:10;32316:27;;;;;;;;:::i;:::-;;;;;;;;;32304:9;:39;;;;:::i;:::-;32282:61;-1:-1:-1;32364:15:0;;32360:185;;32460:11;32430:4;:15;;32446:10;32430:27;;;;;;;;:::i;:::-;;;;;;;;;:41;;;;:::i;:::-;32400:4;:15;;32416:10;32400:27;;;;;;;;:::i;:::-;;;;;;;;:71;;;;32520:9;32490:4;:15;;32506:10;32490:27;;;;;;;;:::i;:::-;;;;;;;;;;:39;32360:185;32159:397;;32145:12;;;;;:::i;:::-;;;;32082:474;;27015:603;-1:-1:-1;;;;;27093:18:0;;27069:21;27093:18;;;:8;:18;;;;;27122:25;:23;:25::i;:::-;27158:34;27183:8;27158:24;:34::i;:::-;27235:13;:20;27205:27;27268:343;27292:19;27288:1;:23;27268:343;;;27333:14;27350:4;:15;;27366:1;27350:18;;;;;;;;:::i;:::-;;;;;;;;;27333:35;;27404:1;27383:4;:15;;27399:1;27383:18;;;;;;;;:::i;:::-;;;;;;;;:22;;;;27456:6;27438:12;27451:1;27438:15;;;;;;;;:::i;:::-;;;;;;;;;:24;;;;:::i;:::-;27420:12;27433:1;27420:15;;;;;;;;:::i;:::-;;;;;;;;:42;;;;27492:8;-1:-1:-1;;;;;27484:43:0;;27502:6;27510:13;27524:1;27510:16;;;;;;;;:::i;:::-;;;;;;;;;;;27484:43;;;;;-1:-1:-1;;;;;27510:16:0;;18568:25:1;;;-1:-1:-1;;;;;18629:32:1;18624:2;18609:18;;18602:60;18556:2;18541:18;;18394:274;27484:43:0;;;;;;;;27544:55;27582:8;27592:6;27551:13;27565:1;27551:16;;;;;;;;:::i;27544:55::-;-1:-1:-1;27313:3:0;;;;:::i;:::-;;;;27268:343;;17869:716;18293:23;18319:69;18347:4;18319:69;;;;;;;;;;;;;;;;;18327:5;-1:-1:-1;;;;;18319:27:0;;;:69;;;;;:::i;:::-;18403:17;;18293:95;;-1:-1:-1;18403:21:0;18399:179;;18500:10;18489:30;;;;;;;;;;;;:::i;:::-;18481:85;;;;-1:-1:-1;;;18481:85:0;;18875:2:1;18481:85:0;;;18857:21:1;18914:2;18894:18;;;18887:30;18953:34;18933:18;;;18926:62;-1:-1:-1;;;19004:18:1;;;18997:40;19054:19;;18481:85:0;18673:406:1;15515:248:0;15686:68;;-1:-1:-1;;;;;19342:15:1;;;15686:68:0;;;19324:34:1;19394:15;;19374:18;;;19367:43;19426:18;;;19419:34;;;15659:96:0;;15679:5;;-1:-1:-1;;;15709:27:0;19259:18:1;;15686:68:0;19084:375:1;47498:790:0;47637:10;47604:21;47628:20;;;:8;:20;;;;;47685:18;;47667:15;:36;47659:87;;;;-1:-1:-1;;;47659:87:0;;19666:2:1;47659:87:0;;;19648:21:1;19705:2;19685:18;;;19678:30;19744:34;19724:18;;;19717:62;-1:-1:-1;;;19795:18:1;;;19788:36;19841:19;;47659:87:0;19464:402:1;47659:87:0;47783:14;;;;47816:17;47808:60;;;;-1:-1:-1;;;47808:60:0;;20073:2:1;47808:60:0;;;20055:21:1;20112:2;20092:18;;;20085:30;20151:32;20131:18;;;20124:60;20201:18;;47808:60:0;19871:354:1;47808:60:0;47896:1;47879:14;;;:18;47910:70;-1:-1:-1;;;;;47910:34:0;;47953:10;47966:13;47910:34;:70::i;:::-;47998:9;47993:230;48017:14;:21;48013:1;:25;47993:230;;;48060:19;48082:4;:12;;48095:1;48082:15;;;;;;;;:::i;:::-;;;;;;;;;48060:37;;48130:1;48112:4;:12;;48125:1;48112:15;;;;;;;;:::i;:::-;;;;;;;;:19;;;;48148:63;48187:10;48199:11;48155:14;48170:1;48155:17;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;48148:38:0;;;:63;;;;;:::i;:::-;-1:-1:-1;48040:3:0;;;;:::i;:::-;;;;47993:230;;;-1:-1:-1;48240:40:0;;;48254:10;12346:51:1;;12428:2;12413:18;;12406:34;;;48240:40:0;;12319:18:1;48240:40:0;12172:274:1;46886:604:0;47018:18;;47049:51;47068:10;47018:18;47049;:51::i;:::-;47146:10;47113:21;47137:20;;;:8;:20;;;;;47189:34;47210:12;47189:20;:34::i;:::-;47168:55;;47251:14;;;;:29;;47268:12;;47251:29;:::i;:::-;47234:14;;;:46;47298:9;47293:127;47317:19;47313:1;:23;47293:127;;;47394:11;47406:1;47394:14;;;;;;;;:::i;:::-;;;;;;;47376:4;:12;;47389:1;47376:15;;;;;;;;:::i;:::-;;;;;;;;;:32;;;;:::i;:::-;47358:4;:12;;47371:1;47358:15;;;;;;;;:::i;:::-;;;;;;;;;;:50;47338:3;;;;:::i;:::-;;;;47293:127;;;-1:-1:-1;47463:18:0;;47437:45;;;47451:10;12346:51:1;;12428:2;12413:18;;12406:34;;;;47437:45:0;;12319:18:1;47437:45:0;12172:274:1;10068:229:0;10205:12;10237:52;10259:6;10267:4;10273:1;10276:12;10237:21;:52::i;:::-;10230:59;10068:229;-1:-1:-1;;;;10068:229:0:o;50169:363::-;-1:-1:-1;;;;;50284:22:0;;50260:21;50284:22;;;:8;:22;;;;;50323:12;;;:19;:35;;50319:110;;;50411:7;50169:363;;:::o;50319:110::-;50441:22;50480:12;50466:27;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;50466:27:0;-1:-1:-1;50504:20:0;;50441:52;;-1:-1:-1;50504:20:0;;:12;;;;:20;;;;;:::i;:::-;;50249:283;;50169:363;;:::o;48296:1513::-;48476:26;;48364:21;;48425:15;;48457:45;;48453:835;;;48598:31;48682:20;;48652:26;;48633:16;:45;;;;:::i;:::-;48632:70;;;;:::i;:::-;48865:20;;48598:104;;-1:-1:-1;48820:42:0;48598:104;48820:16;:42;:::i;:::-;:65;;;;:::i;:::-;48791:26;:94;;;48987:28;:41;;;;-1:-1:-1;48791:94:0;;48296:1513;-1:-1:-1;;48296:1513:0:o;48453:835::-;49252:10;49221:28;;:41;;;;:::i;:::-;49190:28;:72;49316:26;;49300:42;;49391:16;;49359:28;;:48;49355:447;;49513:20;;49484:26;;:49;;;;:::i;:::-;49455:26;:78;49773:1;49742:28;:32;49355:447;48387:1422;48296:1513;;;:::o;11188:510::-;11358:12;11416:5;11391:21;:30;;11383:81;;;;-1:-1:-1;;;11383:81:0;;20549:2:1;11383:81:0;;;20531:21:1;20588:2;20568:18;;;20561:30;20627:34;20607:18;;;20600:62;-1:-1:-1;;;20678:18:1;;;20671:36;20724:19;;11383:81:0;20347:402:1;11383:81:0;7585:20;;11475:60;;;;-1:-1:-1;;;11475:60:0;;20956:2:1;11475:60:0;;;20938:21:1;20995:2;20975:18;;;20968:30;21034:31;21014:18;;;21007:59;21083:18;;11475:60:0;20754:353:1;11475:60:0;11549:12;11563:23;11590:6;-1:-1:-1;;;;;11590:11:0;11609:5;11616:4;11590:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11548:73;;;;11639:51;11656:7;11665:10;11677:12;11639:16;:51::i;:::-;11632:58;11188:510;-1:-1:-1;;;;;;;11188:510:0:o;13874:712::-;14024:12;14053:7;14049:530;;;-1:-1:-1;14084:10:0;14077:17;;14049:530;14198:17;;:21;14194:374;;14396:10;14390:17;14457:15;14444:10;14440:2;14436:19;14429:44;14194:374;14539:12;14532:20;;-1:-1:-1;;;14532:20:0;;;;;;;;:::i;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14:173:1;82:20;;-1:-1:-1;;;;;131:31:1;;121:42;;111:70;;177:1;174;167:12;111:70;14:173;;;:::o;192:186::-;251:6;304:2;292:9;283:7;279:23;275:32;272:52;;;320:1;317;310:12;272:52;343:29;362:9;343:29;:::i;565:258::-;637:1;647:113;661:6;658:1;655:13;647:113;;;737:11;;;731:18;718:11;;;711:39;683:2;676:10;647:113;;;778:6;775:1;772:13;769:48;;;-1:-1:-1;;813:1:1;795:16;;788:27;565:258::o;828:383::-;977:2;966:9;959:21;940:4;1009:6;1003:13;1052:6;1047:2;1036:9;1032:18;1025:34;1068:66;1127:6;1122:2;1111:9;1107:18;1102:2;1094:6;1090:15;1068:66;:::i;:::-;1195:2;1174:15;-1:-1:-1;;1170:29:1;1155:45;;;;1202:2;1151:54;;828:383;-1:-1:-1;;828:383:1:o;1469:180::-;1528:6;1581:2;1569:9;1560:7;1556:23;1552:32;1549:52;;;1597:1;1594;1587:12;1549:52;-1:-1:-1;1620:23:1;;1469:180;-1:-1:-1;1469:180:1:o;1846:254::-;1914:6;1922;1975:2;1963:9;1954:7;1950:23;1946:32;1943:52;;;1991:1;1988;1981:12;1943:52;2014:29;2033:9;2014:29;:::i;:::-;2004:39;2090:2;2075:18;;;;2062:32;;-1:-1:-1;;;1846:254:1:o;2105:367::-;2168:8;2178:6;2232:3;2225:4;2217:6;2213:17;2209:27;2199:55;;2250:1;2247;2240:12;2199:55;-1:-1:-1;2273:20:1;;2316:18;2305:30;;2302:50;;;2348:1;2345;2338:12;2302:50;2385:4;2377:6;2373:17;2361:29;;2445:3;2438:4;2428:6;2425:1;2421:14;2413:6;2409:27;2405:38;2402:47;2399:67;;;2462:1;2459;2452:12;2399:67;2105:367;;;;;:::o;2477:505::-;2572:6;2580;2588;2641:2;2629:9;2620:7;2616:23;2612:32;2609:52;;;2657:1;2654;2647:12;2609:52;2693:9;2680:23;2670:33;;2754:2;2743:9;2739:18;2726:32;2781:18;2773:6;2770:30;2767:50;;;2813:1;2810;2803:12;2767:50;2852:70;2914:7;2905:6;2894:9;2890:22;2852:70;:::i;:::-;2477:505;;2941:8;;-1:-1:-1;2826:96:1;;-1:-1:-1;;;;2477:505:1:o;3208:573::-;3312:6;3320;3328;3336;3389:2;3377:9;3368:7;3364:23;3360:32;3357:52;;;3405:1;3402;3395:12;3357:52;3441:9;3428:23;3418:33;;3498:2;3487:9;3483:18;3470:32;3460:42;;3553:2;3542:9;3538:18;3525:32;3580:18;3572:6;3569:30;3566:50;;;3612:1;3609;3602:12;3566:50;3651:70;3713:7;3704:6;3693:9;3689:22;3651:70;:::i;:::-;3208:573;;;;-1:-1:-1;3740:8:1;-1:-1:-1;;;;3208:573:1:o;3994:260::-;4062:6;4070;4123:2;4111:9;4102:7;4098:23;4094:32;4091:52;;;4139:1;4136;4129:12;4091:52;4162:29;4181:9;4162:29;:::i;:::-;4152:39;;4210:38;4244:2;4233:9;4229:18;4210:38;:::i;:::-;4200:48;;3994:260;;;;;:::o;4259:118::-;4345:5;4338:13;4331:21;4324:5;4321:32;4311:60;;4367:1;4364;4357:12;4382:315;4447:6;4455;4508:2;4496:9;4487:7;4483:23;4479:32;4476:52;;;4524:1;4521;4514:12;4476:52;4547:29;4566:9;4547:29;:::i;:::-;4537:39;;4626:2;4615:9;4611:18;4598:32;4639:28;4661:5;4639:28;:::i;:::-;4686:5;4676:15;;;4382:315;;;;;:::o;4702:322::-;4779:6;4787;4795;4848:2;4836:9;4827:7;4823:23;4819:32;4816:52;;;4864:1;4861;4854:12;4816:52;4887:29;4906:9;4887:29;:::i;:::-;4877:39;4963:2;4948:18;;4935:32;;-1:-1:-1;5014:2:1;4999:18;;;4986:32;;4702:322;-1:-1:-1;;;4702:322:1:o;5029:380::-;5108:1;5104:12;;;;5151;;;5172:61;;5226:4;5218:6;5214:17;5204:27;;5172:61;5279:2;5271:6;5268:14;5248:18;5245:38;5242:161;;;5325:10;5320:3;5316:20;5313:1;5306:31;5360:4;5357:1;5350:15;5388:4;5385:1;5378:15;5414:470;5616:2;5598:21;;;5655:2;5635:18;;;5628:30;5694:34;5689:2;5674:18;;5667:62;5765:34;5760:2;5745:18;;5738:62;-1:-1:-1;;;5831:3:1;5816:19;;5809:33;5874:3;5859:19;;5414:470::o;5889:356::-;6091:2;6073:21;;;6110:18;;;6103:30;6169:34;6164:2;6149:18;;6142:62;6236:2;6221:18;;5889:356::o;7097:127::-;7158:10;7153:3;7149:20;7146:1;7139:31;7189:4;7186:1;7179:15;7213:4;7210:1;7203:15;7229:127;7290:10;7285:3;7281:20;7278:1;7271:31;7321:4;7318:1;7311:15;7345:4;7342:1;7335:15;7361:135;7400:3;-1:-1:-1;;7421:17:1;;7418:43;;;7441:18;;:::i;:::-;-1:-1:-1;7488:1:1;7477:13;;7361:135::o;8730:184::-;8800:6;8853:2;8841:9;8832:7;8828:23;8824:32;8821:52;;;8869:1;8866;8859:12;8821:52;-1:-1:-1;8892:16:1;;8730:184;-1:-1:-1;8730:184:1:o;9275:410::-;9477:2;9459:21;;;9516:2;9496:18;;;9489:30;9555:34;9550:2;9535:18;;9528:62;-1:-1:-1;;;9621:2:1;9606:18;;9599:44;9675:3;9660:19;;9275:410::o;10104:128::-;10144:3;10175:1;10171:6;10168:1;10165:13;10162:39;;;10181:18;;:::i;:::-;-1:-1:-1;10217:9:1;;10104:128::o;10237:125::-;10277:4;10305:1;10302;10299:8;10296:34;;;10310:18;;:::i;:::-;-1:-1:-1;10347:9:1;;10237:125::o;10367:168::-;10407:7;10473:1;10469;10465:6;10461:14;10458:1;10455:21;10450:1;10443:9;10436:17;10432:45;10429:71;;;10480:18;;:::i;:::-;-1:-1:-1;10520:9:1;;10367:168::o;10540:127::-;10601:10;10596:3;10592:20;10589:1;10582:31;10632:4;10629:1;10622:15;10656:4;10653:1;10646:15;10672:120;10712:1;10738;10728:35;;10743:18;;:::i;:::-;-1:-1:-1;10777:9:1;;10672:120::o;11220:127::-;11281:10;11276:3;11272:20;11269:1;11262:31;11312:4;11309:1;11302:15;11336:4;11333:1;11326:15;12451:245;12518:6;12571:2;12559:9;12550:7;12546:23;12542:32;12539:52;;;12587:1;12584;12577:12;12539:52;12619:9;12613:16;12638:28;12660:5;12638:28;:::i;16811:798::-;17006:4;17054:2;17043:9;17039:18;17084:6;17073:9;17066:25;17110:2;17148:6;17143:2;17132:9;17128:18;17121:34;17191:2;17186;17175:9;17171:18;17164:30;17214:6;17249;17243:13;17280:6;17272;17265:22;17318:3;17307:9;17303:19;17296:26;;17341:6;17338:1;17331:17;17384:2;17381:1;17371:16;17357:30;;17405:1;17415:168;17429:6;17426:1;17423:13;17415:168;;;17490:13;;17478:26;;17571:1;17559:14;;;;17524:12;;;;17444:9;17415:168;;;-1:-1:-1;17600:3:1;;16811:798;-1:-1:-1;;;;;;;;16811:798:1:o;17614:775::-;17812:4;17860:2;17849:9;17845:18;17890:6;17879:9;17872:25;17916:2;17954:6;17949:2;17938:9;17934:18;17927:34;17997:2;17992;17981:9;17977:18;17970:30;18020:6;18055;18049:13;18086:6;18078;18071:22;18124:3;18113:9;18109:19;18102:26;;18163:2;18155:6;18151:15;18137:29;;18184:1;18194:169;18208:6;18205:1;18202:13;18194:169;;;18269:13;;18257:26;;18338:15;;;;18303:12;;;;18230:1;18223:9;18194:169;;20230:112;20262:1;20288;20278:35;;20293:18;;:::i;:::-;-1:-1:-1;20327:9:1;;20230:112::o;21112:274::-;21241:3;21279:6;21273:13;21295:53;21341:6;21336:3;21329:4;21321:6;21317:17;21295:53;:::i;:::-;21364:16;;;;;21112:274;-1:-1:-1;;21112:274:1:o

Swarm Source

ipfs://7d784b3f6b055f07674adbfd25309dc364490bca96fee7dbd150f72e563448e8

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
[ Download: CSV Export  ]

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