Address Details
contract

0x7C5d7986259354a80bB83c101754587Bfc3bBCAc

Contract Name
FactorySCBCrowdsale
Creator
0x067b6e–041cd7 at 0xf282ec–34c776
Balance
0.900000000000000004 CELO ( )
Locked CELO Balance
0.00 CELO
Voting CELO Balance
0.00 CELO
Pending Unlocked Gold
0.00 CELO
Tokens
Fetching tokens...
Transactions
11 Transactions
Transfers
7 Transfers
Gas Used
17,535,595
Last Balance Update
11103501
This contract has been verified via Sourcify. View contract in Sourcify repository
Contract name:
FactorySCBCrowdsale




Optimization enabled
true
Compiler version
v0.8.10+commit.fc410830




Optimization runs
25000
EVM Version
london




Verified at
2022-05-30T08:02:51.059031Z

project:/contracts/crowdsale/FactorySCBCrowdsale.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

import "./SCCrowdsale/SCBonusableCrowdsale.sol";
import "./SCCrowdsale/SCBonusableDatesChangeableCrowdsale.sol";

contract FactorySCBCrowdsale is Ownable, ReentrancyGuard {
    using SafeERC20 for IERC20;

    mapping (address => uint256[2]) public price;

    event NewContract(address contractAddress, uint8 contractType);

    function setPrice(address _token, uint256[2] calldata _price) external onlyOwner {
        price[_token] = _price;
    }

    function deploySoftCappableBonusableCrowdsale(
        address[2] calldata tokenToPayAndOwner,
        address _token, uint256 _tokenDecimals,
        uint256 _duration,
        uint256 _soft_cap,
        address[] calldata _tokens, uint256[] calldata _rates,
        uint256[2] calldata _limits,
        uint256[2] calldata _bonus
    ) external nonReentrant {
        uint256 _price = price[tokenToPayAndOwner[0]][0];
        require(_price > 0, "Wrong payment method");
        IERC20(tokenToPayAndOwner[0]).safeTransferFrom(_msgSender(), address(this), _price);
        require(_tokens.length == _rates.length, "Invalid parameters");
        SoftCappableBonusableCrowdsale crowdsale = new SoftCappableBonusableCrowdsale(_token, _tokenDecimals, _duration, _soft_cap);
        crowdsale.setLimits(_limits[0], _limits[1]);
        crowdsale.setBonus(_bonus[0], _bonus[1]);
        for (uint256 i; i < _tokens.length; i++) {
            crowdsale.addPaymentMethod(_tokens[i], _rates[i]);
        }
        crowdsale.transferOwnership(tokenToPayAndOwner[1]);
        emit NewContract(address(crowdsale), 0);
    }

    function deploySoftCappableBonusableDatesChangeableCrowdsale(
        address[2] calldata tokenToPayAndOwner,
        address _token, uint256 _tokenDecimals,
        uint256 _duration,
        uint256 _soft_cap,
        address[] calldata _tokens, uint256[] calldata _rates,
        uint256[2] calldata _limits,
        uint256[2] calldata _bonus
    ) external nonReentrant {
        uint256 _price = price[tokenToPayAndOwner[0]][1];
        require(_price > 0, "Wrong payment method");
        IERC20(tokenToPayAndOwner[0]).safeTransferFrom(_msgSender(), address(this), _price);
        require(_tokens.length == _rates.length, "Invalid parameters");
        SoftCappableBonusableDatesChangeableCrowdsale crowdsale = new SoftCappableBonusableDatesChangeableCrowdsale(_token, _tokenDecimals, _duration, _soft_cap);
        crowdsale.setLimits(_limits[0], _limits[1]);
        crowdsale.setBonus(_bonus[0], _bonus[1]);
        for (uint256 i; i < _tokens.length; i++) {
            crowdsale.addPaymentMethod(_tokens[i], _rates[i]);
        }
        crowdsale.transferOwnership(tokenToPayAndOwner[1]);
        emit NewContract(address(crowdsale), 1);
    }

    function getToken(address _token) external onlyOwner {
        IERC20 token = IERC20(_token);
        token.safeTransfer(_msgSender(), token.balanceOf(address(this)));
    }
}
        

/_openzeppelin/contracts/access/Ownable.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @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() {
        _setOwner(_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 {
        _setOwner(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");
        _setOwner(newOwner);
    }

    function _setOwner(address newOwner) private {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}
          

/_openzeppelin/contracts/security/ReentrancyGuard.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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

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

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and make it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

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

        _;

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

/_openzeppelin/contracts/token/ERC20/IERC20.sol

// SPDX-License-Identifier: MIT

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

/_openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../../../utils/Address.sol";

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

/_openzeppelin/contracts/utils/Address.sol

// SPDX-License-Identifier: MIT

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

/_openzeppelin/contracts/utils/Context.sol

// SPDX-License-Identifier: MIT

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

/project_/contracts/crowdsale/Bonusable.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

import "./CrowdsaleBase.sol";

abstract contract BonusableCrowdsale is CrowdsaleBase {
    uint256 public bonusBreakpoint;
    uint256 public bonusPercentage;

    function setBonus(uint256 _bonusBreakpoint, uint256 _bonusPercentage) external onlyOwner {
        bonusBreakpoint = _bonusBreakpoint;
        bonusPercentage = _bonusPercentage;
    }

    function _calculate(uint256 amountToPay, uint256 _rate) internal virtual override returns(uint256) {
        uint256 initAmount = super._calculate(amountToPay, _rate);
        if (initAmount >= bonusBreakpoint) {
            uint256 finalAmount = initAmount + ((initAmount * bonusPercentage) / 1000);
            if (finalAmount <= tokenToSell.balanceOf(address(this))) {
                return finalAmount;
            }
        }
        return initAmount;
    }
}
          

/project_/contracts/crowdsale/CrowdsaleBase.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

abstract contract CrowdsaleBase is Ownable, ReentrancyGuard {

    IERC20 public tokenToSell;
    uint256 public tokenDecimals;
    uint256 public DURATION;

    uint256 public totalSold;
    uint256 public endTime;

    uint256 public lowerLimit;
    uint256 public upperLimit;

    mapping(address => uint256) public bought;

    modifier afterStartAndBeforeEnd() {
        require(endTime > block.timestamp, "Already ended or not started");
        _;
    }

    constructor(address _token, uint256 _tokenDecimals, uint256 _duration) {
        tokenToSell = IERC20(_token);
        tokenDecimals = _tokenDecimals;
        DURATION = _duration;
    }

    function setLimits(uint256 _lowerLimit, uint256 _upperLimit) external onlyOwner {
        lowerLimit = _lowerLimit;
        upperLimit = _upperLimit;
    }

    function _calculate(uint256 amountToPay, uint256 _rate) internal virtual returns(uint256) {
        return ((amountToPay * (10 ** tokenDecimals)) / _rate);
    }

    function _beforeSending(uint256 _toGet) internal virtual {
        require(_toGet >= lowerLimit, "Cannot receive less than lower limit");
        bought[_msgSender()] += _toGet;
        require(upperLimit == 0 || bought[_msgSender()] <= upperLimit, "Cannot receive more than upper limit");
    }
}
          

/project_/contracts/crowdsale/DatesChangeable.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

import "./CrowdsaleBase.sol";

abstract contract DatesChangeableCrowdsale is CrowdsaleBase {

    function endCrowdsale() external onlyOwner afterStartAndBeforeEnd {
        endTime = block.timestamp;
    }
}
          

/project_/contracts/crowdsale/SCCrowdsale/SCBonusableCrowdsale.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.10;

import "../Bonusable.sol";

contract SoftCappableBonusableCrowdsale is BonusableCrowdsale {
    using SafeERC20 for IERC20;

    uint256 public SOFT_CAP;

    address[] public paymentMethods;
    uint256[] public ratePerFullToken;
    mapping (address => uint256[]) public amounts;
    uint256[] private refundable;
    mapping (address => uint256) private _paymentMethodExists;

    constructor(address _token, uint256 _tokenDecimals, uint256 _duration, uint256 _soft_cap) CrowdsaleBase(_token, _tokenDecimals, _duration) {
        SOFT_CAP = _soft_cap;
    }

    function start() external onlyOwner {
        require(endTime == 0, "Already started");
        endTime = block.timestamp + DURATION;
        refundable.push(0);
    }

    function addPaymentMethod(address token, uint256 rate) external onlyOwner {
        require(token != address(tokenToSell), "Cannot add sellable token as payment method");
        uint256 ID = _paymentMethodExists[token];
        if (ID == 0) {
            require(paymentMethods.length < 3, "Cannot add more than three payment methods");
            paymentMethods.push(token);
            ratePerFullToken.push(rate);
            _paymentMethodExists[token] = paymentMethods.length;
            refundable.push(0);
        }
        else {
            ratePerFullToken[ID - 1] = rate;
        }
    }

    function buy(address tokenToPay, uint256 amountToPay) external afterStartAndBeforeEnd nonReentrant {
        uint256 ID = _paymentMethodExists[tokenToPay];
        require(ID != 0, "Invalid payment method");
        uint256 _rate = ratePerFullToken[ID - 1];
        require(_rate > 0, "Invalid payment method");

        IERC20(tokenToPay).safeTransferFrom(_msgSender(), address(this), amountToPay);
        uint256 toGet = _calculate(amountToPay, _rate);

        _beforeSending(toGet);
        require(toGet <= (tokenToSell.balanceOf(address(this)) - refundable[0]), "Cannot buy this much");
        totalSold += toGet;

        if (totalSold < SOFT_CAP) {
            while (amounts[_msgSender()].length <= ID) {
                amounts[_msgSender()].push(0);
            }
            amounts[_msgSender()][0] += toGet;
            refundable[0] += toGet;
            amounts[_msgSender()][ID] += amountToPay;
            refundable[ID] += amountToPay;
        }
        else {
            if (amounts[_msgSender()].length > 0) {
                toGet += amounts[_msgSender()][0];
                for (uint256 i; i < amounts[_msgSender()].length; i++) {
                    refundable[i] -= amounts[_msgSender()][i];
                }
                delete amounts[_msgSender()];
            }
            tokenToSell.safeTransfer(_msgSender(), toGet);
        }
    }

    function redeem() external nonReentrant {
        tokenToSell.safeTransfer(_msgSender(), amounts[_msgSender()][0]);
        for (uint256 i; i < amounts[_msgSender()].length; i++) {
            refundable[i] -= amounts[_msgSender()][i];
        }
        delete amounts[_msgSender()];
    }

    function refund() external nonReentrant {
        require(block.timestamp > endTime, "Not ended yet");
        require(totalSold < SOFT_CAP, "Soft cap is reached");
        for (uint256 i; i < amounts[_msgSender()].length; i++) {
            uint256 toRefund = amounts[_msgSender()][i];
            if (toRefund > 0) {
                if (i != 0) {
                    address token = paymentMethods[i - 1];
                    IERC20(token).safeTransfer(_msgSender(), toRefund);
                }
                else {
                    totalSold -= toRefund;
                    bought[_msgSender()] -= toRefund;
                }
                refundable[i] -= toRefund;
            }
        }
        delete amounts[_msgSender()];
    }

    function getToken(address token) external onlyOwner nonReentrant {
        if (token == address(tokenToSell)) {
            require(block.timestamp > endTime, "Not ended yet");
            tokenToSell.safeTransfer(_msgSender(), tokenToSell.balanceOf(address(this)) - refundable[0]);
        }
        else {
            uint256 toGet = IERC20(token).balanceOf(address(this));
            uint256 ID = _paymentMethodExists[token];
            if (ID != 0 && totalSold < SOFT_CAP) {
                toGet -= refundable[ID];
            }
            if (toGet > 0) {
                IERC20(token).safeTransfer(_msgSender(), toGet);
            }
        }
    }
}
          

/project_/contracts/crowdsale/SCCrowdsale/SCBonusableDatesChangeableCrowdsale.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.10;

import "../Bonusable.sol";
import "../DatesChangeable.sol";

contract SoftCappableBonusableDatesChangeableCrowdsale is BonusableCrowdsale, DatesChangeableCrowdsale {
    using SafeERC20 for IERC20;

    uint256 public SOFT_CAP;

    address[] public paymentMethods;
    uint256[] public ratePerFullToken;
    mapping (address => uint256[]) public amounts;
    uint256[] private refundable;
    mapping (address => uint256) private _paymentMethodExists;

    constructor(address _token, uint256 _tokenDecimals, uint256 _duration, uint256 _soft_cap) CrowdsaleBase(_token, _tokenDecimals, _duration) {
        SOFT_CAP = _soft_cap;
    }

    function start() external onlyOwner {
        require(endTime == 0, "Already started");
        endTime = block.timestamp + DURATION;
        refundable.push(0);
    }

    function addPaymentMethod(address token, uint256 rate) external onlyOwner {
        require(token != address(tokenToSell), "Cannot add sellable token as payment method");
        uint256 ID = _paymentMethodExists[token];
        if (ID == 0) {
            require(paymentMethods.length < 3, "Cannot add more than three payment methods");
            paymentMethods.push(token);
            ratePerFullToken.push(rate);
            _paymentMethodExists[token] = paymentMethods.length;
            refundable.push(0);
        }
        else {
            ratePerFullToken[ID - 1] = rate;
        }
    }

    function buy(address tokenToPay, uint256 amountToPay) external afterStartAndBeforeEnd nonReentrant {
        uint256 ID = _paymentMethodExists[tokenToPay];
        require(ID != 0, "Invalid payment method");
        uint256 _rate = ratePerFullToken[ID - 1];
        require(_rate > 0, "Invalid payment method");

        IERC20(tokenToPay).safeTransferFrom(_msgSender(), address(this), amountToPay);
        uint256 toGet = _calculate(amountToPay, _rate);

        _beforeSending(toGet);
        require(toGet <= (tokenToSell.balanceOf(address(this)) - refundable[0]), "Cannot buy this much");
        totalSold += toGet;

        if (totalSold < SOFT_CAP) {
            while (amounts[_msgSender()].length <= ID) {
                amounts[_msgSender()].push(0);
            }
            amounts[_msgSender()][0] += toGet;
            refundable[0] += toGet;
            amounts[_msgSender()][ID] += amountToPay;
            refundable[ID] += amountToPay;
        }
        else {
            if (amounts[_msgSender()].length > 0) {
                toGet += amounts[_msgSender()][0];
                for (uint256 i; i < amounts[_msgSender()].length; i++) {
                    refundable[i] -= amounts[_msgSender()][i];
                }
                delete amounts[_msgSender()];
            }
            tokenToSell.safeTransfer(_msgSender(), toGet);
        }
    }

    function redeem() external nonReentrant {
        tokenToSell.safeTransfer(_msgSender(), amounts[_msgSender()][0]);
        for (uint256 i; i < amounts[_msgSender()].length; i++) {
            refundable[i] -= amounts[_msgSender()][i];
        }
        delete amounts[_msgSender()];
    }

    function refund() external nonReentrant {
        require(block.timestamp > endTime, "Not ended yet");
        require(totalSold < SOFT_CAP, "Soft cap is reached");
        for (uint256 i; i < amounts[_msgSender()].length; i++) {
            uint256 toRefund = amounts[_msgSender()][i];
            if (toRefund > 0) {
                if (i != 0) {
                    address token = paymentMethods[i - 1];
                    IERC20(token).safeTransfer(_msgSender(), toRefund);
                }
                else {
                    totalSold -= toRefund;
                    bought[_msgSender()] -= toRefund;
                }
                refundable[i] -= toRefund;
            }
        }
        delete amounts[_msgSender()];
    }

    function getToken(address token) external onlyOwner nonReentrant {
        if (token == address(tokenToSell)) {
            require(block.timestamp > endTime, "Not ended yet");
            tokenToSell.safeTransfer(_msgSender(), tokenToSell.balanceOf(address(this)) - refundable[0]);
        }
        else {
            uint256 toGet = IERC20(token).balanceOf(address(this));
            uint256 ID = _paymentMethodExists[token];
            if (ID != 0 && totalSold < SOFT_CAP) {
                toGet -= refundable[ID];
            }
            if (toGet > 0) {
                IERC20(token).safeTransfer(_msgSender(), toGet);
            }
        }
    }

    function _calculate(uint256 amountToPay, uint256 _rate) internal virtual override(CrowdsaleBase, BonusableCrowdsale) returns(uint256) {
        return BonusableCrowdsale._calculate(amountToPay, _rate);
    }
}
          

Contract ABI

[{"type":"event","name":"NewContract","inputs":[{"type":"address","name":"contractAddress","internalType":"address","indexed":false},{"type":"uint8","name":"contractType","internalType":"uint8","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"deploySoftCappableBonusableCrowdsale","inputs":[{"type":"address[2]","name":"tokenToPayAndOwner","internalType":"address[2]"},{"type":"address","name":"_token","internalType":"address"},{"type":"uint256","name":"_tokenDecimals","internalType":"uint256"},{"type":"uint256","name":"_duration","internalType":"uint256"},{"type":"uint256","name":"_soft_cap","internalType":"uint256"},{"type":"address[]","name":"_tokens","internalType":"address[]"},{"type":"uint256[]","name":"_rates","internalType":"uint256[]"},{"type":"uint256[2]","name":"_limits","internalType":"uint256[2]"},{"type":"uint256[2]","name":"_bonus","internalType":"uint256[2]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"deploySoftCappableBonusableDatesChangeableCrowdsale","inputs":[{"type":"address[2]","name":"tokenToPayAndOwner","internalType":"address[2]"},{"type":"address","name":"_token","internalType":"address"},{"type":"uint256","name":"_tokenDecimals","internalType":"uint256"},{"type":"uint256","name":"_duration","internalType":"uint256"},{"type":"uint256","name":"_soft_cap","internalType":"uint256"},{"type":"address[]","name":"_tokens","internalType":"address[]"},{"type":"uint256[]","name":"_rates","internalType":"uint256[]"},{"type":"uint256[2]","name":"_limits","internalType":"uint256[2]"},{"type":"uint256[2]","name":"_bonus","internalType":"uint256[2]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"getToken","inputs":[{"type":"address","name":"_token","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"price","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setPrice","inputs":[{"type":"address","name":"_token","internalType":"address"},{"type":"uint256[2]","name":"_price","internalType":"uint256[2]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]}]
              

Contract Creation Code

0x608060405234801561001057600080fd5b5061001a33610023565b60018055610073565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b615f5d806100826000396000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c80638da5cb5b1161005b5780638da5cb5b146100d0578063ad9b8024146100fd578063e101f7c01461011e578063f2fde38b1461013157600080fd5b806319cfe1e71461008d57806359770438146100a2578063715018a6146100b557806384fb1aae146100bd575b600080fd5b6100a061009b3660046114af565b610144565b005b6100a06100b03660046114e3565b610202565b6100a0610338565b6100a06100cb36600461154a565b6103c5565b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b61011061010b366004611621565b61090d565b6040519081526020016100f4565b6100a061012c36600461154a565b610932565b6100a061013f3660046114e3565b610e2b565b60005473ffffffffffffffffffffffffffffffffffffffff1633146101ca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff821660009081526002602081905260409091206101fd918390611400565b505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610283576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016101c1565b80610334336040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa1580156102f2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610316919061164b565b73ffffffffffffffffffffffffffffffffffffffff84169190610f5b565b5050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146103b9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016101c1565b6103c3600061102f565b565b60026001541415610432576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016101c1565b600260018190556000908161044a60208f018f6114e3565b73ffffffffffffffffffffffffffffffffffffffff1681526020810191909152604001600020600101549050600081116104e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f57726f6e67207061796d656e74206d6574686f6400000000000000000000000060448201526064016101c1565b61051b335b30838f60006020020160208101906104fd91906114e3565b73ffffffffffffffffffffffffffffffffffffffff169291906110a4565b858414610584576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f496e76616c696420706172616d6574657273000000000000000000000000000060448201526064016101c1565b60008b8b8b8b6040516105969061143e565b73ffffffffffffffffffffffffffffffffffffffff9094168452602084019290925260408301526060820152608001604051809103906000f0801580156105e1573d6000803e3d6000fd5b506040517fc4590d3f000000000000000000000000000000000000000000000000000000008152853560048201526020860135602482015290915073ffffffffffffffffffffffffffffffffffffffff82169063c4590d3f90604401600060405180830381600087803b15801561065757600080fd5b505af115801561066b573d6000803e3d6000fd5b50506040517f037c99b0000000000000000000000000000000000000000000000000000000008152853560048201526020860135602482015273ffffffffffffffffffffffffffffffffffffffff8416925063037c99b09150604401600060405180830381600087803b1580156106e157600080fd5b505af11580156106f5573d6000803e3d6000fd5b5050505060005b878110156107f8578173ffffffffffffffffffffffffffffffffffffffff1663539270bc8a8a8481811061073257610732611664565b905060200201602081019061074791906114e3565b89898581811061075957610759611664565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b16815273ffffffffffffffffffffffffffffffffffffffff90941660048501526020029190910135602483015250604401600060405180830381600087803b1580156107cd57600080fd5b505af11580156107e1573d6000803e3d6000fd5b5050505080806107f090611693565b9150506106fc565b5073ffffffffffffffffffffffffffffffffffffffff811663f2fde38b8e600160200201602081019061082b91906114e3565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401600060405180830381600087803b15801561089157600080fd5b505af11580156108a5573d6000803e3d6000fd5b50506040805173ffffffffffffffffffffffffffffffffffffffff85168152600160208201527f6a52a393150c061e1a1d151cdb19dda10b47bde43e6dca17727226d75861a2db93500190505b60405180910390a15050600180555050505050505050505050565b6002602052816000526040600020816002811061092957600080fd5b01549150829050565b6002600154141561099f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016101c1565b60026001819055600090816109b760208f018f6114e3565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002054905080610a47576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f57726f6e67207061796d656e74206d6574686f6400000000000000000000000060448201526064016101c1565b610a50336104e5565b858414610ab9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f496e76616c696420706172616d6574657273000000000000000000000000000060448201526064016101c1565b60008b8b8b8b604051610acb9061144c565b73ffffffffffffffffffffffffffffffffffffffff9094168452602084019290925260408301526060820152608001604051809103906000f080158015610b16573d6000803e3d6000fd5b506040517fc4590d3f000000000000000000000000000000000000000000000000000000008152853560048201526020860135602482015290915073ffffffffffffffffffffffffffffffffffffffff82169063c4590d3f90604401600060405180830381600087803b158015610b8c57600080fd5b505af1158015610ba0573d6000803e3d6000fd5b50506040517f037c99b0000000000000000000000000000000000000000000000000000000008152853560048201526020860135602482015273ffffffffffffffffffffffffffffffffffffffff8416925063037c99b09150604401600060405180830381600087803b158015610c1657600080fd5b505af1158015610c2a573d6000803e3d6000fd5b5050505060005b87811015610d2d578173ffffffffffffffffffffffffffffffffffffffff1663539270bc8a8a84818110610c6757610c67611664565b9050602002016020810190610c7c91906114e3565b898985818110610c8e57610c8e611664565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b16815273ffffffffffffffffffffffffffffffffffffffff90941660048501526020029190910135602483015250604401600060405180830381600087803b158015610d0257600080fd5b505af1158015610d16573d6000803e3d6000fd5b505050508080610d2590611693565b915050610c31565b5073ffffffffffffffffffffffffffffffffffffffff811663f2fde38b8e6001602002016020810190610d6091906114e3565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401600060405180830381600087803b158015610dc657600080fd5b505af1158015610dda573d6000803e3d6000fd5b50506040805173ffffffffffffffffffffffffffffffffffffffff85168152600060208201527f6a52a393150c061e1a1d151cdb19dda10b47bde43e6dca17727226d75861a2db93500190506108f2565b60005473ffffffffffffffffffffffffffffffffffffffff163314610eac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016101c1565b73ffffffffffffffffffffffffffffffffffffffff8116610f4f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016101c1565b610f588161102f565b50565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526101fd9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152611108565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526111029085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401610fad565b50505050565b600061116a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166112149092919063ffffffff16565b8051909150156101fd578080602001905181019061118891906116f3565b6101fd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016101c1565b6060611223848460008561122d565b90505b9392505050565b6060824710156112bf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016101c1565b843b611327576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016101c1565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516113509190611741565b60006040518083038185875af1925050503d806000811461138d576040519150601f19603f3d011682016040523d82523d6000602084013e611392565b606091505b50915091506113a28282866113ad565b979650505050505050565b606083156113bc575081611226565b8251156113cc5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101c1919061175d565b826002810192821561142e579160200282015b8281111561142e578235825591602001919060010190611413565b5061143a92915061145a565b5090565b6122c280620017af83390190565b6124b78062003a7183390190565b5b8082111561143a576000815560010161145b565b803573ffffffffffffffffffffffffffffffffffffffff8116811461149357600080fd5b919050565b80604081018310156114a957600080fd5b92915050565b600080606083850312156114c257600080fd5b6114cb8361146f565b91506114da8460208501611498565b90509250929050565b6000602082840312156114f557600080fd5b6112268261146f565b60008083601f84011261151057600080fd5b50813567ffffffffffffffff81111561152857600080fd5b6020830191508360208260051b850101111561154357600080fd5b9250929050565b60008060008060008060008060008060006101808c8e03121561156c57600080fd5b6115768d8d611498565b9a5061158460408d0161146f565b995060608c0135985060808c0135975060a08c0135965067ffffffffffffffff8060c08e013511156115b557600080fd5b6115c58e60c08f01358f016114fe565b909750955060e08d01358110156115db57600080fd5b506115ec8d60e08e01358e016114fe565b90945092506115ff8d6101008e01611498565b915061160f8d6101408e01611498565b90509295989b509295989b9093969950565b6000806040838503121561163457600080fd5b61163d8361146f565b946020939093013593505050565b60006020828403121561165d57600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156116ec577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b60006020828403121561170557600080fd5b8151801515811461122657600080fd5b60005b83811015611730578181015183820152602001611718565b838111156111025750506000910152565b60008251611753818460208701611715565b9190910192915050565b602081526000825180602084015261177c816040850160208701611715565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fe60806040523480156200001157600080fd5b50604051620022c2380380620022c28339810160408190526200003491620000ca565b83838362000042336200007a565b60018055600280546001600160a01b0319166001600160a01b039490941693909317909255600355600455600c555062000117915050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60008060008060808587031215620000e157600080fd5b84516001600160a01b0381168114620000f957600080fd5b60208601516040870151606090970151919890975090945092505050565b61219b80620001276000396000f3fe608060405234801561001057600080fd5b50600436106101ae5760003560e01c80638b90cdc9116100ee578063b652dc2f11610097578063c4590d3f11610071578063c4590d3f14610323578063cce7ec1314610336578063dfbf8b1614610349578063f2fde38b1461035c57600080fd5b8063b652dc2f1461030a578063be040fb014610313578063be9a65551461031b57600080fd5b80639731d9f6116100c85780639731d9f6146102e5578063a05d479d146102ee578063af0f325c1461030157600080fd5b80638b90cdc9146102ab5780638da5cb5b146102be5780639106d7ba146102dc57600080fd5b8063539270bc1161015b578063667022fd11610135578063667022fd146102355780636cd0715414610255578063715018a61461029a578063813d6c9a146102a257600080fd5b8063539270bc14610207578063590e1ae31461021a578063597704381461022257600080fd5b80633197cbb61161018c5780633197cbb6146101ec57806338392c40146101f55780633b97e856146101fe57600080fd5b8063037c99b0146101b35780631be05289146101c85780632095f2d4146101e4575b600080fd5b6101c66101c1366004611d7e565b61036f565b005b6101d160045481565b6040519081526020015b60405180910390f35b6101c66103e6565b6101d160065481565b6101d160085481565b6101d160035481565b6101c6610215366004611dc9565b6104a4565b6101c6610751565b6101c6610230366004611df3565b610999565b6101d1610243366004611df3565b60096020526000908152604090205481565b6002546102759073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101db565b6101c6610cdf565b6101d1600b5481565b6102756102b9366004611e0e565b610d52565b60005473ffffffffffffffffffffffffffffffffffffffff16610275565b6101d160055481565b6101d160075481565b6101d16102fc366004611e0e565b610d89565b6101d1600a5481565b6101d1600c5481565b6101c6610daa565b6101c6610edb565b6101c6610331366004611d7e565b610fd6565b6101c6610344366004611dc9565b611048565b6101d1610357366004611dc9565b611592565b6101c661036a366004611df3565b6115c3565b60005473ffffffffffffffffffffffffffffffffffffffff1633146103db5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b600a91909155600b55565b60005473ffffffffffffffffffffffffffffffffffffffff16331461044d5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103d2565b426006541161049e5760405162461bcd60e51b815260206004820152601c60248201527f416c726561647920656e646564206f72206e6f7420737461727465640000000060448201526064016103d2565b42600655565b60005473ffffffffffffffffffffffffffffffffffffffff16331461050b5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103d2565b60025473ffffffffffffffffffffffffffffffffffffffff8381169116141561059c5760405162461bcd60e51b815260206004820152602b60248201527f43616e6e6f74206164642073656c6c61626c6520746f6b656e2061732070617960448201527f6d656e74206d6574686f6400000000000000000000000000000000000000000060648201526084016103d2565b73ffffffffffffffffffffffffffffffffffffffff82166000908152601160205260409020548061072157600d5460031161063f5760405162461bcd60e51b815260206004820152602a60248201527f43616e6e6f7420616464206d6f7265207468616e207468726565207061796d6560448201527f6e74206d6574686f64730000000000000000000000000000000000000000000060648201526084016103d2565b50600d8054600180820183557fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb590910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff959095169485179055600e80548083019091557fbb7b4a454dc3493923482f07822329ed19e8244eff582cc204f8554c3620c3fd01929092555460009283526011602052604083205560108054918201815582527f1b6847dc741a1b0cd08d278845f9d819d87b734759afb55fe2de5cb82a9ae6720155565b81600e61072f600184611e56565b8154811061073f5761073f611e6d565b6000918252602090912001555b505050565b600260015414156107a45760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016103d2565b600260015560065442116107fa5760405162461bcd60e51b815260206004820152600d60248201527f4e6f7420656e646564207965740000000000000000000000000000000000000060448201526064016103d2565b600c546005541061084d5760405162461bcd60e51b815260206004820152601360248201527f536f66742063617020697320726561636865640000000000000000000000000060448201526064016103d2565b60005b336000908152600f602052604090205481101561097a57336000908152600f6020526040812080548390811061088857610888611e6d565b9060005260206000200154905060008111156109675781156108f8576000600d6108b3600185611e56565b815481106108c3576108c3611e6d565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1690506108f28133846116bf565b50610934565b806005600082825461090a9190611e56565b9091555050336000908152600960205260408120805483929061092e908490611e56565b90915550505b806010838154811061094857610948611e6d565b9060005260206000200160008282546109619190611e56565b90915550505b508061097281611e9c565b915050610850565b50336000908152600f6020526040812061099391611d4c565b60018055565b60005473ffffffffffffffffffffffffffffffffffffffff163314610a005760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103d2565b60026001541415610a535760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016103d2565b600260018190555473ffffffffffffffffffffffffffffffffffffffff82811691161415610bb1576006544211610acc5760405162461bcd60e51b815260206004820152600d60248201527f4e6f7420656e646564207965740000000000000000000000000000000000000060448201526064016103d2565b610bac336010600081548110610ae457610ae4611e6d565b6000918252602090912001546002546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff909116906370a0823190602401602060405180830381865afa158015610b5e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b829190611ed5565b610b8c9190611e56565b60025473ffffffffffffffffffffffffffffffffffffffff1691906116bf565b610cd8565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009073ffffffffffffffffffffffffffffffffffffffff8316906370a0823190602401602060405180830381865afa158015610c1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c429190611ed5565b73ffffffffffffffffffffffffffffffffffffffff83166000908152601160205260409020549091508015801590610c7d5750600c54600554105b15610cae5760108181548110610c9557610c95611e6d565b906000526020600020015482610cab9190611e56565b91505b8115610cd557610cd573ffffffffffffffffffffffffffffffffffffffff841633846116bf565b50505b5060018055565b60005473ffffffffffffffffffffffffffffffffffffffff163314610d465760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103d2565b610d506000611793565b565b600d8181548110610d6257600080fd5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b600e8181548110610d9957600080fd5b600091825260209091200154905081565b60026001541415610dfd5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016103d2565b6002600155336000818152600f602052604081208054610e51939290610e2557610e25611e6d565b60009182526020909120015460025473ffffffffffffffffffffffffffffffffffffffff1691906116bf565b60005b336000908152600f602052604090205481101561097a57336000908152600f60205260409020805482908110610e8c57610e8c611e6d565b906000526020600020015460108281548110610eaa57610eaa611e6d565b906000526020600020016000828254610ec39190611e56565b90915550819050610ed381611e9c565b915050610e54565b60005473ffffffffffffffffffffffffffffffffffffffff163314610f425760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103d2565b60065415610f925760405162461bcd60e51b815260206004820152600f60248201527f416c72656164792073746172746564000000000000000000000000000000000060448201526064016103d2565b600454610f9f9042611eee565b6006556010805460018101825560009182527f1b6847dc741a1b0cd08d278845f9d819d87b734759afb55fe2de5cb82a9ae6720155565b60005473ffffffffffffffffffffffffffffffffffffffff16331461103d5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103d2565b600791909155600855565b42600654116110995760405162461bcd60e51b815260206004820152601c60248201527f416c726561647920656e646564206f72206e6f7420737461727465640000000060448201526064016103d2565b600260015414156110ec5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016103d2565b600260015573ffffffffffffffffffffffffffffffffffffffff8216600090815260116020526040902054806111645760405162461bcd60e51b815260206004820152601660248201527f496e76616c6964207061796d656e74206d6574686f640000000000000000000060448201526064016103d2565b6000600e611173600184611e56565b8154811061118357611183611e6d565b90600052602060002001549050600081116111e05760405162461bcd60e51b815260206004820152601660248201527f496e76616c6964207061796d656e74206d6574686f640000000000000000000060448201526064016103d2565b61120273ffffffffffffffffffffffffffffffffffffffff8516333086611808565b600061120e848361186c565b905061121981611881565b601060008154811061122d5761122d611e6d565b6000918252602090912001546002546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff909116906370a0823190602401602060405180830381865afa1580156112a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112cb9190611ed5565b6112d59190611e56565b8111156113245760405162461bcd60e51b815260206004820152601460248201527f43616e6e6f74206275792074686973206d75636800000000000000000000000060448201526064016103d2565b80600560008282546113369190611eee565b9091555050600c546005541015611473575b336000908152600f6020526040902054831061138457336000908152600f60209081526040822080546001810182559083529082200155611348565b336000908152600f6020526040812080548392906113a4576113a4611e6d565b9060005260206000200160008282546113bd9190611eee565b925050819055508060106000815481106113d9576113d9611e6d565b9060005260206000200160008282546113f29190611eee565b9091555050336000908152600f6020526040902080548591908590811061141b5761141b611e6d565b9060005260206000200160008282546114349190611eee565b92505081905550836010848154811061144f5761144f611e6d565b9060005260206000200160008282546114689190611eee565b909155506115879050565b336000908152600f60205260409020541561156357336000908152600f6020526040812080549091906114a8576114a8611e6d565b9060005260206000200154816114be9190611eee565b905060005b336000908152600f602052604090205481101561154a57336000908152600f602052604090208054829081106114fb576114fb611e6d565b90600052602060002001546010828154811061151957611519611e6d565b9060005260206000200160008282546115329190611e56565b9091555081905061154281611e9c565b9150506114c3565b50336000908152600f6020526040812061156391611d4c565b6115873360025473ffffffffffffffffffffffffffffffffffffffff1690836116bf565b505060018055505050565b600f60205281600052604060002081815481106115ae57600080fd5b90600052602060002001600091509150505481565b60005473ffffffffffffffffffffffffffffffffffffffff16331461162a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103d2565b73ffffffffffffffffffffffffffffffffffffffff81166116b35760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016103d2565b6116bc81611793565b50565b60405173ffffffffffffffffffffffffffffffffffffffff831660248201526044810182905261074c9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526119ad565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526118669085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401611711565b50505050565b60006118788383611a9f565b90505b92915050565b6007548110156118f85760405162461bcd60e51b8152602060048201526024808201527f43616e6e6f742072656365697665206c657373207468616e206c6f776572206c60448201527f696d69740000000000000000000000000000000000000000000000000000000060648201526084016103d2565b3360009081526009602052604081208054839290611917908490611eee565b9091555050600854158061193c57506008543360009081526009602052604090205411155b6116bc5760405162461bcd60e51b8152602060048201526024808201527f43616e6e6f742072656365697665206d6f7265207468616e207570706572206c60448201527f696d69740000000000000000000000000000000000000000000000000000000060648201526084016103d2565b6000611a0f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16611b889092919063ffffffff16565b80519091501561074c5780806020019051810190611a2d9190611f06565b61074c5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016103d2565b600080611aac8484611ba1565b9050600a5481106118785760006103e8600b5483611aca9190611f28565b611ad49190611f65565b611ade9083611eee565b6002546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015291925073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015611b4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b719190611ed5565b8111611b8057915061187b9050565b509392505050565b6060611b978484600085611bc7565b90505b9392505050565b600081600354600a611bb391906120c0565b611bbd9085611f28565b6118789190611f65565b606082471015611c3f5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016103d2565b843b611c8d5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016103d2565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051611cb691906120f8565b60006040518083038185875af1925050503d8060008114611cf3576040519150601f19603f3d011682016040523d82523d6000602084013e611cf8565b606091505b5091509150611d08828286611d13565b979650505050505050565b60608315611d22575081611b9a565b825115611d325782518084602001fd5b8160405162461bcd60e51b81526004016103d29190612114565b50805460008255906000526020600020908101906116bc91905b80821115611d7a5760008155600101611d66565b5090565b60008060408385031215611d9157600080fd5b50508035926020909101359150565b803573ffffffffffffffffffffffffffffffffffffffff81168114611dc457600080fd5b919050565b60008060408385031215611ddc57600080fd5b611de583611da0565b946020939093013593505050565b600060208284031215611e0557600080fd5b61187882611da0565b600060208284031215611e2057600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082821015611e6857611e68611e27565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415611ece57611ece611e27565b5060010190565b600060208284031215611ee757600080fd5b5051919050565b60008219821115611f0157611f01611e27565b500190565b600060208284031215611f1857600080fd5b8151801515811461187857600080fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615611f6057611f60611e27565b500290565b600082611f9b577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b600181815b80851115611ff957817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115611fdf57611fdf611e27565b80851615611fec57918102915b93841c9390800290611fa5565b509250929050565b6000826120105750600161187b565b8161201d5750600061187b565b8160018114612033576002811461203d57612059565b600191505061187b565b60ff84111561204e5761204e611e27565b50506001821b61187b565b5060208310610133831016604e8410600b841016171561207c575081810a61187b565b6120868383611fa0565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156120b8576120b8611e27565b029392505050565b60006118788383612001565b60005b838110156120e75781810151838201526020016120cf565b838111156118665750506000910152565b6000825161210a8184602087016120cc565b9190910192915050565b60208152600082518060208401526121338160408501602087016120cc565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea2646970667358221220ae435d09cf9141ab1963f66a4d4ccbc0568eda8efcad71b6a2682c22e5731a6364736f6c634300080a003360806040523480156200001157600080fd5b50604051620024b7380380620024b78339810160408190526200003491620000ca565b83838362000042336200007a565b60018055600280546001600160a01b0319166001600160a01b039490941693909317909255600355600455600c555062000117915050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60008060008060808587031215620000e157600080fd5b84516001600160a01b0381168114620000f957600080fd5b60208601516040870151606090970151919890975090945092505050565b61239080620001276000396000f3fe608060405234801561001057600080fd5b50600436106101a35760003560e01c80638b90cdc9116100ee578063b652dc2f11610097578063c4590d3f11610071578063c4590d3f14610310578063cce7ec1314610323578063dfbf8b1614610336578063f2fde38b1461034957600080fd5b8063b652dc2f146102f7578063be040fb014610300578063be9a65551461030857600080fd5b80639731d9f6116100c85780639731d9f6146102d2578063a05d479d146102db578063af0f325c146102ee57600080fd5b80638b90cdc9146102985780638da5cb5b146102ab5780639106d7ba146102c957600080fd5b8063590e1ae3116101505780636cd071541161012a5780636cd0715414610242578063715018a614610287578063813d6c9a1461028f57600080fd5b8063590e1ae314610207578063597704381461020f578063667022fd1461022257600080fd5b806338392c401161018157806338392c40146101e25780633b97e856146101eb578063539270bc146101f457600080fd5b8063037c99b0146101a85780631be05289146101bd5780633197cbb6146101d9575b600080fd5b6101bb6101b6366004611f73565b61035c565b005b6101c660045481565b6040519081526020015b60405180910390f35b6101c660065481565b6101c660085481565b6101c660035481565b6101bb610202366004611fbe565b6103ed565b6101bb6106e8565b6101bb61021d366004611fe8565b61097e565b6101c6610230366004611fe8565b60096020526000908152604090205481565b6002546102629073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101d0565b6101bb610d12565b6101c6600b5481565b6102626102a6366004612003565b610d9f565b60005473ffffffffffffffffffffffffffffffffffffffff16610262565b6101c660055481565b6101c660075481565b6101c66102e9366004612003565b610dd6565b6101c6600a5481565b6101c6600c5481565b6101bb610df7565b6101bb610f42565b6101bb61031e366004611f73565b611071565b6101bb610331366004611fbe565b6110fd565b6101c6610344366004611fbe565b6116c9565b6101bb610357366004611fe8565b6116fa565b60005473ffffffffffffffffffffffffffffffffffffffff1633146103e2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b600a91909155600b55565b60005473ffffffffffffffffffffffffffffffffffffffff16331461046e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103d9565b60025473ffffffffffffffffffffffffffffffffffffffff83811691161415610519576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f43616e6e6f74206164642073656c6c61626c6520746f6b656e2061732070617960448201527f6d656e74206d6574686f6400000000000000000000000000000000000000000060648201526084016103d9565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260116020526040902054806106b857600d546003116105d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f43616e6e6f7420616464206d6f7265207468616e207468726565207061796d6560448201527f6e74206d6574686f64730000000000000000000000000000000000000000000060648201526084016103d9565b50600d8054600180820183557fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb590910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff959095169485179055600e80548083019091557fbb7b4a454dc3493923482f07822329ed19e8244eff582cc204f8554c3620c3fd01929092555460009283526011602052604083205560108054918201815582527f1b6847dc741a1b0cd08d278845f9d819d87b734759afb55fe2de5cb82a9ae6720155565b81600e6106c660018461204b565b815481106106d6576106d6612062565b6000918252602090912001555b505050565b60026001541415610755576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016103d9565b600260015560065442116107c5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f4e6f7420656e646564207965740000000000000000000000000000000000000060448201526064016103d9565b600c5460055410610832576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f536f66742063617020697320726561636865640000000000000000000000000060448201526064016103d9565b60005b336000908152600f602052604090205481101561095f57336000908152600f6020526040812080548390811061086d5761086d612062565b90600052602060002001549050600081111561094c5781156108dd576000600d61089860018561204b565b815481106108a8576108a8612062565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1690506108d781338461182a565b50610919565b80600560008282546108ef919061204b565b9091555050336000908152600960205260408120805483929061091390849061204b565b90915550505b806010838154811061092d5761092d612062565b906000526020600020016000828254610946919061204b565b90915550505b508061095781612091565b915050610835565b50336000908152600f6020526040812061097891611f41565b60018055565b60005473ffffffffffffffffffffffffffffffffffffffff1633146109ff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103d9565b60026001541415610a6c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016103d9565b600260018190555473ffffffffffffffffffffffffffffffffffffffff82811691161415610be4576006544211610aff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f4e6f7420656e646564207965740000000000000000000000000000000000000060448201526064016103d9565b610bdf336010600081548110610b1757610b17612062565b6000918252602090912001546002546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff909116906370a0823190602401602060405180830381865afa158015610b91573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bb591906120ca565b610bbf919061204b565b60025473ffffffffffffffffffffffffffffffffffffffff16919061182a565b610d0b565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009073ffffffffffffffffffffffffffffffffffffffff8316906370a0823190602401602060405180830381865afa158015610c51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c7591906120ca565b73ffffffffffffffffffffffffffffffffffffffff83166000908152601160205260409020549091508015801590610cb05750600c54600554105b15610ce15760108181548110610cc857610cc8612062565b906000526020600020015482610cde919061204b565b91505b8115610d0857610d0873ffffffffffffffffffffffffffffffffffffffff8416338461182a565b50505b5060018055565b60005473ffffffffffffffffffffffffffffffffffffffff163314610d93576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103d9565b610d9d60006118fe565b565b600d8181548110610daf57600080fd5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b600e8181548110610de657600080fd5b600091825260209091200154905081565b60026001541415610e64576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016103d9565b6002600155336000818152600f602052604081208054610eb8939290610e8c57610e8c612062565b60009182526020909120015460025473ffffffffffffffffffffffffffffffffffffffff16919061182a565b60005b336000908152600f602052604090205481101561095f57336000908152600f60205260409020805482908110610ef357610ef3612062565b906000526020600020015460108281548110610f1157610f11612062565b906000526020600020016000828254610f2a919061204b565b90915550819050610f3a81612091565b915050610ebb565b60005473ffffffffffffffffffffffffffffffffffffffff163314610fc3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103d9565b6006541561102d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c72656164792073746172746564000000000000000000000000000000000060448201526064016103d9565b60045461103a90426120e3565b6006556010805460018101825560009182527f1b6847dc741a1b0cd08d278845f9d819d87b734759afb55fe2de5cb82a9ae6720155565b60005473ffffffffffffffffffffffffffffffffffffffff1633146110f2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103d9565b600791909155600855565b4260065411611168576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f416c726561647920656e646564206f72206e6f7420737461727465640000000060448201526064016103d9565b600260015414156111d5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016103d9565b600260015573ffffffffffffffffffffffffffffffffffffffff821660009081526011602052604090205480611267576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e76616c6964207061796d656e74206d6574686f640000000000000000000060448201526064016103d9565b6000600e61127660018461204b565b8154811061128657611286612062565b90600052602060002001549050600081116112fd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e76616c6964207061796d656e74206d6574686f640000000000000000000060448201526064016103d9565b61131f73ffffffffffffffffffffffffffffffffffffffff8516333086611973565b600061132b84836119d7565b905061133681611ac3565b601060008154811061134a5761134a612062565b6000918252602090912001546002546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff909116906370a0823190602401602060405180830381865afa1580156113c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113e891906120ca565b6113f2919061204b565b81111561145b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f43616e6e6f74206275792074686973206d75636800000000000000000000000060448201526064016103d9565b806005600082825461146d91906120e3565b9091555050600c5460055410156115aa575b336000908152600f602052604090205483106114bb57336000908152600f6020908152604082208054600181018255908352908220015561147f565b336000908152600f6020526040812080548392906114db576114db612062565b9060005260206000200160008282546114f491906120e3565b9250508190555080601060008154811061151057611510612062565b90600052602060002001600082825461152991906120e3565b9091555050336000908152600f6020526040902080548591908590811061155257611552612062565b90600052602060002001600082825461156b91906120e3565b92505081905550836010848154811061158657611586612062565b90600052602060002001600082825461159f91906120e3565b909155506116be9050565b336000908152600f60205260409020541561169a57336000908152600f6020526040812080549091906115df576115df612062565b9060005260206000200154816115f591906120e3565b905060005b336000908152600f602052604090205481101561168157336000908152600f6020526040902080548290811061163257611632612062565b90600052602060002001546010828154811061165057611650612062565b906000526020600020016000828254611669919061204b565b9091555081905061167981612091565b9150506115fa565b50336000908152600f6020526040812061169a91611f41565b6116be3360025473ffffffffffffffffffffffffffffffffffffffff16908361182a565b505060018055505050565b600f60205281600052604060002081815481106116e557600080fd5b90600052602060002001600091509150505481565b60005473ffffffffffffffffffffffffffffffffffffffff16331461177b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103d9565b73ffffffffffffffffffffffffffffffffffffffff811661181e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016103d9565b611827816118fe565b50565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526106e39084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152611c23565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526119d19085907f23b872dd000000000000000000000000000000000000000000000000000000009060840161187c565b50505050565b6000806119e48484611d2f565b9050600a548110611aba5760006103e8600b5483611a0291906120fb565b611a0c9190612138565b611a1690836120e3565b6002546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015291925073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015611a85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aa991906120ca565b8111611ab8579150611abd9050565b505b90505b92915050565b600754811015611b54576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e6e6f742072656365697665206c657373207468616e206c6f776572206c60448201527f696d69740000000000000000000000000000000000000000000000000000000060648201526084016103d9565b3360009081526009602052604081208054839290611b739084906120e3565b90915550506008541580611b9857506008543360009081526009602052604090205411155b611827576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e6e6f742072656365697665206d6f7265207468616e207570706572206c60448201527f696d69740000000000000000000000000000000000000000000000000000000060648201526084016103d9565b6000611c85826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16611d559092919063ffffffff16565b8051909150156106e35780806020019051810190611ca39190612173565b6106e3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016103d9565b600081600354600a611d4191906122b5565b611d4b90856120fb565b611aba9190612138565b6060611d648484600085611d6e565b90505b9392505050565b606082471015611e00576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016103d9565b843b611e68576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016103d9565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051611e9191906122ed565b60006040518083038185875af1925050503d8060008114611ece576040519150601f19603f3d011682016040523d82523d6000602084013e611ed3565b606091505b5091509150611ee3828286611eee565b979650505050505050565b60608315611efd575081611d67565b825115611f0d5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103d99190612309565b508054600082559060005260206000209081019061182791905b80821115611f6f5760008155600101611f5b565b5090565b60008060408385031215611f8657600080fd5b50508035926020909101359150565b803573ffffffffffffffffffffffffffffffffffffffff81168114611fb957600080fd5b919050565b60008060408385031215611fd157600080fd5b611fda83611f95565b946020939093013593505050565b600060208284031215611ffa57600080fd5b611aba82611f95565b60006020828403121561201557600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008282101561205d5761205d61201c565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156120c3576120c361201c565b5060010190565b6000602082840312156120dc57600080fd5b5051919050565b600082198211156120f6576120f661201c565b500190565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156121335761213361201c565b500290565b60008261216e577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60006020828403121561218557600080fd5b81518015158114611aba57600080fd5b600181815b808511156121ee57817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156121d4576121d461201c565b808516156121e157918102915b93841c939080029061219a565b509250929050565b60008261220557506001611abd565b8161221257506000611abd565b816001811461222857600281146122325761224e565b6001915050611abd565b60ff8411156122435761224361201c565b50506001821b611abd565b5060208310610133831016604e8410600b8410161715612271575081810a611abd565b61227b8383612195565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156122ad576122ad61201c565b029392505050565b6000611aba83836121f6565b60005b838110156122dc5781810151838201526020016122c4565b838111156119d15750506000910152565b600082516122ff8184602087016122c1565b9190910192915050565b60208152600082518060208401526123288160408501602087016122c1565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea26469706673582212200da490183565e0bb8d2a00c14fe39e5ed9272a605a91242db7eab8c02051d08c64736f6c634300080a0033a264697066735822122079284746334c8b23df8f66b390e9bb7d17c5584b72e86f04f696fb95071c1ed764736f6c634300080a0033

Deployed ByteCode

0x608060405234801561001057600080fd5b50600436106100885760003560e01c80638da5cb5b1161005b5780638da5cb5b146100d0578063ad9b8024146100fd578063e101f7c01461011e578063f2fde38b1461013157600080fd5b806319cfe1e71461008d57806359770438146100a2578063715018a6146100b557806384fb1aae146100bd575b600080fd5b6100a061009b3660046114af565b610144565b005b6100a06100b03660046114e3565b610202565b6100a0610338565b6100a06100cb36600461154a565b6103c5565b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b61011061010b366004611621565b61090d565b6040519081526020016100f4565b6100a061012c36600461154a565b610932565b6100a061013f3660046114e3565b610e2b565b60005473ffffffffffffffffffffffffffffffffffffffff1633146101ca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff821660009081526002602081905260409091206101fd918390611400565b505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610283576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016101c1565b80610334336040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8416906370a0823190602401602060405180830381865afa1580156102f2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610316919061164b565b73ffffffffffffffffffffffffffffffffffffffff84169190610f5b565b5050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146103b9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016101c1565b6103c3600061102f565b565b60026001541415610432576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016101c1565b600260018190556000908161044a60208f018f6114e3565b73ffffffffffffffffffffffffffffffffffffffff1681526020810191909152604001600020600101549050600081116104e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f57726f6e67207061796d656e74206d6574686f6400000000000000000000000060448201526064016101c1565b61051b335b30838f60006020020160208101906104fd91906114e3565b73ffffffffffffffffffffffffffffffffffffffff169291906110a4565b858414610584576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f496e76616c696420706172616d6574657273000000000000000000000000000060448201526064016101c1565b60008b8b8b8b6040516105969061143e565b73ffffffffffffffffffffffffffffffffffffffff9094168452602084019290925260408301526060820152608001604051809103906000f0801580156105e1573d6000803e3d6000fd5b506040517fc4590d3f000000000000000000000000000000000000000000000000000000008152853560048201526020860135602482015290915073ffffffffffffffffffffffffffffffffffffffff82169063c4590d3f90604401600060405180830381600087803b15801561065757600080fd5b505af115801561066b573d6000803e3d6000fd5b50506040517f037c99b0000000000000000000000000000000000000000000000000000000008152853560048201526020860135602482015273ffffffffffffffffffffffffffffffffffffffff8416925063037c99b09150604401600060405180830381600087803b1580156106e157600080fd5b505af11580156106f5573d6000803e3d6000fd5b5050505060005b878110156107f8578173ffffffffffffffffffffffffffffffffffffffff1663539270bc8a8a8481811061073257610732611664565b905060200201602081019061074791906114e3565b89898581811061075957610759611664565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b16815273ffffffffffffffffffffffffffffffffffffffff90941660048501526020029190910135602483015250604401600060405180830381600087803b1580156107cd57600080fd5b505af11580156107e1573d6000803e3d6000fd5b5050505080806107f090611693565b9150506106fc565b5073ffffffffffffffffffffffffffffffffffffffff811663f2fde38b8e600160200201602081019061082b91906114e3565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401600060405180830381600087803b15801561089157600080fd5b505af11580156108a5573d6000803e3d6000fd5b50506040805173ffffffffffffffffffffffffffffffffffffffff85168152600160208201527f6a52a393150c061e1a1d151cdb19dda10b47bde43e6dca17727226d75861a2db93500190505b60405180910390a15050600180555050505050505050505050565b6002602052816000526040600020816002811061092957600080fd5b01549150829050565b6002600154141561099f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016101c1565b60026001819055600090816109b760208f018f6114e3565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002054905080610a47576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f57726f6e67207061796d656e74206d6574686f6400000000000000000000000060448201526064016101c1565b610a50336104e5565b858414610ab9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f496e76616c696420706172616d6574657273000000000000000000000000000060448201526064016101c1565b60008b8b8b8b604051610acb9061144c565b73ffffffffffffffffffffffffffffffffffffffff9094168452602084019290925260408301526060820152608001604051809103906000f080158015610b16573d6000803e3d6000fd5b506040517fc4590d3f000000000000000000000000000000000000000000000000000000008152853560048201526020860135602482015290915073ffffffffffffffffffffffffffffffffffffffff82169063c4590d3f90604401600060405180830381600087803b158015610b8c57600080fd5b505af1158015610ba0573d6000803e3d6000fd5b50506040517f037c99b0000000000000000000000000000000000000000000000000000000008152853560048201526020860135602482015273ffffffffffffffffffffffffffffffffffffffff8416925063037c99b09150604401600060405180830381600087803b158015610c1657600080fd5b505af1158015610c2a573d6000803e3d6000fd5b5050505060005b87811015610d2d578173ffffffffffffffffffffffffffffffffffffffff1663539270bc8a8a84818110610c6757610c67611664565b9050602002016020810190610c7c91906114e3565b898985818110610c8e57610c8e611664565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e087901b16815273ffffffffffffffffffffffffffffffffffffffff90941660048501526020029190910135602483015250604401600060405180830381600087803b158015610d0257600080fd5b505af1158015610d16573d6000803e3d6000fd5b505050508080610d2590611693565b915050610c31565b5073ffffffffffffffffffffffffffffffffffffffff811663f2fde38b8e6001602002016020810190610d6091906114e3565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401600060405180830381600087803b158015610dc657600080fd5b505af1158015610dda573d6000803e3d6000fd5b50506040805173ffffffffffffffffffffffffffffffffffffffff85168152600060208201527f6a52a393150c061e1a1d151cdb19dda10b47bde43e6dca17727226d75861a2db93500190506108f2565b60005473ffffffffffffffffffffffffffffffffffffffff163314610eac576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016101c1565b73ffffffffffffffffffffffffffffffffffffffff8116610f4f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016101c1565b610f588161102f565b50565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526101fd9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152611108565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526111029085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401610fad565b50505050565b600061116a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166112149092919063ffffffff16565b8051909150156101fd578080602001905181019061118891906116f3565b6101fd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016101c1565b6060611223848460008561122d565b90505b9392505050565b6060824710156112bf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016101c1565b843b611327576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016101c1565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516113509190611741565b60006040518083038185875af1925050503d806000811461138d576040519150601f19603f3d011682016040523d82523d6000602084013e611392565b606091505b50915091506113a28282866113ad565b979650505050505050565b606083156113bc575081611226565b8251156113cc5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101c1919061175d565b826002810192821561142e579160200282015b8281111561142e578235825591602001919060010190611413565b5061143a92915061145a565b5090565b6122c280620017af83390190565b6124b78062003a7183390190565b5b8082111561143a576000815560010161145b565b803573ffffffffffffffffffffffffffffffffffffffff8116811461149357600080fd5b919050565b80604081018310156114a957600080fd5b92915050565b600080606083850312156114c257600080fd5b6114cb8361146f565b91506114da8460208501611498565b90509250929050565b6000602082840312156114f557600080fd5b6112268261146f565b60008083601f84011261151057600080fd5b50813567ffffffffffffffff81111561152857600080fd5b6020830191508360208260051b850101111561154357600080fd5b9250929050565b60008060008060008060008060008060006101808c8e03121561156c57600080fd5b6115768d8d611498565b9a5061158460408d0161146f565b995060608c0135985060808c0135975060a08c0135965067ffffffffffffffff8060c08e013511156115b557600080fd5b6115c58e60c08f01358f016114fe565b909750955060e08d01358110156115db57600080fd5b506115ec8d60e08e01358e016114fe565b90945092506115ff8d6101008e01611498565b915061160f8d6101408e01611498565b90509295989b509295989b9093969950565b6000806040838503121561163457600080fd5b61163d8361146f565b946020939093013593505050565b60006020828403121561165d57600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156116ec577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b60006020828403121561170557600080fd5b8151801515811461122657600080fd5b60005b83811015611730578181015183820152602001611718565b838111156111025750506000910152565b60008251611753818460208701611715565b9190910192915050565b602081526000825180602084015261177c816040850160208701611715565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fe60806040523480156200001157600080fd5b50604051620022c2380380620022c28339810160408190526200003491620000ca565b83838362000042336200007a565b60018055600280546001600160a01b0319166001600160a01b039490941693909317909255600355600455600c555062000117915050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60008060008060808587031215620000e157600080fd5b84516001600160a01b0381168114620000f957600080fd5b60208601516040870151606090970151919890975090945092505050565b61219b80620001276000396000f3fe608060405234801561001057600080fd5b50600436106101ae5760003560e01c80638b90cdc9116100ee578063b652dc2f11610097578063c4590d3f11610071578063c4590d3f14610323578063cce7ec1314610336578063dfbf8b1614610349578063f2fde38b1461035c57600080fd5b8063b652dc2f1461030a578063be040fb014610313578063be9a65551461031b57600080fd5b80639731d9f6116100c85780639731d9f6146102e5578063a05d479d146102ee578063af0f325c1461030157600080fd5b80638b90cdc9146102ab5780638da5cb5b146102be5780639106d7ba146102dc57600080fd5b8063539270bc1161015b578063667022fd11610135578063667022fd146102355780636cd0715414610255578063715018a61461029a578063813d6c9a146102a257600080fd5b8063539270bc14610207578063590e1ae31461021a578063597704381461022257600080fd5b80633197cbb61161018c5780633197cbb6146101ec57806338392c40146101f55780633b97e856146101fe57600080fd5b8063037c99b0146101b35780631be05289146101c85780632095f2d4146101e4575b600080fd5b6101c66101c1366004611d7e565b61036f565b005b6101d160045481565b6040519081526020015b60405180910390f35b6101c66103e6565b6101d160065481565b6101d160085481565b6101d160035481565b6101c6610215366004611dc9565b6104a4565b6101c6610751565b6101c6610230366004611df3565b610999565b6101d1610243366004611df3565b60096020526000908152604090205481565b6002546102759073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101db565b6101c6610cdf565b6101d1600b5481565b6102756102b9366004611e0e565b610d52565b60005473ffffffffffffffffffffffffffffffffffffffff16610275565b6101d160055481565b6101d160075481565b6101d16102fc366004611e0e565b610d89565b6101d1600a5481565b6101d1600c5481565b6101c6610daa565b6101c6610edb565b6101c6610331366004611d7e565b610fd6565b6101c6610344366004611dc9565b611048565b6101d1610357366004611dc9565b611592565b6101c661036a366004611df3565b6115c3565b60005473ffffffffffffffffffffffffffffffffffffffff1633146103db5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b600a91909155600b55565b60005473ffffffffffffffffffffffffffffffffffffffff16331461044d5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103d2565b426006541161049e5760405162461bcd60e51b815260206004820152601c60248201527f416c726561647920656e646564206f72206e6f7420737461727465640000000060448201526064016103d2565b42600655565b60005473ffffffffffffffffffffffffffffffffffffffff16331461050b5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103d2565b60025473ffffffffffffffffffffffffffffffffffffffff8381169116141561059c5760405162461bcd60e51b815260206004820152602b60248201527f43616e6e6f74206164642073656c6c61626c6520746f6b656e2061732070617960448201527f6d656e74206d6574686f6400000000000000000000000000000000000000000060648201526084016103d2565b73ffffffffffffffffffffffffffffffffffffffff82166000908152601160205260409020548061072157600d5460031161063f5760405162461bcd60e51b815260206004820152602a60248201527f43616e6e6f7420616464206d6f7265207468616e207468726565207061796d6560448201527f6e74206d6574686f64730000000000000000000000000000000000000000000060648201526084016103d2565b50600d8054600180820183557fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb590910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff959095169485179055600e80548083019091557fbb7b4a454dc3493923482f07822329ed19e8244eff582cc204f8554c3620c3fd01929092555460009283526011602052604083205560108054918201815582527f1b6847dc741a1b0cd08d278845f9d819d87b734759afb55fe2de5cb82a9ae6720155565b81600e61072f600184611e56565b8154811061073f5761073f611e6d565b6000918252602090912001555b505050565b600260015414156107a45760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016103d2565b600260015560065442116107fa5760405162461bcd60e51b815260206004820152600d60248201527f4e6f7420656e646564207965740000000000000000000000000000000000000060448201526064016103d2565b600c546005541061084d5760405162461bcd60e51b815260206004820152601360248201527f536f66742063617020697320726561636865640000000000000000000000000060448201526064016103d2565b60005b336000908152600f602052604090205481101561097a57336000908152600f6020526040812080548390811061088857610888611e6d565b9060005260206000200154905060008111156109675781156108f8576000600d6108b3600185611e56565b815481106108c3576108c3611e6d565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1690506108f28133846116bf565b50610934565b806005600082825461090a9190611e56565b9091555050336000908152600960205260408120805483929061092e908490611e56565b90915550505b806010838154811061094857610948611e6d565b9060005260206000200160008282546109619190611e56565b90915550505b508061097281611e9c565b915050610850565b50336000908152600f6020526040812061099391611d4c565b60018055565b60005473ffffffffffffffffffffffffffffffffffffffff163314610a005760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103d2565b60026001541415610a535760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016103d2565b600260018190555473ffffffffffffffffffffffffffffffffffffffff82811691161415610bb1576006544211610acc5760405162461bcd60e51b815260206004820152600d60248201527f4e6f7420656e646564207965740000000000000000000000000000000000000060448201526064016103d2565b610bac336010600081548110610ae457610ae4611e6d565b6000918252602090912001546002546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff909116906370a0823190602401602060405180830381865afa158015610b5e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b829190611ed5565b610b8c9190611e56565b60025473ffffffffffffffffffffffffffffffffffffffff1691906116bf565b610cd8565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009073ffffffffffffffffffffffffffffffffffffffff8316906370a0823190602401602060405180830381865afa158015610c1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c429190611ed5565b73ffffffffffffffffffffffffffffffffffffffff83166000908152601160205260409020549091508015801590610c7d5750600c54600554105b15610cae5760108181548110610c9557610c95611e6d565b906000526020600020015482610cab9190611e56565b91505b8115610cd557610cd573ffffffffffffffffffffffffffffffffffffffff841633846116bf565b50505b5060018055565b60005473ffffffffffffffffffffffffffffffffffffffff163314610d465760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103d2565b610d506000611793565b565b600d8181548110610d6257600080fd5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b600e8181548110610d9957600080fd5b600091825260209091200154905081565b60026001541415610dfd5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016103d2565b6002600155336000818152600f602052604081208054610e51939290610e2557610e25611e6d565b60009182526020909120015460025473ffffffffffffffffffffffffffffffffffffffff1691906116bf565b60005b336000908152600f602052604090205481101561097a57336000908152600f60205260409020805482908110610e8c57610e8c611e6d565b906000526020600020015460108281548110610eaa57610eaa611e6d565b906000526020600020016000828254610ec39190611e56565b90915550819050610ed381611e9c565b915050610e54565b60005473ffffffffffffffffffffffffffffffffffffffff163314610f425760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103d2565b60065415610f925760405162461bcd60e51b815260206004820152600f60248201527f416c72656164792073746172746564000000000000000000000000000000000060448201526064016103d2565b600454610f9f9042611eee565b6006556010805460018101825560009182527f1b6847dc741a1b0cd08d278845f9d819d87b734759afb55fe2de5cb82a9ae6720155565b60005473ffffffffffffffffffffffffffffffffffffffff16331461103d5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103d2565b600791909155600855565b42600654116110995760405162461bcd60e51b815260206004820152601c60248201527f416c726561647920656e646564206f72206e6f7420737461727465640000000060448201526064016103d2565b600260015414156110ec5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016103d2565b600260015573ffffffffffffffffffffffffffffffffffffffff8216600090815260116020526040902054806111645760405162461bcd60e51b815260206004820152601660248201527f496e76616c6964207061796d656e74206d6574686f640000000000000000000060448201526064016103d2565b6000600e611173600184611e56565b8154811061118357611183611e6d565b90600052602060002001549050600081116111e05760405162461bcd60e51b815260206004820152601660248201527f496e76616c6964207061796d656e74206d6574686f640000000000000000000060448201526064016103d2565b61120273ffffffffffffffffffffffffffffffffffffffff8516333086611808565b600061120e848361186c565b905061121981611881565b601060008154811061122d5761122d611e6d565b6000918252602090912001546002546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff909116906370a0823190602401602060405180830381865afa1580156112a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112cb9190611ed5565b6112d59190611e56565b8111156113245760405162461bcd60e51b815260206004820152601460248201527f43616e6e6f74206275792074686973206d75636800000000000000000000000060448201526064016103d2565b80600560008282546113369190611eee565b9091555050600c546005541015611473575b336000908152600f6020526040902054831061138457336000908152600f60209081526040822080546001810182559083529082200155611348565b336000908152600f6020526040812080548392906113a4576113a4611e6d565b9060005260206000200160008282546113bd9190611eee565b925050819055508060106000815481106113d9576113d9611e6d565b9060005260206000200160008282546113f29190611eee565b9091555050336000908152600f6020526040902080548591908590811061141b5761141b611e6d565b9060005260206000200160008282546114349190611eee565b92505081905550836010848154811061144f5761144f611e6d565b9060005260206000200160008282546114689190611eee565b909155506115879050565b336000908152600f60205260409020541561156357336000908152600f6020526040812080549091906114a8576114a8611e6d565b9060005260206000200154816114be9190611eee565b905060005b336000908152600f602052604090205481101561154a57336000908152600f602052604090208054829081106114fb576114fb611e6d565b90600052602060002001546010828154811061151957611519611e6d565b9060005260206000200160008282546115329190611e56565b9091555081905061154281611e9c565b9150506114c3565b50336000908152600f6020526040812061156391611d4c565b6115873360025473ffffffffffffffffffffffffffffffffffffffff1690836116bf565b505060018055505050565b600f60205281600052604060002081815481106115ae57600080fd5b90600052602060002001600091509150505481565b60005473ffffffffffffffffffffffffffffffffffffffff16331461162a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103d2565b73ffffffffffffffffffffffffffffffffffffffff81166116b35760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016103d2565b6116bc81611793565b50565b60405173ffffffffffffffffffffffffffffffffffffffff831660248201526044810182905261074c9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526119ad565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526118669085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401611711565b50505050565b60006118788383611a9f565b90505b92915050565b6007548110156118f85760405162461bcd60e51b8152602060048201526024808201527f43616e6e6f742072656365697665206c657373207468616e206c6f776572206c60448201527f696d69740000000000000000000000000000000000000000000000000000000060648201526084016103d2565b3360009081526009602052604081208054839290611917908490611eee565b9091555050600854158061193c57506008543360009081526009602052604090205411155b6116bc5760405162461bcd60e51b8152602060048201526024808201527f43616e6e6f742072656365697665206d6f7265207468616e207570706572206c60448201527f696d69740000000000000000000000000000000000000000000000000000000060648201526084016103d2565b6000611a0f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16611b889092919063ffffffff16565b80519091501561074c5780806020019051810190611a2d9190611f06565b61074c5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016103d2565b600080611aac8484611ba1565b9050600a5481106118785760006103e8600b5483611aca9190611f28565b611ad49190611f65565b611ade9083611eee565b6002546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015291925073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015611b4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b719190611ed5565b8111611b8057915061187b9050565b509392505050565b6060611b978484600085611bc7565b90505b9392505050565b600081600354600a611bb391906120c0565b611bbd9085611f28565b6118789190611f65565b606082471015611c3f5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016103d2565b843b611c8d5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016103d2565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051611cb691906120f8565b60006040518083038185875af1925050503d8060008114611cf3576040519150601f19603f3d011682016040523d82523d6000602084013e611cf8565b606091505b5091509150611d08828286611d13565b979650505050505050565b60608315611d22575081611b9a565b825115611d325782518084602001fd5b8160405162461bcd60e51b81526004016103d29190612114565b50805460008255906000526020600020908101906116bc91905b80821115611d7a5760008155600101611d66565b5090565b60008060408385031215611d9157600080fd5b50508035926020909101359150565b803573ffffffffffffffffffffffffffffffffffffffff81168114611dc457600080fd5b919050565b60008060408385031215611ddc57600080fd5b611de583611da0565b946020939093013593505050565b600060208284031215611e0557600080fd5b61187882611da0565b600060208284031215611e2057600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082821015611e6857611e68611e27565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415611ece57611ece611e27565b5060010190565b600060208284031215611ee757600080fd5b5051919050565b60008219821115611f0157611f01611e27565b500190565b600060208284031215611f1857600080fd5b8151801515811461187857600080fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615611f6057611f60611e27565b500290565b600082611f9b577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b600181815b80851115611ff957817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115611fdf57611fdf611e27565b80851615611fec57918102915b93841c9390800290611fa5565b509250929050565b6000826120105750600161187b565b8161201d5750600061187b565b8160018114612033576002811461203d57612059565b600191505061187b565b60ff84111561204e5761204e611e27565b50506001821b61187b565b5060208310610133831016604e8410600b841016171561207c575081810a61187b565b6120868383611fa0565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156120b8576120b8611e27565b029392505050565b60006118788383612001565b60005b838110156120e75781810151838201526020016120cf565b838111156118665750506000910152565b6000825161210a8184602087016120cc565b9190910192915050565b60208152600082518060208401526121338160408501602087016120cc565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea2646970667358221220ae435d09cf9141ab1963f66a4d4ccbc0568eda8efcad71b6a2682c22e5731a6364736f6c634300080a003360806040523480156200001157600080fd5b50604051620024b7380380620024b78339810160408190526200003491620000ca565b83838362000042336200007a565b60018055600280546001600160a01b0319166001600160a01b039490941693909317909255600355600455600c555062000117915050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60008060008060808587031215620000e157600080fd5b84516001600160a01b0381168114620000f957600080fd5b60208601516040870151606090970151919890975090945092505050565b61239080620001276000396000f3fe608060405234801561001057600080fd5b50600436106101a35760003560e01c80638b90cdc9116100ee578063b652dc2f11610097578063c4590d3f11610071578063c4590d3f14610310578063cce7ec1314610323578063dfbf8b1614610336578063f2fde38b1461034957600080fd5b8063b652dc2f146102f7578063be040fb014610300578063be9a65551461030857600080fd5b80639731d9f6116100c85780639731d9f6146102d2578063a05d479d146102db578063af0f325c146102ee57600080fd5b80638b90cdc9146102985780638da5cb5b146102ab5780639106d7ba146102c957600080fd5b8063590e1ae3116101505780636cd071541161012a5780636cd0715414610242578063715018a614610287578063813d6c9a1461028f57600080fd5b8063590e1ae314610207578063597704381461020f578063667022fd1461022257600080fd5b806338392c401161018157806338392c40146101e25780633b97e856146101eb578063539270bc146101f457600080fd5b8063037c99b0146101a85780631be05289146101bd5780633197cbb6146101d9575b600080fd5b6101bb6101b6366004611f73565b61035c565b005b6101c660045481565b6040519081526020015b60405180910390f35b6101c660065481565b6101c660085481565b6101c660035481565b6101bb610202366004611fbe565b6103ed565b6101bb6106e8565b6101bb61021d366004611fe8565b61097e565b6101c6610230366004611fe8565b60096020526000908152604090205481565b6002546102629073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101d0565b6101bb610d12565b6101c6600b5481565b6102626102a6366004612003565b610d9f565b60005473ffffffffffffffffffffffffffffffffffffffff16610262565b6101c660055481565b6101c660075481565b6101c66102e9366004612003565b610dd6565b6101c6600a5481565b6101c6600c5481565b6101bb610df7565b6101bb610f42565b6101bb61031e366004611f73565b611071565b6101bb610331366004611fbe565b6110fd565b6101c6610344366004611fbe565b6116c9565b6101bb610357366004611fe8565b6116fa565b60005473ffffffffffffffffffffffffffffffffffffffff1633146103e2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b600a91909155600b55565b60005473ffffffffffffffffffffffffffffffffffffffff16331461046e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103d9565b60025473ffffffffffffffffffffffffffffffffffffffff83811691161415610519576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f43616e6e6f74206164642073656c6c61626c6520746f6b656e2061732070617960448201527f6d656e74206d6574686f6400000000000000000000000000000000000000000060648201526084016103d9565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260116020526040902054806106b857600d546003116105d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f43616e6e6f7420616464206d6f7265207468616e207468726565207061796d6560448201527f6e74206d6574686f64730000000000000000000000000000000000000000000060648201526084016103d9565b50600d8054600180820183557fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb590910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff959095169485179055600e80548083019091557fbb7b4a454dc3493923482f07822329ed19e8244eff582cc204f8554c3620c3fd01929092555460009283526011602052604083205560108054918201815582527f1b6847dc741a1b0cd08d278845f9d819d87b734759afb55fe2de5cb82a9ae6720155565b81600e6106c660018461204b565b815481106106d6576106d6612062565b6000918252602090912001555b505050565b60026001541415610755576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016103d9565b600260015560065442116107c5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f4e6f7420656e646564207965740000000000000000000000000000000000000060448201526064016103d9565b600c5460055410610832576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f536f66742063617020697320726561636865640000000000000000000000000060448201526064016103d9565b60005b336000908152600f602052604090205481101561095f57336000908152600f6020526040812080548390811061086d5761086d612062565b90600052602060002001549050600081111561094c5781156108dd576000600d61089860018561204b565b815481106108a8576108a8612062565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1690506108d781338461182a565b50610919565b80600560008282546108ef919061204b565b9091555050336000908152600960205260408120805483929061091390849061204b565b90915550505b806010838154811061092d5761092d612062565b906000526020600020016000828254610946919061204b565b90915550505b508061095781612091565b915050610835565b50336000908152600f6020526040812061097891611f41565b60018055565b60005473ffffffffffffffffffffffffffffffffffffffff1633146109ff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103d9565b60026001541415610a6c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016103d9565b600260018190555473ffffffffffffffffffffffffffffffffffffffff82811691161415610be4576006544211610aff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f4e6f7420656e646564207965740000000000000000000000000000000000000060448201526064016103d9565b610bdf336010600081548110610b1757610b17612062565b6000918252602090912001546002546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff909116906370a0823190602401602060405180830381865afa158015610b91573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bb591906120ca565b610bbf919061204b565b60025473ffffffffffffffffffffffffffffffffffffffff16919061182a565b610d0b565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009073ffffffffffffffffffffffffffffffffffffffff8316906370a0823190602401602060405180830381865afa158015610c51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c7591906120ca565b73ffffffffffffffffffffffffffffffffffffffff83166000908152601160205260409020549091508015801590610cb05750600c54600554105b15610ce15760108181548110610cc857610cc8612062565b906000526020600020015482610cde919061204b565b91505b8115610d0857610d0873ffffffffffffffffffffffffffffffffffffffff8416338461182a565b50505b5060018055565b60005473ffffffffffffffffffffffffffffffffffffffff163314610d93576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103d9565b610d9d60006118fe565b565b600d8181548110610daf57600080fd5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b600e8181548110610de657600080fd5b600091825260209091200154905081565b60026001541415610e64576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016103d9565b6002600155336000818152600f602052604081208054610eb8939290610e8c57610e8c612062565b60009182526020909120015460025473ffffffffffffffffffffffffffffffffffffffff16919061182a565b60005b336000908152600f602052604090205481101561095f57336000908152600f60205260409020805482908110610ef357610ef3612062565b906000526020600020015460108281548110610f1157610f11612062565b906000526020600020016000828254610f2a919061204b565b90915550819050610f3a81612091565b915050610ebb565b60005473ffffffffffffffffffffffffffffffffffffffff163314610fc3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103d9565b6006541561102d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c72656164792073746172746564000000000000000000000000000000000060448201526064016103d9565b60045461103a90426120e3565b6006556010805460018101825560009182527f1b6847dc741a1b0cd08d278845f9d819d87b734759afb55fe2de5cb82a9ae6720155565b60005473ffffffffffffffffffffffffffffffffffffffff1633146110f2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103d9565b600791909155600855565b4260065411611168576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f416c726561647920656e646564206f72206e6f7420737461727465640000000060448201526064016103d9565b600260015414156111d5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016103d9565b600260015573ffffffffffffffffffffffffffffffffffffffff821660009081526011602052604090205480611267576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e76616c6964207061796d656e74206d6574686f640000000000000000000060448201526064016103d9565b6000600e61127660018461204b565b8154811061128657611286612062565b90600052602060002001549050600081116112fd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e76616c6964207061796d656e74206d6574686f640000000000000000000060448201526064016103d9565b61131f73ffffffffffffffffffffffffffffffffffffffff8516333086611973565b600061132b84836119d7565b905061133681611ac3565b601060008154811061134a5761134a612062565b6000918252602090912001546002546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff909116906370a0823190602401602060405180830381865afa1580156113c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113e891906120ca565b6113f2919061204b565b81111561145b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f43616e6e6f74206275792074686973206d75636800000000000000000000000060448201526064016103d9565b806005600082825461146d91906120e3565b9091555050600c5460055410156115aa575b336000908152600f602052604090205483106114bb57336000908152600f6020908152604082208054600181018255908352908220015561147f565b336000908152600f6020526040812080548392906114db576114db612062565b9060005260206000200160008282546114f491906120e3565b9250508190555080601060008154811061151057611510612062565b90600052602060002001600082825461152991906120e3565b9091555050336000908152600f6020526040902080548591908590811061155257611552612062565b90600052602060002001600082825461156b91906120e3565b92505081905550836010848154811061158657611586612062565b90600052602060002001600082825461159f91906120e3565b909155506116be9050565b336000908152600f60205260409020541561169a57336000908152600f6020526040812080549091906115df576115df612062565b9060005260206000200154816115f591906120e3565b905060005b336000908152600f602052604090205481101561168157336000908152600f6020526040902080548290811061163257611632612062565b90600052602060002001546010828154811061165057611650612062565b906000526020600020016000828254611669919061204b565b9091555081905061167981612091565b9150506115fa565b50336000908152600f6020526040812061169a91611f41565b6116be3360025473ffffffffffffffffffffffffffffffffffffffff16908361182a565b505060018055505050565b600f60205281600052604060002081815481106116e557600080fd5b90600052602060002001600091509150505481565b60005473ffffffffffffffffffffffffffffffffffffffff16331461177b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016103d9565b73ffffffffffffffffffffffffffffffffffffffff811661181e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016103d9565b611827816118fe565b50565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526106e39084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152611c23565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526119d19085907f23b872dd000000000000000000000000000000000000000000000000000000009060840161187c565b50505050565b6000806119e48484611d2f565b9050600a548110611aba5760006103e8600b5483611a0291906120fb565b611a0c9190612138565b611a1690836120e3565b6002546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015291925073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015611a85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aa991906120ca565b8111611ab8579150611abd9050565b505b90505b92915050565b600754811015611b54576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e6e6f742072656365697665206c657373207468616e206c6f776572206c60448201527f696d69740000000000000000000000000000000000000000000000000000000060648201526084016103d9565b3360009081526009602052604081208054839290611b739084906120e3565b90915550506008541580611b9857506008543360009081526009602052604090205411155b611827576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f43616e6e6f742072656365697665206d6f7265207468616e207570706572206c60448201527f696d69740000000000000000000000000000000000000000000000000000000060648201526084016103d9565b6000611c85826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16611d559092919063ffffffff16565b8051909150156106e35780806020019051810190611ca39190612173565b6106e3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016103d9565b600081600354600a611d4191906122b5565b611d4b90856120fb565b611aba9190612138565b6060611d648484600085611d6e565b90505b9392505050565b606082471015611e00576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016103d9565b843b611e68576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016103d9565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051611e9191906122ed565b60006040518083038185875af1925050503d8060008114611ece576040519150601f19603f3d011682016040523d82523d6000602084013e611ed3565b606091505b5091509150611ee3828286611eee565b979650505050505050565b60608315611efd575081611d67565b825115611f0d5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103d99190612309565b508054600082559060005260206000209081019061182791905b80821115611f6f5760008155600101611f5b565b5090565b60008060408385031215611f8657600080fd5b50508035926020909101359150565b803573ffffffffffffffffffffffffffffffffffffffff81168114611fb957600080fd5b919050565b60008060408385031215611fd157600080fd5b611fda83611f95565b946020939093013593505050565b600060208284031215611ffa57600080fd5b611aba82611f95565b60006020828403121561201557600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008282101561205d5761205d61201c565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156120c3576120c361201c565b5060010190565b6000602082840312156120dc57600080fd5b5051919050565b600082198211156120f6576120f661201c565b500190565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156121335761213361201c565b500290565b60008261216e577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60006020828403121561218557600080fd5b81518015158114611aba57600080fd5b600181815b808511156121ee57817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156121d4576121d461201c565b808516156121e157918102915b93841c939080029061219a565b509250929050565b60008261220557506001611abd565b8161221257506000611abd565b816001811461222857600281146122325761224e565b6001915050611abd565b60ff8411156122435761224361201c565b50506001821b611abd565b5060208310610133831016604e8410600b8410161715612271575081810a611abd565b61227b8383612195565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156122ad576122ad61201c565b029392505050565b6000611aba83836121f6565b60005b838110156122dc5781810151838201526020016122c4565b838111156119d15750506000910152565b600082516122ff8184602087016122c1565b9190910192915050565b60208152600082518060208401526123288160408501602087016122c1565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fea26469706673582212200da490183565e0bb8d2a00c14fe39e5ed9272a605a91242db7eab8c02051d08c64736f6c634300080a0033a264697066735822122079284746334c8b23df8f66b390e9bb7d17c5584b72e86f04f696fb95071c1ed764736f6c634300080a0033