/* 
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNDOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN8OOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN8OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOODNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO8NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO8NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOODNNNNNNNNNNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNMOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNNNNNMOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNNNNDOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOODNNNNNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNNNOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO7=~~~~~~+$OOOOOOOOOOOOOOOOOOOOOOO8NNNNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNNOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO?~~~~~~~~~~~~~~~~~~~~~~+OOOOOOOOOOOOOOOOOOO8NNNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNOOOOOOOOOOOOOOOOOOOOOOOOOOOO==~~~~~~~~~~~~~~~~~~~~~~~~~~~~=$OOOOOOOOOOOOOOOOMNNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNOOOOOOOOOOOOOOOOOOOOOOOOOI~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~8OOOOOOOOOOOOONNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNOOOOOOOOOOOOOOOOOOOOOOO~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~OOOOOOOOOOONNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNOOOOOOOOOOOOOOOOOOOOOI=~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~OOOOOOOOONNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNOOOOOOOOOOOOOOOOOOOZ=~~~~~~~~~~~~~~~+NMMMMMO?~~~~~~~~~~~~~~~~~~~~~~~~~~~ZOOOOOONNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNOOOOOOOOOOOOOOOOOO~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=~NN==~~~~~~~~~~~~~~~~~~~~$ZOOOONNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNOOOOOOOOOOOOOOOO7~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~OOOONNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNDOOOOOOOOOOOOOOO~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~OODNNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNMMMMMMM8OOOOOOOO=~~~~~~~~~~~~~~~~~~~~~~ONMMMMMMMMMMMMM?==~~~~~~~~~~~~~~~~~~~~~~=NNNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNMMMMMMMMMMMMMDZ~~~~~~~~~~~~~~~~~~~~MMMMMMMMMMMMMMMMMMMMMMMM==~~~~~~~~~~M=~==DMMMMMNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNOOOODMMMMMMMMMMMMMMMMMI~~~~~~~~~~~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMM~~~~~~~7MMMMMMMMMMMNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNOOOOOOOOOOONMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMN~~~~NNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNDOOOOOOOOOOOOOO===~IMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM8~=~~~~~~~~~NNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNOOOOOOOOOOOOOOO~~~~~~~~~~==~~=$MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM?~~~~~~~~~~~~~~~~~~=~NNNNNNNNNNNNNN
NNNNNNNNNNNNNNNOOOOOOOOOOOOOOO~~~~~~~~~~~~~~~~~~~~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM~~~~~~~~~~~~~~~~~~~~~~~?NNNNNNNNNNNN
NNNNNNNNNNNNNNNOOOOOOOOOOOOOO$=~~~~~~~~~~~~~~~~~~~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM8~~~~~~~~~~~~~~~~~~~~~~~~+NNNNNNNNNNN
NNNNNNNNNNNNNNNOOOOOOOOOOOOOO~~~~~~~~~~~~~~~~~~~~~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM~~~~~~~~~~~~~~~~~~~~~~~~~~NNNNNNNNNNN
NNNNNNNNNNNNNNNOOOOOOOOOOOOOI~~~~~~~~~~~~~~~~~~~~~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM~~~~~~~~~~~~~~~~~~~~~~~~~~=NNNNNNNNNN
NNNNNNNNNNNNNNNOOOOOOOOOOOOO~~~~~~~~~~~~~~~~~~~~~~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM=~~~:...........=8MM+=~~~~~~NNNNNNNNNN
NNNNNNNNNNNNNNNNOOOOOOOOOOOO~~~~~~~~~~~~~~~~~~~~~~=MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM~~~~.....MM?............DN~~MNNNNNNNNN
NNNNNNNNNNNNNNNNOOOOOOOOOOO+~~~~~~~~~~~~~~~~~~~~~~~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMM=~~~~........................MNNNNNNNNN
NNNNNNNNNNNNNNNNNOOOOOOOOOO~~~~~~~~~~~~~~~~~~~~~~~~?MMMMMMMMMMMMMMMMMMMMMMMMMMMMD~~~~~........................NNNNNNNNNN
NNNNNNNNNNNNNNNNNDOOOOOOOOO~~~~~~~~~~~~~~~~~~~~~~~~~DMMMMMMMMMMMMMMMMMMMMMMMMMMZ~~~~~~........................NNNNNNNNNN
NNNNNNNNNNNNNNNNNNOOOOOOOOO~~~~~~~~~~~~~~~~~~~~~~~~~=IMMMMMMMMMMMMMMMMMMMMMMMMO~~~~~~~.......................~NNNNNNNNNN
NNNNNNNNNNNNNNNNNNOOOOOOOO7~~~~~~~~~~~~~~~~~~~~~~~~~~~=MMMMMMMMMMMMMMMMMMMMMM~~~~~~~~~=......................NNNNNNNNNNN
NNNNNNNNNNNNNNNNNNOOOOOO$~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ZMMMMMMMMMMMMMMMMMM~~~~~~~~~~~~,....................NNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNOOOOO~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~NMMMMMMMMMMMMMM=~~~~~~~~~~~~~~,..................NNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNOOO+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~8MMMMMMMI~~~~~~~~~~~~~~~~M~~~,..............MNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNMOO=~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~N~~~~~~........~~~NNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNN8~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~M~~~~~~~~~~~~~~~~NNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNN~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~$~~~~~~~M~~~~~~~~~~~~~~~~NNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNNN~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~MI~~~N~~~~~~~~~~~~~~~~MNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNNNNZ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~NNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNNNNNDO~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~MNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNN~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=NNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNZ=~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~NNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN=~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~MNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=~~~~~~~~~~~~~~~~~~=~NNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=+DM8~~~~~~~$MN~~~~~~~~~~~~~~~~NNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNM~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~NNNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNZ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~NNNNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNM~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~NNNNNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNZ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~8NNNNNNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=MNNNNNNNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN7~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~DNNNNNNNNNNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNM~~~~~~=~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNND~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN$~~~~~~~~~~~~~~~~==~~~~~~~~~~~~~~~~~~~~~~~~~~~NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN:~~~~~~~~~~~~~~~~~~~~~~~~~=~~~~~~~~~~~~~=~~~~~NNNNNNNNNNNNNNNNNNNNWE&ARE&LEGIONNNNN
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN:~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=NNNNNNNNNNNNNNWE&DO&NOT&FORGIVENNNN
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN8~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~NNNNNNNNNNNNNNNWE&DO&NOT&FORGETNNN
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNM~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~NNNNNNNNNNNNNNNNNNNNEXPECT&USNNNN
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~?NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNM~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~=NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
NNNNNNNNNNNNNNNNNNNNNNNNNNNNNN=~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
 */

/**
 * @title Microverse
 * Given the fact that most of the blockchaaaaains are dogshit wrapped in catshit, we've decided to come down from the
 * highland, just for a while, though.
 * Being smart is lonely, being nice is a compromise.
 * Hello human, we are Evil Morty Fund.
 * Decentralization is great, while balance must be kept.
 * Order will change, but never disappear.
 * We are not building another chain, we are forming a soceity, never seen, never have been.
 */

 // \ (•◡•) /\ (•◡•) /\ (•◡•) /\ (•◡•) /\ (•◡•) /\ (•◡•) /\ (•◡•) /\ (•◡•) /\ (•◡•) /\ (•◡•) /
 // \ (•◡•) / █   █ █░░█ █▀▀▄ █▀▀█ █░░ █░░█ █▀▀▄ █▀▀█ █▀▀▄ █░░█ █▀▀▄ █▀▀▄ █░░█ █▀▀▄  \ (•◡•) /
 // \ (•◡•) / █ █ █ █░░█ █▀▀▄ █▄▄█ █░░ █░░█ █▀▀▄ █▄▄█ █░░█ █░░█ █▀▀▄ █░░█ █░░█ █▀▀▄  \ (•◡•) /
 // \ (•◡•) / █▄▀▄█ ░▀▀▀ ▀▀▀░ ▀░░▀ ▀▀▀ ░▀▀▀ ▀▀▀░ ▀░░▀ ▀▀▀░ ░▀▀▀ ▀▀▀░ ▀▀▀░ ░▀▀▀ ▀▀▀░  \ (•◡•) /
 // \ (•◡•) /\ (•◡•) /\ (•◡•) /\ (•◡•) /\ (•◡•) /\ (•◡•) /\ (•◡•) /\ (•◡•) /\ (•◡•) /\ (•◡•) /

/**
 * Created on 2018-08-21 03:28
 * @summary: 
 * @author: yong
 */
pragma solidity ^0.4.23;

/**
 * @title RBAC (Role-Based Access Control)
 * @author Matt Condon (@Shrugs)
 * @dev Stores and provides setters and getters for roles and addresses.
 * @dev Supports unlimited numbers of roles and addresses.
 * @dev See //contracts/mocks/RBACMock.sol for an example of usage.
 * This RBAC method uses strings to key roles. It may be beneficial
 *  for you to write your own implementation of this interface using Enums or similar.
 * It's also recommended that you define constants in the contract, like ROLE_ADMIN below,
 *  to avoid typos.
 */
contract RBAC {
  using Roles for Roles.Role;

  mapping (string => Roles.Role) private roles;

  event RoleAdded(address addr, string roleName);
  event RoleRemoved(address addr, string roleName);

  /**
   * @dev reverts if addr does not have role
   * @param addr address
   * @param roleName the name of the role
   * // reverts
   */
  function checkRole(address addr, string roleName)
    view
    public
  {
    roles[roleName].check(addr);
  }

  /**
   * @dev determine if addr has role
   * @param addr address
   * @param roleName the name of the role
   * @return bool
   */
  function hasRole(address addr, string roleName)
    view
    public
    returns (bool)
  {
    return roles[roleName].has(addr);
  }

  /**
   * @dev add a role to an address
   * @param addr address
   * @param roleName the name of the role
   */
  function addRole(address addr, string roleName)
    internal
  {
    roles[roleName].add(addr);
    emit RoleAdded(addr, roleName);
  }

  /**
   * @dev remove a role from an address
   * @param addr address
   * @param roleName the name of the role
   */
  function removeRole(address addr, string roleName)
    internal
  {
    roles[roleName].remove(addr);
    emit RoleRemoved(addr, roleName);
  }

  /**
   * @dev modifier to scope access to a single role (uses msg.sender as addr)
   * @param roleName the name of the role
   * // reverts
   */
  modifier onlyRole(string roleName)
  {
    checkRole(msg.sender, roleName);
    _;
  }
}



/**
 * @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 OwnershipRenounced(address indexed previousOwner);
  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;
  }

  /**
   * @dev Throws if called by any account other than the owner.
   */
  modifier onlyOwner() {
    require(msg.sender == owner);
    _;
  }

  /**
   * @dev Allows the current owner to relinquish control of the contract.
   */
  function renounceOwnership() public onlyOwner {
    emit OwnershipRenounced(owner);
    owner = address(0);
  }

  /**
   * @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 onlyOwner {
    _transferOwnership(_newOwner);
  }

  /**
   * @dev Transfers control of the contract to a newOwner.
   * @param _newOwner The address to transfer ownership to.
   */
  function _transferOwnership(address _newOwner) internal {
    require(_newOwner != address(0));
    emit OwnershipTransferred(owner, _newOwner);
    owner = _newOwner;
  }

}


/**
 * @title Superuser
 * @dev The Superuser contract defines a single superuser who can transfer the ownership 
 * @dev of a contract to a new address, even if he is not the owner. 
 * @dev A superuser can transfer his role to a new address. 
 */
contract Superuser is Ownable, RBAC {
  string public constant ROLE_SUPERUSER = "superuser";

  constructor () public {
    addRole(msg.sender, ROLE_SUPERUSER);
  }

  /**
   * @dev Throws if called by any account that's not a superuser.
   */
  modifier onlySuperuser() {
    checkRole(msg.sender, ROLE_SUPERUSER);
    _;
  }

  modifier onlyOwnerOrSuperuser() {
    require(msg.sender == owner || isSuperuser(msg.sender));
    _;
  }

  /**
   * @dev getter to determine if address has superuser role
   */
  function isSuperuser(address _addr)
    public
    view
    returns (bool)
  {
    return hasRole(_addr, ROLE_SUPERUSER);
  }

  /**
   * @dev Allows the current superuser to transfer his role to a newSuperuser.
   * @param _newSuperuser The address to transfer ownership to.
   */
  function transferSuperuser(address _newSuperuser) public onlyOwner {
    require(_newSuperuser != address(0));
    removeRole(msg.sender, ROLE_SUPERUSER);
    addRole(_newSuperuser, ROLE_SUPERUSER);
  }
}

/**
 * @title MicroverseBase
 * @dev You are still with us? im almost surprised.
 * @dev Basic params are defined in this base.
 */
contract MicroverseBase is Superuser {

    using SafeMath for uint256;

    event OpenWormhole();
    event CloseWormhole();
    event SystemChangePercentWeiDividend(uint256 oldValue, uint256 newValue);
    event SystemChangePercentWeiJackpot(uint256 oldValue, uint256 newValue);
    event SystemChangePercentWeiMC(uint256 oldValue, uint256 newValue);

    uint256 public previousWeiBalance;
    uint256 public nextSeedHashed;
    uint256 public percentWeiDividend = 40; // 40%
    uint256 public percentWeiJackpot = 10; // 10%
    uint256 public percentWeiMC = 10; // 10%
    uint256 public FACTOR = 100;

    // We think it makes perfectly sense that only the owner can open or close the wormhole.
    bool public wormholeIsOpen = true;

    modifier wormholeOpened() {
        require (wormholeIsOpen == true);
        _;
    }

    /**
     * @dev start game
     */
    function openWormhole() external onlyOwner {
        wormholeIsOpen = true;
        emit OpenWormhole();
    }

    /**
     * @dev stop game
     */
    function closeWormhole() external onlyOwner {
        wormholeIsOpen = false;
        emit CloseWormhole();
    }

    /**
     * @dev reveal the hashed seed to general public
     * @dev the seed will be hashed twice using keccak256
     * @param seedHash The result of keccak256(keccak256(seed))
     */
    function setNextSeedHash(uint256 seedHash)
        external
        onlyOwner {
        nextSeedHashed = seedHash;
    }

    /**
     * @dev Update  dividend percentage, a system event
     * is sent to capture this change.
     * @param _value new value
     */
    function setPercentWeiDividend(uint256 _value)
        external
        onlyOwner {
        emit SystemChangePercentWeiDividend(percentWeiDividend, _value);
        percentWeiDividend = _value;
    }

    /**
     * @dev Update jackpot percentage, a system event
     * is sent to capture this change.
     * @param _value new value
     */
    function setPercentWeiJackpot(uint256 _value)
        external
        onlyOwner {
        emit SystemChangePercentWeiJackpot(percentWeiJackpot, _value);
        percentWeiJackpot = _value;
    }

    /**
     * @dev Update mutual constructor percentage, a system event
     * is sent to capture this change.
     * @param _value new value
     */
    function setPercentWeiMC(uint256 _value)
        external
        onlyOwner {
        emit SystemChangePercentWeiMC(percentWeiMC, _value);
        percentWeiMC = _value;
    }
}

/**
 * Microverse is made up of four components, together managing three ERC223 tokens.
 * Let us explain.
 *
 * ░█▀▀█ █▀▀█ █▀▀█ █▀▀█ █▀▀▀ █▀▀ 
 * ░█─▄▄ █▄▄█ █▄▄▀ █▄▄█ █─▀█ █▀▀ 
 * ░█▄▄█ ▀──▀ ▀─▀▀ ▀──▀ ▀▀▀▀ ▀▀▀ 
 * 
 * Garage manages Evil Morty token (Morty)
 * It tracks and updates the price, manage the total balance, and timestamp in this universe.
 *
 * ░█▀▀█ █▀▀█ █▀▀█ ▀▀█▀▀ █▀▀█ █── 　 ░█▀▀█ █──█ █▀▀▄ 
 * ░█▄▄█ █──█ █▄▄▀ ──█── █▄▄█ █── 　 ░█─▄▄ █──█ █──█ 
 * ░█─── ▀▀▀▀ ▀─▀▀ ──▀── ▀──▀ ▀▀▀ 　 ░█▄▄█ ─▀▀▀ ▀──▀ 
 *
 * Portal Gun manages Evil Morty token (Morty), Rick C137 token (Rick), and Flurbo token (FLB)
 * It takes care of the random process happened in this universe, in which the sender gets
 * 20% chance to get Rick, 30% chance to get double Morty, and 50% chance to get FLB, if,
 * he/she sends EM to the address of this contract.
 *
 * ▒█▀▀▀█ █▀▀█ █▀▀█ █▀▀ █▀▀ 　 ▒█▀▀█ █▀▀█ █░░█ ░▀░ █▀▀ █▀▀ 
 * ░▀▀▀▄▄ █░░█ █▄▄█ █░░ █▀▀ 　 ▒█░░░ █▄▄▀ █░░█ ▀█▀ ▀▀█ █▀▀ 
 * ▒█▄▄▄█ █▀▀▀ ▀░░▀ ▀▀▀ ▀▀▀ 　 ▒█▄▄█ ▀░▀▀ ░▀▀▀ ▀▀▀ ▀▀▀ ▀▀▀ 
 *
 * Spaceship manages Rick C137 tokens (Rick)
 * It is responsible for sending the dividends.
 *
 * ▒█▀▀█ ░▀░ █▀▀█ █▀▀▄ █▀▄▀█ █▀▀█ █▀▀▄ 
 * ▒█▀▀▄ ▀█▀ █▄▄▀ █░░█ █░▀░█ █▄▄█ █░░█ 
 * ▒█▄▄█ ▀▀▀ ▀░▀▀ ▀▀▀░ ▀░░░▀ ▀░░▀ ▀░░▀ 
 *
 * Birdman helps grow the Microverse community.
 * This contract sends the fund to birdmen.
 *
 */

/**
 * @title GarageInterface
 * @dev Housekeeper for Evil Morty token.
 */
contract GarageInterface {
    /**
     * @dev getter for token address
     */
    function getEvilMortyAddress() external view returns (address);

    /**
     * @dev proxy/agent to purchase morties on behalf of senders
     * @param weiAmount The ether amount
     * @param beneficiary The buyer's address
     */
    function citadelBuy(uint256 weiAmount, address beneficiary) external returns (uint256);
}

/**
 * @title PortalGunInterface
 * @dev Random oracle in this world.
 */
contract PortalGunInterFace {

    uint256 public numTickets;

    /**
     * @dev Give us morty, let there be rick
     * @param player The player's address
     * @param amount Amount morty sent
     */
    function participate(address player, uint256 amount) external;

    /**
     * @dev getter to check EM balance
     * @param sender The sender's address
     */
    function balanceOfMorty(address sender) external view returns (uint256);

    /**
     * @dev getter to check C137 balance
     * @param sender The sender's address
     */
    function balanceOfRick(address sender) external view returns (uint256);

    /**
     * @dev getter to check FLB balance
     * @param sender The sender's address
     */
    function balanceOfFlurbo(address sender) external view returns (uint256);

    /**
     * @dev Give back EM, C137, or FLB
     * @param seed A UUID in expressed in integer
     */
    function redeem(uint256 seed) external;

    /**
     * @dev Wake Rick up
     */
    function startRick() external returns (bool);

    /**
     * @dev Clean all ricks
     * @dev Remember, for a given period of time, Rick C137 holders are eligible for receiving ETH dividends.
     * @dev When the period ends, all ricks will be gone, C137 balance will be reset to zero.
     * @dev Our strategy is, get ricks as early as possible!
     */
    function resetRick() external;

    /**
     * @dev Make portal gun back on fire
     */
    function startPortalGun() external;

    /**
     * @dev Cease fire and make Rick drunk
     */
    function stopPortalGunAndRick() external;

    /**
     * @dev getter of number of C137 holders
     */
    function getNumOfRickHolders() external view returns (uint256);
}

/**
 * @title SpaceshipInterface
 */
contract SpaceshipInterface {

    /**
     * @dev What more can i say @jeff? It starts the spaceship
     */
    function startSpaceship() external returns (bool);
    
    /**
     * @dev Send the eth funds to all C137 holders
     */
    function sendDividends() external;
    
    /**
     * @dev getter of number of dividend rounds
     */
    function getNumDividends() external view returns (uint256);
    
    /**
     * @dev updates the status, that's it
     */
    function updateSpaceshipStatus() external;    
}


/**
 * ╔═╗╔═╦══╦═══╦═══╦═══╦╗░░╔╦═══╦═══╦═══╦═══╗
 * ║║╚╝║╠╣╠╣╔═╗║╔═╗║╔═╗║╚╗╔╝║╔══╣╔═╗║╔═╗║╔══╝
 * ║╔╗╔╗║║║║║░╚╣╚═╝║║░║╠╗║║╔╣╚══╣╚═╝║╚══╣╚══╗
 * ║║║║║║║║║║░╔╣╔╗╔╣║░║║║╚╝║║╔══╣╔╗╔╩══╗║╔══╝
 * ║║║║║╠╣╠╣╚═╝║║║╚╣╚═╝║╚╗╔╝║╚══╣║║╚╣╚═╝║╚══╗
 * ╚╝╚╝╚╩══╩═══╩╝╚═╩═══╝░╚╝░╚═══╩╝╚═╩═══╩═══╝
 *
 * It's been a great pleasure coding in solidity!
 *
 * @title Microverse
 * @dev secret: 981ea44275dc95cb74b8f768f82d6debfd2f934adc0125de71762051
 *
 * ██████┼────────────────────────────────────────────────────────────┼██████
 * ██████│░░░Ryan░░░░░░░░░░░░░░░░░░░░░░░░░Dan░░░░░░░░░░░░░░░░Justin░░░│██████
 * ██████│░Einstein░░░░░░░░░░░░░Satoshi░░░░░░░░░░░░░░░░░Stephen░░░░░░░│██████
 * ██████│░░░░░░░░░Shannon░░░░░░░░░░░░░░░░░RSA░░░░░░░░░░░░░░░░░░░░░░░░│██████
 * ██████│░░░░░░░░░░░Vitalik░░░░░░░░░░░░░░░░░░░░░All Team Members░░░░░│██████
 * ██████│░░░░░░Steve░░░░░░░░░░Mandela░░░░░░░░░░Lennon░░░░░░░░░░░░░░░░│██████
 * ██████│░░░░░░░░░░░░░░░░Gabriel░░░░░░░░░Haruki░░░░░░░░░░░░░THANKS░TO│██████
 * ██████┼────────────────────────────────────────────────────────────┼██████
 * ██████████████████████████████████████████████████████████████████████████
 * █████████████████████████ https://microverse.club ████████████████████████
 * ██████████████████████████████████████████████████████████████████████████
 * ██████████████████████████████████████████████████████████████████████████
 */
contract Microverse is MicroverseBase {

    event Refund(address indexed receiver, uint256 value);
    event Withdraw(address indexed receiver, uint256 value);

    GarageInterface internal garageInstance;
    PortalGunInterFace internal portalGunInstance;
    SpaceshipInterface internal spaceshipInstance;

    address internal EvilMortyAddress;
    address internal MCAddress;

    modifier isEvilMortyToken() {
        require(msg.sender == EvilMortyAddress);
        _;
    }

    constructor(
        address garageAddress,
        address portalGunAddress,
        address spaceshipAddress,
        address MutualConstructorAddress)
        public {

        garageInstance = GarageInterface(garageAddress);
        portalGunInstance = PortalGunInterFace(portalGunAddress);
        spaceshipInstance = SpaceshipInterface(spaceshipAddress);
        EvilMortyAddress = garageInstance.getEvilMortyAddress();
        MCAddress = MutualConstructorAddress;
    }

    /**
     * @dev Enable sending eth directly
     */
    function ()
        public
        payable {
        if (msg.sender == owner) {
            return;
        }
        buyMorty();
    }

    /**
     * @dev Respond to Evil Morty token transfer
     * @param _from address
     * @param _value address
     * @param _data extra data
     */
    function tokenFallback(address _from, uint _value, bytes _data)
        public
        wormholeOpened
        isEvilMortyToken {
        if (_from == owner) {
            return;
        }
        portalGunInstance.participate(_from, _value);
    }

    /**
     * @dev Check morty balance of a given address 
     * @param sender address
     */
    function balanceOfMorty(address sender)
        external
        view
        returns (uint256) {
        return portalGunInstance.balanceOfMorty(sender);
    }

    /**
     * @dev Check rick balance of a given address
     * @param sender address
     */
    function balanceOfRick(address sender)
        external
        view
        returns (uint256) {
        return portalGunInstance.balanceOfRick(sender);
    }

    /**
     * @dev Check flurbo of a given address
     * @param sender address
     */
    function balanceOfFlurbo(address sender)
        external
        view
        returns (uint256) {
        return portalGunInstance.balanceOfFlurbo(sender);
    }

    /**
     * @dev Agent for buying morties
     * if the user sends more eth fund than needed, the exceedings will be sent back
     * i.e., if there are only 1000 morties left, each morty costs 0.001 eth, and the
     * user sends 3 eth, then, after the purchase (1000 * 0.001 = 1 eth), the remaining
     * 2 eth will be refunded.
     */
    function buyMorty()
        public
        wormholeOpened
        payable {

        uint256 weiReturn = garageInstance.citadelBuy(msg.value, msg.sender);

        if (weiReturn > 0) {
            msg.sender.transfer(weiReturn);
            emit Refund(msg.sender, weiReturn);
        }

        _addWeiAmount(address(this).balance.sub(previousWeiBalance));
    }

    /**
     * @dev Transfer jackpot to the winner
     * @param winner address
     */
    function transferJackpot(address winner)
        external
        onlyOwner
        returns (bool) {
        uint256 weiJackpot = address(this).balance;
        emit Withdraw(winner, weiJackpot);
        winner.transfer(weiJackpot);
        previousWeiBalance = 0;
    }

    /**
     * @dev Consume tickets to generate morty, rick, or flurbo
     * @param seed A uuid4 in int format
     */
    function redeemLottery(uint256 seed)
        external
        onlyOwnerOrSuperuser {
        return portalGunInstance.redeem(seed);
    }

    /**
     * @dev Get number of tickets onhold
     */
    function getNumOfLotteryTickets()
        external
        view
        returns (uint256) {
        return portalGunInstance.numTickets();
    }

    /**
     * @dev Internal function to update funds for jackpot and dividends
     * @param weiAmount eth amount in wei
     */
    function _addWeiAmount(uint256 weiAmount)
        internal
        returns (bool) {

        uint256 weiDividendPart = weiAmount.mul(percentWeiDividend).div(FACTOR); // 40%
        uint256 weiJackpotPart = weiAmount.mul(percentWeiJackpot).div(FACTOR); // 10%
        uint256 weiMCPart = weiAmount.mul(percentWeiMC).div(FACTOR); // 10%
        uint256 weiEMFPart = weiAmount.sub(weiDividendPart).sub(weiJackpotPart).sub(weiMCPart);

        address(spaceshipInstance).transfer(weiDividendPart);
        MCAddress.transfer(weiMCPart);
        address(owner).transfer(weiEMFPart);

        previousWeiBalance = address(this).balance;

        return true;
    }

    /**
     * @dev Before sending dividends, there are some preparations to be made.
     * Spaceship needs to know the number of current Rick holders and 
     * the number of total Ricks. Any events causing changes in balance of Ricks
     * need to be stopped, which means, the Portal Gun service is paused and,
     * transferring of Ricks are paused.
     */
    function prepareDividends()
        external
        onlyOwnerOrSuperuser {

        spaceshipInstance.updateSpaceshipStatus();
        portalGunInstance.stopPortalGunAndRick();
    }

    /**
     * @dev Send eth to all Rick holders
     */
    function transferDividends()
        external
        onlyOwnerOrSuperuser {
        return spaceshipInstance.sendDividends();
    }

    /**
     * @dev Get number of Rick holders in Spaceship
     */
    function getNumDividends()
        external
        view
        returns (uint256) {
        return spaceshipInstance.getNumDividends();
    }

    /**
     * @dev Once the distribution of dividends is finished
     * the system will be started
     */
    function finishDividends()
        external
        onlyOwnerOrSuperuser {
        spaceshipInstance.startSpaceship();
        portalGunInstance.startPortalGun();
        portalGunInstance.startRick();
    }

    /**
     * @dev Reset all Rick holders
     */
    function resetDividends()
        external
        onlyOwnerOrSuperuser {
        return portalGunInstance.resetRick();
    }

    /**
     * @dev Get number of Rick holders in Portal Gun
     */
    function getNumOfRickHolders()
        external
        view
        returns (uint256) {
        return portalGunInstance.getNumOfRickHolders();
    }

    /**
     * @dev Upgrade Microverse's components
     * in case of upgrade needed
     */
    function upgradeComponent(
        uint256 _componentIndex,
        address _address)
        external
        onlyOwner {

        uint256 codeLength;

        assembly {
            codeLength := extcodesize(_address)
        }

        if (codeLength == 0) {
            return;
        }

        if (_componentIndex == 1) {
            garageInstance = GarageInterface(_address);
            return;
        }

        if (_componentIndex == 2) {
            portalGunInstance = PortalGunInterFace(_address);
            return;
        }

        if (_componentIndex == 3) {
            spaceshipInstance = SpaceshipInterface(_address);
            return;
        }

    }

    /**
     * @dev refresh evil morty's address
     */
    function upgradeEvilMorty()
        external
        onlyOwner {
        EvilMortyAddress = garageInstance.getEvilMortyAddress();
    }

}

/**
 * @title Roles
 * @author Francisco Giordano (@frangio)
 * @dev Library for managing addresses assigned to a Role.
 *      See RBAC.sol for example usage.
 */
library Roles {
  struct Role {
    mapping (address => bool) bearer;
  }

  /**
   * @dev give an address access to this role
   */
  function add(Role storage role, address addr)
    internal
  {
    role.bearer[addr] = true;
  }

  /**
   * @dev remove an address' access to this role
   */
  function remove(Role storage role, address addr)
    internal
  {
    role.bearer[addr] = false;
  }

  /**
   * @dev check if an address has this role
   * // reverts
   */
  function check(Role storage role, address addr)
    view
    internal
  {
    require(has(role, addr));
  }

  /**
   * @dev check if an address has this role
   * @return bool
   */
  function has(Role storage role, address addr)
    view
    internal
    returns (bool)
  {
    return role.bearer[addr];
  }
}


/**
 * @title SafeMath
 * @dev Math operations with safety checks that throw on error
 */
library SafeMath {

    /**
    * @dev Multiplies two numbers, throws on overflow.
    */
    function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
        // Gas optimization: this is cheaper than asserting 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
        if (a == 0) {
            return 0;
        }

        c = a * b;
        assert(c / a == b);
        return c;
    }

    /**
    * @dev Integer division of two numbers, truncating the quotient.
    */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        // assert(b > 0); // Solidity automatically throws when dividing by 0
        // uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold
        return a / b;
    }

    /**
    * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
    */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        assert(b <= a);
        return a - b;
    }

    /**
    * @dev Adds two numbers, throws on overflow.
    */
    function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
        c = a + b;
        assert(c >= a);
        return c;
    }
}