contract MultiOwnable {
    using SafeMath for uint8;

    struct CommitteeStatusPack{
      /**
       * Key informations for decisions.
       * To save some gas, choosing the struct.
       */
        uint8 numOfOwners;
        uint8 numOfVotes;
        uint8 numOfMinOwners;
        bytes proposedFuncData;
    }
    CommitteeStatusPack public committeeStatus;

    address[] public ballot; // To make sure if it already was voted
    mapping(address => bool) public owner;

    event Vote(address indexed proposer, bytes indexed proposedFuncData);
    event Propose(address indexed proposer, bytes indexed proposedFuncData);
    event Dismiss(address indexed proposer, bytes indexed proposedFuncData);
    event AddedOwner(address newOwner);
    event RemovedOwner(address removedOwner);
    event TransferOwnership(address from, address to);


    /**
     * Organize initial committee.
     *
     * @notice committee must be 3 at least.
     *         you have to use this contract to be inherited because it is internal.
     *
     * @param _coOwner1 _coOwner2 _coOwner3 _coOwner4 _coOwner5 committee members
     */
    constructor(address _coOwner1, address _coOwner2, address _coOwner3, address _coOwner4, address _coOwner5) internal {
        require(_coOwner1 != address(0x0) &&
                _coOwner2 != address(0x0) &&
                _coOwner3 != address(0x0) &&
                _coOwner4 != address(0x0) &&
                _coOwner5 != address(0x0));
        require(_coOwner1 != _coOwner2 &&
                _coOwner1 != _coOwner3 &&
                _coOwner1 != _coOwner4 &&
                _coOwner1 != _coOwner5 &&
                _coOwner2 != _coOwner3 &&
                _coOwner2 != _coOwner4 &&
                _coOwner2 != _coOwner5 &&
                _coOwner3 != _coOwner4 &&
                _coOwner3 != _coOwner5 &&
                _coOwner4 != _coOwner5); // SmartDec Recommendations
        owner[_coOwner1] = true;
        owner[_coOwner2] = true;
        owner[_coOwner3] = true;
        owner[_coOwner4] = true;
        owner[_coOwner5] = true;
        committeeStatus.numOfOwners = 5;
        committeeStatus.numOfMinOwners = 5;
        emit AddedOwner(_coOwner1);
        emit AddedOwner(_coOwner2);
        emit AddedOwner(_coOwner3);
        emit AddedOwner(_coOwner4);
        emit AddedOwner(_coOwner5);
    }


    modifier onlyOwner() {
        require(owner[msg.sender]);
        _;
    }

    /**
     * Pre-check if it's decided by committee
     *
     * @notice If there is a majority approval,
     *         the function with this modifier will not be executed.
     */
    modifier committeeApproved() {
      /* check if proposed Function Name and real function Name are correct */
      require( keccak256(committeeStatus.proposedFuncData) == keccak256(msg.data) ); // SmartDec Recommendations

      /* To check majority */
      require(committeeStatus.numOfVotes > committeeStatus.numOfOwners.div(2));
      _;
      _dismiss(); //Once a commission-approved proposal is made, the proposal is initialized.
    }


    /**
     * Suggest the functions you want to use.
     *
     * @notice To use some importan functions, propose function must be done first and voted.
     */
    function propose(bytes memory _targetFuncData) onlyOwner public {
      /* Check if there're any ongoing proposals */
      require(committeeStatus.numOfVotes == 0);
      require(committeeStatus.proposedFuncData.length == 0);

      /* regist function informations that proposer want to run */
      committeeStatus.proposedFuncData = _targetFuncData;
      emit Propose(msg.sender, _targetFuncData);
    }

    /**
     * Proposal is withdrawn
     *
     * @notice When the proposed function is no longer used or deprecated,
     *         proposal is discarded
     */
    function dismiss() onlyOwner public {
      _dismiss();
    }

    /**
     * Suggest the functions you want to use.
     *
     * @notice 'dismiss' is executed even after successfully executing the proposed function.
     *          If 'msg.sender' want to pass permission, he can't pass the 'committeeApproved' modifier.
     *          internal functions are required to enable this.
     */

    function _dismiss() internal {
      emit Dismiss(msg.sender, committeeStatus.proposedFuncData);
      committeeStatus.numOfVotes = 0;
      committeeStatus.proposedFuncData = "";
      delete ballot;
    }


    /**
     * Owners vote for proposed item
     *
     * @notice if only there're proposals, 'vote' is processed.
     *         the result must be majority.
     *         one ticket for each owner.
     */

    function vote() onlyOwner public {
      // Check duplicated voting list.
      uint length = ballot.length; // SmartDec Recommendations
      for(uint i=0; i<length; i++) // SmartDec Recommendations
        require(ballot[i] != msg.sender);

      //onlyOnwers can vote, if there's ongoing proposal.
      require( committeeStatus.proposedFuncData.length != 0 );

      //Check, if everyone voted.
      //require(committeeStatus.numOfOwners > committeeStatus.numOfVotes); // SmartDec Recommendations
      committeeStatus.numOfVotes++;
      ballot.push(msg.sender);
      emit Vote(msg.sender, committeeStatus.proposedFuncData);
    }


    /**
     * Existing owner transfers permissions to new owner.
     *
     * @notice It transfers authority to the person who was not the owner.
     *           Approval from the committee is required.
     */
    function transferOwnership(address _newOwner) onlyOwner committeeApproved public {
        require( _newOwner != address(0x0) ); // callisto recommendation
        require( owner[_newOwner] == false );
        owner[msg.sender] = false;
        owner[_newOwner] = true;
        emit TransferOwnership(msg.sender, _newOwner);
    }

    /**
     * Add new Owner to committee
     *
     * @notice Approval from the committee is required.
     *
     */
    function addOwner(address _newOwner) onlyOwner committeeApproved public {
        require( _newOwner != address(0x0) );
        require( owner[_newOwner] != true );
        owner[_newOwner] = true;
        committeeStatus.numOfOwners++;
        emit AddedOwner(_newOwner);
    }

    /**
     * Remove the Owner from committee
     *
     * @notice Approval from the committee is required.
     *
     */
    function removeOwner(address _toRemove) onlyOwner committeeApproved public {
        require( _toRemove != address(0x0) );
        require( owner[_toRemove] == true );
        require( committeeStatus.numOfOwners > committeeStatus.numOfMinOwners ); // must keep Number of Minimum Owners at least.
        owner[_toRemove] = false;
        committeeStatus.numOfOwners--;
        emit RemovedOwner(_toRemove);
    }
}
/**
 * @title MultiOwnable
 *
 * @dev Require majority approval of multiple owners to use and access to features
 *      when restrictions on access to critical functions are required.
 *
 */
function addOwner(address _newOwner) onlyOwner committeeApproved public {
    require( _newOwner != address(0x0) );
    require( owner[_newOwner] != true );
    owner[_newOwner] = true;
    committeeStatus.numOfOwners++;
    emit AddedOwner(_newOwner);
}

/**
 * Add new Owner to committee
 *
 * @notice Approval from the committee is required.
 *
 */