ETH Price: $3,041.86 (+0.60%)
Gas: 2 Gwei

Contract

0xfFf846a56D6332D92728bdbb597CBf83c917bFa0
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Value
Init115109292020-12-23 16:37:251294 days ago1608741445IN
0xfFf846a5...3c917bFa0
0 ETH0.02883601118
0x60806040115109032020-12-23 16:31:421294 days ago1608741102IN
 Create: ACOToken
0 ETH0.47154227118

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
ACOToken

Compiler Version
v0.6.6+commit.6c089d02

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, None license

Contract Source Code (Solidity Multiple files format)

File 1 of 8: ACOToken.sol
pragma solidity ^0.6.6;

import "./ERC20.sol";
import "./Address.sol";
import "./ACONameFormatter.sol";

/**
 * @title ACOToken
 * @dev The implementation of the ACO token.
 * The token is ERC20 compliant.
 */
contract ACOToken is ERC20 {
    using Address for address;
    
    /**
     * @dev Struct to store the accounts that generated tokens with a collateral deposit.
     */
    struct TokenCollateralized {
        /**
         * @dev Current amount of tokens.
         */
        uint256 amount;
        
        /**
         * @dev Index on the collateral owners array.
         */
        uint256 index;
    }
    
    /**
     * @dev Emitted when collateral is deposited on the contract.
     * @param account Address of the collateral owner.
     * @param amount Amount of collateral deposited.
     */
    event CollateralDeposit(address indexed account, uint256 amount);
    
    /**
     * @dev Emitted when collateral is withdrawn from the contract.
     * @param account Address of the account.
     * @param recipient Address of the collateral destination.
     * @param amount Amount of collateral withdrawn.
     * @param fee The fee amount charged on the withdrawal.
     */
    event CollateralWithdraw(address indexed account, address indexed recipient, uint256 amount, uint256 fee);
    
    /**
     * @dev Emitted when the collateral is used on an assignment.
     * @param from Address of the account of the collateral owner.
     * @param to Address of the account that exercises tokens to get the collateral.
     * @param paidAmount Amount paid to the collateral owner.
     * @param tokenAmount Amount of tokens used to exercise.
     */
    event Assigned(address indexed from, address indexed to, uint256 paidAmount, uint256 tokenAmount);

    /**
     * @dev Emitted when the collateralized token is transferred.
     * @param from Address of the account of the collateral owner.
     * @param to Address of the account to get the collateralized tokens.
     * @param tokenCollateralizedAmount Amount of collateralized tokens transferred.
     */
    event TransferCollateralOwnership(address indexed from, address indexed to, uint256 tokenCollateralizedAmount);

    /**
     * @dev The ERC20 token address for the underlying asset (0x0 for Ethereum). 
     */
    address public underlying;
    
    /**
     * @dev The ERC20 token address for the strike asset (0x0 for Ethereum). 
     */
    address public strikeAsset;
    
    /**
     * @dev Address of the fee destination charged on the exercise.
     */
    address payable public feeDestination;
    
    /**
     * @dev True if the type is CALL, false for PUT.
     */
    bool public isCall;
    
    /**
     * @dev The strike price for the token with the strike asset precision.
     */
    uint256 public strikePrice;
    
    /**
     * @dev The UNIX time for the token expiration.
     */
    uint256 public expiryTime;
    
    /**
     * @dev The total amount of collateral on the contract.
     */
    uint256 public totalCollateral;
    
    /**
     * @dev The fee value. It is a percentage value (100000 is 100%).
     */
    uint256 public acoFee;
    
    /**
     * @dev Symbol of the underlying asset.
     */
    string public underlyingSymbol;
    
    /**
     * @dev Symbol of the strike asset.
     */
    string public strikeAssetSymbol;
    
    /**
     * @dev Decimals for the underlying asset.
     */
    uint8 public underlyingDecimals;
    
    /**
     * @dev Decimals for the strike asset.
     */
    uint8 public strikeAssetDecimals;
    
    /**
     * @dev The maximum number of accounts that can be exercised by transaction.
     */
    uint256 public maxExercisedAccounts;
    
    /**
     * @dev Underlying precision. (10 ^ underlyingDecimals)
     */
    uint256 internal underlyingPrecision;
    
    /**
     * @dev Accounts that generated tokens with a collateral deposit.
     */
    mapping(address => TokenCollateralized) internal tokenData;
    
    /**
     * @dev Array with all accounts with collateral deposited.
     */
    address[] internal _collateralOwners;
    
    /**
     * @dev Internal data to control the reentrancy.
     */
    bool internal _notEntered;
    
    /**
     * @dev Selector for ERC20 transfer function.
     */
    bytes4 internal _transferSelector;
    
    /**
     * @dev Selector for ERC20 transfer from function.
     */
    bytes4 internal _transferFromSelector;
    
    /**
     * @dev Modifier to check if the token is not expired.
     * It is executed only while the token is not expired.
     */
    modifier notExpired() {
        require(_notExpired(), "ACOToken::Expired");
        _;
    }
    
    /**
     * @dev Modifier to prevent a contract from calling itself during the function execution.
     */
    modifier nonReentrant() {
        require(_notEntered, "ACOToken::Reentry");
        _notEntered = false;
        _;
        _notEntered = true;
    }
    
    /**
     * @dev Function to initialize the contract.
     * It should be called when creating the token.
     * It must be called only once. The first `require` is to guarantee that behavior.
     * @param _underlying Address of the underlying asset (0x0 for Ethereum).
     * @param _strikeAsset Address of the strike asset (0x0 for Ethereum).
     * @param _isCall True if the type is CALL, false for PUT.
     * @param _strikePrice The strike price with the strike asset precision.
     * @param _expiryTime The UNIX time for the token expiration.
     * @param _acoFee Value of the ACO fee. It is a percentage value (100000 is 100%).
     * @param _feeDestination Address of the fee destination charged on the exercise.
     * @param _maxExercisedAccounts The maximum number of accounts that can be exercised by transaction.
     */
    function init(
        address _underlying,
        address _strikeAsset,
        bool _isCall,
        uint256 _strikePrice,
        uint256 _expiryTime,
        uint256 _acoFee,
        address payable _feeDestination,
        uint256 _maxExercisedAccounts
    ) public {
        require(underlying == address(0) && strikeAsset == address(0) && strikePrice == 0, "ACOToken::init: Already initialized");
        
        require(_expiryTime > now, "ACOToken::init: Invalid expiry");
        require(_strikePrice > 0, "ACOToken::init: Invalid strike price");
        require(_underlying != _strikeAsset, "ACOToken::init: Same assets");
        require(_acoFee <= 500, "ACOToken::init: Invalid ACO fee"); // Maximum is 0.5%
        require(_isEther(_underlying) || _underlying.isContract(), "ACOToken::init: Invalid underlying");
        require(_isEther(_strikeAsset) || _strikeAsset.isContract(), "ACOToken::init: Invalid strike asset");
        require(_maxExercisedAccounts >= 25 && _maxExercisedAccounts <= 150, "ACOToken::init: Invalid number to max exercised accounts");
        
        underlying = _underlying;
        strikeAsset = _strikeAsset;
        isCall = _isCall;
        strikePrice = _strikePrice;
        expiryTime = _expiryTime;
        acoFee = _acoFee;
        feeDestination = _feeDestination;
        maxExercisedAccounts = _maxExercisedAccounts;
        underlyingDecimals = _getAssetDecimals(_underlying);
        require(underlyingDecimals < 78, "ACOToken::init: Invalid underlying decimals");
        strikeAssetDecimals = _getAssetDecimals(_strikeAsset);
        underlyingSymbol = _getAssetSymbol(_underlying);
        strikeAssetSymbol = _getAssetSymbol(_strikeAsset);
        underlyingPrecision = 10 ** uint256(underlyingDecimals);

        _transferSelector = bytes4(keccak256(bytes("transfer(address,uint256)")));
        _transferFromSelector = bytes4(keccak256(bytes("transferFrom(address,address,uint256)")));
        _notEntered = true;
    }
    
    /**
     * @dev Function to guarantee that the contract will not receive ether directly.
     */
    receive() external payable {
        revert();
    }
    
    /**
     * @dev Function to get the token name.
     */
    function name() public view override returns(string memory) {
        return _name();
    }
    
    /**
     * @dev Function to get the token symbol, that it is equal to the name.
     */
    function symbol() public view override returns(string memory) {
        return _name();
    }
    
    /**
     * @dev Function to get the token decimals, that it is equal to the underlying asset decimals.
     */
    function decimals() public view override returns(uint8) {
        return underlyingDecimals;
    }
    
    /**
     * @dev Function to get the current amount of collateral for an account.
     * @param account Address of the account.
     * @return The current amount of collateral.
     */
    function currentCollateral(address account) public view returns(uint256) {
        return getCollateralAmount(currentCollateralizedTokens(account));
    }
    
    /**
     * @dev Function to get the current amount of unassignable collateral for an account.
     * After expiration, the unassignable collateral is equal to the account's collateral balance.
     * @param account Address of the account.
     * @return The respective amount of unassignable collateral.
     */
    function unassignableCollateral(address account) public view returns(uint256) {
        return getCollateralAmount(unassignableTokens(account));
    }
    
    /**
     * @dev Function to get  the current amount of assignable collateral for an account.
     * After expiration, the assignable collateral is zero.
     * @param account Address of the account.
     * @return The respective amount of assignable collateral.
     */
    function assignableCollateral(address account) public view returns(uint256) {
        return getCollateralAmount(assignableTokens(account));
    }
    
    /**
     * @dev Function to get the current amount of collateralized tokens for an account.
     * @param account Address of the account.
     * @return The current amount of collateralized tokens.
     */
    function currentCollateralizedTokens(address account) public view returns(uint256) {
        return tokenData[account].amount;
    }
    
    /**
     * @dev Function to get the current amount of unassignable tokens for an account.
     * After expiration, the unassignable tokens is equal to the account's collateralized tokens.
     * @param account Address of the account.
     * @return The respective amount of unassignable tokens.
     */
    function unassignableTokens(address account) public view returns(uint256) {
        if (balanceOf(account) > tokenData[account].amount || !_notExpired()) {
            return tokenData[account].amount;
        } else {
            return balanceOf(account);
        }
    }
    
    /**
     * @dev Function to get  the current amount of assignable tokens for an account.
     * After expiration, the assignable tokens is zero.
     * @param account Address of the account.
     * @return The respective amount of assignable tokens.
     */
    function assignableTokens(address account) public view returns(uint256) {
        if (_notExpired()) {
            return _getAssignableAmount(account);
        } else {
            return 0;
        }
    }
    
    /**
     * @dev Function to get the equivalent collateral amount for a token amount.
     * @param tokenAmount Amount of tokens.
     * @return The respective amount of collateral.
     */
    function getCollateralAmount(uint256 tokenAmount) public view returns(uint256) {
        if (isCall) {
            return tokenAmount;
        } else if (tokenAmount > 0) {
            return _getTokenStrikePriceRelation(tokenAmount);
        } else {
            return 0;
        }
    }
    
    /**
     * @dev Function to get the equivalent token amount for a collateral amount.
     * @param collateralAmount Amount of collateral.
     * @return The respective amount of tokens.
     */
    function getTokenAmount(uint256 collateralAmount) public view returns(uint256) {
        if (isCall) {
            return collateralAmount;
        } else if (collateralAmount > 0) {
            return collateralAmount.mul(underlyingPrecision).div(strikePrice);
        } else {
            return 0;
        }
    }

    /**
     * @dev Function to get the number of addresses that have collateral deposited.
     * @return The number of addresses.
     */
    function numberOfAccountsWithCollateral() public view returns(uint256) {
        return _collateralOwners.length;
    }
    
    /**
     * @dev Function to get the base data for exercise of an amount of token.
     * To call the exercise the value returned must be added by the number of accounts that could be exercised:
     * - using the ´exercise´ or ´exerciseFrom´ functions it will be equal to `maxExercisedAccounts`.
     * - using the ´exerciseAccounts´ or `exerciseAccountsFrom` functions it will be equal to the number of accounts sent as function argument.
     * @param tokenAmount Amount of tokens.
     * @return The asset and the respective base amount that should be sent to get the collateral.
     */
    function getBaseExerciseData(uint256 tokenAmount) public view returns(address, uint256) {
        if (isCall) {
            return (strikeAsset, _getTokenStrikePriceRelation(tokenAmount)); 
        } else {
            return (underlying, tokenAmount);
        }
    }
    
    /**
     * @dev Function to get the collateral to be received on an exercise and the respective fee.
     * @param tokenAmount Amount of tokens.
     * @return The collateral to be received and the respective fee.
     */
    function getCollateralOnExercise(uint256 tokenAmount) public view returns(uint256, uint256) {
        uint256 collateralAmount = getCollateralAmount(tokenAmount);
        uint256 fee = collateralAmount.mul(acoFee).div(100000);
        collateralAmount = collateralAmount.sub(fee);
        return (collateralAmount, fee);
    }
    
    /**
     * @dev Function to get the collateral asset.
     * @return The address of the collateral asset.
     */
    function collateral() public view returns(address) {
        if (isCall) {
            return underlying;
        } else {
            return strikeAsset;
        }
    }
    
    /**
     * @dev Function to mint tokens with Ether deposited as collateral.
     * NOTE: The function only works when the token is NOT expired yet. 
     * @return The amount of tokens minted.
     */
    function mintPayable() external payable returns(uint256) {
        require(_isEther(collateral()), "ACOToken::mintPayable: Invalid call");
        return _mintToken(msg.sender, msg.value);
    }
    
    /**
     * @dev Function to mint tokens with Ether deposited as collateral to an informed account.
     * However, the minted tokens are assigned to the transaction sender.
     * NOTE: The function only works when the token is NOT expired yet. 
     * @param account Address of the account that will be the collateral owner.
     * @return The amount of tokens minted.
     */
    function mintToPayable(address account) external payable returns(uint256) {
        require(_isEther(collateral()), "ACOToken::mintToPayable: Invalid call");
       return _mintToken(account, msg.value);
    }
    
    /**
     * @dev Function to mint tokens with ERC20 deposited as collateral.
     * NOTE: The function only works when the token is NOT expired yet. 
     * @param collateralAmount Amount of collateral deposited.
     * @return The amount of tokens minted.
     */
    function mint(uint256 collateralAmount) external returns(uint256) {
        address _collateral = collateral();
        require(!_isEther(_collateral), "ACOToken::mint: Invalid call");
        
        _transferFromERC20(_collateral, msg.sender, address(this), collateralAmount);
        return _mintToken(msg.sender, collateralAmount);
    }
    
    /**
     * @dev Function to mint tokens with ERC20 deposited as collateral to an informed account.
     * However, the minted tokens are assigned to the transaction sender.
     * NOTE: The function only works when the token is NOT expired yet. 
     * @param account Address of the account that will be the collateral owner.
     * @param collateralAmount Amount of collateral deposited.
     * @return The amount of tokens minted.
     */
    function mintTo(address account, uint256 collateralAmount) external returns(uint256) {
        address _collateral = collateral();
        require(!_isEther(_collateral), "ACOToken::mintTo: Invalid call");
        
        _transferFromERC20(_collateral, msg.sender, address(this), collateralAmount);
        return _mintToken(account, collateralAmount);
    }
    
    /**
     * @dev Function to burn tokens and get the collateral, not assigned, back.
     * NOTE: The function only works when the token is NOT expired yet. 
     * @param tokenAmount Amount of tokens to be burned.
     * @return The amount of collateral transferred.
     */
    function burn(uint256 tokenAmount) external returns(uint256) {
        return _burn(msg.sender, tokenAmount);
    }
    
    /**
     * @dev Function to burn tokens from a specific account and send the collateral to its address.
     * The token allowance must be respected.
     * The collateral is sent to the transaction sender.
     * NOTE: The function only works when the token is NOT expired yet. 
     * @param account Address of the account.
     * @param tokenAmount Amount of tokens to be burned.
     * @return The amount of collateral transferred.
     */
    function burnFrom(address account, uint256 tokenAmount) external returns(uint256) {
        return _burn(account, tokenAmount);
    }
    
    /**
     * @dev Function to get the collateral, not assigned, back.
     * NOTE: The function only works when the token IS expired. 
     * @return The amount of collateral transferred.
     */
    function redeem() external returns(uint256) {
        return _redeem(msg.sender);
    }
    
    /**
     * @dev Function to get the collateral from a specific account sent back to its address .
     * The token allowance must be respected.
     * The collateral is sent to the transaction sender.
     * NOTE: The function only works when the token IS expired. 
     * @param account Address of the account.
     * @return The amount of collateral transferred.
     */
    function redeemFrom(address account) external returns(uint256) {
        require(tokenData[account].amount <= allowance(account, msg.sender), "ACOToken::redeemFrom: Allowance too low");
        return _redeem(account);
    }
    
    /**
     * @dev Function to exercise the tokens, paying to get the equivalent collateral.
     * The paid amount is sent to the collateral owners that were assigned.
     * NOTE: The function only works when the token is NOT expired. 
     * @param tokenAmount Amount of tokens.
     * @param salt Random number to calculate the start index of the array of accounts to be exercised.
     * @return The amount of collateral transferred.
     */
    function exercise(uint256 tokenAmount, uint256 salt) external payable returns(uint256) {
        return _exercise(msg.sender, tokenAmount, salt);
    }
    
    /**
     * @dev Function to exercise the tokens from an account, paying to get the equivalent collateral.
     * The token allowance must be respected.
     * The paid amount is sent to the collateral owners that were assigned.
     * The collateral is transferred to the transaction sender.
     * NOTE: The function only works when the token is NOT expired. 
     * @param account Address of the account.
     * @param tokenAmount Amount of tokens.
     * @param salt Random number to calculate the start index of the array of accounts to be exercised.
     * @return The amount of collateral transferred.
     */
    function exerciseFrom(address account, uint256 tokenAmount, uint256 salt) external payable returns(uint256) {
        return _exercise(account, tokenAmount, salt);
    }
    
    /**
     * @dev Function to exercise the tokens, paying to get the equivalent collateral.
     * The paid amount is sent to the collateral owners (on accounts list) that were assigned.
     * NOTE: The function only works when the token is NOT expired. 
     * @param tokenAmount Amount of tokens.
     * @param accounts The array of addresses to get collateral from.
     * @return The amount of collateral transferred.
     */
    function exerciseAccounts(uint256 tokenAmount, address[] calldata accounts) external payable returns(uint256) {
        return _exerciseFromAccounts(msg.sender, tokenAmount, accounts);
    }

    /**
     * @dev Function to transfer collateralized tokens.
     * @param recipient Address of the destination.
     * @param tokenCollateralizedAmount Amount of collateralized tokens to be transferred.
     */
    function transferCollateralOwnership(address recipient, uint256 tokenCollateralizedAmount) external {
        require(recipient != address(0), "ACOToken::transferCollateralOwnership: Invalid recipient");
        require(tokenCollateralizedAmount > 0, "ACOToken::transferCollateralOwnership: Invalid amount");

        TokenCollateralized storage senderData = tokenData[msg.sender];
        senderData.amount = senderData.amount.sub(tokenCollateralizedAmount);

        _removeCollateralDataIfNecessary(msg.sender);

        TokenCollateralized storage recipientData = tokenData[recipient];
        if (_hasCollateral(recipientData)) {
            recipientData.amount = recipientData.amount.add(tokenCollateralizedAmount);
        } else {
            tokenData[recipient] = TokenCollateralized(tokenCollateralizedAmount, _collateralOwners.length);
            _collateralOwners.push(recipient);
        }

        emit TransferCollateralOwnership(msg.sender, recipient, tokenCollateralizedAmount);
    }
    
    /**
     * @dev Function to exercise the tokens from a specific account, paying to get the equivalent collateral sent to its address.
     * The token allowance must be respected.
     * The paid amount is sent to the collateral owners (on accounts list) that were assigned.
     * The collateral is transferred to the transaction sender.
     * NOTE: The function only works when the token is NOT expired. 
     * @param account Address of the account.
     * @param tokenAmount Amount of tokens.
     * @param accounts The array of addresses to get the deposited collateral.
     * @return The amount of collateral transferred.
     */
    function exerciseAccountsFrom(address account, uint256 tokenAmount, address[] calldata accounts) external payable returns(uint256) {
        return _exerciseFromAccounts(account, tokenAmount, accounts);
    }
    
    /**
     * @dev Internal function to redeem respective collateral from an account.
     * @param account Address of the account.
     * @param tokenAmount Amount of tokens.
     * @return The amount of collateral transferred.
     */
    function _redeemCollateral(address account, uint256 tokenAmount) internal returns(uint256) {
        require(_accountHasCollateral(account), "ACOToken::_redeemCollateral: No collateral available");
        require(tokenAmount > 0, "ACOToken::_redeemCollateral: Invalid token amount");
        
        TokenCollateralized storage data = tokenData[account];
        data.amount = data.amount.sub(tokenAmount);
        
        _removeCollateralDataIfNecessary(account);
        
        return _transferCollateral(account, getCollateralAmount(tokenAmount), 0);
    }
    
    /**
     * @dev Internal function to mint tokens.
     * The tokens are minted for the transaction sender.
     * @param account Address of the account.
     * @param collateralAmount Amount of collateral deposited.
     * @return The amount of tokens minted.
     */
    function _mintToken(address account, uint256 collateralAmount) nonReentrant notExpired internal returns(uint256) {
        require(collateralAmount > 0, "ACOToken::_mintToken: Invalid collateral amount");
        
        if (!_accountHasCollateral(account)) {
            tokenData[account].index = _collateralOwners.length;
            _collateralOwners.push(account);
        }
        
        uint256 tokenAmount = getTokenAmount(collateralAmount);
        require(tokenAmount != 0, "ACOToken::_mintToken: Invalid token amount");
        tokenData[account].amount = tokenData[account].amount.add(tokenAmount);
        
        totalCollateral = totalCollateral.add(collateralAmount);
        
        emit CollateralDeposit(account, collateralAmount);
        
        super._mintAction(msg.sender, tokenAmount);
        return tokenAmount;
    }
    
    /**
     * @dev Internal function to transfer collateral. 
     * When there is a fee, the calculated fee is also transferred to the destination fee address.
     * The collateral destination is always the transaction sender address.
     * @param account Address of the account.
     * @param collateralAmount Amount of collateral to be transferred.
     * @param fee Amount of fee charged.
     * @return The amount of collateral transferred.
     */
    function _transferCollateral(address account, uint256 collateralAmount, uint256 fee) internal returns(uint256) {
        
        totalCollateral = totalCollateral.sub(collateralAmount.add(fee));
        
        address _collateral = collateral();
        if (_isEther(_collateral)) {
            payable(msg.sender).transfer(collateralAmount);
            if (fee > 0) {
                feeDestination.transfer(fee);   
            }
        } else {
            _transferERC20(_collateral, msg.sender, collateralAmount);
            if (fee > 0) {
                _transferERC20(_collateral, feeDestination, fee);
            }
        }
        
        emit CollateralWithdraw(account, msg.sender, collateralAmount, fee);
        return collateralAmount;
    }
    
    /**
     * @dev Internal function to exercise the tokens from an account. 
     * @param account Address of the account that is exercising.
     * @param tokenAmount Amount of tokens.
     * @param salt Random number to calculate the start index of the array of accounts to be exercised.
     * @return The amount of collateral transferred.
     */
    function _exercise(address account, uint256 tokenAmount, uint256 salt) nonReentrant internal returns(uint256) {
        _validateAndBurn(account, tokenAmount, maxExercisedAccounts);
         _exerciseOwners(account, tokenAmount, salt);
        (uint256 collateralAmount, uint256 fee) = getCollateralOnExercise(tokenAmount);
        return _transferCollateral(account, collateralAmount, fee);
    }
    
    /**
     * @dev Internal function to exercise the tokens from an account. 
     * @param account Address of the account that is exercising.
     * @param tokenAmount Amount of tokens.
     * @param accounts The array of addresses to get the collateral from.
     * @return The amount of collateral transferred.
     */
    function _exerciseFromAccounts(address account, uint256 tokenAmount, address[] memory accounts) nonReentrant internal returns(uint256) {
        _validateAndBurn(account, tokenAmount, accounts.length);
        _exerciseAccounts(account, tokenAmount, accounts);
        (uint256 collateralAmount, uint256 fee) = getCollateralOnExercise(tokenAmount);
        return _transferCollateral(account, collateralAmount, fee);
    }
    
    /**
     * @dev Internal function to exercise the assignable tokens from the stored list of collateral owners. 
     * @param exerciseAccount Address of the account that is exercising.
     * @param tokenAmount Amount of tokens.
     * @param salt Random number to calculate the start index of the array of accounts to be exercised.
     */
    function _exerciseOwners(address exerciseAccount, uint256 tokenAmount, uint256 salt) internal {
        uint256 accountsExercised = 0;
        uint256 start = salt.mod(_collateralOwners.length);
        uint256 index = start;
        uint256 count = 0;
        while (tokenAmount > 0 && count < _collateralOwners.length) {
            
            uint256 remainingAmount = _exerciseAccount(_collateralOwners[index], tokenAmount, exerciseAccount);
            if (remainingAmount < tokenAmount) {
                accountsExercised++;
                require(accountsExercised < maxExercisedAccounts || remainingAmount == 0, "ACOToken::_exerciseOwners: Too many accounts to exercise");
            }
            tokenAmount = remainingAmount;
            
            ++index;
            if (index == _collateralOwners.length) {
                index = 0;
            }
            ++count;
        }
        require(tokenAmount == 0, "ACOToken::_exerciseOwners: Invalid remaining amount");
        
        uint256 indexOnModifyIteration;
        bool shouldModifyIteration = false;
        if (index == 0) {
            index = _collateralOwners.length;
        } else if (index <= start) {
            indexOnModifyIteration = index - 1;
            shouldModifyIteration = true;
            index = _collateralOwners.length;
        }
            
        for (uint256 i = 0; i < count; ++i) {
            --index;
            if (shouldModifyIteration && index < start) {
                index = indexOnModifyIteration;
                shouldModifyIteration = false;
            }
            _removeCollateralDataIfNecessary(_collateralOwners[index]);
        }
    }
    
    /**
     * @dev Internal function to exercise the assignable tokens from an accounts list. 
     * @param exerciseAccount Address of the account that is exercising.
     * @param tokenAmount Amount of tokens.
     * @param accounts The array of addresses to get the collateral from.
     */
    function _exerciseAccounts(address exerciseAccount, uint256 tokenAmount, address[] memory accounts) internal {
        for (uint256 i = 0; i < accounts.length; ++i) {
            if (tokenAmount == 0) {
                break;
            }
            tokenAmount = _exerciseAccount(accounts[i], tokenAmount, exerciseAccount);
            _removeCollateralDataIfNecessary(accounts[i]);
        }
        require(tokenAmount == 0, "ACOToken::_exerciseAccounts: Invalid remaining amount");
    }
    
    /**
     * @dev Internal function to exercise the assignable tokens from an account and transfer to its address the respective payment. 
     * @param account Address of the account.
     * @param tokenAmount Amount of tokens.
     * @param exerciseAccount Address of the account that is exercising.
     * @return Remaining amount of tokens.
     */
    function _exerciseAccount(address account, uint256 tokenAmount, address exerciseAccount) internal returns(uint256) {
        uint256 available = _getAssignableAmount(account);
        if (available > 0) {
            
            TokenCollateralized storage data = tokenData[account];
            uint256 valueToTransfer;
            if (available < tokenAmount) {
                valueToTransfer = available;
                tokenAmount = tokenAmount.sub(available);
            } else {
                valueToTransfer = tokenAmount;
                tokenAmount = 0;
            }
            
            (address exerciseAsset, uint256 amount) = getBaseExerciseData(valueToTransfer);
            // To guarantee that the minter will be paid.
            amount = amount.add(1);
            
            data.amount = data.amount.sub(valueToTransfer); 
            
            if (_isEther(exerciseAsset)) {
                payable(account).transfer(amount);
            } else {
                _transferERC20(exerciseAsset, account, amount);
            }
            emit Assigned(account, exerciseAccount, amount, valueToTransfer);
        }
        return tokenAmount;
    }
    
    /**
     * @dev Internal function to validate the exercise operation and burn the respective tokens.
     * @param account Address of the account that is exercising.
     * @param tokenAmount Amount of tokens.
     * @param maximumNumberOfAccounts The maximum number of accounts that can be exercised.
     */
    function _validateAndBurn(address account, uint256 tokenAmount, uint256 maximumNumberOfAccounts) notExpired internal {
        require(tokenAmount > 0, "ACOToken::_validateAndBurn: Invalid token amount");
        
        // Whether an account has deposited collateral it only can exercise the extra amount of unassignable tokens.
        if (_accountHasCollateral(account)) {
            require(tokenAmount <= balanceOf(account).sub(tokenData[account].amount), "ACOToken::_validateAndBurn: Token amount not available"); 
        }
        
        _callBurn(account, tokenAmount);
        
        (address exerciseAsset, uint256 expectedAmount) = getBaseExerciseData(tokenAmount);
        expectedAmount = expectedAmount.add(maximumNumberOfAccounts);

        if (_isEther(exerciseAsset)) {
            require(msg.value == expectedAmount, "ACOToken::_validateAndBurn: Invalid ether amount");
        } else {
            require(msg.value == 0, "ACOToken::_validateAndBurn: No ether expected");
            _transferFromERC20(exerciseAsset, msg.sender, address(this), expectedAmount);
        }
    }
    
    /**
     * @dev Internal function to calculate the token strike price relation.
     * @param tokenAmount Amount of tokens.
     * @return Calculated value with strike asset precision.
     */
    function _getTokenStrikePriceRelation(uint256 tokenAmount) internal view returns(uint256) {
        return tokenAmount.mul(strikePrice).div(underlyingPrecision);
    }
    
    /**
     * @dev Internal function to get the collateral sent back from an account.
     * Function to be called when the token IS expired.
     * @param account Address of the account.
     * @return The amount of collateral transferred.
     */
    function _redeem(address account) nonReentrant internal returns(uint256) {
        require(!_notExpired(), "ACOToken::_redeem: Token not expired yet");
        
        uint256 collateralAmount = _redeemCollateral(account, tokenData[account].amount);
        super._burnAction(account, balanceOf(account));
        return collateralAmount;
    }
    
    /**
     * @dev Internal function to burn tokens from an account and get the collateral, not assigned, back.
     * @param account Address of the account.
     * @param tokenAmount Amount of tokens to be burned.
     * @return The amount of collateral transferred.
     */
    function _burn(address account, uint256 tokenAmount) nonReentrant notExpired internal returns(uint256) {
        uint256 collateralAmount = _redeemCollateral(account, tokenAmount);
        _callBurn(account, tokenAmount);
        return collateralAmount;
    }
    
    /**
     * @dev Internal function to burn tokens.
     * @param account Address of the account.
     * @param tokenAmount Amount of tokens to be burned.
     */
    function _callBurn(address account, uint256 tokenAmount) internal {
        if (account == msg.sender) {
            super._burnAction(account, tokenAmount);
        } else {
            super._burnFrom(account, tokenAmount);
        }
    }
    
    /**
     * @dev Internal function to get the amount of assignable token from an account.
     * @param account Address of the account.
     * @return The assignable amount of tokens.
     */
    function _getAssignableAmount(address account) internal view returns(uint256) {
        if (tokenData[account].amount > balanceOf(account)) {
            return tokenData[account].amount.sub(balanceOf(account));
        } else {
            return 0;
        }
    }
    
    /**
     * @dev Internal function to remove the token data with collateral if its total amount was assigned.
     * @param account Address of account.
     */
    function _removeCollateralDataIfNecessary(address account) internal {
        TokenCollateralized storage data = tokenData[account];
        if (!_hasCollateral(data)) {
            uint256 lastIndex = _collateralOwners.length - 1;
            if (lastIndex != data.index) {
                address last = _collateralOwners[lastIndex];
                tokenData[last].index = data.index;
                _collateralOwners[data.index] = last;
            }
            _collateralOwners.pop();
            delete tokenData[account];
        }
    }
    
    /**
     * @dev Internal function to get if the token is not expired.
     * @return Whether the token is NOT expired.
     */
    function _notExpired() internal view returns(bool) {
        return now < expiryTime;
    }
    
    /**
     * @dev Internal function to get if an account has collateral deposited.
     * @param account Address of the account.
     * @return Whether the account has collateral deposited.
     */
    function _accountHasCollateral(address account) internal view returns(bool) {
        return _hasCollateral(tokenData[account]);
    }
    
    /**
     * @dev Internal function to get if an account has collateral deposited.
     * @param data Token data from an account.
     * @return Whether the account has collateral deposited.
     */    
    function _hasCollateral(TokenCollateralized storage data) internal view returns(bool) {
        return data.amount > 0;
    }
    
    /**
     * @dev Internal function to get if the address is for Ethereum (0x0).
     * @param _address Address to be checked.
     * @return Whether the address is for Ethereum.
     */ 
    function _isEther(address _address) internal pure returns(bool) {
        return _address == address(0);
    } 
    
    /**
     * @dev Internal function to get the token name.
     * The token name is assembled  with the token data:
     * ACO UNDERLYING_SYMBOL-STRIKE_PRICE_STRIKE_ASSET_SYMBOL-TYPE-EXPIRYTIME
     * @return The token name.
     */
    function _name() internal view returns(string memory) {
        return string(abi.encodePacked(
            "ACO ",
            underlyingSymbol,
            "-",
            ACONameFormatter.formatNumber(strikePrice, strikeAssetDecimals),
            strikeAssetSymbol,
            "-",
            ACONameFormatter.formatType(isCall),
            "-",
            ACONameFormatter.formatTime(expiryTime)
        ));
    }
    
    /**
     * @dev Internal function to the asset decimals.
     * @param asset Address of the asset.
     * @return The asset decimals.
     */
    function _getAssetDecimals(address asset) internal view returns(uint8) {
        if (_isEther(asset)) {
            return uint8(18);
        } else {
            (bool success, bytes memory returndata) = asset.staticcall(abi.encodeWithSignature("decimals()"));
            require(success, "ACOToken::_getAssetDecimals: Invalid asset decimals");
            return abi.decode(returndata, (uint8));
        }
    }
    
    /**
     * @dev Internal function to the asset symbol.
     * @param asset Address of the asset.
     * @return The asset symbol.
     */
    function _getAssetSymbol(address asset) internal view returns(string memory) {
        if (_isEther(asset)) {
            return "ETH";
        } else {
            (bool success, bytes memory returndata) = asset.staticcall(abi.encodeWithSignature("symbol()"));
            require(success, "ACOToken::_getAssetSymbol: Invalid asset symbol");
            return abi.decode(returndata, (string));
        }
    }
    
    /**
     * @dev Internal function to transfer ERC20 tokens.
     * @param token Address of the token.
     * @param recipient Address of the transfer destination.
     * @param amount Amount to transfer.
     */
     function _transferERC20(address token, address recipient, uint256 amount) internal {
        (bool success, bytes memory returndata) = token.call(abi.encodeWithSelector(_transferSelector, recipient, amount));
        require(success && (returndata.length == 0 || abi.decode(returndata, (bool))), "ACOToken::_transferERC20");
    }
    
    /**
     * @dev Internal function to call transferFrom on ERC20 tokens.
     * @param token Address of the token.
     * @param sender Address of the sender.
     * @param recipient Address of the transfer destination.
     * @param amount Amount to transfer.
     */
     function _transferFromERC20(address token, address sender, address recipient, uint256 amount) internal {
        (bool success, bytes memory returndata) = token.call(abi.encodeWithSelector(_transferFromSelector, sender, recipient, amount));
        require(success && (returndata.length == 0 || abi.decode(returndata, (bool))), "ACOToken::_transferFromERC20");
    }
}

File 2 of 8: ACONameFormatter.sol
pragma solidity ^0.6.6;

import './BokkyPooBahsDateTimeLibrary.sol';
import './Strings.sol';

library ACONameFormatter {
    
    /**
     * @dev Function to get the `value` formatted.
	 * The function returns a string for the `value` with a point (character '.') in the proper position considering the `decimals`.
	 * Beyond that, the string returned presents only representative digits.
	 * For example, a `value` with 18 decimals:
	 *  - For 100000000000000000000 the return is "100"
	 *  - For 100100000000000000000 the return is "100.1"
	 *  - For 100000000000000000 the return is "0.1"
	 *  - For 100000000000000 the return is "0.0001"
	 *  - For 100000000000000000001 the return is "100.000000000000000001"
	 * @param value The number to be formatted.
	 * @param decimals The respective number decimals.
     * @return The value formatted on a string.
     */
    function formatNumber(uint256 value, uint8 decimals) internal pure returns(string memory) {
        uint256 digits;
        uint256 count;
        bool foundRepresentativeDigit = false;
        uint256 addPointAt = 0;
        uint256 temp = value;
        uint256 number = value;
        while (temp != 0) {
            if (!foundRepresentativeDigit && (temp % 10 != 0 || count == uint256(decimals))) {
                foundRepresentativeDigit = true;
                number = temp;
            }
            if (foundRepresentativeDigit) {
                if (count == uint256(decimals)) {
                    addPointAt = digits;
                }
                digits++;
            }
            temp /= 10;
            count++;
        }
        if (count <= uint256(decimals)) {
            digits = digits + 2 + uint256(decimals) - count;
            addPointAt = digits - 2;
        } else if (addPointAt > 0) {
            digits++;
        }
        bytes memory buffer = new bytes(digits);
        uint256 index = digits - 1;
        temp = number;
        for (uint256 i = 0; i < digits; ++i) {
            if (i > 0 && i == addPointAt) {
                buffer[index--] = byte(".");
            } else if (number == 0) {
                buffer[index--] = byte("0");
            } else {
                buffer[index--] = byte(uint8(48 + number % 10));
                number /= 10;
            }
        }
        return string(buffer);
    }
    
    /**
     * @dev Function to get the `unixTime` formatted.
     * @param unixTime The UNIX time to be formatted.
     * @return The unix time formatted on a string.
     */
    function formatTime(uint256 unixTime) internal pure returns(string memory) {
        (uint256 year, uint256 month, uint256 day, uint256 hour, uint256 minute,) = BokkyPooBahsDateTimeLibrary.timestampToDateTime(unixTime); 
        return string(abi.encodePacked(
            _getDateNumberWithTwoCharacters(day),
            _getMonthFormatted(month),
            _getYearFormatted(year),
            "-",
            _getDateNumberWithTwoCharacters(hour),
            _getDateNumberWithTwoCharacters(minute),
            "UTC"
            )); 
    }
    
    /**
     * @dev Function to get the token type description.
     * @return The token type description.
     */
    function formatType(bool isCall) internal pure returns(string memory) {
        if (isCall) {
            return "C";
        } else {
            return "P";
        }
    }
    
    /**
     * @dev Function to get the year formatted with 2 characters.
     * @return The year formatted.
     */
    function _getYearFormatted(uint256 year) private pure returns(string memory) {
        bytes memory yearBytes = bytes(Strings.toString(year));
        bytes memory result = new bytes(2);
        uint256 startIndex = yearBytes.length - 2;
        for (uint256 i = startIndex; i < yearBytes.length; i++) {
            result[i - startIndex] = yearBytes[i];
        }
        return string(result);
    }
    
    /**
     * @dev Function to get the month abbreviation.
     * @return The month abbreviation.
     */
    function _getMonthFormatted(uint256 month) private pure returns(string memory) {
        if (month == 1) {
            return "JAN";
        } else if (month == 2) {
            return "FEB";
        } else if (month == 3) {
            return "MAR";
        } else if (month == 4) {
            return "APR";
        } else if (month == 5) {
            return "MAY";
        } else if (month == 6) {
            return "JUN";
        } else if (month == 7) {
            return "JUL";
        } else if (month == 8) {
            return "AUG";
        } else if (month == 9) {
            return "SEP";
        } else if (month == 10) {
            return "OCT";
        } else if (month == 11) {
            return "NOV";
        } else if (month == 12) {
            return "DEC";
        } else {
            return "INVALID";
        }
    }
    
    /**
     * @dev Function to get the date number with 2 characters.
     * @return The 2 characters for the number.
     */
    function _getDateNumberWithTwoCharacters(uint256 number) private pure returns(string memory) {
        string memory _string = Strings.toString(number);
        if (number < 10) {
            return string(abi.encodePacked("0", _string));
        } else {
            return _string;
        }
    }
}

File 3 of 8: Address.sol
pragma solidity ^0.6.6;

// Contract on https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts

/**
 * @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) {
        // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
        // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
        // for accounts without code, i.e. `keccak256('')`
        bytes32 codehash;
        bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
        // solhint-disable-next-line no-inline-assembly
        assembly { codehash := extcodehash(account) }
        return (codehash != accountHash && codehash != 0x0);
    }

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

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (bool success, ) = recipient.call{ value: amount }("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }
}

File 4 of 8: BokkyPooBahsDateTimeLibrary.sol
pragma solidity ^0.6.6;

// ----------------------------------------------------------------------------
// BokkyPooBah's DateTime Library v1.01
//
// A gas-efficient Solidity date and time library
//
// https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary
//
// Tested date range 1970/01/01 to 2345/12/31
//
// Conventions:
// Unit      | Range         | Notes
// :-------- |:-------------:|:-----
// timestamp | >= 0          | Unix timestamp, number of seconds since 1970/01/01 00:00:00 UTC
// year      | 1970 ... 2345 |
// month     | 1 ... 12      |
// day       | 1 ... 31      |
// hour      | 0 ... 23      |
// minute    | 0 ... 59      |
// second    | 0 ... 59      |
// dayOfWeek | 1 ... 7       | 1 = Monday, ..., 7 = Sunday
//
//
// Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2018-2019. The MIT Licence.
// ----------------------------------------------------------------------------

library BokkyPooBahsDateTimeLibrary {

    uint constant SECONDS_PER_DAY = 24 * 60 * 60;
    uint constant SECONDS_PER_HOUR = 60 * 60;
    uint constant SECONDS_PER_MINUTE = 60;
    int constant OFFSET19700101 = 2440588;

    uint constant DOW_MON = 1;
    uint constant DOW_TUE = 2;
    uint constant DOW_WED = 3;
    uint constant DOW_THU = 4;
    uint constant DOW_FRI = 5;
    uint constant DOW_SAT = 6;
    uint constant DOW_SUN = 7;

    // ------------------------------------------------------------------------
    // Calculate the number of days from 1970/01/01 to year/month/day using
    // the date conversion algorithm from
    //   http://aa.usno.navy.mil/faq/docs/JD_Formula.php
    // and subtracting the offset 2440588 so that 1970/01/01 is day 0
    //
    // days = day
    //      - 32075
    //      + 1461 * (year + 4800 + (month - 14) / 12) / 4
    //      + 367 * (month - 2 - (month - 14) / 12 * 12) / 12
    //      - 3 * ((year + 4900 + (month - 14) / 12) / 100) / 4
    //      - offset
    // ------------------------------------------------------------------------
    function _daysFromDate(uint year, uint month, uint day) internal pure returns (uint _days) {
        require(year >= 1970);
        int _year = int(year);
        int _month = int(month);
        int _day = int(day);

        int __days = _day
          - 32075
          + 1461 * (_year + 4800 + (_month - 14) / 12) / 4
          + 367 * (_month - 2 - (_month - 14) / 12 * 12) / 12
          - 3 * ((_year + 4900 + (_month - 14) / 12) / 100) / 4
          - OFFSET19700101;

        _days = uint(__days);
    }

    // ------------------------------------------------------------------------
    // Calculate year/month/day from the number of days since 1970/01/01 using
    // the date conversion algorithm from
    //   http://aa.usno.navy.mil/faq/docs/JD_Formula.php
    // and adding the offset 2440588 so that 1970/01/01 is day 0
    //
    // int L = days + 68569 + offset
    // int N = 4 * L / 146097
    // L = L - (146097 * N + 3) / 4
    // year = 4000 * (L + 1) / 1461001
    // L = L - 1461 * year / 4 + 31
    // month = 80 * L / 2447
    // dd = L - 2447 * month / 80
    // L = month / 11
    // month = month + 2 - 12 * L
    // year = 100 * (N - 49) + year + L
    // ------------------------------------------------------------------------
    function _daysToDate(uint _days) internal pure returns (uint year, uint month, uint day) {
        int __days = int(_days);

        int L = __days + 68569 + OFFSET19700101;
        int N = 4 * L / 146097;
        L = L - (146097 * N + 3) / 4;
        int _year = 4000 * (L + 1) / 1461001;
        L = L - 1461 * _year / 4 + 31;
        int _month = 80 * L / 2447;
        int _day = L - 2447 * _month / 80;
        L = _month / 11;
        _month = _month + 2 - 12 * L;
        _year = 100 * (N - 49) + _year + L;

        year = uint(_year);
        month = uint(_month);
        day = uint(_day);
    }

    function timestampFromDate(uint year, uint month, uint day) internal pure returns (uint timestamp) {
        timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY;
    }
    function timestampFromDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) internal pure returns (uint timestamp) {
        timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + hour * SECONDS_PER_HOUR + minute * SECONDS_PER_MINUTE + second;
    }
    function timestampToDate(uint timestamp) internal pure returns (uint year, uint month, uint day) {
        (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY);
    }
    function timestampToDateTime(uint timestamp) internal pure returns (uint year, uint month, uint day, uint hour, uint minute, uint second) {
        (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY);
        uint secs = timestamp % SECONDS_PER_DAY;
        hour = secs / SECONDS_PER_HOUR;
        secs = secs % SECONDS_PER_HOUR;
        minute = secs / SECONDS_PER_MINUTE;
        second = secs % SECONDS_PER_MINUTE;
    }

    function isValidDate(uint year, uint month, uint day) internal pure returns (bool valid) {
        if (year >= 1970 && month > 0 && month <= 12) {
            uint daysInMonth = _getDaysInMonth(year, month);
            if (day > 0 && day <= daysInMonth) {
                valid = true;
            }
        }
    }
    function isValidDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) internal pure returns (bool valid) {
        if (isValidDate(year, month, day)) {
            if (hour < 24 && minute < 60 && second < 60) {
                valid = true;
            }
        }
    }
    function isLeapYear(uint timestamp) internal pure returns (bool leapYear) {
        (uint year,,) = _daysToDate(timestamp / SECONDS_PER_DAY);
        leapYear = _isLeapYear(year);
    }
    function _isLeapYear(uint year) internal pure returns (bool leapYear) {
        leapYear = ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
    }
    function isWeekDay(uint timestamp) internal pure returns (bool weekDay) {
        weekDay = getDayOfWeek(timestamp) <= DOW_FRI;
    }
    function isWeekEnd(uint timestamp) internal pure returns (bool weekEnd) {
        weekEnd = getDayOfWeek(timestamp) >= DOW_SAT;
    }
    function getDaysInMonth(uint timestamp) internal pure returns (uint daysInMonth) {
        (uint year, uint month,) = _daysToDate(timestamp / SECONDS_PER_DAY);
        daysInMonth = _getDaysInMonth(year, month);
    }
    function _getDaysInMonth(uint year, uint month) internal pure returns (uint daysInMonth) {
        if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) {
            daysInMonth = 31;
        } else if (month != 2) {
            daysInMonth = 30;
        } else {
            daysInMonth = _isLeapYear(year) ? 29 : 28;
        }
    }
    // 1 = Monday, 7 = Sunday
    function getDayOfWeek(uint timestamp) internal pure returns (uint dayOfWeek) {
        uint _days = timestamp / SECONDS_PER_DAY;
        dayOfWeek = (_days + 3) % 7 + 1;
    }

    function getYear(uint timestamp) internal pure returns (uint year) {
        (year,,) = _daysToDate(timestamp / SECONDS_PER_DAY);
    }
    function getMonth(uint timestamp) internal pure returns (uint month) {
        (,month,) = _daysToDate(timestamp / SECONDS_PER_DAY);
    }
    function getDay(uint timestamp) internal pure returns (uint day) {
        (,,day) = _daysToDate(timestamp / SECONDS_PER_DAY);
    }
    function getHour(uint timestamp) internal pure returns (uint hour) {
        uint secs = timestamp % SECONDS_PER_DAY;
        hour = secs / SECONDS_PER_HOUR;
    }
    function getMinute(uint timestamp) internal pure returns (uint minute) {
        uint secs = timestamp % SECONDS_PER_HOUR;
        minute = secs / SECONDS_PER_MINUTE;
    }
    function getSecond(uint timestamp) internal pure returns (uint second) {
        second = timestamp % SECONDS_PER_MINUTE;
    }

    function addYears(uint timestamp, uint _years) internal pure returns (uint newTimestamp) {
        (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY);
        year += _years;
        uint daysInMonth = _getDaysInMonth(year, month);
        if (day > daysInMonth) {
            day = daysInMonth;
        }
        newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY;
        require(newTimestamp >= timestamp);
    }
    function addMonths(uint timestamp, uint _months) internal pure returns (uint newTimestamp) {
        (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY);
        month += _months;
        year += (month - 1) / 12;
        month = (month - 1) % 12 + 1;
        uint daysInMonth = _getDaysInMonth(year, month);
        if (day > daysInMonth) {
            day = daysInMonth;
        }
        newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY;
        require(newTimestamp >= timestamp);
    }
    function addDays(uint timestamp, uint _days) internal pure returns (uint newTimestamp) {
        newTimestamp = timestamp + _days * SECONDS_PER_DAY;
        require(newTimestamp >= timestamp);
    }
    function addHours(uint timestamp, uint _hours) internal pure returns (uint newTimestamp) {
        newTimestamp = timestamp + _hours * SECONDS_PER_HOUR;
        require(newTimestamp >= timestamp);
    }
    function addMinutes(uint timestamp, uint _minutes) internal pure returns (uint newTimestamp) {
        newTimestamp = timestamp + _minutes * SECONDS_PER_MINUTE;
        require(newTimestamp >= timestamp);
    }
    function addSeconds(uint timestamp, uint _seconds) internal pure returns (uint newTimestamp) {
        newTimestamp = timestamp + _seconds;
        require(newTimestamp >= timestamp);
    }

    function subYears(uint timestamp, uint _years) internal pure returns (uint newTimestamp) {
        (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY);
        year -= _years;
        uint daysInMonth = _getDaysInMonth(year, month);
        if (day > daysInMonth) {
            day = daysInMonth;
        }
        newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY;
        require(newTimestamp <= timestamp);
    }
    function subMonths(uint timestamp, uint _months) internal pure returns (uint newTimestamp) {
        (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY);
        uint yearMonth = year * 12 + (month - 1) - _months;
        year = yearMonth / 12;
        month = yearMonth % 12 + 1;
        uint daysInMonth = _getDaysInMonth(year, month);
        if (day > daysInMonth) {
            day = daysInMonth;
        }
        newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY;
        require(newTimestamp <= timestamp);
    }
    function subDays(uint timestamp, uint _days) internal pure returns (uint newTimestamp) {
        newTimestamp = timestamp - _days * SECONDS_PER_DAY;
        require(newTimestamp <= timestamp);
    }
    function subHours(uint timestamp, uint _hours) internal pure returns (uint newTimestamp) {
        newTimestamp = timestamp - _hours * SECONDS_PER_HOUR;
        require(newTimestamp <= timestamp);
    }
    function subMinutes(uint timestamp, uint _minutes) internal pure returns (uint newTimestamp) {
        newTimestamp = timestamp - _minutes * SECONDS_PER_MINUTE;
        require(newTimestamp <= timestamp);
    }
    function subSeconds(uint timestamp, uint _seconds) internal pure returns (uint newTimestamp) {
        newTimestamp = timestamp - _seconds;
        require(newTimestamp <= timestamp);
    }

    function diffYears(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _years) {
        require(fromTimestamp <= toTimestamp);
        (uint fromYear,,) = _daysToDate(fromTimestamp / SECONDS_PER_DAY);
        (uint toYear,,) = _daysToDate(toTimestamp / SECONDS_PER_DAY);
        _years = toYear - fromYear;
    }
    function diffMonths(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _months) {
        require(fromTimestamp <= toTimestamp);
        (uint fromYear, uint fromMonth,) = _daysToDate(fromTimestamp / SECONDS_PER_DAY);
        (uint toYear, uint toMonth,) = _daysToDate(toTimestamp / SECONDS_PER_DAY);
        _months = toYear * 12 + toMonth - fromYear * 12 - fromMonth;
    }
    function diffDays(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _days) {
        require(fromTimestamp <= toTimestamp);
        _days = (toTimestamp - fromTimestamp) / SECONDS_PER_DAY;
    }
    function diffHours(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _hours) {
        require(fromTimestamp <= toTimestamp);
        _hours = (toTimestamp - fromTimestamp) / SECONDS_PER_HOUR;
    }
    function diffMinutes(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _minutes) {
        require(fromTimestamp <= toTimestamp);
        _minutes = (toTimestamp - fromTimestamp) / SECONDS_PER_MINUTE;
    }
    function diffSeconds(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _seconds) {
        require(fromTimestamp <= toTimestamp);
        _seconds = toTimestamp - fromTimestamp;
    }
}

File 5 of 8: ERC20.sol
pragma solidity ^0.6.6;

import "./SafeMath.sol";
import "./IERC20.sol";

/**
 * @title ERC20
 * @dev Base implementation of ERC20 token.
 */
abstract contract ERC20 is IERC20 {
    using SafeMath for uint256;
    
    uint256 private _totalSupply;
    mapping (address => uint256) private _balances;
    mapping (address => mapping (address => uint256)) private _allowances;

    function name() public view virtual returns(string memory);
    function symbol() public view virtual returns(string memory);
    function decimals() public view virtual returns(uint8);

    function totalSupply() public view override returns(uint256) {
        return _totalSupply;
    }

    function balanceOf(address account) public view override returns(uint256) {
        return _balances[account];
    }

    function allowance(address owner, address spender) public view override returns(uint256) {
        return _allowances[owner][spender];
    }

    function transfer(address recipient, uint256 amount) public override returns(bool) {
        _transfer(msg.sender, recipient, amount);
        return true;
    }

    function transferFrom(address sender, address recipient, uint256 amount) public override returns(bool) {
        _approveAction(sender, msg.sender, _allowances[sender][msg.sender].sub(amount));
        _transfer(sender, recipient, amount);
        return true;
    }

    function approve(address spender, uint256 amount) public override returns(bool) {
        _approve(msg.sender, spender, amount);
        return true;
    }

    function increaseAllowance(address spender, uint256 amount) public returns(bool) {
        _approve(msg.sender, spender, _allowances[msg.sender][spender].add(amount));
        return true;
    }

    function decreaseAllowance(address spender, uint256 amount) public returns(bool) {
        _approve(msg.sender, spender, _allowances[msg.sender][spender].sub(amount));
        return true;
    }
    
    function _transfer(address sender, address recipient, uint256 amount) internal virtual {
        _transferAction(sender, recipient, amount);
    }

    function _approve(address owner, address spender, uint256 amount) internal virtual {
        _approveAction(owner, spender, amount);
    }
    
    function _burnFrom(address account, uint256 amount) internal {
        _approveAction(account, msg.sender, _allowances[account][msg.sender].sub(amount));
        _burnAction(account, amount);
    }

    function _transferAction(address sender, address recipient, uint256 amount) internal {
        require(sender != address(0), "ERC20::_transferAction: Invalid sender");
        require(recipient != address(0), "ERC20::_transferAction: Invalid recipient");

        _balances[sender] = _balances[sender].sub(amount);
        _balances[recipient] = _balances[recipient].add(amount);
        
        emit Transfer(sender, recipient, amount);
    }
    
    function _approveAction(address owner, address spender, uint256 amount) internal {
        require(owner != address(0), "ERC20::_approveAction: Invalid owner");
        require(spender != address(0), "ERC20::_approveAction: Invalid spender");

        _allowances[owner][spender] = amount;
        
        emit Approval(owner, spender, amount);
    }
    
    function _mintAction(address account, uint256 amount) internal {
        require(account != address(0), "ERC20::_mintAction: Invalid account");

        _totalSupply = _totalSupply.add(amount);
        _balances[account] = _balances[account].add(amount);
        
        emit Transfer(address(0), account, amount);
    }

    function _burnAction(address account, uint256 amount) internal {
        require(account != address(0), "ERC20::_burnAction: Invalid account");

        _balances[account] = _balances[account].sub(amount);
        _totalSupply = _totalSupply.sub(amount);
        
        emit Transfer(account, address(0), amount);
    }
}    

File 6 of 8: IERC20.sol
pragma solidity ^0.6.6;

// Contract on https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts

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

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

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

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

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

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

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

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

File 7 of 8: SafeMath.sol
pragma solidity ^0.6.6;

// Contract on https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

File 8 of 8: Strings.sol
pragma solidity ^0.6.6;

// Contract on https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts

/**
 * @dev String operations.
 */
library Strings {
    /**
     * @dev Converts a `uint256` to its ASCII `string` representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        uint256 index = digits - 1;
        temp = value;
        while (temp != 0) {
            buffer[index--] = byte(uint8(48 + temp % 10));
            temp /= 10;
        }
        return string(buffer);
    }
}

Contract Security Audit

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"paidAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"name":"Assigned","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"CollateralDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"CollateralWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenCollateralizedAmount","type":"uint256"}],"name":"TransferCollateralOwnership","type":"event"},{"inputs":[],"name":"acoFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"assignableCollateral","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"assignableTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"name":"burn","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"name":"burnFrom","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"collateral","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"currentCollateral","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"currentCollateralizedTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"internalType":"uint256","name":"salt","type":"uint256"}],"name":"exercise","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"internalType":"address[]","name":"accounts","type":"address[]"}],"name":"exerciseAccounts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"internalType":"address[]","name":"accounts","type":"address[]"}],"name":"exerciseAccountsFrom","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"internalType":"uint256","name":"salt","type":"uint256"}],"name":"exerciseFrom","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"expiryTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeDestination","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"name":"getBaseExerciseData","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"name":"getCollateralAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"name":"getCollateralOnExercise","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"collateralAmount","type":"uint256"}],"name":"getTokenAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_underlying","type":"address"},{"internalType":"address","name":"_strikeAsset","type":"address"},{"internalType":"bool","name":"_isCall","type":"bool"},{"internalType":"uint256","name":"_strikePrice","type":"uint256"},{"internalType":"uint256","name":"_expiryTime","type":"uint256"},{"internalType":"uint256","name":"_acoFee","type":"uint256"},{"internalType":"address payable","name":"_feeDestination","type":"address"},{"internalType":"uint256","name":"_maxExercisedAccounts","type":"uint256"}],"name":"init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isCall","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxExercisedAccounts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"collateralAmount","type":"uint256"}],"name":"mint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mintPayable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"collateralAmount","type":"uint256"}],"name":"mintTo","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"mintToPayable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"numberOfAccountsWithCollateral","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"redeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"redeemFrom","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"strikeAsset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"strikeAssetDecimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"strikeAssetSymbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"strikePrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalCollateral","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"tokenCollateralizedAmount","type":"uint256"}],"name":"transferCollateralOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"unassignableCollateral","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"unassignableTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"underlying","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"underlyingDecimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"underlyingSymbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

608060405234801561001057600080fd5b50614751806100206000396000f3fe6080604052600436106102cd5760003560e01c806379cc679011610175578063a95ad147116100dc578063c52987cf11610095578063d90a730e1161006f578063d90a730e14610b62578063dd62ed3e14610b77578063de53fcd514610bb2578063e503d23914610bc7576102d7565b8063c52987cf14610b05578063c54e486214610b1a578063d8dfeb4514610b4d576102d7565b8063a95ad147146109ea578063b0df1cc714610a61578063bdc7c12b14610a87578063be040fb014610ab1578063c132566114610ac6578063c2507ac114610adb576102d7565b806399bc0aea1161012e57806399bc0aea146108e35780639c83c847146108f8578063a0712d681461092b578063a457c2d714610955578063a86265bb1461098e578063a9059cbb146109b1576102d7565b806379cc67901461075b5780637c974fc41461079457806387ab4a18146108195780638ff1516b1461084c5780639152cb591461087f57806395d89b41146102dc576102d7565b8063449a52f8116102345780634dd662ee116101ed5780636f012b8d116101c75780636f012b8d146106c85780636f307dc31461070b57806370a0823114610720578063732a950d14610753576102d7565b80634dd662ee146106515780635d97d3e2146106665780636d636478146106b3576102d7565b8063449a52f81461054e57806345f79d1b14610587578063464673c6146105ba5780634701eaa8146105f5578063477130981461060a5780634ac8eb5f1461063c576102d7565b806325a760c21161028657806325a760c214610463578063313a9b4e1461048e578063313ce567146104a357806339509351146104b85780633acc3af2146104f157806342966c6814610524576102d7565b806306fdde03146102dc578063095ea7b31461036657806311b7bda7146103b357806317d69bc8146103c857806318160ddd146103f957806323b872dd14610420576102d7565b366102d757600080fd5b600080fd5b3480156102e857600080fd5b506102f1610bfa565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561032b578181015183820152602001610313565b50505050905090810190601f1680156103585780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561037257600080fd5b5061039f6004803603604081101561038957600080fd5b506001600160a01b038135169060200135610c0a565b604080519115158252519081900360200190f35b3480156103bf57600080fd5b506102f1610c21565b3480156103d457600080fd5b506103dd610caf565b604080516001600160a01b039092168252519081900360200190f35b34801561040557600080fd5b5061040e610cbe565b60408051918252519081900360200190f35b34801561042c57600080fd5b5061039f6004803603606081101561044357600080fd5b506001600160a01b03813581169160208101359091169060400135610cc4565b34801561046f57600080fd5b50610478610d18565b6040805160ff9092168252519081900360200190f35b34801561049a57600080fd5b5061040e610d21565b3480156104af57600080fd5b50610478610d27565b3480156104c457600080fd5b5061039f600480360360408110156104db57600080fd5b506001600160a01b038135169060200135610d30565b3480156104fd57600080fd5b5061040e6004803603602081101561051457600080fd5b50356001600160a01b0316610d71565b34801561053057600080fd5b5061040e6004803603602081101561054757600080fd5b5035610d8c565b34801561055a57600080fd5b5061040e6004803603604081101561057157600080fd5b506001600160a01b038135169060200135610d98565b34801561059357600080fd5b5061040e600480360360208110156105aa57600080fd5b50356001600160a01b0316610e1e565b3480156105c657600080fd5b506105f3600480360360408110156105dd57600080fd5b506001600160a01b038135169060200135610e39565b005b34801561060157600080fd5b5061040e610fe5565b61040e6004803603606081101561062057600080fd5b506001600160a01b038135169060208101359060400135610feb565b34801561064857600080fd5b5061040e610ff8565b34801561065d57600080fd5b5061040e610ffe565b34801561067257600080fd5b506106906004803603602081101561068957600080fd5b5035611004565b604080516001600160a01b03909316835260208301919091528051918290030190f35b3480156106bf57600080fd5b5061039f61104e565b3480156106d457600080fd5b506106f2600480360360208110156106eb57600080fd5b503561105e565b6040805192835260208301919091528051918290030190f35b34801561071757600080fd5b506103dd6110b4565b34801561072c57600080fd5b5061040e6004803603602081101561074357600080fd5b50356001600160a01b03166110c3565b61040e6110de565b34801561076757600080fd5b5061040e6004803603604081101561077e57600080fd5b506001600160a01b038135169060200135611135565b61040e600480360360608110156107aa57600080fd5b6001600160a01b03823516916020810135918101906060810160408201356401000000008111156107da57600080fd5b8201836020820111156107ec57600080fd5b8035906020019184602083028401116401000000008311171561080e57600080fd5b509092509050611148565b34801561082557600080fd5b5061040e6004803603602081101561083c57600080fd5b50356001600160a01b0316611191565b34801561085857600080fd5b5061040e6004803603602081101561086f57600080fd5b50356001600160a01b03166111b8565b34801561088b57600080fd5b506105f360048036036101008110156108a357600080fd5b506001600160a01b0381358116916020810135821691604082013515159160608101359160808201359160a08101359160c0820135169060e001356111c6565b3480156108ef57600080fd5b5061040e61164c565b34801561090457600080fd5b5061040e6004803603602081101561091b57600080fd5b50356001600160a01b0316611652565b34801561093757600080fd5b5061040e6004803603602081101561094e57600080fd5b5035611660565b34801561096157600080fd5b5061039f6004803603604081101561097857600080fd5b506001600160a01b0381351690602001356116de565b61040e600480360360408110156109a457600080fd5b508035906020013561171a565b3480156109bd57600080fd5b5061039f600480360360408110156109d457600080fd5b506001600160a01b038135169060200135611727565b61040e60048036036040811015610a0057600080fd5b81359190810190604081016020820135640100000000811115610a2257600080fd5b820183602082011115610a3457600080fd5b80359060200191846020830284011164010000000083111715610a5657600080fd5b509092509050611734565b61040e60048036036020811015610a7757600080fd5b50356001600160a01b0316611774565b348015610a9357600080fd5b5061040e60048036036020811015610aaa57600080fd5b50356117c6565b348015610abd57600080fd5b5061040e6117f1565b348015610ad257600080fd5b506104786117fc565b348015610ae757600080fd5b5061040e60048036036020811015610afe57600080fd5b503561180a565b348015610b1157600080fd5b5061040e611847565b348015610b2657600080fd5b5061040e60048036036020811015610b3d57600080fd5b50356001600160a01b031661184d565b348015610b5957600080fd5b506103dd6118b8565b348015610b6e57600080fd5b506102f16118f1565b348015610b8357600080fd5b5061040e60048036036040811015610b9a57600080fd5b506001600160a01b038135811691602001351661194c565b348015610bbe57600080fd5b506103dd611977565b348015610bd357600080fd5b5061040e60048036036020811015610bea57600080fd5b50356001600160a01b0316611986565b6060610c046119e6565b90505b90565b6000610c17338484611c17565b5060015b92915050565b600b805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610ca75780601f10610c7c57610100808354040283529160200191610ca7565b820191906000526020600020905b815481529060010190602001808311610c8a57829003601f168201915b505050505081565b6004546001600160a01b031681565b60005490565b6001600160a01b0383166000908152600260209081526040808320338085529252822054610d03918691610cfe908663ffffffff611c2716565b611c69565b610d0e848484611d55565b5060019392505050565b600c5460ff1681565b600d5481565b600c5460ff1690565b3360008181526002602090815260408083206001600160a01b03871684529091528120549091610c17918590610d6c908663ffffffff611d6016565b611c17565b6000610d84610d7f83611191565b6117c6565b90505b919050565b6000610d843383611dba565b600080610da36118b8565b9050610dae81611e8c565b15610e00576040805162461bcd60e51b815260206004820152601e60248201527f41434f546f6b656e3a3a6d696e74546f3a20496e76616c69642063616c6c0000604482015290519081900360640190fd5b610e0c81333086611e99565b610e168484612022565b949350505050565b6001600160a01b03166000908152600f602052604090205490565b6001600160a01b038216610e7e5760405162461bcd60e51b81526004018080602001828103825260388152602001806143426038913960400191505060405180910390fd5b60008111610ebd5760405162461bcd60e51b81526004018080602001828103825260358152602001806144a96035913960400191505060405180910390fd5b336000908152600f602052604090208054610ede908363ffffffff611c2716565b8155610ee93361225d565b6001600160a01b0383166000908152600f60205260409020610f0a8161236d565b15610f28578054610f21908463ffffffff611d6016565b8155610f9f565b6040805180820182528481526010805460208084019182526001600160a01b0389166000818152600f90925294812093518455905160019384015581549283018255527f1b6847dc741a1b0cd08d278845f9d819d87b734759afb55fe2de5cb82a9ae6720180546001600160a01b03191690911790555b6040805184815290516001600160a01b0386169133917ff268b386023666001c794e23f1bc2285c15f9ae8db3025abbc16bf45edc6d08d9181900360200190a350505050565b60095481565b6000610e16848484612373565b60085481565b60105490565b6005546000908190600160a01b900460ff1615611039576004546001600160a01b031661103084612419565b91509150611049565b50506003546001600160a01b0316815b915091565b600554600160a01b900460ff1681565b600080600061106c846117c6565b90506000611098620186a061108c6009548561243690919063ffffffff16565b9063ffffffff61248f16565b90506110aa828263ffffffff611c2716565b9350915050915091565b6003546001600160a01b031681565b6001600160a01b031660009081526001602052604090205490565b60006110f06110eb6118b8565b611e8c565b61112b5760405162461bcd60e51b81526004018080602001828103825260238152602001806145d36023913960400191505060405180910390fd5b610c043334612022565b60006111418383611dba565b9392505050565b600061118885858585808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506124d192505050565b95945050505050565b600061119b612543565b156111b0576111a98261254b565b9050610d87565b506000610d87565b6000610d84610d7f83610e1e565b6003546001600160a01b03161580156111e857506004546001600160a01b0316155b80156111f45750600654155b61122f5760405162461bcd60e51b815260040180806020018281038252602381526020018061464f6023913960400191505060405180910390fd5b428411611283576040805162461bcd60e51b815260206004820152601e60248201527f41434f546f6b656e3a3a696e69743a20496e76616c6964206578706972790000604482015290519081900360640190fd5b600085116112c25760405162461bcd60e51b815260040180806020018281038252602481526020018061439d6024913960400191505060405180910390fd5b866001600160a01b0316886001600160a01b03161415611329576040805162461bcd60e51b815260206004820152601b60248201527f41434f546f6b656e3a3a696e69743a2053616d65206173736574730000000000604482015290519081900360640190fd5b6101f4831115611380576040805162461bcd60e51b815260206004820152601f60248201527f41434f546f6b656e3a3a696e69743a20496e76616c69642041434f2066656500604482015290519081900360640190fd5b61138988611e8c565b806113a157506113a1886001600160a01b03166125a6565b6113dc5760405162461bcd60e51b81526004018080602001828103825260228152602001806141e66022913960400191505060405180910390fd5b6113e587611e8c565b806113fd57506113fd876001600160a01b03166125a6565b6114385760405162461bcd60e51b81526004018080602001828103825260248152602001806145f66024913960400191505060405180910390fd5b6019811015801561144a575060968111155b6114855760405162461bcd60e51b815260040180806020018281038252603881526020018061430a6038913960400191505060405180910390fd5b600380546001600160a01b03199081166001600160a01b038b8116919091179092556004805482168a84161790556005805460068990556007889055600987905560ff60a01b1916600160a01b8a15150217909116918416919091179055600d8190556114f1886125df565b600c805460ff191660ff9283161790819055604e9116106115435760405162461bcd60e51b815260040180806020018281038252602b815260200180614237602b913960400191505060405180910390fd5b61154c876125df565b600c60016101000a81548160ff021916908360ff16021790555061156f88612724565b805161158391600a916020909101906140e7565b5061158d87612724565b80516115a191600b916020909101906140e7565b50600c5460ff16600a0a600e55604080518082018252601981527f7472616e7366657228616464726573732c75696e7432353629000000000000006020918201526011805464ffffffff00191664a9059cbb001790558151606081019092526025808352906142629083013980516020909101206011805460ff1960e09390931c650100000000000268ffffffff000000000019909116179190911660011790555050505050505050565b60075481565b6000610d84610d7f83611986565b60008061166b6118b8565b905061167681611e8c565b156116c8576040805162461bcd60e51b815260206004820152601c60248201527f41434f546f6b656e3a3a6d696e743a20496e76616c69642063616c6c00000000604482015290519081900360640190fd5b6116d481333086611e99565b6111413384612022565b3360008181526002602090815260408083206001600160a01b03871684529091528120549091610c17918590610d6c908663ffffffff611c2716565b6000611141338484612373565b6000610c17338484611d55565b6000610e1633858585808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506124d192505050565b60006117816110eb6118b8565b6117bc5760405162461bcd60e51b81526004018080602001828103825260258152602001806142bb6025913960400191505060405180910390fd5b610d848234612022565b600554600090600160a01b900460ff16156117e2575080610d87565b81156111b0576111a982612419565b6000610c043361292e565b600c54610100900460ff1681565b600554600090600160a01b900460ff1615611826575080610d87565b81156111b0576111a960065461108c600e548561243690919063ffffffff16565b60065481565b6000611859823361194c565b6001600160a01b0383166000908152600f602052604090205411156118af5760405162461bcd60e51b81526004018080602001828103825260278152602001806145ac6027913960400191505060405180910390fd5b610d848261292e565b600554600090600160a01b900460ff16156118df57506003546001600160a01b0316610c07565b506004546001600160a01b0316610c07565b600a805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610ca75780601f10610c7c57610100808354040283529160200191610ca7565b6001600160a01b03918216600090815260026020908152604080832093909416825291909152205490565b6005546001600160a01b031681565b6001600160a01b0381166000908152600f60205260408120546119a8836110c3565b11806119b957506119b7612543565b155b156119dd57506001600160a01b0381166000908152600f6020526040902054610d87565b6111a9826110c3565b6060600a611a05600654600c60019054906101000a900460ff16612a16565b600554600b90611a1e90600160a01b900460ff16612bbe565b611a29600754612c02565b604051602001808063020a1a7960e51b81525060040186805460018160011615610100020316600290048015611a965780601f10611a74576101008083540402835291820191611a96565b820191906000526020600020905b815481529060010190602001808311611a82575b505080602d60f81b81525060010185805190602001908083835b60208310611acf5780518252601f199092019160209182019101611ab0565b6001836020036101000a03801982511681845116808217855250505050505090500184805460018160011615610100020316600290048015611b485780601f10611b26576101008083540402835291820191611b48565b820191906000526020600020905b815481529060010190602001808311611b34575b505080602d60f81b81525060010183805190602001908083835b60208310611b815780518252601f199092019160209182019101611b62565b6001836020036101000a03801982511681845116808217855250505050505090500180602d60f81b81525060010182805190602001908083835b60208310611bda5780518252601f199092019160209182019101611bbb565b6001836020036101000a03801982511681845116808217855250505050505090500195505050505050604051602081830303815290604052905090565b611c22838383611c69565b505050565b600061114183836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612e00565b6001600160a01b038316611cae5760405162461bcd60e51b81526004018080602001828103825260248152602001806146c76024913960400191505060405180910390fd5b6001600160a01b038216611cf35760405162461bcd60e51b81526004018080602001828103825260268152602001806145566026913960400191505060405180910390fd5b6001600160a01b03808416600081815260026020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b611c22838383612e97565b600082820183811015611141576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b60115460009060ff16611e08576040805162461bcd60e51b815260206004820152601160248201527041434f546f6b656e3a3a5265656e74727960781b604482015290519081900360640190fd5b6011805460ff19169055611e1a612543565b611e5f576040805162461bcd60e51b81526020600482015260116024820152701050d3d51bdad95b8e8e915e1c1a5c9959607a1b604482015290519081900360640190fd5b6000611e6b8484612fdb565b9050611e7784846130a9565b90506011805460ff1916600117905592915050565b6001600160a01b03161590565b601154604080516001600160a01b0386811660248301528581166044830152606480830186905283518084039091018152608490920183526020820180516501000000000090950460e01b6001600160e01b0319166001600160e01b03909516949094178452915181516000946060948a169392918291908083835b60208310611f345780518252601f199092019160209182019101611f15565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114611f96576040519150601f19603f3d011682016040523d82523d6000602084013e611f9b565b606091505b5091509150818015611fc9575080511580611fc95750808060200190516020811015611fc657600080fd5b50515b61201a576040805162461bcd60e51b815260206004820152601c60248201527f41434f546f6b656e3a3a5f7472616e7366657246726f6d455243323000000000604482015290519081900360640190fd5b505050505050565b60115460009060ff16612070576040805162461bcd60e51b815260206004820152601160248201527041434f546f6b656e3a3a5265656e74727960781b604482015290519081900360640190fd5b6011805460ff19169055612082612543565b6120c7576040805162461bcd60e51b81526020600482015260116024820152701050d3d51bdad95b8e8e915e1c1a5c9959607a1b604482015290519081900360640190fd5b600082116121065760405162461bcd60e51b815260040180806020018281038252602f815260200180614208602f913960400191505060405180910390fd5b61210f836130d3565b61217357601080546001600160a01b0385166000818152600f60205260408120600190810184905583018455929092527f1b6847dc741a1b0cd08d278845f9d819d87b734759afb55fe2de5cb82a9ae6720180546001600160a01b03191690911790555b600061217e8361180a565b9050806121bc5760405162461bcd60e51b815260040180806020018281038252602a8152602001806142e0602a913960400191505060405180910390fd5b6001600160a01b0384166000908152600f60205260409020546121e5908263ffffffff611d6016565b6001600160a01b0385166000908152600f6020526040902055600854612211908463ffffffff611d6016565b6008556040805184815290516001600160a01b038616917ff645c19720906ca336d36d26058a9489c6c757fe35843b75a74e3b8aa972ecf5919081900360200190a2611e7733826130f4565b6001600160a01b0381166000908152600f6020526040902061227e8161236d565b61236957601054600182015460001990910190811461231b576000601082815481106122a657fe5b60009182526020808320909101546001868101546001600160a01b03909216808552600f9093526040909320909201829055601080549193508392909181106122eb57fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550505b601080548061232657fe5b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b0385168252600f90526040812081815560010155505b5050565b54151590565b60115460009060ff166123c1576040805162461bcd60e51b815260206004820152601160248201527041434f546f6b656e3a3a5265656e74727960781b604482015290519081900360640190fd5b6011805460ff19169055600d546123db90859085906131cf565b6123e68484846133a7565b6000806123f28561105e565b91509150612401868383613552565b925050506011805460ff191660011790559392505050565b6000610d84600e5461108c6006548561243690919063ffffffff16565b60008261244557506000610c1b565b8282028284828161245257fe5b04146111415760405162461bcd60e51b81526004018080602001828103825260218152602001806144586021913960400191505060405180910390fd5b600061114183836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613682565b60115460009060ff1661251f576040805162461bcd60e51b815260206004820152601160248201527041434f546f6b656e3a3a5265656e74727960781b604482015290519081900360640190fd5b6011805460ff19169055815161253890859085906131cf565b6123e68484846136e7565b600754421090565b6000612556826110c3565b6001600160a01b0383166000908152600f602052604090205411156111b0576111a9612581836110c3565b6001600160a01b0384166000908152600f60205260409020549063ffffffff611c2716565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590610e16575050151592915050565b60006125ea82611e8c565b156125f757506012610d87565b60408051600481526024810182526020810180516001600160e01b031663313ce56760e01b178152915181516000936060936001600160a01b038816939092909182918083835b6020831061265d5780518252601f19909201916020918201910161263e565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d80600081146126bd576040519150601f19603f3d011682016040523d82523d6000602084013e6126c2565b606091505b5091509150816127035760405162461bcd60e51b81526004018080602001828103825260338152602001806141b36033913960400191505060405180910390fd5b80806020019051602081101561271857600080fd5b50519250610d87915050565b606061272f82611e8c565b15612754575060408051808201909152600381526208aa8960eb1b6020820152610d87565b60408051600481526024810182526020810180516001600160e01b03166395d89b4160e01b178152915181516000936060936001600160a01b038816939092909182918083835b602083106127ba5780518252601f19909201916020918201910161279b565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d806000811461281a576040519150601f19603f3d011682016040523d82523d6000602084013e61281f565b606091505b5091509150816128605760405162461bcd60e51b815260040180806020018281038252602f815260200180614672602f913960400191505060405180910390fd5b80806020019051602081101561287557600080fd5b810190808051604051939291908464010000000082111561289557600080fd5b9083019060208201858111156128aa57600080fd5b82516401000000008111828201881017156128c457600080fd5b82525081516020918201929091019080838360005b838110156128f15781810151838201526020016128d9565b50505050905090810190601f16801561291e5780820380516001836020036101000a031916815260200191505b5060405250505092505050610d87565b60115460009060ff1661297c576040805162461bcd60e51b815260206004820152601160248201527041434f546f6b656e3a3a5265656e74727960781b604482015290519081900360640190fd5b6011805460ff1916905561298e612543565b156129ca5760405162461bcd60e51b815260040180806020018281038252602881526020018061452e6028913960400191505060405180910390fd5b6001600160a01b0382166000908152600f60205260408120546129ee908490612fdb565b9050612a02836129fd856110c3565b61377f565b90506011805460ff19166001179055919050565b6060600080808086805b8115612a7b5783158015612a425750600a8206151580612a4257508760ff1685145b15612a4e575060019250805b8315612a6a578760ff16851415612a63578592505b6001909501945b600a82600190960195049150612a20565b8760ff168511612a9d57848860ff168760020101039550600286039250612aaa565b8215612aaa576001909501945b60608667ffffffffffffffff81118015612ac357600080fd5b506040519080825280601f01601f191660200182016040528015612aee576020820181803683370190505b5091925082919050600019870160005b88811015612bae57600081118015612b1557508581145b15612b4e57601760f91b83838060019003945081518110612b3257fe5b60200101906001600160f81b031916908160001a905350612ba6565b83612b6b57600360fc1b83838060019003945081518110612b3257fe5b600a840660300160f81b83838060019003945081518110612b8857fe5b60200101906001600160f81b031916908160001a905350600a840493505b600101612afe565b50909a9950505050505050505050565b60608115612be457506040805180820190915260018152604360f81b6020820152610d87565b506040805180820190915260018152600560fc1b6020820152610d87565b60606000806000806000612c1587613862565b5094509450945094509450612c29836138a2565b612c3285613934565b612c3b87613b46565b612c44856138a2565b612c4d856138a2565b6040516020018086805190602001908083835b60208310612c7f5780518252601f199092019160209182019101612c60565b51815160209384036101000a600019018019909216911617905288519190930192880191508083835b60208310612cc75780518252601f199092019160209182019101612ca8565b51815160209384036101000a600019018019909216911617905287519190930192870191508083835b60208310612d0f5780518252601f199092019160209182019101612cf0565b6001836020036101000a03801982511681845116808217855250505050505090500180602d60f81b81525060010183805190602001908083835b60208310612d685780518252601f199092019160209182019101612d49565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b60208310612db05780518252601f199092019160209182019101612d91565b5181516020939093036101000a60001901801990911692169190911790526255544360e81b92019182525060408051808303601c19018152600390920190529d9c50505050505050505050505050565b60008184841115612e8f5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015612e54578181015183820152602001612e3c565b50505050905090810190601f168015612e815780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6001600160a01b038316612edc5760405162461bcd60e51b81526004018080602001828103825260268152602001806146a16026913960400191505060405180910390fd5b6001600160a01b038216612f215760405162461bcd60e51b81526004018080602001828103825260298152602001806143f96029913960400191505060405180910390fd5b6001600160a01b038316600090815260016020526040902054612f4a908263ffffffff611c2716565b6001600160a01b038085166000908152600160205260408082209390935590841681522054612f7f908263ffffffff611d6016565b6001600160a01b0380841660008181526001602090815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b6000612fe6836130d3565b6130215760405162461bcd60e51b81526004018080602001828103825260348152602001806142876034913960400191505060405180910390fd5b600082116130605760405162461bcd60e51b81526004018080602001828103825260318152602001806146eb6031913960400191505060405180910390fd5b6001600160a01b0383166000908152600f60205260409020805461308a908463ffffffff611c2716565b81556130958461225d565b610e16846130a2856117c6565b6000613552565b6001600160a01b0382163314156130c9576130c4828261377f565b612369565b6123698282613bd6565b6001600160a01b0381166000908152600f60205260408120610d849061236d565b6001600160a01b0382166131395760405162461bcd60e51b81526004018080602001828103825260238152602001806144de6023913960400191505060405180910390fd5b60005461314c908263ffffffff611d6016565b60009081556001600160a01b038316815260016020526040902054613177908263ffffffff611d6016565b6001600160a01b03831660008181526001602090815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b6131d7612543565b61321c576040805162461bcd60e51b81526020600482015260116024820152701050d3d51bdad95b8e8e915e1c1a5c9959607a1b604482015290519081900360640190fd5b6000821161325b5760405162461bcd60e51b81526004018080602001828103825260308152602001806144796030913960400191505060405180910390fd5b613264836130d3565b156132d9576001600160a01b0383166000908152600f602052604090205461329b9061328f856110c3565b9063ffffffff611c2716565b8211156132d95760405162461bcd60e51b81526004018080602001828103825260368152602001806144226036913960400191505060405180910390fd5b6132e383836130a9565b6000806132ef84611004565b9092509050613304818463ffffffff611d6016565b905061330f82611e8c565b15613357578034146133525760405162461bcd60e51b815260040180806020018281038252603081526020018061457c6030913960400191505060405180910390fd5b6133a0565b34156133945760405162461bcd60e51b815260040180806020018281038252602d815260200180614501602d913960400191505060405180910390fd5b6133a082333084611e99565b5050505050565b60105460009081906133c090849063ffffffff613c1b16565b90508060005b6000861180156133d7575060105481105b1561348657600061340a601084815481106133ee57fe5b6000918252602090912001546001600160a01b0316888a613c5d565b90508681101561346357600d54600190950194851080613428575080155b6134635760405162461bcd60e51b81526004018080602001828103825260388152602001806143c16038913960400191505060405180910390fd5b601054909650600190920191869083141561347d57600092505b506001016133c6565b85156134c35760405162461bcd60e51b81526004018080602001828103825260338152602001806141806033913960400191505060405180910390fd5b600080836134d55760105493506134e9565b8484116134e9575050601054916000190160015b60005b83811015613546576000199094019381801561350757508585105b1561351457829450600091505b61353e6010868154811061352457fe5b6000918252602090912001546001600160a01b031661225d565b6001016134ec565b50505050505050505050565b6000613576613567848463ffffffff611d6016565b6008549063ffffffff611c2716565b60085560006135836118b8565b905061358e81611e8c565b1561360857604051339085156108fc029086906000818181858888f193505050501580156135c0573d6000803e3d6000fd5b508215613603576005546040516001600160a01b039091169084156108fc029085906000818181858888f19350505050158015613601573d6000803e3d6000fd5b505b613631565b613613813386613d9f565b8215613631576005546136319082906001600160a01b031685613d9f565b6040805185815260208101859052815133926001600160a01b038916927fd3506bcc260407a7f95f487dd7c600bc45888cce58989ceadbe8c0bbf9257b28929081900390910190a350919392505050565b600081836136d15760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315612e54578181015183820152602001612e3c565b5060008385816136dd57fe5b0495945050505050565b60005b815181101561374157826136fd57613741565b61371b82828151811061370c57fe5b60200260200101518486613c5d565b925061373982828151811061372c57fe5b602002602001015161225d565b6001016136ea565b508115611c225760405162461bcd60e51b815260040180806020018281038252603581526020018061461a6035913960400191505060405180910390fd5b6001600160a01b0382166137c45760405162461bcd60e51b815260040180806020018281038252602381526020018061437a6023913960400191505060405180910390fd5b6001600160a01b0382166000908152600160205260409020546137ed908263ffffffff611c2716565b6001600160a01b0383166000908152600160205260408120919091555461381a908263ffffffff611c2716565b60009081556040805183815290516001600160a01b038516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef919081900360200190a35050565b60008080808080613877620151808804613f14565b91999098919750610e10620151809092068281049750603c9290068281049650919091069350915050565b6060806138ae83613faa565b9050600a8310156111a957806040516020018080600360fc1b81525060010182805190602001908083835b602083106138f85780518252601f1990920191602091820191016138d9565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051602081830303815290604052915050610d87565b6060816001141561395f57506040805180820190915260038152622520a760e91b6020820152610d87565b816002141561398857506040805180820190915260038152622322a160e91b6020820152610d87565b81600314156139b1575060408051808201909152600381526226a0a960e91b6020820152610d87565b81600414156139da575060408051808201909152600381526220a82960e91b6020820152610d87565b8160051415613a0357506040805180820190915260038152624d415960e81b6020820152610d87565b8160061415613a2c5750604080518082019091526003815262252aa760e91b6020820152610d87565b8160071415613a55575060408051808201909152600381526212955360ea1b6020820152610d87565b8160081415613a7e575060408051808201909152600381526241554760e81b6020820152610d87565b8160091415613aa7575060408051808201909152600381526205345560ec1b6020820152610d87565b81600a1415613ad0575060408051808201909152600381526213d0d560ea1b6020820152610d87565b81600b1415613af957506040805180820190915260038152622727ab60e91b6020820152610d87565b81600c1415613b22575060408051808201909152600381526244454360e81b6020820152610d87565b506040805180820190915260078152661253959053125160ca1b6020820152610d87565b606080613b5283613faa565b60408051600280825281830190925291925060609190602082018180368337505083519192505060011901805b8351811015613bcc57838181518110613b9457fe5b602001015160f81c60f81b8383830381518110613bad57fe5b60200101906001600160f81b031916908160001a905350600101613b7f565b5090949350505050565b6001600160a01b038216600090815260026020908152604080832033808552925290912054613c11918491610cfe908563ffffffff611c2716565b612369828261377f565b600061114183836040518060400160405280601881526020017f536166654d6174683a206d6f64756c6f206279207a65726f0000000000000000815250614085565b600080613c698561254b565b90508015613d96576001600160a01b0385166000908152600f602052604081209085831015613cab575081613ca4868263ffffffff611c2716565b9550613cb0565b506000945b600080613cbc83611004565b9092509050613cd281600163ffffffff611d6016565b8454909150613ce7908463ffffffff611c2716565b8455613cf282611e8c565b15613d33576040516001600160a01b038a169082156108fc029083906000818181858888f19350505050158015613d2d573d6000803e3d6000fd5b50613d3e565b613d3e828a83613d9f565b866001600160a01b0316896001600160a01b03167f5f283076724262032199f54be27a9364634b895b3a37c1e66bfe47d5d05347698386604051808381526020018281526020019250505060405180910390a3505050505b50919392505050565b601154604080516001600160a01b0385811660248301526044808301869052835180840390910181526064909201835260208201805161010090950460e01b6001600160e01b0319166001600160e01b039095169490941784529151815160009460609489169392918291908083835b60208310613e2e5780518252601f199092019160209182019101613e0f565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114613e90576040519150601f19603f3d011682016040523d82523d6000602084013e613e95565b606091505b5091509150818015613ec3575080511580613ec35750808060200190516020811015613ec057600080fd5b50515b6133a0576040805162461bcd60e51b815260206004820152601860248201527f41434f546f6b656e3a3a5f7472616e7366657245524332300000000000000000604482015290519081900360640190fd5b60008080836226496581018262023ab1600483020590506004600362023ab18302010590910390600062164b09610fa0600185010205905060046105b58202058303601f019250600061098f8460500281613f6b57fe5b0590506000605061098f83020585039050600b820560301994909401606402929092018301996002600c90940290910392909201975095509350505050565b606081613fcf57506040805180820190915260018152600360fc1b6020820152610d87565b8160005b8115613fe757600101600a82049150613fd3565b60608167ffffffffffffffff8111801561400057600080fd5b506040519080825280601f01601f19166020018201604052801561402b576020820181803683370190505b50859350905060001982015b831561407c57600a840660300160f81b8282806001900393508151811061405a57fe5b60200101906001600160f81b031916908160001a905350600a84049350614037565b50949350505050565b600081836140d45760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315612e54578181015183820152602001612e3c565b508284816140de57fe5b06949350505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061412857805160ff1916838001178555614155565b82800160010185558215614155579182015b8281111561415557825182559160200191906001019061413a565b50614161929150614165565b5090565b610c0791905b80821115614161576000815560010161416b56fe41434f546f6b656e3a3a5f65786572636973654f776e6572733a20496e76616c69642072656d61696e696e6720616d6f756e7441434f546f6b656e3a3a5f6765744173736574446563696d616c733a20496e76616c696420617373657420646563696d616c7341434f546f6b656e3a3a696e69743a20496e76616c696420756e6465726c79696e6741434f546f6b656e3a3a5f6d696e74546f6b656e3a20496e76616c696420636f6c6c61746572616c20616d6f756e7441434f546f6b656e3a3a696e69743a20496e76616c696420756e6465726c79696e6720646563696d616c737472616e7366657246726f6d28616464726573732c616464726573732c75696e743235362941434f546f6b656e3a3a5f72656465656d436f6c6c61746572616c3a204e6f20636f6c6c61746572616c20617661696c61626c6541434f546f6b656e3a3a6d696e74546f50617961626c653a20496e76616c69642063616c6c41434f546f6b656e3a3a5f6d696e74546f6b656e3a20496e76616c696420746f6b656e20616d6f756e7441434f546f6b656e3a3a696e69743a20496e76616c6964206e756d62657220746f206d617820657865726369736564206163636f756e747341434f546f6b656e3a3a7472616e73666572436f6c6c61746572616c4f776e6572736869703a20496e76616c696420726563697069656e7445524332303a3a5f6275726e416374696f6e3a20496e76616c6964206163636f756e7441434f546f6b656e3a3a696e69743a20496e76616c696420737472696b6520707269636541434f546f6b656e3a3a5f65786572636973654f776e6572733a20546f6f206d616e79206163636f756e747320746f20657865726369736545524332303a3a5f7472616e73666572416374696f6e3a20496e76616c696420726563697069656e7441434f546f6b656e3a3a5f76616c6964617465416e644275726e3a20546f6b656e20616d6f756e74206e6f7420617661696c61626c65536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7741434f546f6b656e3a3a5f76616c6964617465416e644275726e3a20496e76616c696420746f6b656e20616d6f756e7441434f546f6b656e3a3a7472616e73666572436f6c6c61746572616c4f776e6572736869703a20496e76616c696420616d6f756e7445524332303a3a5f6d696e74416374696f6e3a20496e76616c6964206163636f756e7441434f546f6b656e3a3a5f76616c6964617465416e644275726e3a204e6f20657468657220657870656374656441434f546f6b656e3a3a5f72656465656d3a20546f6b656e206e6f7420657870697265642079657445524332303a3a5f617070726f7665416374696f6e3a20496e76616c6964207370656e64657241434f546f6b656e3a3a5f76616c6964617465416e644275726e3a20496e76616c696420657468657220616d6f756e7441434f546f6b656e3a3a72656465656d46726f6d3a20416c6c6f77616e636520746f6f206c6f7741434f546f6b656e3a3a6d696e7450617961626c653a20496e76616c69642063616c6c41434f546f6b656e3a3a696e69743a20496e76616c696420737472696b6520617373657441434f546f6b656e3a3a5f65786572636973654163636f756e74733a20496e76616c69642072656d61696e696e6720616d6f756e7441434f546f6b656e3a3a696e69743a20416c726561647920696e697469616c697a656441434f546f6b656e3a3a5f676574417373657453796d626f6c3a20496e76616c69642061737365742073796d626f6c45524332303a3a5f7472616e73666572416374696f6e3a20496e76616c69642073656e64657245524332303a3a5f617070726f7665416374696f6e3a20496e76616c6964206f776e657241434f546f6b656e3a3a5f72656465656d436f6c6c61746572616c3a20496e76616c696420746f6b656e20616d6f756e74a2646970667358221220cb30ae80319463574ff120f520633d68378fa215960c0dd60da4052df64ca49164736f6c63430006060033

Deployed Bytecode

0x6080604052600436106102cd5760003560e01c806379cc679011610175578063a95ad147116100dc578063c52987cf11610095578063d90a730e1161006f578063d90a730e14610b62578063dd62ed3e14610b77578063de53fcd514610bb2578063e503d23914610bc7576102d7565b8063c52987cf14610b05578063c54e486214610b1a578063d8dfeb4514610b4d576102d7565b8063a95ad147146109ea578063b0df1cc714610a61578063bdc7c12b14610a87578063be040fb014610ab1578063c132566114610ac6578063c2507ac114610adb576102d7565b806399bc0aea1161012e57806399bc0aea146108e35780639c83c847146108f8578063a0712d681461092b578063a457c2d714610955578063a86265bb1461098e578063a9059cbb146109b1576102d7565b806379cc67901461075b5780637c974fc41461079457806387ab4a18146108195780638ff1516b1461084c5780639152cb591461087f57806395d89b41146102dc576102d7565b8063449a52f8116102345780634dd662ee116101ed5780636f012b8d116101c75780636f012b8d146106c85780636f307dc31461070b57806370a0823114610720578063732a950d14610753576102d7565b80634dd662ee146106515780635d97d3e2146106665780636d636478146106b3576102d7565b8063449a52f81461054e57806345f79d1b14610587578063464673c6146105ba5780634701eaa8146105f5578063477130981461060a5780634ac8eb5f1461063c576102d7565b806325a760c21161028657806325a760c214610463578063313a9b4e1461048e578063313ce567146104a357806339509351146104b85780633acc3af2146104f157806342966c6814610524576102d7565b806306fdde03146102dc578063095ea7b31461036657806311b7bda7146103b357806317d69bc8146103c857806318160ddd146103f957806323b872dd14610420576102d7565b366102d757600080fd5b600080fd5b3480156102e857600080fd5b506102f1610bfa565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561032b578181015183820152602001610313565b50505050905090810190601f1680156103585780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561037257600080fd5b5061039f6004803603604081101561038957600080fd5b506001600160a01b038135169060200135610c0a565b604080519115158252519081900360200190f35b3480156103bf57600080fd5b506102f1610c21565b3480156103d457600080fd5b506103dd610caf565b604080516001600160a01b039092168252519081900360200190f35b34801561040557600080fd5b5061040e610cbe565b60408051918252519081900360200190f35b34801561042c57600080fd5b5061039f6004803603606081101561044357600080fd5b506001600160a01b03813581169160208101359091169060400135610cc4565b34801561046f57600080fd5b50610478610d18565b6040805160ff9092168252519081900360200190f35b34801561049a57600080fd5b5061040e610d21565b3480156104af57600080fd5b50610478610d27565b3480156104c457600080fd5b5061039f600480360360408110156104db57600080fd5b506001600160a01b038135169060200135610d30565b3480156104fd57600080fd5b5061040e6004803603602081101561051457600080fd5b50356001600160a01b0316610d71565b34801561053057600080fd5b5061040e6004803603602081101561054757600080fd5b5035610d8c565b34801561055a57600080fd5b5061040e6004803603604081101561057157600080fd5b506001600160a01b038135169060200135610d98565b34801561059357600080fd5b5061040e600480360360208110156105aa57600080fd5b50356001600160a01b0316610e1e565b3480156105c657600080fd5b506105f3600480360360408110156105dd57600080fd5b506001600160a01b038135169060200135610e39565b005b34801561060157600080fd5b5061040e610fe5565b61040e6004803603606081101561062057600080fd5b506001600160a01b038135169060208101359060400135610feb565b34801561064857600080fd5b5061040e610ff8565b34801561065d57600080fd5b5061040e610ffe565b34801561067257600080fd5b506106906004803603602081101561068957600080fd5b5035611004565b604080516001600160a01b03909316835260208301919091528051918290030190f35b3480156106bf57600080fd5b5061039f61104e565b3480156106d457600080fd5b506106f2600480360360208110156106eb57600080fd5b503561105e565b6040805192835260208301919091528051918290030190f35b34801561071757600080fd5b506103dd6110b4565b34801561072c57600080fd5b5061040e6004803603602081101561074357600080fd5b50356001600160a01b03166110c3565b61040e6110de565b34801561076757600080fd5b5061040e6004803603604081101561077e57600080fd5b506001600160a01b038135169060200135611135565b61040e600480360360608110156107aa57600080fd5b6001600160a01b03823516916020810135918101906060810160408201356401000000008111156107da57600080fd5b8201836020820111156107ec57600080fd5b8035906020019184602083028401116401000000008311171561080e57600080fd5b509092509050611148565b34801561082557600080fd5b5061040e6004803603602081101561083c57600080fd5b50356001600160a01b0316611191565b34801561085857600080fd5b5061040e6004803603602081101561086f57600080fd5b50356001600160a01b03166111b8565b34801561088b57600080fd5b506105f360048036036101008110156108a357600080fd5b506001600160a01b0381358116916020810135821691604082013515159160608101359160808201359160a08101359160c0820135169060e001356111c6565b3480156108ef57600080fd5b5061040e61164c565b34801561090457600080fd5b5061040e6004803603602081101561091b57600080fd5b50356001600160a01b0316611652565b34801561093757600080fd5b5061040e6004803603602081101561094e57600080fd5b5035611660565b34801561096157600080fd5b5061039f6004803603604081101561097857600080fd5b506001600160a01b0381351690602001356116de565b61040e600480360360408110156109a457600080fd5b508035906020013561171a565b3480156109bd57600080fd5b5061039f600480360360408110156109d457600080fd5b506001600160a01b038135169060200135611727565b61040e60048036036040811015610a0057600080fd5b81359190810190604081016020820135640100000000811115610a2257600080fd5b820183602082011115610a3457600080fd5b80359060200191846020830284011164010000000083111715610a5657600080fd5b509092509050611734565b61040e60048036036020811015610a7757600080fd5b50356001600160a01b0316611774565b348015610a9357600080fd5b5061040e60048036036020811015610aaa57600080fd5b50356117c6565b348015610abd57600080fd5b5061040e6117f1565b348015610ad257600080fd5b506104786117fc565b348015610ae757600080fd5b5061040e60048036036020811015610afe57600080fd5b503561180a565b348015610b1157600080fd5b5061040e611847565b348015610b2657600080fd5b5061040e60048036036020811015610b3d57600080fd5b50356001600160a01b031661184d565b348015610b5957600080fd5b506103dd6118b8565b348015610b6e57600080fd5b506102f16118f1565b348015610b8357600080fd5b5061040e60048036036040811015610b9a57600080fd5b506001600160a01b038135811691602001351661194c565b348015610bbe57600080fd5b506103dd611977565b348015610bd357600080fd5b5061040e60048036036020811015610bea57600080fd5b50356001600160a01b0316611986565b6060610c046119e6565b90505b90565b6000610c17338484611c17565b5060015b92915050565b600b805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610ca75780601f10610c7c57610100808354040283529160200191610ca7565b820191906000526020600020905b815481529060010190602001808311610c8a57829003601f168201915b505050505081565b6004546001600160a01b031681565b60005490565b6001600160a01b0383166000908152600260209081526040808320338085529252822054610d03918691610cfe908663ffffffff611c2716565b611c69565b610d0e848484611d55565b5060019392505050565b600c5460ff1681565b600d5481565b600c5460ff1690565b3360008181526002602090815260408083206001600160a01b03871684529091528120549091610c17918590610d6c908663ffffffff611d6016565b611c17565b6000610d84610d7f83611191565b6117c6565b90505b919050565b6000610d843383611dba565b600080610da36118b8565b9050610dae81611e8c565b15610e00576040805162461bcd60e51b815260206004820152601e60248201527f41434f546f6b656e3a3a6d696e74546f3a20496e76616c69642063616c6c0000604482015290519081900360640190fd5b610e0c81333086611e99565b610e168484612022565b949350505050565b6001600160a01b03166000908152600f602052604090205490565b6001600160a01b038216610e7e5760405162461bcd60e51b81526004018080602001828103825260388152602001806143426038913960400191505060405180910390fd5b60008111610ebd5760405162461bcd60e51b81526004018080602001828103825260358152602001806144a96035913960400191505060405180910390fd5b336000908152600f602052604090208054610ede908363ffffffff611c2716565b8155610ee93361225d565b6001600160a01b0383166000908152600f60205260409020610f0a8161236d565b15610f28578054610f21908463ffffffff611d6016565b8155610f9f565b6040805180820182528481526010805460208084019182526001600160a01b0389166000818152600f90925294812093518455905160019384015581549283018255527f1b6847dc741a1b0cd08d278845f9d819d87b734759afb55fe2de5cb82a9ae6720180546001600160a01b03191690911790555b6040805184815290516001600160a01b0386169133917ff268b386023666001c794e23f1bc2285c15f9ae8db3025abbc16bf45edc6d08d9181900360200190a350505050565b60095481565b6000610e16848484612373565b60085481565b60105490565b6005546000908190600160a01b900460ff1615611039576004546001600160a01b031661103084612419565b91509150611049565b50506003546001600160a01b0316815b915091565b600554600160a01b900460ff1681565b600080600061106c846117c6565b90506000611098620186a061108c6009548561243690919063ffffffff16565b9063ffffffff61248f16565b90506110aa828263ffffffff611c2716565b9350915050915091565b6003546001600160a01b031681565b6001600160a01b031660009081526001602052604090205490565b60006110f06110eb6118b8565b611e8c565b61112b5760405162461bcd60e51b81526004018080602001828103825260238152602001806145d36023913960400191505060405180910390fd5b610c043334612022565b60006111418383611dba565b9392505050565b600061118885858585808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506124d192505050565b95945050505050565b600061119b612543565b156111b0576111a98261254b565b9050610d87565b506000610d87565b6000610d84610d7f83610e1e565b6003546001600160a01b03161580156111e857506004546001600160a01b0316155b80156111f45750600654155b61122f5760405162461bcd60e51b815260040180806020018281038252602381526020018061464f6023913960400191505060405180910390fd5b428411611283576040805162461bcd60e51b815260206004820152601e60248201527f41434f546f6b656e3a3a696e69743a20496e76616c6964206578706972790000604482015290519081900360640190fd5b600085116112c25760405162461bcd60e51b815260040180806020018281038252602481526020018061439d6024913960400191505060405180910390fd5b866001600160a01b0316886001600160a01b03161415611329576040805162461bcd60e51b815260206004820152601b60248201527f41434f546f6b656e3a3a696e69743a2053616d65206173736574730000000000604482015290519081900360640190fd5b6101f4831115611380576040805162461bcd60e51b815260206004820152601f60248201527f41434f546f6b656e3a3a696e69743a20496e76616c69642041434f2066656500604482015290519081900360640190fd5b61138988611e8c565b806113a157506113a1886001600160a01b03166125a6565b6113dc5760405162461bcd60e51b81526004018080602001828103825260228152602001806141e66022913960400191505060405180910390fd5b6113e587611e8c565b806113fd57506113fd876001600160a01b03166125a6565b6114385760405162461bcd60e51b81526004018080602001828103825260248152602001806145f66024913960400191505060405180910390fd5b6019811015801561144a575060968111155b6114855760405162461bcd60e51b815260040180806020018281038252603881526020018061430a6038913960400191505060405180910390fd5b600380546001600160a01b03199081166001600160a01b038b8116919091179092556004805482168a84161790556005805460068990556007889055600987905560ff60a01b1916600160a01b8a15150217909116918416919091179055600d8190556114f1886125df565b600c805460ff191660ff9283161790819055604e9116106115435760405162461bcd60e51b815260040180806020018281038252602b815260200180614237602b913960400191505060405180910390fd5b61154c876125df565b600c60016101000a81548160ff021916908360ff16021790555061156f88612724565b805161158391600a916020909101906140e7565b5061158d87612724565b80516115a191600b916020909101906140e7565b50600c5460ff16600a0a600e55604080518082018252601981527f7472616e7366657228616464726573732c75696e7432353629000000000000006020918201526011805464ffffffff00191664a9059cbb001790558151606081019092526025808352906142629083013980516020909101206011805460ff1960e09390931c650100000000000268ffffffff000000000019909116179190911660011790555050505050505050565b60075481565b6000610d84610d7f83611986565b60008061166b6118b8565b905061167681611e8c565b156116c8576040805162461bcd60e51b815260206004820152601c60248201527f41434f546f6b656e3a3a6d696e743a20496e76616c69642063616c6c00000000604482015290519081900360640190fd5b6116d481333086611e99565b6111413384612022565b3360008181526002602090815260408083206001600160a01b03871684529091528120549091610c17918590610d6c908663ffffffff611c2716565b6000611141338484612373565b6000610c17338484611d55565b6000610e1633858585808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506124d192505050565b60006117816110eb6118b8565b6117bc5760405162461bcd60e51b81526004018080602001828103825260258152602001806142bb6025913960400191505060405180910390fd5b610d848234612022565b600554600090600160a01b900460ff16156117e2575080610d87565b81156111b0576111a982612419565b6000610c043361292e565b600c54610100900460ff1681565b600554600090600160a01b900460ff1615611826575080610d87565b81156111b0576111a960065461108c600e548561243690919063ffffffff16565b60065481565b6000611859823361194c565b6001600160a01b0383166000908152600f602052604090205411156118af5760405162461bcd60e51b81526004018080602001828103825260278152602001806145ac6027913960400191505060405180910390fd5b610d848261292e565b600554600090600160a01b900460ff16156118df57506003546001600160a01b0316610c07565b506004546001600160a01b0316610c07565b600a805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610ca75780601f10610c7c57610100808354040283529160200191610ca7565b6001600160a01b03918216600090815260026020908152604080832093909416825291909152205490565b6005546001600160a01b031681565b6001600160a01b0381166000908152600f60205260408120546119a8836110c3565b11806119b957506119b7612543565b155b156119dd57506001600160a01b0381166000908152600f6020526040902054610d87565b6111a9826110c3565b6060600a611a05600654600c60019054906101000a900460ff16612a16565b600554600b90611a1e90600160a01b900460ff16612bbe565b611a29600754612c02565b604051602001808063020a1a7960e51b81525060040186805460018160011615610100020316600290048015611a965780601f10611a74576101008083540402835291820191611a96565b820191906000526020600020905b815481529060010190602001808311611a82575b505080602d60f81b81525060010185805190602001908083835b60208310611acf5780518252601f199092019160209182019101611ab0565b6001836020036101000a03801982511681845116808217855250505050505090500184805460018160011615610100020316600290048015611b485780601f10611b26576101008083540402835291820191611b48565b820191906000526020600020905b815481529060010190602001808311611b34575b505080602d60f81b81525060010183805190602001908083835b60208310611b815780518252601f199092019160209182019101611b62565b6001836020036101000a03801982511681845116808217855250505050505090500180602d60f81b81525060010182805190602001908083835b60208310611bda5780518252601f199092019160209182019101611bbb565b6001836020036101000a03801982511681845116808217855250505050505090500195505050505050604051602081830303815290604052905090565b611c22838383611c69565b505050565b600061114183836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612e00565b6001600160a01b038316611cae5760405162461bcd60e51b81526004018080602001828103825260248152602001806146c76024913960400191505060405180910390fd5b6001600160a01b038216611cf35760405162461bcd60e51b81526004018080602001828103825260268152602001806145566026913960400191505060405180910390fd5b6001600160a01b03808416600081815260026020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b611c22838383612e97565b600082820183811015611141576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b60115460009060ff16611e08576040805162461bcd60e51b815260206004820152601160248201527041434f546f6b656e3a3a5265656e74727960781b604482015290519081900360640190fd5b6011805460ff19169055611e1a612543565b611e5f576040805162461bcd60e51b81526020600482015260116024820152701050d3d51bdad95b8e8e915e1c1a5c9959607a1b604482015290519081900360640190fd5b6000611e6b8484612fdb565b9050611e7784846130a9565b90506011805460ff1916600117905592915050565b6001600160a01b03161590565b601154604080516001600160a01b0386811660248301528581166044830152606480830186905283518084039091018152608490920183526020820180516501000000000090950460e01b6001600160e01b0319166001600160e01b03909516949094178452915181516000946060948a169392918291908083835b60208310611f345780518252601f199092019160209182019101611f15565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114611f96576040519150601f19603f3d011682016040523d82523d6000602084013e611f9b565b606091505b5091509150818015611fc9575080511580611fc95750808060200190516020811015611fc657600080fd5b50515b61201a576040805162461bcd60e51b815260206004820152601c60248201527f41434f546f6b656e3a3a5f7472616e7366657246726f6d455243323000000000604482015290519081900360640190fd5b505050505050565b60115460009060ff16612070576040805162461bcd60e51b815260206004820152601160248201527041434f546f6b656e3a3a5265656e74727960781b604482015290519081900360640190fd5b6011805460ff19169055612082612543565b6120c7576040805162461bcd60e51b81526020600482015260116024820152701050d3d51bdad95b8e8e915e1c1a5c9959607a1b604482015290519081900360640190fd5b600082116121065760405162461bcd60e51b815260040180806020018281038252602f815260200180614208602f913960400191505060405180910390fd5b61210f836130d3565b61217357601080546001600160a01b0385166000818152600f60205260408120600190810184905583018455929092527f1b6847dc741a1b0cd08d278845f9d819d87b734759afb55fe2de5cb82a9ae6720180546001600160a01b03191690911790555b600061217e8361180a565b9050806121bc5760405162461bcd60e51b815260040180806020018281038252602a8152602001806142e0602a913960400191505060405180910390fd5b6001600160a01b0384166000908152600f60205260409020546121e5908263ffffffff611d6016565b6001600160a01b0385166000908152600f6020526040902055600854612211908463ffffffff611d6016565b6008556040805184815290516001600160a01b038616917ff645c19720906ca336d36d26058a9489c6c757fe35843b75a74e3b8aa972ecf5919081900360200190a2611e7733826130f4565b6001600160a01b0381166000908152600f6020526040902061227e8161236d565b61236957601054600182015460001990910190811461231b576000601082815481106122a657fe5b60009182526020808320909101546001868101546001600160a01b03909216808552600f9093526040909320909201829055601080549193508392909181106122eb57fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550505b601080548061232657fe5b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b0385168252600f90526040812081815560010155505b5050565b54151590565b60115460009060ff166123c1576040805162461bcd60e51b815260206004820152601160248201527041434f546f6b656e3a3a5265656e74727960781b604482015290519081900360640190fd5b6011805460ff19169055600d546123db90859085906131cf565b6123e68484846133a7565b6000806123f28561105e565b91509150612401868383613552565b925050506011805460ff191660011790559392505050565b6000610d84600e5461108c6006548561243690919063ffffffff16565b60008261244557506000610c1b565b8282028284828161245257fe5b04146111415760405162461bcd60e51b81526004018080602001828103825260218152602001806144586021913960400191505060405180910390fd5b600061114183836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613682565b60115460009060ff1661251f576040805162461bcd60e51b815260206004820152601160248201527041434f546f6b656e3a3a5265656e74727960781b604482015290519081900360640190fd5b6011805460ff19169055815161253890859085906131cf565b6123e68484846136e7565b600754421090565b6000612556826110c3565b6001600160a01b0383166000908152600f602052604090205411156111b0576111a9612581836110c3565b6001600160a01b0384166000908152600f60205260409020549063ffffffff611c2716565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590610e16575050151592915050565b60006125ea82611e8c565b156125f757506012610d87565b60408051600481526024810182526020810180516001600160e01b031663313ce56760e01b178152915181516000936060936001600160a01b038816939092909182918083835b6020831061265d5780518252601f19909201916020918201910161263e565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d80600081146126bd576040519150601f19603f3d011682016040523d82523d6000602084013e6126c2565b606091505b5091509150816127035760405162461bcd60e51b81526004018080602001828103825260338152602001806141b36033913960400191505060405180910390fd5b80806020019051602081101561271857600080fd5b50519250610d87915050565b606061272f82611e8c565b15612754575060408051808201909152600381526208aa8960eb1b6020820152610d87565b60408051600481526024810182526020810180516001600160e01b03166395d89b4160e01b178152915181516000936060936001600160a01b038816939092909182918083835b602083106127ba5780518252601f19909201916020918201910161279b565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d806000811461281a576040519150601f19603f3d011682016040523d82523d6000602084013e61281f565b606091505b5091509150816128605760405162461bcd60e51b815260040180806020018281038252602f815260200180614672602f913960400191505060405180910390fd5b80806020019051602081101561287557600080fd5b810190808051604051939291908464010000000082111561289557600080fd5b9083019060208201858111156128aa57600080fd5b82516401000000008111828201881017156128c457600080fd5b82525081516020918201929091019080838360005b838110156128f15781810151838201526020016128d9565b50505050905090810190601f16801561291e5780820380516001836020036101000a031916815260200191505b5060405250505092505050610d87565b60115460009060ff1661297c576040805162461bcd60e51b815260206004820152601160248201527041434f546f6b656e3a3a5265656e74727960781b604482015290519081900360640190fd5b6011805460ff1916905561298e612543565b156129ca5760405162461bcd60e51b815260040180806020018281038252602881526020018061452e6028913960400191505060405180910390fd5b6001600160a01b0382166000908152600f60205260408120546129ee908490612fdb565b9050612a02836129fd856110c3565b61377f565b90506011805460ff19166001179055919050565b6060600080808086805b8115612a7b5783158015612a425750600a8206151580612a4257508760ff1685145b15612a4e575060019250805b8315612a6a578760ff16851415612a63578592505b6001909501945b600a82600190960195049150612a20565b8760ff168511612a9d57848860ff168760020101039550600286039250612aaa565b8215612aaa576001909501945b60608667ffffffffffffffff81118015612ac357600080fd5b506040519080825280601f01601f191660200182016040528015612aee576020820181803683370190505b5091925082919050600019870160005b88811015612bae57600081118015612b1557508581145b15612b4e57601760f91b83838060019003945081518110612b3257fe5b60200101906001600160f81b031916908160001a905350612ba6565b83612b6b57600360fc1b83838060019003945081518110612b3257fe5b600a840660300160f81b83838060019003945081518110612b8857fe5b60200101906001600160f81b031916908160001a905350600a840493505b600101612afe565b50909a9950505050505050505050565b60608115612be457506040805180820190915260018152604360f81b6020820152610d87565b506040805180820190915260018152600560fc1b6020820152610d87565b60606000806000806000612c1587613862565b5094509450945094509450612c29836138a2565b612c3285613934565b612c3b87613b46565b612c44856138a2565b612c4d856138a2565b6040516020018086805190602001908083835b60208310612c7f5780518252601f199092019160209182019101612c60565b51815160209384036101000a600019018019909216911617905288519190930192880191508083835b60208310612cc75780518252601f199092019160209182019101612ca8565b51815160209384036101000a600019018019909216911617905287519190930192870191508083835b60208310612d0f5780518252601f199092019160209182019101612cf0565b6001836020036101000a03801982511681845116808217855250505050505090500180602d60f81b81525060010183805190602001908083835b60208310612d685780518252601f199092019160209182019101612d49565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b60208310612db05780518252601f199092019160209182019101612d91565b5181516020939093036101000a60001901801990911692169190911790526255544360e81b92019182525060408051808303601c19018152600390920190529d9c50505050505050505050505050565b60008184841115612e8f5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015612e54578181015183820152602001612e3c565b50505050905090810190601f168015612e815780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6001600160a01b038316612edc5760405162461bcd60e51b81526004018080602001828103825260268152602001806146a16026913960400191505060405180910390fd5b6001600160a01b038216612f215760405162461bcd60e51b81526004018080602001828103825260298152602001806143f96029913960400191505060405180910390fd5b6001600160a01b038316600090815260016020526040902054612f4a908263ffffffff611c2716565b6001600160a01b038085166000908152600160205260408082209390935590841681522054612f7f908263ffffffff611d6016565b6001600160a01b0380841660008181526001602090815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b6000612fe6836130d3565b6130215760405162461bcd60e51b81526004018080602001828103825260348152602001806142876034913960400191505060405180910390fd5b600082116130605760405162461bcd60e51b81526004018080602001828103825260318152602001806146eb6031913960400191505060405180910390fd5b6001600160a01b0383166000908152600f60205260409020805461308a908463ffffffff611c2716565b81556130958461225d565b610e16846130a2856117c6565b6000613552565b6001600160a01b0382163314156130c9576130c4828261377f565b612369565b6123698282613bd6565b6001600160a01b0381166000908152600f60205260408120610d849061236d565b6001600160a01b0382166131395760405162461bcd60e51b81526004018080602001828103825260238152602001806144de6023913960400191505060405180910390fd5b60005461314c908263ffffffff611d6016565b60009081556001600160a01b038316815260016020526040902054613177908263ffffffff611d6016565b6001600160a01b03831660008181526001602090815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b6131d7612543565b61321c576040805162461bcd60e51b81526020600482015260116024820152701050d3d51bdad95b8e8e915e1c1a5c9959607a1b604482015290519081900360640190fd5b6000821161325b5760405162461bcd60e51b81526004018080602001828103825260308152602001806144796030913960400191505060405180910390fd5b613264836130d3565b156132d9576001600160a01b0383166000908152600f602052604090205461329b9061328f856110c3565b9063ffffffff611c2716565b8211156132d95760405162461bcd60e51b81526004018080602001828103825260368152602001806144226036913960400191505060405180910390fd5b6132e383836130a9565b6000806132ef84611004565b9092509050613304818463ffffffff611d6016565b905061330f82611e8c565b15613357578034146133525760405162461bcd60e51b815260040180806020018281038252603081526020018061457c6030913960400191505060405180910390fd5b6133a0565b34156133945760405162461bcd60e51b815260040180806020018281038252602d815260200180614501602d913960400191505060405180910390fd5b6133a082333084611e99565b5050505050565b60105460009081906133c090849063ffffffff613c1b16565b90508060005b6000861180156133d7575060105481105b1561348657600061340a601084815481106133ee57fe5b6000918252602090912001546001600160a01b0316888a613c5d565b90508681101561346357600d54600190950194851080613428575080155b6134635760405162461bcd60e51b81526004018080602001828103825260388152602001806143c16038913960400191505060405180910390fd5b601054909650600190920191869083141561347d57600092505b506001016133c6565b85156134c35760405162461bcd60e51b81526004018080602001828103825260338152602001806141806033913960400191505060405180910390fd5b600080836134d55760105493506134e9565b8484116134e9575050601054916000190160015b60005b83811015613546576000199094019381801561350757508585105b1561351457829450600091505b61353e6010868154811061352457fe5b6000918252602090912001546001600160a01b031661225d565b6001016134ec565b50505050505050505050565b6000613576613567848463ffffffff611d6016565b6008549063ffffffff611c2716565b60085560006135836118b8565b905061358e81611e8c565b1561360857604051339085156108fc029086906000818181858888f193505050501580156135c0573d6000803e3d6000fd5b508215613603576005546040516001600160a01b039091169084156108fc029085906000818181858888f19350505050158015613601573d6000803e3d6000fd5b505b613631565b613613813386613d9f565b8215613631576005546136319082906001600160a01b031685613d9f565b6040805185815260208101859052815133926001600160a01b038916927fd3506bcc260407a7f95f487dd7c600bc45888cce58989ceadbe8c0bbf9257b28929081900390910190a350919392505050565b600081836136d15760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315612e54578181015183820152602001612e3c565b5060008385816136dd57fe5b0495945050505050565b60005b815181101561374157826136fd57613741565b61371b82828151811061370c57fe5b60200260200101518486613c5d565b925061373982828151811061372c57fe5b602002602001015161225d565b6001016136ea565b508115611c225760405162461bcd60e51b815260040180806020018281038252603581526020018061461a6035913960400191505060405180910390fd5b6001600160a01b0382166137c45760405162461bcd60e51b815260040180806020018281038252602381526020018061437a6023913960400191505060405180910390fd5b6001600160a01b0382166000908152600160205260409020546137ed908263ffffffff611c2716565b6001600160a01b0383166000908152600160205260408120919091555461381a908263ffffffff611c2716565b60009081556040805183815290516001600160a01b038516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef919081900360200190a35050565b60008080808080613877620151808804613f14565b91999098919750610e10620151809092068281049750603c9290068281049650919091069350915050565b6060806138ae83613faa565b9050600a8310156111a957806040516020018080600360fc1b81525060010182805190602001908083835b602083106138f85780518252601f1990920191602091820191016138d9565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051602081830303815290604052915050610d87565b6060816001141561395f57506040805180820190915260038152622520a760e91b6020820152610d87565b816002141561398857506040805180820190915260038152622322a160e91b6020820152610d87565b81600314156139b1575060408051808201909152600381526226a0a960e91b6020820152610d87565b81600414156139da575060408051808201909152600381526220a82960e91b6020820152610d87565b8160051415613a0357506040805180820190915260038152624d415960e81b6020820152610d87565b8160061415613a2c5750604080518082019091526003815262252aa760e91b6020820152610d87565b8160071415613a55575060408051808201909152600381526212955360ea1b6020820152610d87565b8160081415613a7e575060408051808201909152600381526241554760e81b6020820152610d87565b8160091415613aa7575060408051808201909152600381526205345560ec1b6020820152610d87565b81600a1415613ad0575060408051808201909152600381526213d0d560ea1b6020820152610d87565b81600b1415613af957506040805180820190915260038152622727ab60e91b6020820152610d87565b81600c1415613b22575060408051808201909152600381526244454360e81b6020820152610d87565b506040805180820190915260078152661253959053125160ca1b6020820152610d87565b606080613b5283613faa565b60408051600280825281830190925291925060609190602082018180368337505083519192505060011901805b8351811015613bcc57838181518110613b9457fe5b602001015160f81c60f81b8383830381518110613bad57fe5b60200101906001600160f81b031916908160001a905350600101613b7f565b5090949350505050565b6001600160a01b038216600090815260026020908152604080832033808552925290912054613c11918491610cfe908563ffffffff611c2716565b612369828261377f565b600061114183836040518060400160405280601881526020017f536166654d6174683a206d6f64756c6f206279207a65726f0000000000000000815250614085565b600080613c698561254b565b90508015613d96576001600160a01b0385166000908152600f602052604081209085831015613cab575081613ca4868263ffffffff611c2716565b9550613cb0565b506000945b600080613cbc83611004565b9092509050613cd281600163ffffffff611d6016565b8454909150613ce7908463ffffffff611c2716565b8455613cf282611e8c565b15613d33576040516001600160a01b038a169082156108fc029083906000818181858888f19350505050158015613d2d573d6000803e3d6000fd5b50613d3e565b613d3e828a83613d9f565b866001600160a01b0316896001600160a01b03167f5f283076724262032199f54be27a9364634b895b3a37c1e66bfe47d5d05347698386604051808381526020018281526020019250505060405180910390a3505050505b50919392505050565b601154604080516001600160a01b0385811660248301526044808301869052835180840390910181526064909201835260208201805161010090950460e01b6001600160e01b0319166001600160e01b039095169490941784529151815160009460609489169392918291908083835b60208310613e2e5780518252601f199092019160209182019101613e0f565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114613e90576040519150601f19603f3d011682016040523d82523d6000602084013e613e95565b606091505b5091509150818015613ec3575080511580613ec35750808060200190516020811015613ec057600080fd5b50515b6133a0576040805162461bcd60e51b815260206004820152601860248201527f41434f546f6b656e3a3a5f7472616e7366657245524332300000000000000000604482015290519081900360640190fd5b60008080836226496581018262023ab1600483020590506004600362023ab18302010590910390600062164b09610fa0600185010205905060046105b58202058303601f019250600061098f8460500281613f6b57fe5b0590506000605061098f83020585039050600b820560301994909401606402929092018301996002600c90940290910392909201975095509350505050565b606081613fcf57506040805180820190915260018152600360fc1b6020820152610d87565b8160005b8115613fe757600101600a82049150613fd3565b60608167ffffffffffffffff8111801561400057600080fd5b506040519080825280601f01601f19166020018201604052801561402b576020820181803683370190505b50859350905060001982015b831561407c57600a840660300160f81b8282806001900393508151811061405a57fe5b60200101906001600160f81b031916908160001a905350600a84049350614037565b50949350505050565b600081836140d45760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315612e54578181015183820152602001612e3c565b508284816140de57fe5b06949350505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061412857805160ff1916838001178555614155565b82800160010185558215614155579182015b8281111561415557825182559160200191906001019061413a565b50614161929150614165565b5090565b610c0791905b80821115614161576000815560010161416b56fe41434f546f6b656e3a3a5f65786572636973654f776e6572733a20496e76616c69642072656d61696e696e6720616d6f756e7441434f546f6b656e3a3a5f6765744173736574446563696d616c733a20496e76616c696420617373657420646563696d616c7341434f546f6b656e3a3a696e69743a20496e76616c696420756e6465726c79696e6741434f546f6b656e3a3a5f6d696e74546f6b656e3a20496e76616c696420636f6c6c61746572616c20616d6f756e7441434f546f6b656e3a3a696e69743a20496e76616c696420756e6465726c79696e6720646563696d616c737472616e7366657246726f6d28616464726573732c616464726573732c75696e743235362941434f546f6b656e3a3a5f72656465656d436f6c6c61746572616c3a204e6f20636f6c6c61746572616c20617661696c61626c6541434f546f6b656e3a3a6d696e74546f50617961626c653a20496e76616c69642063616c6c41434f546f6b656e3a3a5f6d696e74546f6b656e3a20496e76616c696420746f6b656e20616d6f756e7441434f546f6b656e3a3a696e69743a20496e76616c6964206e756d62657220746f206d617820657865726369736564206163636f756e747341434f546f6b656e3a3a7472616e73666572436f6c6c61746572616c4f776e6572736869703a20496e76616c696420726563697069656e7445524332303a3a5f6275726e416374696f6e3a20496e76616c6964206163636f756e7441434f546f6b656e3a3a696e69743a20496e76616c696420737472696b6520707269636541434f546f6b656e3a3a5f65786572636973654f776e6572733a20546f6f206d616e79206163636f756e747320746f20657865726369736545524332303a3a5f7472616e73666572416374696f6e3a20496e76616c696420726563697069656e7441434f546f6b656e3a3a5f76616c6964617465416e644275726e3a20546f6b656e20616d6f756e74206e6f7420617661696c61626c65536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7741434f546f6b656e3a3a5f76616c6964617465416e644275726e3a20496e76616c696420746f6b656e20616d6f756e7441434f546f6b656e3a3a7472616e73666572436f6c6c61746572616c4f776e6572736869703a20496e76616c696420616d6f756e7445524332303a3a5f6d696e74416374696f6e3a20496e76616c6964206163636f756e7441434f546f6b656e3a3a5f76616c6964617465416e644275726e3a204e6f20657468657220657870656374656441434f546f6b656e3a3a5f72656465656d3a20546f6b656e206e6f7420657870697265642079657445524332303a3a5f617070726f7665416374696f6e3a20496e76616c6964207370656e64657241434f546f6b656e3a3a5f76616c6964617465416e644275726e3a20496e76616c696420657468657220616d6f756e7441434f546f6b656e3a3a72656465656d46726f6d3a20416c6c6f77616e636520746f6f206c6f7741434f546f6b656e3a3a6d696e7450617961626c653a20496e76616c69642063616c6c41434f546f6b656e3a3a696e69743a20496e76616c696420737472696b6520617373657441434f546f6b656e3a3a5f65786572636973654163636f756e74733a20496e76616c69642072656d61696e696e6720616d6f756e7441434f546f6b656e3a3a696e69743a20416c726561647920696e697469616c697a656441434f546f6b656e3a3a5f676574417373657453796d626f6c3a20496e76616c69642061737365742073796d626f6c45524332303a3a5f7472616e73666572416374696f6e3a20496e76616c69642073656e64657245524332303a3a5f617070726f7665416374696f6e3a20496e76616c6964206f776e657241434f546f6b656e3a3a5f72656465656d436f6c6c61746572616c3a20496e76616c696420746f6b656e20616d6f756e74a2646970667358221220cb30ae80319463574ff120f520633d68378fa215960c0dd60da4052df64ca49164736f6c63430006060033

Deployed Bytecode Sourcemap

221:41335:1:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12:1:-1;9;2:12;221:41335:1;12:1:-1;9;2:12;8256:93:1;;5:9:-1;2:2;;;27:1;24;17:12;2:2;8256:93:1;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:100:-1;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;8256:93:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1425:158:4;;5:9:-1;2:2;;;27:1;24;17:12;2:2;1425:158:4;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;;;;;;1425:158:4;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;3432:31:1;;5:9:-1;2:2;;;27:1;24;17:12;2:2;3432:31:1;;;:::i;2500:26::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;2500:26:1;;;:::i;:::-;;;;-1:-1:-1;;;;;2500:26:1;;;;;;;;;;;;;;592:99:4;;5:9:-1;2:2;;;27:1;24;17:12;2:2;592:99:4;;;:::i;:::-;;;;;;;;;;;;;;;;1147:270;;5:9:-1;2:2;;;27:1;24;17:12;2:2;1147:270:4;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;;;;;;1147:270:4;;;;;;;;;;;;;;;;;:::i;3542:31:1:-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;3542:31:1;;;:::i;:::-;;;;;;;;;;;;;;;;;;;3793:35;;5:9:-1;2:2;;;27:1;24;17:12;2:2;3793:35:1;;;:::i;8681:100::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;8681:100:1;;;:::i;1591:197:4:-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;1591:197:4;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;;;;;;1591:197:4;;;;;;;;:::i;9920:148:1:-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;9920:148:1;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;9920:148:1;-1:-1:-1;;;;;9920:148:1;;:::i;17418:117::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;17418:117:1;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;17418:117:1;;:::i;16755:366::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;16755:366:1;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;;;;;;16755:366:1;;;;;;;;:::i;10295:134::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;10295:134:1;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;10295:134:1;-1:-1:-1;;;;;10295:134:1;;:::i;21375:1022::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;21375:1022:1;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;;;;;;21375:1022:1;;;;;;;;:::i;:::-;;3233:21;;5:9:-1;2:2;;;27:1;24;17:12;2:2;3233:21:1;;;:::i;20331:171::-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;;;;;;20331:171:1;;;;;;;;;;;;;:::i;3101:30::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;3101:30:1;;;:::i;12724:121::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;12724:121:1;;;:::i;13466:274::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;13466:274:1;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;13466:274:1;;:::i;:::-;;;;-1:-1:-1;;;;;13466:274:1;;;;;;;;;;;;;;;;;;;;;2748:18;;5:9:-1;2:2;;;27:1;24;17:12;2:2;2748:18:1;;;:::i;13983:331::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;13983:331:1;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;13983:331:1;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;2365:25;;5:9:-1;2:2;;;27:1;24;17:12;2:2;2365:25:1;;;:::i;699:118:4:-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;699:118:4;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;699:118:4;-1:-1:-1;;;;;699:118:4;;:::i;14846:197:1:-;;;:::i;18004:135::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;18004:135:1;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;;;;;;18004:135:1;;;;;;;;:::i;23062:210::-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;;;;;23062:210:1;;;;;;;;;;;;;;;;;;;27:11:-1;11:28;;8:2;;;52:1;49;42:12;8:2;23062:210:1;;41:9:-1;34:4;18:14;14:25;11:40;8:2;;;64:1;61;54:12;8:2;23062:210:1;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;39:11;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;-1:-1;23062:210:1;;-1:-1:-1;23062:210:1;-1:-1:-1;23062:210:1;:::i;11313:213::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;11313:213:1;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;11313:213:1;-1:-1:-1;;;;;11313:213:1;;:::i;8986:156::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;8986:156:1;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;8986:156:1;-1:-1:-1;;;;;8986:156:1;;:::i;5989:2022::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;5989:2022:1;;;;;;15:3:-1;10;7:12;4:2;;;32:1;29;22:12;4:2;-1:-1;;;;;;5989:2022:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;2984:25::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;2984:25:1;;;:::i;9476:152::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;9476:152:1;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;9476:152:1;-1:-1:-1;;;;;9476:152:1;;:::i;15942:348::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;15942:348:1;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;15942:348:1;;:::i;1796:197:4:-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;1796:197:4;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;;;;;;1796:197:4;;;;;;;;:::i;19535:153:1:-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;19535:153:1;;;;;;;:::i;975:164:4:-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;975:164:4;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;;;;;;975:164:4;;;;;;;;:::i;20955:192:1:-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;20955:192:1;;;;;;;;;;;;;;27:11:-1;11:28;;8:2;;;52:1;49;42:12;8:2;20955:192:1;;41:9:-1;34:4;18:14;14:25;11:40;8:2;;;64:1;61;54:12;8:2;20955:192:1;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;39:11;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;-1:-1;20955:192:1;;-1:-1:-1;20955:192:1;-1:-1:-1;20955:192:1;:::i;15444:212::-;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;15444:212:1;-1:-1:-1;;;;;15444:212:1;;:::i;11736:297::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;11736:297:1;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;11736:297:1;;:::i;18354:89::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;18354:89:1;;;:::i;3648:32::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;3648:32:1;;;:::i;12248:324::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;12248:324:1;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;12248:324:1;;:::i;2874:26::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;2874:26:1;;;:::i;18840:227::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;18840:227:1;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;18840:227:1;-1:-1:-1;;;;;18840:227:1;;:::i;14448:176::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;14448:176:1;;;:::i;3330:30::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;3330:30:1;;;:::i;825:142:4:-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;825:142:4;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;;;;;;825:142:4;;;;;;;;;;:::i;2626:37:1:-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;2626:37:1;;;:::i;10754:279::-;;5:9:-1;2:2;;;27:1;24;17:12;2:2;10754:279:1;;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;10754:279:1;-1:-1:-1;;;;;10754:279:1;;:::i;8256:93::-;8301:13;8334:7;:5;:7::i;:::-;8327:14;;8256:93;;:::o;1425:158:4:-;1499:4;1516:37;1525:10;1537:7;1546:6;1516:8;:37::i;:::-;-1:-1:-1;1571:4:4;1425:158;;;;;:::o;3432:31:1:-;;;;;;;;;;;;;;;-1:-1:-1;;3432:31:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;2500:26::-;;;-1:-1:-1;;;;;2500:26:1;;:::o;592:99:4:-;644:7;671:12;592:99;:::o;1147:270::-;-1:-1:-1;;;;;1296:19:4;;1244:4;1296:19;;;:11;:19;;;;;;;;1284:10;1296:31;;;;;;;;1261:79;;1276:6;;1296:43;;1332:6;1296:43;:35;:43;:::i;:::-;1261:14;:79::i;:::-;1351:36;1361:6;1369:9;1380:6;1351:9;:36::i;:::-;-1:-1:-1;1405:4:4;1147:270;;;;;:::o;3542:31:1:-;;;;;;:::o;3793:35::-;;;;:::o;8681:100::-;8755:18;;;;8681:100;:::o;1591:197:4:-;1692:10;1666:4;1713:23;;;:11;:23;;;;;;;;-1:-1:-1;;;;;1713:32:4;;;;;;;;;;1666:4;;1683:75;;1704:7;;1713:44;;1750:6;1713:44;:36;:44;:::i;:::-;1683:8;:75::i;9920:148:1:-;9987:7;10014:46;10034:25;10051:7;10034:16;:25::i;:::-;10014:19;:46::i;:::-;10007:53;;9920:148;;;;:::o;17418:117::-;17470:7;17497:30;17503:10;17515:11;17497:5;:30::i;16755:366::-;16831:7;16851:19;16873:12;:10;:12::i;:::-;16851:34;;16905:21;16914:11;16905:8;:21::i;:::-;16904:22;16896:65;;;;;-1:-1:-1;;;16896:65:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;16982:76;17001:11;17014:10;17034:4;17041:16;16982:18;:76::i;:::-;17076:37;17087:7;17096:16;17076:10;:37::i;:::-;17069:44;16755:366;-1:-1:-1;;;;16755:366:1:o;10295:134::-;-1:-1:-1;;;;;10396:18:1;10369:7;10396:18;;;:9;:18;;;;;:25;;10295:134::o;21375:1022::-;-1:-1:-1;;;;;21494:23:1;;21486:92;;;;-1:-1:-1;;;21486:92:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;21625:1;21597:25;:29;21589:95;;;;-1:-1:-1;;;21589:95:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;21748:10;21697:38;21738:21;;;:9;:21;;;;;21790:17;;:48;;21812:25;21790:48;:21;:48;:::i;:::-;21770:68;;21851:44;21884:10;21851:32;:44::i;:::-;-1:-1:-1;;;;;21952:20:1;;21908:41;21952:20;;;:9;:20;;;;;21987:29;21952:20;21987:14;:29::i;:::-;21983:312;;;22056:20;;:51;;22081:25;22056:51;:24;:51;:::i;:::-;22033:74;;21983:312;;;22163:72;;;;;;;;;;;22210:17;:24;;22163:72;;;;;;;-1:-1:-1;;;;;22140:20:1;;-1:-1:-1;22140:20:1;;;:9;:20;;;;;;:95;;;;;;;;;;;27:10:-1;;23:18;;;45:23;;22250:33:1;;;;;-1:-1:-1;;;;;;22250:33:1;;;;;;21983:312;22312:77;;;;;;;;-1:-1:-1;;;;;22312:77:1;;;22340:10;;22312:77;;;;;;;;;21375:1022;;;;:::o;3233:21::-;;;;:::o;20331:171::-;20430:7;20457:37;20467:7;20476:11;20489:4;20457:9;:37::i;3101:30::-;;;;:::o;12724:121::-;12813:17;:24;12724:121;:::o;13466:274::-;13569:6;;13536:7;;;;-1:-1:-1;;;13569:6:1;;;;13565:168;;;13600:11;;-1:-1:-1;;;;;13600:11:1;13613:41;13642:11;13613:28;:41::i;:::-;13592:63;;;;;;13565:168;-1:-1:-1;;13697:10:1;;-1:-1:-1;;;;;13697:10:1;13709:11;13565:168;13466:274;;;:::o;2748:18::-;;;-1:-1:-1;;;2748:18:1;;;;;:::o;13983:331::-;14057:7;14066;14086:24;14113:32;14133:11;14113:19;:32::i;:::-;14086:59;;14156:11;14170:40;14203:6;14170:28;14191:6;;14170:16;:20;;:28;;;;:::i;:::-;:32;:40;:32;:40;:::i;:::-;14156:54;-1:-1:-1;14240:25:1;:16;14156:54;14240:25;:20;:25;:::i;:::-;14221:44;-1:-1:-1;14302:3:1;-1:-1:-1;;13983:331:1;;;:::o;2365:25::-;;;-1:-1:-1;;;;;2365:25:1;;:::o;699:118:4:-;-1:-1:-1;;;;;791:18:4;764:7;791:18;;;:9;:18;;;;;;;699:118::o;14846:197:1:-;14894:7;14922:22;14931:12;:10;:12::i;:::-;14922:8;:22::i;:::-;14914:70;;;;-1:-1:-1;;;14914:70:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;15002:33;15013:10;15025:9;15002:10;:33::i;18004:135::-;18077:7;18104:27;18110:7;18119:11;18104:5;:27::i;:::-;18097:34;18004:135;-1:-1:-1;;;18004:135:1:o;23062:210::-;23184:7;23211:53;23233:7;23242:11;23255:8;;23211:53;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;23211:21:1;;-1:-1:-1;;;23211:53:1:i;:::-;23204:60;23062:210;-1:-1:-1;;;;;23062:210:1:o;11313:213::-;11376:7;11400:13;:11;:13::i;:::-;11396:123;;;11437:29;11458:7;11437:20;:29::i;:::-;11430:36;;;;11396:123;-1:-1:-1;11506:1:1;11499:8;;8986:156;9050:7;9077:57;9097:36;9125:7;9097:27;:36::i;5989:2022::-;6289:10;;-1:-1:-1;;;;;6289:10:1;:24;:53;;;;-1:-1:-1;6317:11:1;;-1:-1:-1;;;;;6317:11:1;:25;6289:53;:73;;;;-1:-1:-1;6346:11:1;;:16;6289:73;6281:121;;;;-1:-1:-1;;;6281:121:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6445:3;6431:11;:17;6423:60;;;;;-1:-1:-1;;;6423:60:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;6517:1;6502:12;:16;6494:65;;;;-1:-1:-1;;;6494:65:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6593:12;-1:-1:-1;;;;;6578:27:1;:11;-1:-1:-1;;;;;6578:27:1;;;6570:67;;;;;-1:-1:-1;;;6570:67:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;6667:3;6656:7;:14;;6648:58;;;;;-1:-1:-1;;;6648:58:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;6744:21;6753:11;6744:8;:21::i;:::-;:49;;;;6769:24;:11;-1:-1:-1;;;;;6769:22:1;;:24::i;:::-;6736:96;;;;-1:-1:-1;;;6736:96:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6851:22;6860:12;6851:8;:22::i;:::-;:51;;;;6877:25;:12;-1:-1:-1;;;;;6877:23:1;;:25::i;:::-;6843:100;;;;-1:-1:-1;;;6843:100:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6987:2;6962:21;:27;;:59;;;;;7018:3;6993:21;:28;;6962:59;6954:128;;;;-1:-1:-1;;;6954:128:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7103:10;:24;;-1:-1:-1;;;;;;7103:24:1;;;-1:-1:-1;;;;;7103:24:1;;;;;;;;;;7138:11;:26;;;;;;;;;;7175:6;:16;;7202:11;:26;;;7239:10;:24;;;7274:6;:16;;;-1:-1:-1;;;;7175:16:1;-1:-1:-1;;;7175:16:1;;;;;7301:32;;;;;;;;;;;;7344:20;:44;;;7420:30;7103:24;7420:17;:30::i;:::-;7399:18;:51;;-1:-1:-1;;7399:51:1;;;;;;;;;;7490:2;7469:18;;:23;7461:79;;;;-1:-1:-1;;;7461:79:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7573:31;7591:12;7573:17;:31::i;:::-;7551:19;;:53;;;;;;;;;;;;;;;;;;7634:28;7650:11;7634:15;:28::i;:::-;7615:47;;;;:16;;:47;;;;;;:::i;:::-;;7693:29;7709:12;7693:15;:29::i;:::-;7673:49;;;;:17;;:49;;;;;;:::i;:::-;-1:-1:-1;7769:18:1;;;;7755:2;:33;7733:19;:55;7838:34;;;;;;;;;;;;;;;;;7801:17;:73;;-1:-1:-1;;7801:73:1;;;;;7926:46;;;;;;;;;;;;;;;;;;7916:57;;;;;;;7885:21;:89;;-1:-1:-1;;7885:89:1;;;;;;;-1:-1:-1;;7885:89:1;;;;7985:18;;;;-1:-1:-1;7985:18:1;;;-1:-1:-1;;;;;;;;5989:2022:1:o;2984:25::-;;;;:::o;9476:152::-;9545:7;9572:48;9592:27;9611:7;9592:18;:27::i;15942:348::-;15999:7;16019:19;16041:12;:10;:12::i;:::-;16019:34;;16073:21;16082:11;16073:8;:21::i;:::-;16072:22;16064:63;;;;;-1:-1:-1;;;16064:63:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;16148:76;16167:11;16180:10;16200:4;16207:16;16148:18;:76::i;:::-;16242:40;16253:10;16265:16;16242:10;:40::i;1796:197:4:-;1897:10;1871:4;1918:23;;;:11;:23;;;;;;;;-1:-1:-1;;;;;1918:32:4;;;;;;;;;;1871:4;;1888:75;;1909:7;;1918:44;;1955:6;1918:44;:36;:44;:::i;19535:153:1:-;19613:7;19640:40;19650:10;19662:11;19675:4;19640:9;:40::i;975:164:4:-;1052:4;1069:40;1079:10;1091:9;1102:6;1069:9;:40::i;20955:192:1:-;21056:7;21083:56;21105:10;21117:11;21130:8;;21083:56;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;21083:21:1;;-1:-1:-1;;;21083:56:1:i;15444:212::-;15509:7;15537:22;15546:12;:10;:12::i;15537:22::-;15529:72;;;;-1:-1:-1;;;15529:72:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;15618:30;15629:7;15638:9;15618:10;:30::i;11736:297::-;11830:6;;11806:7;;-1:-1:-1;;;11830:6:1;;;;11826:200;;;-1:-1:-1;11860:11:1;11853:18;;11826:200;11893:15;;11889:137;;11932:41;11961:11;11932:28;:41::i;18354:89::-;18389:7;18416:19;18424:10;18416:7;:19::i;3648:32::-;;;;;;;;;:::o;12248:324::-;12342:6;;12318:7;;-1:-1:-1;;;12342:6:1;;;;12338:227;;;-1:-1:-1;12372:16:1;12365:23;;12338:227;12410:20;;12406:159;;12454:58;12500:11;;12454:41;12475:19;;12454:16;:20;;:41;;;;:::i;2874:26::-;;;;:::o;18840:227::-;18894:7;18951:30;18961:7;18970:10;18951:9;:30::i;:::-;-1:-1:-1;;;;;18922:18:1;;;;;;:9;:18;;;;;:25;:59;;18914:111;;;;-1:-1:-1;;;18914:111:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19043:16;19051:7;19043;:16::i;14448:176::-;14514:6;;14490:7;;-1:-1:-1;;;14514:6:1;;;;14510:107;;;-1:-1:-1;14544:10:1;;-1:-1:-1;;;;;14544:10:1;14537:17;;14510:107;-1:-1:-1;14594:11:1;;-1:-1:-1;;;;;14594:11:1;14587:18;;3330:30;;;;;;;;;;;;;;;-1:-1:-1;;3330:30:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;825:142:4;-1:-1:-1;;;;;932:18:4;;;905:7;932:18;;;:11;:18;;;;;;;;:27;;;;;;;;;;;;;825:142::o;2626:37:1:-;;;-1:-1:-1;;;;;2626:37:1;;:::o;10754:279::-;-1:-1:-1;;;;;10864:18:1;;10819:7;10864:18;;;:9;:18;;;;;:25;10843:18;10874:7;10843:9;:18::i;:::-;:46;:64;;;;10894:13;:11;:13::i;:::-;10893:14;10843:64;10839:187;;;-1:-1:-1;;;;;;10931:18:1;;;;;;:9;:18;;;;;:25;10924:32;;10839:187;10996:18;11006:7;10996:9;:18::i;38726:435::-;38765:13;38857:16;38906:63;38936:11;;38949:19;;;;;;;;;;;38906:29;:63::i;:::-;39062:6;;38984:17;;39034:35;;-1:-1:-1;;;39062:6:1;;;;39034:27;:35::i;:::-;39102:39;39130:10;;39102:27;:39::i;:::-;38805:347;;;;;;-1:-1:-1;;;38805:347:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;38805:347:1;;;;;;;;;;;;;;;36:153:-1;66:2;61:3;58:11;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;274:1;267:3;263:2;259:12;254:3;250:22;246:30;315:4;311:9;305:3;299:10;295:26;356:4;350:3;344:10;340:21;389:7;380;377:20;372:3;365:33;3:399;;;38805:347:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;38805:347:1;;;;;;;;;;;;;;;36:153:-1;66:2;61:3;58:11;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;274:1;267:3;263:2;259:12;254:3;250:22;246:30;315:4;311:9;305:3;299:10;295:26;356:4;350:3;344:10;340:21;389:7;380;377:20;372:3;365:33;3:399;;;38805:347:1;;;;;;;-1:-1:-1;;;38805:347:1;;;;;;;;;;;;;;;36:153:-1;66:2;61:3;58:11;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;274:1;267:3;263:2;259:12;254:3;250:22;246:30;315:4;311:9;305:3;299:10;295:26;356:4;350:3;344:10;340:21;389:7;380;377:20;372:3;365:33;3:399;;;38805:347:1;;;;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;38805:347:1;;;38791:362;;38726:435;:::o;2161:140:4:-;2255:38;2270:5;2277:7;2286:6;2255:14;:38::i;:::-;2161:140;;;:::o;1410:136:6:-;1468:7;1495:43;1499:1;1502;1495:43;;;;;;;;;;;;;;;;;:3;:43::i;2985:358:4:-;-1:-1:-1;;;;;3085:19:4;;3077:68;;;;-1:-1:-1;;;3077:68:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;3164:21:4;;3156:72;;;;-1:-1:-1;;;3156:72:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;3241:18:4;;;;;;;:11;:18;;;;;;;;:27;;;;;;;;;;;;;:36;;;3303:32;;;;;;;;;;;;;;;;;2985:358;;;:::o;2005:148::-;2103:42;2119:6;2127:9;2138:6;2103:15;:42::i;954:181:6:-;1012:7;1044:5;;;1068:6;;;;1060:46;;;;;-1:-1:-1;;;1060:46:6;;;;;;;;;;;;;;;;;;;;;;;;;;;35296:264:1;5011:11;;35390:7;;5011:11;;5003:41;;;;;-1:-1:-1;;;5003:41:1;;;;;;;;;;;;-1:-1:-1;;;5003:41:1;;;;;;;;;;;;;;;5055:11;:19;;-1:-1:-1;;5055:19:1;;;4788:13:::1;:11;:13::i;:::-;4780:43;;;::::0;;-1:-1:-1;;;4780:43:1;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;4780:43:1;;;;;;;;;;;;;::::1;;35410:24:::2;35437:39;35455:7;35464:11;35437:17;:39::i;:::-;35410:66;;35487:31;35497:7;35506:11;35487:9;:31::i;:::-;35536:16:::0;-1:-1:-1;5097:11:1;:18;;-1:-1:-1;;5097:18:1;5111:4;5097:18;;;35296:264;;-1:-1:-1;;35296:264:1:o;38360:112::-;-1:-1:-1;;;;;38442:22:1;;;38360:112::o;41184:369::-;41374:21;;41351:72;;;-1:-1:-1;;;;;41351:72:1;;;;;;;;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;41351:72:1;;;;;;;25:18:-1;;61:17;;41374:21:1;;;;;;-1:-1:-1;;;;;;41351:72:1;-1:-1:-1;;;;;182:15;;;179:29;;;;160:49;;41340:84:1;;;;-1:-1:-1;;41313:23:1;;41340:10;;;41351:72;41340:84;;;25:18:-1;41340:84:1;;25:18:-1;36:153;66:2;61:3;58:11;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;274:1;267:3;263:2;259:12;254:3;250:22;246:30;315:4;311:9;305:3;299:10;295:26;356:4;350:3;344:10;340:21;389:7;380;377:20;372:3;365:33;3:399;;;41340:84:1;;;;;;;;;;;;;;;;;;;;;;;;12:1:-1;19;14:27;;;;67:4;61:11;56:16;;134:4;130:9;123:4;105:16;101:27;97:43;94:1;90:51;84:4;77:65;157:16;154:1;147:27;211:16;208:1;201:4;198:1;194:12;179:49;5:228;;14:27;32:4;27:9;;5:228;;41298:126:1;;;;41443:7;:69;;;;-1:-1:-1;41455:17:1;;:22;;:56;;;41492:10;41481:30;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;41481:30:1;41455:56;41435:110;;;;;-1:-1:-1;;;41435:110:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;41184:369;;;;;;:::o;24394:869::-;5011:11;;24498:7;;5011:11;;5003:41;;;;;-1:-1:-1;;;5003:41:1;;;;;;;;;;;;-1:-1:-1;;;5003:41:1;;;;;;;;;;;;;;;5055:11;:19;;-1:-1:-1;;5055:19:1;;;4788:13:::1;:11;:13::i;:::-;4780:43;;;::::0;;-1:-1:-1;;;4780:43:1;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;-1:-1:-1;;;4780:43:1;;;;;;;;;;;;;::::1;;24545:1:::2;24526:16;:20;24518:80;;;;-1:-1:-1::0;;;24518:80:1::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;24624:30;24646:7;24624:21;:30::i;:::-;24619:161;;24698:17;:24:::0;;-1:-1:-1;;;;;24671:18:1;::::2;;::::0;;;:9:::2;:18;::::0;;;;:24:::2;::::0;;::::2;:51:::0;;;23:18:-1;::::2;45:23:::0;;24737:31:1;;;;;::::2;::::0;;-1:-1:-1;;;;;;24737:31:1::2;::::0;;::::2;::::0;;24619:161:::2;24800:19;24822:32;24837:16;24822:14;:32::i;:::-;24800:54:::0;-1:-1:-1;24873:16:1;24865:71:::2;;;;-1:-1:-1::0;;;24865:71:1::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1::0;;;;;24975:18:1;::::2;;::::0;;;:9:::2;:18;::::0;;;;:25;:42:::2;::::0;25005:11;24975:42:::2;:29;:42;:::i;:::-;-1:-1:-1::0;;;;;24947:18:1;::::2;;::::0;;;:9:::2;:18;::::0;;;;:70;25056:15:::2;::::0;:37:::2;::::0;25076:16;25056:37:::2;:19;:37;:::i;:::-;25038:15;:55:::0;25119:44:::2;::::0;;;;;;;-1:-1:-1;;;;;25119:44:1;::::2;::::0;::::2;::::0;;;;;::::2;::::0;;::::2;25184:42;25202:10;25214:11;25184:17;:42::i;36652:559::-:0;-1:-1:-1;;;;;36766:18:1;;36731:32;36766:18;;;:9;:18;;;;;36800:20;36766:18;36800:14;:20::i;:::-;36795:409;;36857:17;:24;36884:1;36917:10;;;-1:-1:-1;;36857:28:1;;;;36904:23;;36900:215;;36948:12;36963:17;36981:9;36963:28;;;;;;;;;;;;;;;;;;;;;37034:10;;;;-1:-1:-1;;;;;36963:28:1;;;37010:15;;;:9;:15;;;;;;;:21;;;:34;;;37063:17;:29;;36963:28;;-1:-1:-1;36963:28:1;;37063:17;;:29;;;;;;;;;;;;;;:36;;;;;-1:-1:-1;;;;;37063:36:1;;;;;-1:-1:-1;;;;;37063:36:1;;;;;;36900:215;;37129:17;:23;;;;;;;;;;;;;;;;;-1:-1:-1;;37129:23:1;;;;;-1:-1:-1;;;;;;37129:23:1;;;;;;;;;-1:-1:-1;;;;;37174:18:1;;;;:9;:18;;;;;37167:25;;;37129:23;37167:25;;-1:-1:-1;36795:409:1;36652:559;;:::o;38026:127::-;38130:11;:15;;;38026:127::o;26897:402::-;5011:11;;26998:7;;5011:11;;5003:41;;;;;-1:-1:-1;;;5003:41:1;;;;;;;;;;;;-1:-1:-1;;;5003:41:1;;;;;;;;;;;;;;;5055:11;:19;;-1:-1:-1;;5055:19:1;;;27057:20:::1;::::0;27018:60:::1;::::0;27035:7;;27044:11;;27018:16:::1;:60::i;:::-;27090:43;27106:7;27115:11;27128:4;27090:15;:43::i;:::-;27145:24;27171:11:::0;27186:36:::1;27210:11;27186:23;:36::i;:::-;27144:78;;;;27240:51;27260:7;27269:16;27287:3;27240:19;:51::i;:::-;27233:58;;;;5097:11:::0;:18;;-1:-1:-1;;5097:18:1;5111:4;5097:18;;;26897:402;;-1:-1:-1;;;26897:402:1:o;34213:169::-;34294:7;34321:53;34354:19;;34321:28;34337:11;;34321;:15;;:28;;;;:::i;2284:471:6:-;2342:7;2587:6;2583:47;;-1:-1:-1;2617:1:6;2610:8;;2583:47;2654:5;;;2658:1;2654;:5;:1;2678:5;;;;;:10;2670:56;;;;-1:-1:-1;;;2670:56:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3223:132;3281:7;3308:39;3312:1;3315;3308:39;;;;;;;;;;;;;;;;;:3;:39::i;27641:427:1:-;5011:11;;27767:7;;5011:11;;5003:41;;;;;-1:-1:-1;;;5003:41:1;;;;;;;;;;;;-1:-1:-1;;;5003:41:1;;;;;;;;;;;;;;;5055:11;:19;;-1:-1:-1;;5055:19:1;;;27826:15;;27787:55:::1;::::0;27804:7;;27813:11;;27787:16:::1;:55::i;:::-;27853:49;27871:7;27880:11;27893:8;27853:17;:49::i;37358:93::-:0;37433:10;;37427:3;:16;37358:93;:::o;36201:272::-;36270:7;36322:18;36332:7;36322:9;:18::i;:::-;-1:-1:-1;;;;;36294:18:1;;;;;;:9;:18;;;;;:25;:46;36290:176;;;36364:49;36394:18;36404:7;36394:9;:18::i;:::-;-1:-1:-1;;;;;36364:18:1;;;;;;:9;:18;;;;;:25;;:49;:29;:49;:::i;803:619:2:-;863:4;1331:20;;1174:66;1371:23;;;;;;:42;;-1:-1:-1;;1398:15:2;;;1363:51;-1:-1:-1;;803:619:2:o;39324:422:1:-;39388:5;39410:15;39419:5;39410:8;:15::i;:::-;39406:333;;;-1:-1:-1;39455:2:1;39442:16;;39406:333;39550:37;;;22:32:-1;6:49;;39550:37:1;;;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;39533:55:1;;;;39492:12;;39506:23;;-1:-1:-1;;;;;39533:16:1;;;39550:37;;39533:55;;;;;;25:18:-1;36:153;66:2;61:3;58:11;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;274:1;267:3;263:2;259:12;254:3;250:22;246:30;315:4;311:9;305:3;299:10;295:26;356:4;350:3;344:10;340:21;389:7;380;377:20;372:3;365:33;3:399;;;39533:55:1;;;;;;;;;;;;;;;;;;;;;;;12:1:-1;19;14:27;;;;67:4;61:11;56:16;;134:4;130:9;123:4;105:16;101:27;97:43;94:1;90:51;84:4;77:65;157:16;154:1;147:27;211:16;208:1;201:4;198:1;194:12;179:49;5:228;;14:27;32:4;27:9;;5:228;;39491:97:1;;;;39611:7;39603:71;;;;-1:-1:-1;;;39603:71:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;39707:10;39696:31;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;39696:31:1;;-1:-1:-1;39689:38:1;;-1:-1:-1;;39689:38:1;39905:419;39967:13;39997:15;40006:5;39997:8;:15::i;:::-;39993:324;;;-1:-1:-1;40029:12:1;;;;;;;;;;;;-1:-1:-1;;;40029:12:1;;;;;;39993:324;40133:35;;;22:32:-1;6:49;;40133:35:1;;;;;49:4:-1;25:18;;61:17;;-1:-1;;;;;182:15;-1:-1;;;179:29;160:49;;40116:53:1;;;;40075:12;;40089:23;;-1:-1:-1;;;;;40116:16:1;;;40133:35;;40116:53;;;;;;25:18:-1;36:153;66:2;61:3;58:11;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;274:1;267:3;263:2;259:12;254:3;250:22;246:30;315:4;311:9;305:3;299:10;295:26;356:4;350:3;344:10;340:21;389:7;380;377:20;372:3;365:33;3:399;;;40116:53:1;;;;;;;;;;;;;;;;;;;;;;;12:1:-1;19;14:27;;;;67:4;61:11;56:16;;134:4;130:9;123:4;105:16;101:27;97:43;94:1;90:51;84:4;77:65;157:16;154:1;147:27;211:16;208:1;201:4;198:1;194:12;179:49;5:228;;14:27;32:4;27:9;;5:228;;40074:95:1;;;;40192:7;40184:67;;;;-1:-1:-1;;;40184:67:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;40284:10;40273:32;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;40273:32:1;;;;;;;;;;;;;19:11:-1;14:3;11:20;8:2;;;44:1;41;34:12;8:2;62:21;;;;123:4;114:14;;138:31;;;135:2;;;182:1;179;172:12;135:2;213:10;;261:11;244:29;;285:43;;;282:58;-1:-1;233:115;230:2;;;361:1;358;351:12;230:2;372:25;;-1:-1;40273:32:1;;420:4:-1;411:14;;;;40273:32:1;;;;;411:14:-1;40273:32:1;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;40273:32:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;40266:39;;;;;;34650:351;5011:11;;34714:7;;5011:11;;5003:41;;;;;-1:-1:-1;;;5003:41:1;;;;;;;;;;;;-1:-1:-1;;;5003:41:1;;;;;;;;;;;;;;;5055:11;:19;;-1:-1:-1;;5055:19:1;;;34743:13:::1;:11;:13::i;:::-;34742:14;34734:67;;;;-1:-1:-1::0;;;34734:67:1::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1::0;;;;;34876:18:1;::::1;34822:24;34876:18:::0;;;:9:::1;:18;::::0;;;;:25;34849:53:::1;::::0;34867:7;;34849:17:::1;:53::i;:::-;34822:80;;34913:46;34931:7;34940:18;34950:7;34940:9;:18::i;:::-;34913:17;:46::i;:::-;34977:16:::0;-1:-1:-1;5097:11:1;:18;;-1:-1:-1;;5097:18:1;5111:4;5097:18;;;34650:351;;-1:-1:-1;34650:351:1:o;892:1498:0:-;967:13;993:14;;;;1138:5;;1187:469;1194:9;;1187:469;;1225:24;1224:25;:75;;;;-1:-1:-1;1261:2:0;1254:4;:9;:14;;;:44;;;1289:8;1281:17;;1272:5;:26;1254:44;1220:179;;;-1:-1:-1;1347:4:0;;-1:-1:-1;1379:4:0;1220:179;1417:24;1413:185;;;1483:8;1475:17;;1466:5;:26;1462:94;;;1530:6;1517:19;;1462:94;1574:8;;;;;1413:185;1620:2;1612:10;1637:7;;;;;1612:10;;-1:-1:-1;1187:469:0;;;1687:8;1679:17;;1670:5;:26;1666:205;;1755:5;1743:8;1735:17;;1722:6;1731:1;1722:10;:30;:38;1713:47;;1797:1;1788:6;:10;1775:23;;1666:205;;;1820:14;;1816:55;;1851:8;;;;;1816:55;1881:19;1913:6;1903:17;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;1903:17:0;;;;;;;;;;;;;;;;;;;;;;;;;;21:6:-1;;108:14;1903:17:0;87:42:-1;143:17;;-1:-1;1903:17:0;-1:-1:-1;1975:6:0;;-1:-1:-1;1975:6:0;;1881:39;-1:-1:-1;;;1947:10:0;;1931:13;1992:359;2016:6;2012:1;:10;1992:359;;;2052:1;2048;:5;:24;;;;;2062:10;2057:1;:15;2048:24;2044:296;;;-1:-1:-1;;;2093:6:0;2100:7;;;;;;;2093:15;;;;;;;;;;;:27;-1:-1:-1;;;;;2093:27:0;;;;;;;;;2044:296;;;2146:11;2142:198;;-1:-1:-1;;;2178:6:0;2185:7;;;;;;;2178:15;;;;;;;2142:198;2289:2;2280:6;:11;2275:2;:16;2264:29;;2246:6;2253:7;;;;;;;2246:15;;;;;;;;;;;:47;-1:-1:-1;;;;;2246:47:0;;;;;;;;-1:-1:-1;2322:2:0;2312:12;;;;2142:198;2024:3;;1992:359;;;-1:-1:-1;2375:6:0;;892:1498;-1:-1:-1;;;;;;;;;;892:1498:0:o;3273:180::-;3328:13;3358:6;3354:92;;;-1:-1:-1;3381:10:0;;;;;;;;;;;;-1:-1:-1;;;3381:10:0;;;;;;3354:92;-1:-1:-1;3424:10:0;;;;;;;;;;;;-1:-1:-1;;;3424:10:0;;;;;;2583:559;2643:13;2670:12;2684:13;2699:11;2712:12;2726:14;2745:57;2793:8;2745:47;:57::i;:::-;2669:133;;;;;;;;;;;2859:36;2891:3;2859:31;:36::i;:::-;2910:25;2929:5;2910:18;:25::i;:::-;2950:23;2968:4;2950:17;:23::i;:::-;3006:37;3038:4;3006:31;:37::i;:::-;3058:39;3090:6;3058:31;:39::i;:::-;2828:304;;;;;;;;;;;;;;;36:153:-1;66:2;61:3;58:11;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;299:10;344;;263:2;259:12;;;254:3;250:22;-1:-1;;246:30;311:9;;295:26;;;340:21;;377:20;365:33;;2828:304:0;;;;;;;;;;-1:-1:-1;2828:304:0;;;36:153:-1;66:2;61:3;58:11;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;299:10;344;;263:2;259:12;;;254:3;250:22;-1:-1;;246:30;311:9;;295:26;;;340:21;;377:20;365:33;;2828:304:0;;;;;;;;;;-1:-1:-1;2828:304:0;;;36:153:-1;66:2;61:3;58:11;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;274:1;267:3;263:2;259:12;254:3;250:22;246:30;315:4;311:9;305:3;299:10;295:26;356:4;350:3;344:10;340:21;389:7;380;377:20;372:3;365:33;3:399;;;2828:304:0;;;;;;;-1:-1:-1;;;2828:304:0;;;;;;;;;;;;;;;36:153:-1;66:2;61:3;58:11;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;299:10;344;;263:2;259:12;;;254:3;250:22;-1:-1;;246:30;311:9;;295:26;;;340:21;;377:20;365:33;;2828:304:0;;;;;;;;;;-1:-1:-1;2828:304:0;;;36:153:-1;66:2;61:3;58:11;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;299:10;344;;263:2;259:12;;;;254:3;250:22;-1:-1;;246:30;311:9;;295:26;;;340:21;;377:20;;;;365:33;;-1:-1;;;2828:304:0;;;;;-1:-1:-1;2828:304:0;;;26:21:-1;;;-1:-1;;22:32;6:49;;2828:304:0;;;;;;;;-1:-1:-1;;;;;;;;;;;;;2583:559:0:o;1841:192:6:-;1927:7;1963:12;1955:6;;;;1947:29;;;;-1:-1:-1;;;1947:29:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;1947:29:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;1999:5:6;;;1841:192::o;2521:452:4:-;-1:-1:-1;;;;;2625:20:4;;2617:71;;;;-1:-1:-1;;;2617:71:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;2707:23:4;;2699:77;;;;-1:-1:-1;;;2699:77:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;2809:17:4;;;;;;:9;:17;;;;;;:29;;2831:6;2809:29;:21;:29;:::i;:::-;-1:-1:-1;;;;;2789:17:4;;;;;;;:9;:17;;;;;;:49;;;;2872:20;;;;;;;:32;;2897:6;2872:32;:24;:32;:::i;:::-;-1:-1:-1;;;;;2849:20:4;;;;;;;:9;:20;;;;;;;;;:55;;;;2930:35;;;;;;;2849:20;;2930:35;;;;;;;;;;;;;2521:452;;;:::o;23528:575:1:-;23610:7;23638:30;23660:7;23638:21;:30::i;:::-;23630:95;;;;-1:-1:-1;;;23630:95:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23758:1;23744:11;:15;23736:77;;;;-1:-1:-1;;;23736:77:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;23869:18:1;;23834:32;23869:18;;;:9;:18;;;;;23912:11;;:28;;23928:11;23912:28;:15;:28;:::i;:::-;23898:42;;23961:41;23994:7;23961:32;:41::i;:::-;24030:65;24050:7;24059:32;24079:11;24059:19;:32::i;:::-;24093:1;24030:19;:65::i;35742:247::-;-1:-1:-1;;;;;35823:21:1;;35834:10;35823:21;35819:163;;;35861:39;35879:7;35888:11;35861:17;:39::i;:::-;35819:163;;;35933:37;35949:7;35958:11;35933:15;:37::i;37668:136::-;-1:-1:-1;;;;;37777:18:1;;37738:4;37777:18;;;:9;:18;;;;;37762:34;;:14;:34::i;3355:328:4:-;-1:-1:-1;;;;;3437:21:4;;3429:69;;;;-1:-1:-1;;;3429:69:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3526:12;;:24;;3543:6;3526:24;:16;:24;:::i;:::-;3511:12;:39;;;-1:-1:-1;;;;;3582:18:4;;;;:9;:18;;;;;;:30;;3605:6;3582:30;:22;:30;:::i;:::-;-1:-1:-1;;;;;3561:18:4;;;;;;:9;:18;;;;;;;;:51;;;;3638:37;;;;;;;3561:18;;;;3638:37;;;;;;;;;;3355:328;;:::o;32876:1123:1:-;4788:13;:11;:13::i;:::-;4780:43;;;;;-1:-1:-1;;;4780:43:1;;;;;;;;;;;;-1:-1:-1;;;4780:43:1;;;;;;;;;;;;;;;33026:1:::1;33012:11;:15;33004:76;;;;-1:-1:-1::0;;;33004:76:1::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;33223:30;33245:7;33223:21;:30::i;:::-;33219:195;;;-1:-1:-1::0;;;;;33316:18:1;::::1;;::::0;;;:9:::1;:18;::::0;;;;:25;33293:49:::1;::::0;:18:::1;33326:7:::0;33293:9:::1;:18::i;:::-;:22:::0;:49:::1;:22;:49;:::i;:::-;33278:11;:64;;33270:131;;;;-1:-1:-1::0;;;33270:131:1::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;33434:31;33444:7;33453:11;33434:9;:31::i;:::-;33487:21;33510:22:::0;33536:32:::1;33556:11;33536:19;:32::i;:::-;33486:82:::0;;-1:-1:-1;33486:82:1;-1:-1:-1;33596:43:1::1;33486:82:::0;33615:23;33596:43:::1;:18;:43;:::i;:::-;33579:60;;33656:23;33665:13;33656:8;:23::i;:::-;33652:340;;;33717:14;33704:9;:27;33696:88;;;;-1:-1:-1::0;;;33696:88:1::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;33652:340;;;33825:9;:14:::0;33817:72:::1;;;;-1:-1:-1::0;;;33817:72:1::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;33904:76;33923:13;33938:10;33958:4;33965:14;33904:18;:76::i;:::-;4834:1;;32876:1123:::0;;;:::o;28431:1713::-;28601:17;:24;28536:25;;;;28592:34;;:4;;:34;:8;:34;:::i;:::-;28576:50;-1:-1:-1;28576:50:1;28637:13;28697:653;28718:1;28704:11;:15;:51;;;;-1:-1:-1;28731:17:1;:24;28723:32;;28704:51;28697:653;;;28786:23;28812:72;28829:17;28847:5;28829:24;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;28829:24:1;28855:11;28868:15;28812:16;:72::i;:::-;28786:98;;28921:11;28903:15;:29;28899:241;;;29019:20;;28953:19;;;;;28999:40;;;:64;;-1:-1:-1;29043:20:1;;28999:64;28991:133;;;;-1:-1:-1;;;28991:133:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;29247:17;:24;29168:15;;-1:-1:-1;29212:7:1;;;;;29168:15;;29238:33;;29234:83;;;29300:1;29292:9;;29234:83;-1:-1:-1;29331:7:1;;28697:653;;;29368:16;;29360:80;;;;-1:-1:-1;;;29360:80:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;29461:30;;29551:10;29547:252;;29586:17;:24;;-1:-1:-1;29547:252:1;;;29641:5;29632;:14;29628:171;;-1:-1:-1;;29763:17:1;:24;;-1:-1:-1;;29688:9:1;29696:1;29628:171;29828:9;29823:314;29847:5;29843:1;:9;29823:314;;;-1:-1:-1;;29874:7:1;;;;29900:21;:38;;;;;29933:5;29925;:13;29900:38;29896:157;;;29967:22;29959:30;;30032:5;30008:29;;29896:157;30067:58;30100:17;30118:5;30100:24;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;30100:24:1;30067:32;:58::i;:::-;29854:3;;29823:314;;;;28431:1713;;;;;;;;;:::o;25741:784::-;25843:7;25891:46;25911:25;:16;25932:3;25911:25;:20;:25;:::i;:::-;25891:15;;;:46;:19;:46;:::i;:::-;25873:15;:64;25958:19;25980:12;:10;:12::i;:::-;25958:34;;26007:21;26016:11;26007:8;:21::i;:::-;26003:393;;;26045:46;;26053:10;;26045:46;;;;;26074:16;;26045:46;;;;26074:16;26053:10;26045:46;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;26110:7:1;;26106:79;;26138:14;;:28;;-1:-1:-1;;;;;26138:14:1;;;;:28;;;;;26162:3;;26138:14;:28;:14;:28;26162:3;26138:14;:28;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;26138:28:1;26106:79;26003:393;;;26217:57;26232:11;26245:10;26257:16;26217:14;:57::i;:::-;26293:7;;26289:96;;26349:14;;26321:48;;26336:11;;-1:-1:-1;;;;;26349:14:1;26365:3;26321:14;:48::i;:::-;26421:62;;;;;;;;;;;;;;26449:10;;-1:-1:-1;;;;;26421:62:1;;;;;;;;;;;;;;-1:-1:-1;26501:16:1;;25741:784;-1:-1:-1;;;25741:784:1:o;3843:278:6:-;3929:7;3964:12;3957:5;3949:28;;;;-1:-1:-1;;;3949:28:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;3949:28:6;;3988:9;4004:1;4000;:5;;;;;;;3843:278;-1:-1:-1;;;;;3843:278:6:o;30457:502:1:-;30582:9;30577:282;30601:8;:15;30597:1;:19;30577:282;;;30642:16;30638:62;;30679:5;;30638:62;30728:59;30745:8;30754:1;30745:11;;;;;;;;;;;;;;30758;30771:15;30728:16;:59::i;:::-;30714:73;;30802:45;30835:8;30844:1;30835:11;;;;;;;;;;;;;;30802:32;:45::i;:::-;30618:3;;30577:282;;;-1:-1:-1;30877:16:1;;30869:82;;;;-1:-1:-1;;;30869:82:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3691:328:4;-1:-1:-1;;;;;3773:21:4;;3765:69;;;;-1:-1:-1;;;3765:69:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;3868:18:4;;;;;;:9;:18;;;;;;:30;;3891:6;3868:30;:22;:30;:::i;:::-;-1:-1:-1;;;;;3847:18:4;;;;;;:9;:18;;;;;:51;;;;3924:12;:24;;3941:6;3924:24;:16;:24;:::i;:::-;3909:12;:39;;;3974:37;;;;;;;;-1:-1:-1;;;;;3974:37:4;;;;;;;;;;;;;3691:328;;:::o;4652:440:3:-;4720:9;;;;;;4822:40;1015:12;4834:9;:27;4822:11;:40::i;:::-;4801:61;;;;;;-1:-1:-1;1067:7:3;1015:12;4885:27;;;4930:23;;;;-1:-1:-1;1116:2:3;4971:23;;;5014:25;;;;-1:-1:-1;5059:25:3;;;;;-1:-1:-1;4652:440:3;-1:-1:-1;;4652:440:3:o;5136:306:0:-;5214:13;5240:21;5264:24;5281:6;5264:16;:24::i;:::-;5240:48;;5312:2;5303:6;:11;5299:136;;;5367:7;5345:30;;;;;;-1:-1:-1;;;5345:30:0;;;;;;;;;;;;;;;36:153:-1;66:2;61:3;58:11;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;274:1;267:3;263:2;259:12;254:3;250:22;246:30;315:4;311:9;305:3;299:10;295:26;356:4;350:3;344:10;340:21;389:7;380;377:20;372:3;365:33;3:399;;;5345:30:0;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;5345:30:0;;;5331:45;;;;;4118:875;4182:13;4212:5;4221:1;4212:10;4208:778;;;-1:-1:-1;4239:12:0;;;;;;;;;;;;-1:-1:-1;;;4239:12:0;;;;;;4208:778;4273:5;4282:1;4273:10;4269:717;;;-1:-1:-1;4300:12:0;;;;;;;;;;;;-1:-1:-1;;;4300:12:0;;;;;;4269:717;4334:5;4343:1;4334:10;4330:656;;;-1:-1:-1;4361:12:0;;;;;;;;;;;;-1:-1:-1;;;4361:12:0;;;;;;4330:656;4395:5;4404:1;4395:10;4391:595;;;-1:-1:-1;4422:12:0;;;;;;;;;;;;-1:-1:-1;;;4422:12:0;;;;;;4391:595;4456:5;4465:1;4456:10;4452:534;;;-1:-1:-1;4483:12:0;;;;;;;;;;;;-1:-1:-1;;;4483:12:0;;;;;;4452:534;4517:5;4526:1;4517:10;4513:473;;;-1:-1:-1;4544:12:0;;;;;;;;;;;;-1:-1:-1;;;4544:12:0;;;;;;4513:473;4578:5;4587:1;4578:10;4574:412;;;-1:-1:-1;4605:12:0;;;;;;;;;;;;-1:-1:-1;;;4605:12:0;;;;;;4574:412;4639:5;4648:1;4639:10;4635:351;;;-1:-1:-1;4666:12:0;;;;;;;;;;;;-1:-1:-1;;;4666:12:0;;;;;;4635:351;4700:5;4709:1;4700:10;4696:290;;;-1:-1:-1;4727:12:0;;;;;;;;;;;;-1:-1:-1;;;4727:12:0;;;;;;4696:290;4761:5;4770:2;4761:11;4757:229;;;-1:-1:-1;4789:12:0;;;;;;;;;;;;-1:-1:-1;;;4789:12:0;;;;;;4757:229;4823:5;4832:2;4823:11;4819:167;;;-1:-1:-1;4851:12:0;;;;;;;;;;;;-1:-1:-1;;;4851:12:0;;;;;;4819:167;4885:5;4894:2;4885:11;4881:105;;;-1:-1:-1;4913:12:0;;;;;;;;;;;;-1:-1:-1;;;4913:12:0;;;;;;4881:105;-1:-1:-1;4958:16:0;;;;;;;;;;;;-1:-1:-1;;;4958:16:0;;;;;;3586:409;3648:13;3674:22;3705;3722:4;3705:16;:22::i;:::-;3761:12;;;3771:1;3761:12;;;;;;;;;3674:54;;-1:-1:-1;3739:19:0;;3761:12;;;;21:6:-1;;108:14;3761:12:0;87:42:-1;-1:-1;;3805:16:0;;3739:34;;-1:-1:-1;;;;3805:20:0;;3836:120;3869:9;:16;3865:1;:20;3836:120;;;3932:9;3942:1;3932:12;;;;;;;;;;;;;;;;3907:6;3918:10;3914:1;:14;3907:22;;;;;;;;;;;:37;-1:-1:-1;;;;;3907:37:0;;;;;;;;-1:-1:-1;3887:3:0;;3836:120;;;-1:-1:-1;3980:6:0;;3586:409;-1:-1:-1;;;;3586:409:0:o;2313:200:4:-;-1:-1:-1;;;;;2421:20:4;;;;;;:11;:20;;;;;;;;2409:10;2421:32;;;;;;;;;2385:81;;2400:7;;2421:44;;2458:6;2421:44;:36;:44;:::i;2385:81::-;2477:28;2489:7;2498:6;2477:11;:28::i;4578:130:6:-;4636:7;4663:37;4667:1;4670;4663:37;;;;;;;;;;;;;;;;;:3;:37::i;31333:1211:1:-;31439:7;31459:17;31479:29;31500:7;31479:20;:29::i;:::-;31459:49;-1:-1:-1;31523:13:1;;31519:989;;-1:-1:-1;;;;;31602:18:1;;31567:32;31602:18;;;:9;:18;;;;;;31677:23;;;31673:254;;;-1:-1:-1;31739:9:1;31781:26;:11;31739:9;31781:26;:15;:26;:::i;:::-;31767:40;;31673:254;;;-1:-1:-1;31910:1:1;;31673:254;31956:21;31979:14;31997:36;32017:15;31997:19;:36::i;:::-;31955:78;;-1:-1:-1;31955:78:1;-1:-1:-1;32116:13:1;31955:78;32127:1;32116:13;:10;:13;:::i;:::-;32172:11;;32107:22;;-1:-1:-1;32172:32:1;;32188:15;32172:32;:15;:32;:::i;:::-;32158:46;;32238:23;32247:13;32238:8;:23::i;:::-;32234:184;;;32282:33;;-1:-1:-1;;;;;32282:25:1;;;:33;;;;;32308:6;;32282:33;;;;32308:6;32282:25;:33;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;32282:33:1;32234:184;;;32356:46;32371:13;32386:7;32395:6;32356:14;:46::i;:::-;32455:15;-1:-1:-1;;;;;32437:59:1;32446:7;-1:-1:-1;;;;;32437:59:1;;32472:6;32480:15;32437:59;;;;;;;;;;;;;;;;;;;;;;;;31519:989;;;;;-1:-1:-1;32525:11:1;;31333:1211;-1:-1:-1;;;31333:1211:1:o;40559:333::-;40729:17;;40706:60;;;-1:-1:-1;;;;;40706:60:1;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;40706:60:1;;;;;;;25:18:-1;;61:17;;40729::1;;;;;;-1:-1:-1;;;;;;40706:60:1;-1:-1:-1;;;;;182:15;;;179:29;;;;160:49;;40695:72:1;;;;-1:-1:-1;;40668:23:1;;40695:10;;;40706:60;40695:72;;;25:18:-1;40695:72:1;;25:18:-1;36:153;66:2;61:3;58:11;36:153;;176:10;;164:23;;-1:-1;;139:12;;;;98:2;89:12;;;;114;36:153;;;274:1;267:3;263:2;259:12;254:3;250:22;246:30;315:4;311:9;305:3;299:10;295:26;356:4;350:3;344:10;340:21;389:7;380;377:20;372:3;365:33;3:399;;;40695:72:1;;;;;;;;;;;;;;;;;;;;;;;;12:1:-1;19;14:27;;;;67:4;61:11;56:16;;134:4;130:9;123:4;105:16;101:27;97:43;94:1;90:51;84:4;77:65;157:16;154:1;147:27;211:16;208:1;201:4;198:1;194:12;179:49;5:228;;14:27;32:4;27:9;;5:228;;40653:114:1;;;;40786:7;:69;;;;-1:-1:-1;40798:17:1;;:22;;:56;;;40835:10;40824:30;;;;;15:2:-1;10:3;7:11;4:2;;;31:1;28;21:12;4:2;-1:-1;40824:30:1;40798:56;40778:106;;;;;-1:-1:-1;;;40778:106:1;;;;;;;;;;;;;;;;;;;;;;;;;;;3363:622:3;3419:9;;;3480:5;3507:31;;;3419:9;3565:6;3557:1;:5;;:14;;-1:-1:-1;3609:1:3;3604;3591:6;:10;;:14;3590:20;3586:24;;;;3621:9;3650:7;3633:4;3645:1;3641:5;;3633:14;:24;;-1:-1:-1;3691:1:3;3676:4;:12;;:16;3672:1;:20;3695:2;3672:25;3668:29;;3708:10;3730:4;3726:1;3721:2;:6;:13;;;;;;;-1:-1:-1;3745:8:3;3776:2;3760:4;:13;;:18;3756:22;;;-1:-1:-1;3802:2:3;3793:6;:11;-1:-1:-1;;3869:6:3;;;;3862:3;:14;:22;;;;:26;;;3833:1;3837:2;:6;;;3824:19;;;;;;;;-1:-1:-1;3793:11:3;-1:-1:-1;3862:26:3;-1:-1:-1;;;;3363:622:3:o;273:744:7:-;329:13;550:10;546:53;;-1:-1:-1;577:10:7;;;;;;;;;;;;-1:-1:-1;;;577:10:7;;;;;;546:53;624:5;609:12;665:78;672:9;;665:78;;698:8;;729:2;721:10;;;;665:78;;;753:19;785:6;775:17;;;5:9:-1;2:2;;;27:1;24;17:12;2:2;775:17:7;;;;;;;;;;;;;;;;;;;;;;;;;;21:6:-1;;108:14;775:17:7;87:42:-1;143:17;;-1:-1;775:17:7;-1:-1:-1;847:5:7;;-1:-1:-1;753:39:7;-1:-1:-1;;;819:10:7;;863:115;870:9;;863:115;;937:2;930:4;:9;925:2;:14;914:27;;896:6;903:7;;;;;;;896:15;;;;;;;;;;;:45;-1:-1:-1;;;;;896:45:7;;;;;;;;-1:-1:-1;964:2:7;956:10;;;;863:115;;;-1:-1:-1;1002:6:7;273:744;-1:-1:-1;;;;273:744:7:o;5185:166:6:-;5271:7;5307:12;5299:6;5291:29;;;;-1:-1:-1;;;5291:29:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27:10:-1;;8:100;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;5291:29:6;;5342:1;5338;:5;;;;;;;5185:166;-1:-1:-1;;;;5185:166:6:o;221:41335:1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;221:41335:1;;;-1:-1:-1;221:41335:1;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;;

Swarm Source

ipfs://cb30ae80319463574ff120f520633d68378fa215960c0dd60da4052df64ca491

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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