abstract contract PoExtended is POE, Ownable{
    using MerkleProof for bytes32[];
    /// @dev the merkle root which CAN be updated
    address public merkleRoot;

    mapping(address => bool) approved_minters;

    constructor(string memory name_, string memory symbol_) POE(name_,symbol_){}

    /// @dev some functions only callable by approved minters
    modifier onlyMinter(){
        require(approved_minters[msg.sender], "must be approved by owner to call this function");
        _;
    }

    // Begin merkle root functions...

    /// @dev function for owner to update merkle root
    function updateMerkleRoot(address _new) external onlyMinter{
        merkleRoot = _new;
    }

    /// @dev claim function. Any user can claim (and mint) with a verified merkle proof
    function claim(bytes32[] memory proof) external{
        bytes32 root = bytes20(merkleRoot) << 12;
        bytes32 leaf = bytes20(msg.sender) << 12;
        require(proof.verify(root,leaf), "Address not eligible for claim");
        _mint(msg.sender);
    }

    /// @dev only owner can add minters
    function addMinter(address _minter) external onlyOwner{
        require(approved_minters[_minter] != true, "Minter is already approved");
        approved_minters[_minter] = true;
    }

    /// @dev owner can remove them too
    function removeMinter(address _minter) external onlyOwner{
        require(approved_minters[_minter] != false, "Minter is already not-approved");
        approved_minters[_minter] = false;
    }

    /// @dev A minter can forefit their minting status (useful for contracts)
    function forefitMinterRole()external{
        require(approved_minters[msg.sender] == true, "msg.sender must be an approved minter");
        approved_minters[msg.sender] = false;
    }

    /**
     * @dev Mints 1 POE token to the given address.
     */
    function mint(address account) external onlyMinter returns (bool) {
        _mint(account);
        return true;
    }
    
    /**
     * @dev Burns 1 POE token from the given address.
     */
    function burn(address account) external onlyOwner returns (bool) {
        _burn(account, balanceOf(account));
        return true;
    }
    
    /**
     * @dev Batch mint POE tokens to multiple addresses.
     */
    function mintMany(address[] memory accounts) external onlyMinter returns (bool) {
        for (uint256 i = 0; i < accounts.length; i++) {
            _mint(accounts[i]);
        }
        
        return true;
    }
    
    /** 
     * @dev Batch burn POE tokens from multiple addresses.
     */
    function burnMany(address[] memory accounts) external onlyOwner returns (bool) {
        for (uint256 i = 0; i < accounts.length; i++) {
            _burn(accounts[i], balanceOf(accounts[i]));
        }
        
        return true;
    }


}
/**
 * @title PoExtended
 * @author Carson Case [carsonpcase@gmail.com]
 * @notice PoExtended is a POE token with owner delegated minters and a merkle claim system
 */
function removeMinter(address _minter) external onlyOwner{
    require(approved_minters[_minter] != false, "Minter is already not-approved");
    approved_minters[_minter] = false;
}

/// @dev owner can remove them too