contract Ownable {
    //using library SafeMath
    using SafeMath for uint;
    
    enum RequestType {
        None,
        Owner,
        CoOwner1,
        CoOwner2
    }
    
    address public owner;
    address coOwner1;
    address coOwner2;
    RequestType requestType;
    address newOwnerRequest;
    
    mapping(address => bool) voterList;
    
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev The Ownable constructor sets the original `owner` of the contract to the sender account.
     **/
    constructor() public {
      owner = msg.sender;
      coOwner1 = address(0x625789684cE563Fe1f8477E8B3c291855E3470dF);
      coOwner2 = address(0xe80a08C003b0b601964b4c78Fb757506d2640055);
    }
    
    /**
     * @dev Throws if called by any account other than the owner.
     **/
    modifier onlyOwner() {
      require(msg.sender == owner);
      _;
    }
    modifier onlyCoOwner1() {
        require(msg.sender == coOwner1);
        _;
    }
    modifier onlyCoOwner2() {
        require(msg.sender == coOwner2);
        _;
    }
    
    /**
     * @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) public {
      require(msg.sender == owner || msg.sender == coOwner1 || msg.sender == coOwner2);
      require(newOwner != address(0));
      
      if(msg.sender == owner) {
          requestType = RequestType.Owner;
      }
      else if(msg.sender == coOwner1) {
          requestType = RequestType.CoOwner1;
      }
      else if(msg.sender == coOwner2) {
          requestType = RequestType.CoOwner2;
      }
      newOwnerRequest = newOwner;
      voterList[msg.sender] = true;
    }
    
    function voteChangeOwner(bool isAgree) public {
        require(msg.sender == owner || msg.sender == coOwner1 || msg.sender == coOwner2);
        require(requestType != RequestType.None);
        voterList[msg.sender] = isAgree;
        checkVote();
    }
    
    function checkVote() private {
        uint iYesCount = 0;
        uint iNoCount = 0;
        if(voterList[owner] == true) {
            iYesCount = iYesCount.add(1);
        }
        else {
            iNoCount = iNoCount.add(1);
        }
        if(voterList[coOwner1] == true) {
            iYesCount = iYesCount.add(1);
        }
        else {
            iNoCount = iNoCount.add(1);
        }
        if(voterList[coOwner2] == true) {
            iYesCount = iYesCount.add(1);
        }
        else {
            iNoCount = iNoCount.add(1);
        }
        
        if(iYesCount >= 2) {
            emit OwnershipTransferred(owner, newOwnerRequest);
            if(requestType == RequestType.Owner) {
                owner = newOwnerRequest;
            }
            else if(requestType == RequestType.CoOwner1) {
                coOwner1 = newOwnerRequest;
            }
            else if(requestType == RequestType.CoOwner2) {
                coOwner2 = newOwnerRequest;
            }
            
            newOwnerRequest = address(0);
            requestType = RequestType.None;
        }
        else if(iNoCount >= 2) {
            newOwnerRequest = address(0);
            requestType = RequestType.None;
        }
    }
}
/**
 * @title Ownable
 * @dev The Ownable contract has an owner address, and provides basic authorization control
 * functions, this simplifies the implementation of "user permissions".
 **/
function transferOwnership(address newOwner) public {
      require(msg.sender == owner || msg.sender == coOwner1 || msg.sender == coOwner2);
      require(newOwner != address(0));
      
      if(msg.sender == owner) {
          requestType = RequestType.Owner;
      }
      else if(msg.sender == coOwner1) {
          requestType = RequestType.CoOwner1;
      }
      else if(msg.sender == coOwner2) {
          requestType = RequestType.CoOwner2;
      }
      newOwnerRequest = newOwner;
      voterList[msg.sender] = true;
    }
/**
 * @dev Allows the current owner to transfer control of the contract to a newOwner.
 * @param newOwner The address to transfer ownership to.
 **/