pragma solidity ^0.5.8;


interface IERC20 {
    
    function totalSupply() external view returns (uint256);

    
    function balanceOf(address account) external view returns (uint256);

    
    function transfer(address recipient, uint256 amount) external returns (bool);

    
    function allowance(address owner, address spender) external view returns (uint256);

    
    function approve(address spender, uint256 amount) external returns (bool);

    
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    
    event Transfer(address indexed from, address indexed to, uint256 value);

    
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

contract ERC20Detailed is IERC20 {
    string private _name;
    string private _symbol;
    uint8 private _decimals;

    
    constructor (string memory name, string memory symbol, uint8 decimals) public {
        _name = name;
        _symbol = symbol;
        _decimals = decimals;
    }

    
    function name() public view returns (string memory) {
        return _name;
    }

    
    function symbol() public view returns (string memory) {
        return _symbol;
    }

    
    function decimals() public view returns (uint8) {
        return _decimals;
    }
}

library SafeMath {
    
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, "SafeMath: subtraction overflow");
        uint256 c = a - b;

        return c;
    }

    
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        
        
        
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        
        require(b > 0, "SafeMath: division by zero");
        uint256 c = a / b;
        

        return c;
    }

    
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b != 0, "SafeMath: modulo by zero");
        return a % b;
    }
}

contract ERC20 is IERC20 {
    using SafeMath for uint256;

    mapping (address => uint256) private _balances;

    mapping (address => mapping (address => uint256)) private _allowances;

    uint256 private _totalSupply;

    
    function totalSupply() public view returns (uint256) {
        return _totalSupply;
    }

    
    function balanceOf(address account) public view returns (uint256) {
        return _balances[account];
    }

    
    function transfer(address recipient, uint256 amount) public returns (bool) {
        _transfer(msg.sender, recipient, amount);
        return true;
    }

    
    function allowance(address owner, address spender) public view returns (uint256) {
        return _allowances[owner][spender];
    }

    
    function approve(address spender, uint256 value) public returns (bool) {
        _approve(msg.sender, spender, value);
        return true;
    }

    
    function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) {
        _transfer(sender, recipient, amount);
        _approve(sender, msg.sender, _allowances[sender][msg.sender].sub(amount));
        return true;
    }

    
    function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
        _approve(msg.sender, spender, _allowances[msg.sender][spender].add(addedValue));
        return true;
    }

    
    function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
        _approve(msg.sender, spender, _allowances[msg.sender][spender].sub(subtractedValue));
        return true;
    }

    
    function _transfer(address sender, address recipient, uint256 amount) internal {
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");

        _balances[sender] = _balances[sender].sub(amount);
        _balances[recipient] = _balances[recipient].add(amount);
        emit Transfer(sender, recipient, amount);
    }

    
    function _mint(address account, uint256 amount) internal {
        require(account != address(0), "ERC20: mint to the zero address");

        _totalSupply = _totalSupply.add(amount);
        _balances[account] = _balances[account].add(amount);
        emit Transfer(address(0), account, amount);
    }

     
    function _burn(address account, uint256 value) internal {
        require(account != address(0), "ERC20: burn from the zero address");

        _totalSupply = _totalSupply.sub(value);
        _balances[account] = _balances[account].sub(value);
        emit Transfer(account, address(0), value);
    }

    
    function _approve(address owner, address spender, uint256 value) internal {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = value;
        emit Approval(owner, spender, value);
    }

    
    function _burnFrom(address account, uint256 amount) internal {
        _burn(account, amount);
        _approve(account, msg.sender, _allowances[account][msg.sender].sub(amount));
    }
}

library Roles {
    struct Role {
        mapping (address => bool) bearer;
    }

    
    function add(Role storage role, address account) internal {
        require(!has(role, account), "Roles: account already has role");
        role.bearer[account] = true;
    }

    
    function remove(Role storage role, address account) internal {
        require(has(role, account), "Roles: account does not have role");
        role.bearer[account] = false;
    }

    
    function has(Role storage role, address account) internal view returns (bool) {
        require(account != address(0), "Roles: account is the zero address");
        return role.bearer[account];
    }
}

contract MinterRole {
    using Roles for Roles.Role;

    event MinterAdded(address indexed account);
    event MinterRemoved(address indexed account);

    Roles.Role private _minters;

    constructor () internal {
        _addMinter(msg.sender);
    }

    modifier onlyMinter() {
        require(isMinter(msg.sender), "MinterRole: caller does not have the Minter role");
        _;
    }

    function isMinter(address account) public view returns (bool) {
        return _minters.has(account);
    }

    function addMinter(address account) public onlyMinter {
        _addMinter(account);
    }

    function renounceMinter() public {
        _removeMinter(msg.sender);
    }

    function _addMinter(address account) internal {
        _minters.add(account);
        emit MinterAdded(account);
    }

    function _removeMinter(address account) internal {
        _minters.remove(account);
        emit MinterRemoved(account);
    }
}

contract ERC20Mintable is ERC20, MinterRole {
    
    function mint(address account, uint256 amount) public onlyMinter returns (bool) {
        _mint(account, amount);
        return true;
    }
}

contract ERC20Capped is ERC20Mintable {
    uint256 private _cap;

    
    constructor (uint256 cap) public {
        require(cap > 0, "ERC20Capped: cap is 0");
        _cap = cap;
    }

    
    function cap() public view returns (uint256) {
        return _cap;
    }

    
    function _mint(address account, uint256 value) internal {
        require(totalSupply().add(value) <= _cap, "ERC20Capped: cap exceeded");
        super._mint(account, value);
    }
}

contract ERC20Burnable is ERC20 {
    
    function burn(uint256 amount) public {
        _burn(msg.sender, amount);
    }

    
    function burnFrom(address account, uint256 amount) public {
        _burnFrom(account, amount);
    }
}

library Address {
    
    function isContract(address account) internal view returns (bool) {
        
        
        

        uint256 size;
        
        assembly { size := extcodesize(account) }
        return size > 0;
    }
}

library SafeERC20 {
    using SafeMath for uint256;
    using Address for address;

    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        
        
        
        
        require((value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).add(value);
        callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).sub(value);
        callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    
    function callOptionalReturn(IERC20 token, bytes memory data) private {
        
        

        
        
        
        
        
        require(address(token).isContract(), "SafeERC20: call to non-contract");

        
        (bool success, bytes memory returndata) = address(token).call(data);
        require(success, "SafeERC20: low-level call failed");

        if (returndata.length > 0) { 
            
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

contract ReentrancyGuard {
    
    uint256 private _guardCounter;

    constructor () internal {
        
        
        _guardCounter = 1;
    }

    
    modifier nonReentrant() {
        _guardCounter += 1;
        uint256 localCounter = _guardCounter;
        _;
        require(localCounter == _guardCounter, "ReentrancyGuard: reentrant call");
    }
}

contract Crowdsale is ReentrancyGuard {
    using SafeMath for uint256;
    using SafeERC20 for IERC20;

    
    IERC20 private _token;

    
    address payable private _wallet;

    
    
    
    
    uint256 private _rate;

    
    uint256 private _weiRaised;

    
    event TokensPurchased(address indexed purchaser, address indexed beneficiary, uint256 value, uint256 amount);

    event RateAdjusted(uint256 adjustedRate);

    
    constructor (uint256 rate, address payable wallet, IERC20 token) public {
        require(rate > 0, "Crowdsale: rate is 0");
        require(wallet != address(0), "Crowdsale: wallet is the zero address");
        require(address(token) != address(0), "Crowdsale: token is the zero address");

        _rate = rate;
        _wallet = wallet;
        _token = token;
    }

    
    function () external payable {
        buyTokens(msg.sender);
    }

    
    function token() public view returns (IERC20) {
        return _token;
    }

    
    function wallet() public view returns (address payable) {
        return _wallet;
    }

    
    function rate() public view returns (uint256) {
        return _rate;
    }

    
    function weiRaised() public view returns (uint256) {
        return _weiRaised;
    }

    
    function buyTokens(address beneficiary) public nonReentrant payable {
        uint256 weiAmount = msg.value;
        _preValidatePurchase(beneficiary, weiAmount);

        
        uint256 tokens = _getTokenAmount(weiAmount);

        
        _weiRaised = _weiRaised.add(weiAmount);

        _processPurchase(beneficiary, tokens);
        emit TokensPurchased(msg.sender, beneficiary, weiAmount, tokens);

        _updatePurchasingState(beneficiary, weiAmount);

        _forwardFunds();
        _postValidatePurchase(beneficiary, weiAmount);
    }

    
    function _preValidatePurchase(address beneficiary, uint256 weiAmount) internal view {
        require(beneficiary != address(0), "Crowdsale: beneficiary is the zero address");
        require(weiAmount != 0, "Crowdsale: weiAmount is 0");
    }

    
    function _postValidatePurchase(address beneficiary, uint256 weiAmount) internal view {
        
    }

    
    function _deliverTokens(address beneficiary, uint256 tokenAmount) internal {
        _token.safeTransfer(beneficiary, tokenAmount);
    }

    
    function _processPurchase(address beneficiary, uint256 tokenAmount) internal {
        _deliverTokens(beneficiary, tokenAmount);
    }

    
    function _updatePurchasingState(address beneficiary, uint256 weiAmount) internal {
        
    }

    
    function _getTokenAmount(uint256 weiAmount) internal view returns (uint256) {
        return weiAmount.mul(_rate);
    }

    
    function adjustRate(uint256 newRate) public {
        require(newRate > 0, "Crowdsale-adjustRate: Rate has to be non-zero");
        _rate = newRate;
        emit RateAdjusted(newRate);
    }

    
    function _forwardFunds() internal {
        _wallet.transfer(msg.value);
    }
}

contract TimedCrowdsale is Crowdsale {
    using SafeMath for uint256;

    uint256 private _openingTime;
    uint256 private _closingTime;

    
    event TimedCrowdsaleExtended(uint256 prevClosingTime, uint256 newClosingTime);

    
    modifier onlyWhileOpen {
        require(isOpen(), "TimedCrowdsale: not open");
        _;
    }

    
    constructor (uint256 openingTime, uint256 closingTime) public {
        
        require(openingTime >= block.timestamp, "TimedCrowdsale: opening time is before current time");
        
        require(closingTime > openingTime, "TimedCrowdsale: opening time is not before closing time");

        _openingTime = openingTime;
        _closingTime = closingTime;
    }

    
    function openingTime() public view returns (uint256) {
        return _openingTime;
    }

    
    function closingTime() public view returns (uint256) {
        return _closingTime;
    }

    
    function isOpen() public view returns (bool) {
        
        return block.timestamp >= _openingTime && block.timestamp <= _closingTime;
    }

    
    function hasClosed() public view returns (bool) {
        
        return block.timestamp > _closingTime;
    }

    
    function _preValidatePurchase(address beneficiary, uint256 weiAmount) internal onlyWhileOpen view {
        super._preValidatePurchase(beneficiary, weiAmount);
    }

    
    function _extendTime(uint256 newClosingTime) internal {
        require(!hasClosed(), "TimedCrowdsale: already closed");
        
        require(newClosingTime > _closingTime, "TimedCrowdsale: new closing time is before current closing time");

        emit TimedCrowdsaleExtended(_closingTime, newClosingTime);
        _closingTime = newClosingTime;
    }
}

contract Secondary {
    address private _primary;

    
    event PrimaryTransferred(
        address recipient
    );

    
    constructor () internal {
        _primary = msg.sender;
        emit PrimaryTransferred(_primary);
    }

    
    modifier onlyPrimary() {
        require(msg.sender == _primary, "Secondary: caller is not the primary account");
        _;
    }

    
    function primary() public view returns (address) {
        return _primary;
    }

    
    function transferPrimary(address recipient) public onlyPrimary {
        require(recipient != address(0), "Secondary: new primary is the zero address");
        _primary = recipient;
        emit PrimaryTransferred(_primary);
    }
}

contract Ownable {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    
    constructor () internal {
        _owner = msg.sender;
        emit OwnershipTransferred(address(0), _owner);
    }

    
    function owner() public view returns (address) {
        return _owner;
    }

    
    modifier onlyOwner() {
        require(isOwner(), "Ownable: caller is not the owner");
        _;
    }

    
    function isOwner() public view returns (bool) {
        return msg.sender == _owner;
    }

    
    function renounceOwnership() public onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    }

    
    function transferOwnership(address newOwner) public onlyOwner {
        _transferOwnership(newOwner);
    }

    
    function _transferOwnership(address newOwner) internal {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}

contract ManagerRole is Ownable {
    using Roles for Roles.Role;
    using SafeMath for uint256;

    event ManagerAdded(address indexed account);
    event ManagerRemoved(address indexed account);

    Roles.Role private managers;
    uint256 private _numManager;

    constructor() internal {
        _addManager(msg.sender);
        _numManager = 1;
    }

    
    modifier onlyManager() {
        require(isManager(msg.sender), "ManagerRole-onlyManager: The account is not a manager");
        _;
    }

    
    
    function addManagers(address[] calldata accounts) external onlyOwner {
        uint256 length = accounts.length;
        require(length <= 256, "ManagerRole-addManagers:too many accounts");
        for (uint256 i = 0; i < length; i++) {
            _addManager(accounts[i]);
        }
    }
    
    
    function removeManager(address account) external onlyOwner {
        _removeManager(account);
    }

    
    function isManager(address account) public view returns (bool) {
        return managers.has(account);
    }

    
    function numManager() public view returns (uint256) {
        return _numManager;
    }

    
    function addManager(address account) public onlyOwner {
        require(account != address(0), "ManagerRole-addManager: account is zero");
        _addManager(account);
    }

    
    function renounceManager() public {
        require(_numManager >= 2, "ManagerRole-renounceManager: Managers are fewer than 2");
        _removeManager(msg.sender);
    }

    
    function renounceOwnership() public onlyOwner {
        revert("ManagerRole-renounceOwnership: Cannot renounce ownership");
    }

    
    function _addManager(address account) internal {
        _numManager = _numManager.add(1);
        managers.add(account);
        emit ManagerAdded(account);
    }

    
    function _removeManager(address account) internal {
        _numManager = _numManager.sub(1);
        managers.remove(account);
        emit ManagerRemoved(account);
    }
}

contract PausableManager is ManagerRole {

    event BePaused(address manager);
    event BeUnpaused(address manager);

    bool private _paused;   

    constructor() internal {
        _paused = false;
    }

   
    modifier whenNotPaused() {
        require(!_paused, "PausableManager-whenNotPaused: paused");
        _;
    }

    
    modifier whenPaused() {
        require(_paused, "PausableManager-whenPaused: not paused");
        _;
    }

    
    function paused() public view returns(bool) {
        return _paused;
    }

    
    function pause() public onlyManager whenNotPaused {
        _paused = true;
        emit BePaused(msg.sender);
    }

    
    function unpause() public onlyManager whenPaused {
        _paused = false;
        emit BeUnpaused(msg.sender);
    }
}

contract ValidAddress {
    
    modifier onlyValidAddress(address _address) {
        require(_address != address(0), "ValidAddress-onlyValidAddress:Not a valid address");
        _;
    }

    
    modifier isSenderNot(address _address) {
        require(_address != msg.sender, "ValidAddress-isSenderNot:Address is the same as the sender");
        _;
    }

    
    modifier isSender(address _address) {
        require(_address == msg.sender, "ValidAddress-isSender: Address is different from the sender");
        _;
    }
}

contract Whitelist is ValidAddress, PausableManager {

    mapping (address => bool) private _isWhitelisted;       
    mapping(address => uint) public _contributionAmounts;   
    uint public totalWhiteListed;                           
    address[] public holdersIndex;                          

    event AdddWhitelisted(address indexed user);
    event RemovedWhitelisted(address indexed user);


    
    function addWhitelisted(address user, uint256 maxAllowed) external onlyManager {
        _addWhitelisted(user, maxAllowed);
    }

    
    
    function addWhitelistedMultiple(address[] calldata users, uint256[] calldata maxAllowed) external onlyManager {
        uint256 length = users.length;
        require(length <= 256, "Whitelist-addWhitelistedMultiple: List too long");
        for (uint256 i = 0; i < length; i++) {
            _addWhitelisted(users[i], maxAllowed[i]);
        }
    }

    
    function removeWhitelisted(address user)
        external
        onlyManager
    {
        _removeWhitelisted(user);
    }

    
    
    function removeWhitelistedMultiple(address[] calldata users)
        external
        onlyManager
    {
        uint256 length = users.length;
        require(length <= 256, "Whitelist-removeWhitelistedMultiple: List too long");
        for (uint256 i = 0; i < length; i++) {
            _removeWhitelisted(users[i]);
        }
    }

    
    function isWhitelisted(address user) public view returns (bool) {
        return _isWhitelisted[user];
    }

    
    function returnMaxAmountForUser(address user) public view returns (uint256) {
        return  _contributionAmounts[user];
    }

    
    function _addWhitelisted(address user, uint maxToContribute)
        internal
        onlyValidAddress(user)
    {
        require(_isWhitelisted[user] == false, "Whitelist-_addWhitelisted: account already whitelisted");
        _isWhitelisted[user] = true;
        _contributionAmounts[user] = maxToContribute;
        totalWhiteListed++;
        holdersIndex.push(user);
        emit AdddWhitelisted(user);
    }

    
    function _removeWhitelisted(address user)
        internal
        onlyValidAddress(user)
    {
        require(_isWhitelisted[user] == true, "Whitelist-_removeWhitelisted: account was not whitelisted");
        _isWhitelisted[user] = false;
        _contributionAmounts[user] = 0;
        totalWhiteListed--;
        emit RemovedWhitelisted(user);
    }
}

contract WhitelistCrowdsale is Whitelist, Crowdsale {
    
    function _preValidatePurchase(address beneficiary, uint256 weiAmount)
        internal
        view
    {
        require(isWhitelisted(beneficiary), "WhitelistCrowdsale-_preValidatePurchase: beneficiary is not whitelisted");
        super._preValidatePurchase(beneficiary, weiAmount);
    }
}

contract PostDeliveryCrowdsale is TimedCrowdsale, WhitelistCrowdsale {
    using SafeMath for uint256;

    mapping(address => uint256) private _balances;
    __unstable__TokenVault private _vault;

    constructor() public {
        _vault = new __unstable__TokenVault();
         
        _addWhitelisted(address(_vault), 0);
    }

    
    function withdrawTokens(address beneficiary) public {
        require(hasClosed(), "PostDeliveryCrowdsale: not closed");
        uint256 amount = _balances[beneficiary];
        require(amount > 0, "PostDeliveryCrowdsale: beneficiary is not due any tokens");

        _balances[beneficiary] = 0;
        _vault.transfer(token(), beneficiary, amount);
    }

    
    function balanceOf(address account) public view returns (uint256) {
        return _balances[account];
    }

    
    function _processPurchase(address beneficiary, uint256 tokenAmount) internal {
        _balances[beneficiary] = _balances[beneficiary].add(tokenAmount);
        _deliverTokens(address(_vault), tokenAmount);
    }
}

contract __unstable__TokenVault is Secondary {
    function transfer(IERC20 token, address to, uint256 amount) public onlyPrimary {
        token.transfer(to, amount);
    }
}

contract FinalizableCrowdsale is TimedCrowdsale {
    using SafeMath for uint256;

    bool private _finalized;

    event CrowdsaleFinalized();

    constructor () internal {
        _finalized = false;
    }

    
    function finalized() public view returns (bool) {
        return _finalized;
    }

    
    function finalize() public {
        require(!_finalized, "FinalizableCrowdsale: already finalized");
        require(hasClosed(), "FinalizableCrowdsale: not closed");

        _finalized = true;

        _finalization();
        emit CrowdsaleFinalized();
    }

    
    function _finalization() internal {
        
    }
}

contract CounterGuard {
    
    modifier onlyOnce(bool criterion) {
        require(criterion == false, "CounterGuard-onlyOnce: Already been set");
        _;
    }
}

contract PausableCrowdsale is PausableManager, Crowdsale {

    
    function _preValidatePurchase(
        address _beneficiary,
        uint256 _weiAmount
    )
        internal
        view
        whenNotPaused
    {
        return super._preValidatePurchase(_beneficiary, _weiAmount);
    }

}

contract ECrowdsale is CounterGuard, WhitelistCrowdsale,
                          PostDeliveryCrowdsale, FinalizableCrowdsale,
                          PausableCrowdsale {
   
    bool private _setRole;              
    uint256 private _maxCryptoSale;     
    uint256 private _cryptoSaleAmount;  
    bool private _noCryptoLimits;       
    address payable private _wallet;    
    uint256 private _weiRaised;

    event WithdrawTokens(address beneficiary, uint256 value);
    event RefundExtra(address beneficiary, uint256 value);
    event NonEthTokenPurchased(address indexed beneficiary, uint256 tokenAmount);

    

    constructor(
        uint256 startingTime,
        uint256 endingTime,
        uint256 rate,
        address payable wallet,
        IERC20 token,
        uint maxCryptoSale
    )
        public
        Crowdsale(rate, wallet, token)
        TimedCrowdsale(startingTime, endingTime)
         {
            _wallet = wallet;
            _maxCryptoSale = maxCryptoSale;
            _noCryptoLimits = false;
        }

    
    function nonEthPurchase(address beneficiary, uint256 tokenAmount)
        public onlyManager
    {
        require(beneficiary != address(0), "ECrowdsale-nonEthPurchase: beneficiary is the zero address");
        _processPurchase(beneficiary, tokenAmount);
        emit NonEthTokenPurchased(beneficiary, tokenAmount);
    }

    
    function _preValidatePurchaseCrypto(address beneficiary, uint256 weiAmount) private view {
         require(returnMaxAmountForUser(beneficiary).sub(balanceOf(beneficiary)) >= weiAmount,
                "ECrowdsale-_preValidatePurchaseCrypto: contribution exceeds allowed amount");
          super._preValidatePurchase(beneficiary, weiAmount);
    }


     
    function nonEthPurchaseMulti(
        address[] calldata beneficiaries,
        uint256[] calldata amounts
    )
        external
    {
        uint256 length = amounts.length;
        require(beneficiaries.length == length, "length !=");
        require(length <= 256, "ECrowdsale-nonEthPurchaseMulti: List too long, please shorten the array");
        for (uint256 i = 0; i < length; i++) {
            nonEthPurchase(beneficiaries[i], amounts[i]);
        }
    }

    
    function roleSetup(
        address newOwner
    )
        public
        onlyOwner
        onlyOnce(_setRole)
    {
         if (address(newOwner) != address(msg.sender) ) {
            addManager(newOwner);
            _removeManager(msg.sender);
            transferOwnership(newOwner);
         }
        _setRole = true;
    }

    
    function withdrawTokens(address beneficiary) public {

        require(finalized(), "ECrowdsale:withdrawTokens - Crowdsale is not finalized");

        uint256 balanceOf = balanceOf(beneficiary);
        super.withdrawTokens(beneficiary);
        emit WithdrawTokens(beneficiary, balanceOf);
    }

     
    function claimTokens() public {

        address payable beneficiary = msg.sender;
        withdrawTokens(beneficiary);
    }

    
    function cryptoSaleAmount() public view returns(uint256) {

        return _cryptoSaleAmount;
    }

    
    function allowRemainingTokensForCrypto() public onlyManager {

        _noCryptoLimits = true;

    }

    
    function extendTime(uint256 newClosingTime) public onlyManager {
       super._extendTime(newClosingTime);
    }

    
    function weiRaised() public view returns (uint256) {
        return _weiRaised;
    }

    
    function finalize() public  onlyManager {
        super.finalize();
    }

    
    function buyTokens(address beneficiary) public payable   {

        uint256 extra = msg.value % rate();
        uint256 amountPaid;

        amountPaid = msg.value - extra;

        _preValidatePurchaseCrypto(beneficiary, amountPaid);
        uint256 tokens = amountPaid / rate();
        _cryptoSaleAmount += tokens;  

        require(_cryptoSaleAmount <= _maxCryptoSale || _noCryptoLimits,
        "ECrowdsale-buyTokens: Max available for crypto sale has been reached");

        _weiRaised += amountPaid;
        _processPurchase(beneficiary, tokens);
        _wallet.transfer(amountPaid);
        emit TokensPurchased(msg.sender, beneficiary, amountPaid, tokens);

        if (extra > 0) {
            msg.sender.transfer(extra);
            emit RefundExtra(msg.sender, extra);
        }
    }

    
    function adjustRate(uint256 newRate) public onlyManager {
        super.adjustRate(newRate);
    }
}

contract Token is CounterGuard, ERC20Detailed,
    ERC20Capped, ERC20Burnable, PausableManager {

    uint256 private constant ALLOCATION = 200000; 
    bool private _setRole;
    address  payable public crowdsaleContractAddress;

    event logPayment(address indexed paymentAddress, uint amount, uint date);

    
    struct Payment {

        uint date;
        uint amount;
        address paymentContractAddress;
    }

    Payment[] public payments;  


    
    constructor(
        string memory name,
        string memory symbol,
        uint8 decimals,
        uint256 cap
    )
        public
        ERC20Detailed(name, symbol, decimals)
        ERC20Capped(cap) {
            pause();
        }


    
    modifier onlyWhitelisted(address user) {

        require(ECrowdsale(crowdsaleContractAddress).isWhitelisted(user), "Token-onlyWhitelisted: user is not whitelisted");
        _;
    }


    
    function registerPayment(address paymentAddress, uint amount) public  {

        require(msg.sender == owner() || msg.sender == paymentAddress, "Token-registerPayment: You are not authorized to make this call");

        require(paymentAddress != address(0), "Token-registerPayment: Payment address can't be 0x0");
        require(amount > 0, "Token-registerPayment: Payment amount can't be 0");

        uint index = payments.length;
        payments.length ++;

        payments[index].date = now;
        payments[index].amount = amount;
        payments[index].paymentContractAddress = paymentAddress;
        emit logPayment(paymentAddress, amount, now);
    }


    
    function returnPaymentNum() public view returns ( uint) {

        return payments.length;
    }


    
    function isWhitelisted(address user) public view returns (bool) {

        return ECrowdsale(crowdsaleContractAddress).isWhitelisted(user);
    }


    
    function transfer(address to, uint256 value)
        public
        whenNotPaused
        onlyWhitelisted(to)
        returns (bool)
    {
        
        return super.transfer(to, value);
    }

    
    function transferFrom(address from, address to, uint256 value)
        public
        whenNotPaused
        onlyWhitelisted(to)
        returns (bool)
    {
        return super.transferFrom(from, to, value);
    }

    
    function approve(address spender, uint256 value) public whenNotPaused returns (bool) {
        return super.approve(spender, value);
    }

    
    function increaseAllowance(address spender, uint addedValue) public whenNotPaused returns (bool success) {
        return super.increaseAllowance(spender, addedValue);
    }

    
    function decreaseAllowance(address spender, uint subtractedValue) public whenNotPaused returns (bool success) {
        return super.decreaseAllowance(spender, subtractedValue);
    }

    
    function roleSetup(
        address _newOwner,
        address payable _crowdsaleContractAddress
    )
        public
        onlyOwner
        onlyOnce(_setRole)
    {
        _setRole = true;
        crowdsaleContractAddress = _crowdsaleContractAddress;
        mint(crowdsaleContractAddress, ALLOCATION);

        if (address(_newOwner) != address(msg.sender) ) {
            addManager(_newOwner);
            addMinter(_newOwner);
            _removeManager(msg.sender);
            _removeMinter(msg.sender);
            transferOwnership(_newOwner);
        }
    }
}