pragma solidity ^ 0.4.17;


library SafeMath {

    function mul(uint a, uint b) internal pure returns(uint) {
        uint c = a * b;
        assert(a == 0 || c / a == b);
        return c;
    }

    function sub(uint a, uint b) internal pure  returns(uint) {
        assert(b <= a);
        return a - b;
    }

    function add(uint a, uint b) internal  pure returns(uint) {
        uint c = a + b;
        assert(c >= a && c >= b);
        return c;
    }
}


contract ERC20 {
    uint public totalSupply;

    function balanceOf(address who) public view returns(uint);

    function allowance(address owner, address spender) public view returns(uint);

    function transfer(address to, uint value) public returns(bool ok);

    function transferFrom(address from, address to, uint value) public returns(bool ok);

    function approve(address spender, uint value) public returns(bool ok);

    event Transfer(address indexed from, address indexed to, uint value);
    event Approval(address indexed owner, address indexed spender, uint value);
}


/**
 * @title Ownable
 * @dev The Ownable contract has an owner address, and provides basic authorization control
 * functions, this simplifies the implementation of "user permissions".
 */
contract Ownable {

    address public owner;
    
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
    * @dev The Ownable constructor sets the original `owner` of the contract to the sender
    * account.
    */
    function Ownable() public {
        owner = msg.sender;
    }

    /**
    * @dev Throws if called by any account other than the owner.
    */
    modifier onlyOwner() {
        require(msg.sender == owner);
        _;
    }

    /**
    * @dev Allows the current owner to transfer control of the contract to a newOwner.
    * @param newOwner The address to transfer ownership to.
    */
    function transferOwnership(address newOwner) onlyOwner public {
        require(newOwner != address(0));
        OwnershipTransferred(owner, newOwner);
        owner = newOwner;
    }

}


/**
 * @title Pausable
 * @dev Base contract which allows children to implement an emergency stop mechanism.
 */
contract Pausable is Ownable {
    event Pause();
    event Unpause();

    bool public paused = false;

  /**
   * @dev Modifier to make a function callable only when the contract is not paused.
   */
    modifier whenNotPaused() {
        require(!paused);
        _;
    }

  /**
   * @dev Modifier to make a function callable only when the contract is paused.
   */
    modifier whenPaused() {
        require(paused);
        _;
    }

  /**
   * @dev called by the owner to pause, triggers stopped state
   */
    function pause() public onlyOwner whenNotPaused {
        paused = true;
        Pause();
    }

  /**
   * @dev called by the owner to unpause, returns to normal state
   */
    function unpause() public onlyOwner whenPaused {
        paused = false;
        Unpause();
    }
}


// Whitelist smart contract
// This smart contract keeps list of addresses to whitelist
contract WhiteList is Ownable {
    
    mapping(address => bool) public whiteList;
    uint public totalWhiteListed; //white listed users number

    event LogWhiteListed(address indexed user, uint whiteListedNum);
    event LogWhiteListedMultiple(uint whiteListedNum);
    event LogRemoveWhiteListed(address indexed user);

    // @notice it will return status of white listing
    // @return true if user is white listed and false if is not
    function isWhiteListed(address _user) external view returns (bool) {

        return whiteList[_user]; 
    }

    // @notice it will remove whitelisted user
    // @param _contributor {address} of user to unwhitelist
    function removeFromWhiteList(address _user) external onlyOwner() returns (bool) {
       
        require(whiteList[_user] == true);
        whiteList[_user] = false;
        totalWhiteListed--;
        LogRemoveWhiteListed(_user);
        return true;
    }

    // @notice it will white list one member
    // @param _user {address} of user to whitelist
    // @return true if successful
    function addToWhiteList(address _user) external onlyOwner()  returns (bool) {

        if (whiteList[_user] != true) {
            whiteList[_user] = true;
            totalWhiteListed++;
            LogWhiteListed(_user, totalWhiteListed);            
        }
        return true;
    }

    // @notice it will white list multiple members
    // @param _user {address[]} of users to whitelist
    // @return true if successful
    function addToWhiteListMultiple(address[] _users) external onlyOwner()  returns (bool) {

        for (uint i = 0; i < _users.length; ++i) {

            if (whiteList[_users[i]] != true) {
                whiteList[_users[i]] = true;
                totalWhiteListed++;                          
            }           
        }
        LogWhiteListedMultiple(totalWhiteListed); 
        return true;
    }
}


// @note this contract can be inherited by Crowdsale and TeamAllocation contracts and
// control release of tokens through even time release based on the inputted duration time interval
contract TokenVesting is Ownable {
    using SafeMath for uint;

    struct TokenHolder {
        uint weiReceived; // amount of ETH contributed
        uint tokensToSend; // amount of tokens  sent  
        bool refunded; // true if user has been refunded       
        uint releasedAmount; // amount released through vesting schedule
        bool revoked; // true if right to continue vesting is revoked
    }

    event Released(uint256 amount, uint256 tokenDecimals);
    event ContractUpdated(bool done);

    uint256 public cliff;  // time in  when vesting should begin
    uint256 public startCountDown;  // time when countdown starts
    uint256 public duration; // duration of period in which vesting takes place   
    Token public token;  // token contract containing tokens
    mapping(address => TokenHolder) public tokenHolders; //tokenHolder list
    WhiteList public whiteList; // whitelist contract
    uint256 public presaleBonus;
    
    // @note constructor 
    /**
    function TokenVesting(uint256 _start, uint256 _cliff, uint256 _duration) public {   
         require(_cliff <= _duration);   
        duration = _duration;
        cliff = _start.add(_cliff);
        startCountDown = _start;         
        ContractUpdated(true);                    
    }
    */
    // @notice Specify address of token contract
    // @param _tokenAddress {address} address of token contract
    // @return res {bool}
    function initilizeVestingAndTokenAndWhiteList(Token _tokenAddress, 
                                        uint256 _start, 
                                        uint256 _cliff, 
                                        uint256 _duration,
                                        uint256 _presaleBonus, 
                                        WhiteList _whiteList) external onlyOwner() returns(bool res) {
        require(_cliff <= _duration);   
        require(_tokenAddress != address(0));
        duration = _duration;
        cliff = _start.add(_cliff);
        startCountDown = _start;  
        token = _tokenAddress; 
        whiteList = _whiteList;
        presaleBonus = _presaleBonus;
        ContractUpdated(true);
        return true;    
    }

    // @notice Specify address of token contract
    // @param _tokenAddress {address} address of token contract
    // @return res {bool}
    function initilizeVestingAndToken(Token _tokenAddress, 
                                        uint256 _start, 
                                        uint256 _cliff, 
                                        uint256 _duration,
                                        uint256 _presaleBonus
                                        ) external onlyOwner() returns(bool res) {
        require(_cliff <= _duration);   
        require(_tokenAddress != address(0));
        duration = _duration;
        cliff = _start.add(_cliff);
        startCountDown = _start;  
        token = _tokenAddress;        
        presaleBonus = _presaleBonus;
        ContractUpdated(true);
        return true;    
    }

    function returnVestingSchedule() external view returns (uint, uint, uint) {

        return (duration, cliff, startCountDown);
    }

    // @note owner can revoke access to continue vesting of tokens
    // @param _user {address} of user to revoke their right to vesting
    function revoke(address _user) public onlyOwner() {

        TokenHolder storage tokenHolder = tokenHolders[_user];
        tokenHolder.revoked = true; 
    }

    function vestedAmountAvailable() public view returns (uint amount, uint decimals) {

        TokenHolder storage tokenHolder = tokenHolders[msg.sender];
        uint tokensToRelease = vestedAmount(tokenHolder.tokensToSend);

     //   if (tokenHolder.releasedAmount + tokensToRelease > tokenHolder.tokensToSend)
      //      return (tokenHolder.tokensToSend - tokenHolder.releasedAmount, token.decimals());
     //   else 
        return (tokensToRelease - tokenHolder.releasedAmount, token.decimals());
    }
    
    // @notice Transfers vested available tokens to beneficiary   
    function release() public {

        TokenHolder storage tokenHolder = tokenHolders[msg.sender];        
        // check if right to vesting is not revoked
        require(!tokenHolder.revoked);                                   
        uint tokensToRelease = vestedAmount(tokenHolder.tokensToSend);      
        uint currentTokenToRelease = tokensToRelease - tokenHolder.releasedAmount;
        tokenHolder.releasedAmount += currentTokenToRelease;            
        token.transfer(msg.sender, currentTokenToRelease);

        Released(currentTokenToRelease, token.decimals());
    }
  
    // @notice this function will determine vested amount
    // @param _totalBalance {uint} total balance of tokens assigned to this user
    // @return {uint} amount of tokens available to transfer
    function vestedAmount(uint _totalBalance) public view returns (uint) {

        if (now < cliff) {
            return 0;
        } else if (now >= startCountDown.add(duration)) {
            return _totalBalance;
        } else {
            return _totalBalance.mul(now.sub(startCountDown)) / duration;
        }
    }
}


// Crowdsale Smart Contract
// This smart contract collects ETH and in return sends  tokens to the Backers
contract Crowdsale is Pausable, TokenVesting {

    using SafeMath for uint;

    address public multisigETH; // Multisig contract that will receive the ETH
    address public commissionAddress;  // address to deposit commissions
    uint public tokensForTeam; // tokens for the team
    uint public ethReceivedPresale; // Number of ETH received in presale
    uint public ethReceivedMain; // Number of ETH received in main sale
    uint public totalTokensSent; // Number of tokens sent to ETH contributors
    uint public tokensSentMain;
    uint public tokensSentPresale;       
    uint public tokensSentDev;         
    uint public startBlock; // Crowdsale start block
    uint public endBlock; // Crowdsale end block
    uint public maxCap; // Maximum number of token to sell
    uint public minCap; // Minimum number of ETH to raise
    uint public minContributionMainSale; // Minimum amount to contribute in main sale
    uint public minContributionPresale; // Minimum amount to contribut in presale
    uint public maxContribution;
    bool public crowdsaleClosed; // Is crowdsale still on going
    uint public tokenPriceWei;
    uint public refundCount;
    uint public totalRefunded;
    uint public campaignDurationDays; // campaign duration in days 
    uint public firstPeriod; 
    uint public secondPeriod; 
    uint public thirdPeriod; 
    uint public firstBonus; 
    uint public secondBonus;
    uint public thirdBonus;
    uint public multiplier;
    uint public status;    
    Step public currentStep;  // To allow for controlled steps of the campaign 
   
    // Looping through Backer
    //mapping(address => Backer) public backers; //backer list
    address[] public holdersIndex;   // to be able to itarate through backers when distributing the tokens
    address[] public devIndex;   // to be able to itarate through backers when distributing the tokens

    // @notice to set and determine steps of crowdsale
    enum Step {      
        FundingPreSale,     // presale mode
        FundingMainSale,  // public mode
        Refunding  // in case campaign failed during this step contributors will be able to receive refunds
    }

    // @notice to verify if action is not performed out of the campaing range
    modifier respectTimeFrame() {
        if ((block.number < startBlock) || (block.number > endBlock)) 
            revert();
        _;
    }

    modifier minCapNotReached() {
        if (totalTokensSent >= minCap) 
            revert();
        _;
    }

    // Events
    event LogReceivedETH(address indexed backer, uint amount, uint tokenAmount);
    event LogStarted(uint startBlockLog, uint endBlockLog);
    event LogFinalized(bool success);  
    event LogRefundETH(address indexed backer, uint amount);
    event LogStepAdvanced();
    event LogDevTokensAllocated(address indexed dev, uint amount);
    event LogNonVestedTokensSent(address indexed user, uint amount);

    // Crowdsale  {constructor}
    // @notice fired when contract is crated. Initilizes all constnat variables.
    function Crowdsale(uint _decimalPoints,
                        address _multisigETH,
                        uint _toekensForTeam, 
                        uint _minContributionPresale,
                        uint _minContributionMainSale,
                        uint _maxContribution,                        
                        uint _maxCap, 
                        uint _minCap, 
                        uint _tokenPriceWei, 
                        uint _campaignDurationDays,
                        uint _firstPeriod, 
                        uint _secondPeriod, 
                        uint _thirdPeriod, 
                        uint _firstBonus, 
                        uint _secondBonus,
                        uint _thirdBonus) public {
        multiplier = 10**_decimalPoints;
        multisigETH = _multisigETH; 
        tokensForTeam = _toekensForTeam * multiplier; 
        minContributionPresale = _minContributionPresale; 
        minContributionMainSale = _minContributionMainSale;
        maxContribution = _maxContribution;       
        maxCap = _maxCap * multiplier;       
        minCap = _minCap * multiplier;
        tokenPriceWei = _tokenPriceWei;
        campaignDurationDays = _campaignDurationDays;
        firstPeriod = _firstPeriod; 
        secondPeriod = _secondPeriod; 
        thirdPeriod = _thirdPeriod;
        firstBonus = _firstBonus;
        secondBonus = _secondBonus;
        thirdBonus = _thirdBonus;       
        //TODO replace this address below with correct address.
        commissionAddress = 0x326B5E9b8B2ebf415F9e91b42c7911279d296ea1;
        //commissionAddress = 0x853A3F142430658A32f75A0dc891b98BF4bDF5c1;
        currentStep = Step.FundingPreSale; 
    }

    // @notice to populate website with status of the sale 
    function returnWebsiteData() external view returns(uint, 
        uint, uint, uint, uint, uint, uint, uint, uint, uint, bool, bool, uint, Step) {
    
        return (startBlock, endBlock, numberOfBackers(), ethReceivedPresale + ethReceivedMain, maxCap, minCap, 
                totalTokensSent, tokenPriceWei, minContributionPresale, minContributionMainSale, 
                paused, crowdsaleClosed, token.decimals(), currentStep);
    }
    
    // @notice this function will determine status of crowdsale
    function determineStatus() external view returns (uint) {
       
        if (crowdsaleClosed)            // ICO finihsed
            return 1;   

        if (block.number < endBlock && totalTokensSent < maxCap - 100)   // ICO in progress
            return 2;            
    
        if (totalTokensSent < minCap && block.number > endBlock)      // ICO failed    
            return 3;            
    
        if (endBlock == 0)           // ICO hasn't been started yet 
            return 4;            
    
        return 0;         
    } 

    // {fallback function}
    // @notice It will call internal function which handels allocation of Ether and calculates tokens.
    function () public payable {    
             
        contribute(msg.sender);
    }

    // @notice to allow for contribution from interface
    function contributePublic() external payable {
        contribute(msg.sender);
    }

    // @notice set the step of the campaign from presale to public sale
    // contract is deployed in presale mode
    // WARNING: there is no way to go back
    function advanceStep() external onlyOwner() {
        currentStep = Step.FundingMainSale;
        LogStepAdvanced();
    }

    // @notice It will be called by owner to start the sale    
    function start() external onlyOwner() {
        startBlock = block.number;
        endBlock = startBlock + (4*60*24*campaignDurationDays); // assumption is that one block takes 15 sec. 
        crowdsaleClosed = false;
        LogStarted(startBlock, endBlock);
    }

    // @notice This function will finalize the sale.
    // It will only execute if predetermined sale time passed or all tokens are sold.
    function finalize() external onlyOwner() {

        require(!crowdsaleClosed);                       
        require(block.number >= endBlock || totalTokensSent > maxCap - 1000);
                    // - 1000 is used to allow closing of the campaing when contribution is near 
                    // finished as exact amount of maxCap might be not feasible e.g. you can't easily buy few tokens. 
                    // when min contribution is 0.1 Eth.  

        require(totalTokensSent >= minCap);
        crowdsaleClosed = true;
        
        // transfer commission portion to the platform
        commissionAddress.transfer(determineCommissions());         
        
        // transfer remaning funds to the campaign wallet
        multisigETH.transfer(this.balance);
        
        /*if (!token.transfer(owner, token.balanceOf(this))) 
            revert(); // transfer tokens to admin account  
            
        if (!token.burn(this, token.balanceOf(this))) 
            revert();  // burn all the tokens remaining in the contract   */
        token.unlock();    // release lock from transfering tokens. 

        LogFinalized(true);        
    }

    // @notice it will allow contributors to get refund in case campaign failed
    // @return {bool} true if successful
    function refund() external whenNotPaused returns (bool) {      
        
        uint totalEtherReceived = ethReceivedPresale + ethReceivedMain;

        require(totalEtherReceived < minCap);  // ensure that campaign failed
        require(this.balance > 0);  // contract will hold 0 ether at the end of campaign.
                                    // contract needs to be funded through fundContract() 
        TokenHolder storage backer = tokenHolders[msg.sender];

        require(backer.weiReceived > 0);  // ensure that user has sent contribution
        require(!backer.refunded);        // ensure that user hasn't been refunded yet

        backer.refunded = true;  // save refund status to true
        refundCount++;
        totalRefunded += backer.weiReceived;

        if (!token.burn(msg.sender, backer.tokensToSend)) // burn tokens
            revert();        
        msg.sender.transfer(backer.weiReceived);  // send back the contribution 
        LogRefundETH(msg.sender, backer.weiReceived);
        return true;
    }

    // @notice allocate tokens to dev/team/advisors
    // @param _dev {address} 
    // @param _amount {uint} amount of tokens
    function devAllocation(address _dev, uint _amount) external onlyOwner() returns (bool) {

        require(_dev != address(0));
        require(crowdsaleClosed); 
        require(totalTokensSent.add(_amount) <= token.totalSupply());
        devIndex.push(_dev);
        TokenHolder storage tokenHolder = tokenHolders[_dev];
        tokenHolder.tokensToSend = _amount;
        tokensSentDev += _amount;
        totalTokensSent += _amount;        
        LogDevTokensAllocated(_dev, _amount); // Register event
        return true;

    }

    // @notice Failsafe drain
    function drain(uint _amount) external onlyOwner() {
        owner.transfer(_amount);           
    }

    // @notice transfer tokens which are not subject to vesting
    // @param _recipient {addres}
    // @param _amont {uint} amount to transfer
    function transferTokens(address _recipient, uint _amount) external onlyOwner() returns (bool) {

        require(_recipient != address(0));
        if (!token.transfer(_recipient, _amount))
            revert();
        LogNonVestedTokensSent(_recipient, _amount);
    }

    // @notice determine amount of commissions for the platform    
    function determineCommissions() public view returns (uint) {
     
        if (this.balance <= 500 ether) {
            return (this.balance * 10)/100;
        }else if (this.balance <= 1000 ether) {
            return (this.balance * 8)/100;
        }else if (this.balance < 10000 ether) {
            return (this.balance * 6)/100;
        }else {
            return (this.balance * 6)/100;
        }
    }

    // @notice return number of contributors
    // @return  {uint} number of contributors
    function numberOfBackers() public view returns (uint) {
        return holdersIndex.length;
    }

    // @notice It will be called by fallback function whenever ether is sent to it
    // @param  _backer {address} address of beneficiary
    // @return res {bool} true if transaction was successful
    function contribute(address _backer) internal whenNotPaused respectTimeFrame returns(bool res) {

        //require(msg.value <= maxContribution);

        if (whiteList != address(0))  // if whitelist initialized verify member whitelist status
            require(whiteList.isWhiteListed(_backer));  // ensure that user is whitelisted
          
        uint tokensToSend = calculateNoOfTokensToSend(); // calculate number of tokens

        // Ensure that max cap hasn't been reached
        require(totalTokensSent + tokensToSend <= maxCap);
        
        TokenHolder storage backer = tokenHolders[_backer];

        if (backer.weiReceived == 0)
            holdersIndex.push(_backer);

        if (Step.FundingMainSale == currentStep) { // Update the total Ether received and tokens sent during public sale
            require(msg.value >= minContributionMainSale); // stop when required minimum is not met    
            ethReceivedMain = ethReceivedMain.add(msg.value);
            tokensSentMain += tokensToSend;
        }else {  
            require(msg.value >= minContributionPresale); // stop when required minimum is not met
            ethReceivedPresale = ethReceivedPresale.add(msg.value); 
            tokensSentPresale += tokensToSend;
        }  
       
        backer.tokensToSend += tokensToSend;
        backer.weiReceived = backer.weiReceived.add(msg.value);       
        totalTokensSent += tokensToSend;      
        
        // tokens are not transferrd to contributors during this phase
        // tokens will be transferred based on the vesting schedule, when contributor
        // calls release() function of this contract
        LogReceivedETH(_backer, msg.value, tokensToSend); // Register event
        return true;
    }

    // @notice This function will return number of tokens based on time intervals in the campaign
    function calculateNoOfTokensToSend() internal view returns (uint) {

        uint tokenAmount = msg.value.mul(multiplier) / tokenPriceWei;

        if (Step.FundingMainSale == currentStep) {
        
            if (block.number <= startBlock + firstPeriod) {  
                return  tokenAmount + tokenAmount.mul(firstBonus) / 100;
            }else if (block.number <= startBlock + secondPeriod) {
                return  tokenAmount + tokenAmount.mul(secondBonus) / 100; 
            }else if (block.number <= startBlock + thirdPeriod) { 
                return  tokenAmount + tokenAmount.mul(thirdBonus) / 100;        
            }else {              
                return  tokenAmount; 
            }
        }else 
            return  tokenAmount + tokenAmount.mul(presaleBonus) / 100;
    }  
}


// The  token
contract Token is ERC20, Ownable {

    using SafeMath for uint;
    // Public variables of the token
    string public name;
    string public symbol;
    uint public decimals; // How many decimals to show.
    string public version = "v0.1";
    uint public totalSupply;
    bool public locked;
    address public crowdSaleAddress;

    mapping(address => uint) public balances;
    mapping(address => mapping(address => uint)) public allowed;
    
    // Lock transfer during the ICO
    modifier onlyUnlocked() {
        if (msg.sender != crowdSaleAddress && locked && msg.sender != owner) 
            revert();
        _;
    }

    modifier onlyAuthorized() {
        if (msg.sender != crowdSaleAddress && msg.sender != owner) 
            revert();
        _;
    }

    // The Token constructor     
    function Token(uint _initialSupply,
            string _tokenName,
            uint _decimalUnits,
            string _tokenSymbol,
            string _version,
            address _crowdSaleAddress) public {      
        locked = true;  // Lock the transfer of tokens during the crowdsale
        totalSupply = _initialSupply * (10**_decimalUnits);     
                                        
        name = _tokenName; // Set the name for display purposes
        symbol = _tokenSymbol; // Set the symbol for display purposes
        decimals = _decimalUnits; // Amount of decimals for display purposes
        version = _version;
        crowdSaleAddress = _crowdSaleAddress;              
        balances[crowdSaleAddress] = totalSupply;   
    }

    function unlock() public onlyAuthorized {
        locked = false;
    }

    function lock() public onlyAuthorized {
        locked = true;
    }

    function burn(address _member, uint256 _value) public onlyAuthorized returns(bool) {
        require(balances[_member] >= _value);
        balances[_member] -= _value;
        totalSupply -= _value;
        Transfer(_member, 0x0, _value);
        return true;
    }

   
    // @notice transfer tokens to given address
    // @param _to {address} address or recipient
    // @param _value {uint} amount to transfer
    // @return  {bool} true if successful
    function transfer(address _to, uint _value) public onlyUnlocked returns(bool) {

        require(_to != address(0));
        require(balances[msg.sender] >= _value);
        balances[msg.sender] -= _value;
        balances[_to] += _value;
        Transfer(msg.sender, _to, _value);
        return true;
    }

    // @notice transfer tokens from given address to another address
    // @param _from {address} from whom tokens are transferred
    // @param _to {address} to whom tokens are transferred
    // @param _value {uint} amount of tokens to transfer
    // @return  {bool} true if successful
    function transferFrom(address _from, address _to, uint256 _value) public onlyUnlocked returns(bool success) {

        require(_to != address(0));
        require(balances[_from] >= _value); // Check if the sender has enough
        require(_value <= allowed[_from][msg.sender]); // Check if allowed is greater or equal
        balances[_from] -= _value; // Subtract from the sender
        balances[_to] += _value; // Add the same to the recipient
        allowed[_from][msg.sender] -= _value;  // adjust allowed
        Transfer(_from, _to, _value);
        return true;
    }

      // @notice to query balance of account
    // @return _owner {address} address of user to query balance
    function balanceOf(address _owner) public view returns(uint balance) {
        return balances[_owner];
    }

    /**
    * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
    *
    * 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
    * @param _spender The address which will spend the funds.
    * @param _value The amount of tokens to be spent.
    */
    function approve(address _spender, uint _value) public returns(bool) {
        allowed[msg.sender][_spender] = _value;
        Approval(msg.sender, _spender, _value);
        return true;
    }

    // @notice to query of allowance of one user to the other
    // @param _owner {address} of the owner of the account
    // @param _spender {address} of the spender of the account
    // @return remaining {uint} amount of remaining allowance
    function allowance(address _owner, address _spender) public view returns(uint remaining) {
        return allowed[_owner][_spender];
    }

    /**
    * approve should be called when allowed[_spender] == 0. To increment
    * allowed value is better to use this function to avoid 2 calls (and wait until
    * the first transaction is mined)
    * From MonolithDAO Token.sol
    */
    function increaseApproval (address _spender, uint _addedValue) public returns (bool success) {
        allowed[msg.sender][_spender] = allowed[msg.sender][_spender].add(_addedValue);
        Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
        return true;
    }

    function decreaseApproval (address _spender, uint _subtractedValue) public returns (bool success) {
        uint oldValue = allowed[msg.sender][_spender];
        if (_subtractedValue > oldValue) {
            allowed[msg.sender][_spender] = 0;
        } else {
            allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
        }
        Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
        return true;
    }

}