abstract contract ERC721Enumerable is ERC721, IERC721Enumerable {
    mapping(address => uint256[]) internal _balances;

    function balanceOf(address owner)
        public
        view
        virtual
        override(ERC721, IERC721)
        returns (uint256)
    {
        require(owner != address(0), "800");
        return _balances[owner].length;
    }

    function supportsInterface(bytes4 interfaceId)
        public
        view
        virtual
        override(IERC165, ERC721)
        returns (bool)
    {
        return
            interfaceId == type(IERC721Enumerable).interfaceId ||
            super.supportsInterface(interfaceId);
    }

    function tokenOfOwnerByIndex(address owner, uint256 index)
        public
        view
        virtual
        override
        returns (uint256 tokenId)
    {
        require(index < ERC721.balanceOf(owner), "404");
        return _balances[owner][index];
    }

    function totalSupply() public view virtual override returns (uint256) {
        return _owners.length - 1;
    }

    function tokenByIndex(uint256 index)
        public
        view
        virtual
        override
        returns (uint256)
    {
        require(index < _owners.length, "404");
        return index;
    }

    //internal - costs 20k
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual override {
        address zero = address(0);
        if (from != zero || to == zero) {
            //find this token and remove it
            uint256 length = _balances[from].length;
            for (uint256 i; i < length; ++i) {
                if (_balances[from][i] == tokenId) {
                    _balances[from][i] = _balances[from][length - 1];
                    _balances[from].pop();
                    break;
                }
            }
        }
        
        if (to != zero) _balances[to].push(tokenId);
    }
}
/********************
 * @modified code provided by Squeebo *
 ********************/
function _beforeTokenTransfer(
    address from,
    address to,
    uint256 tokenId
) internal virtual override {
    address zero = address(0);
    if (from != zero || to == zero) {
        //find this token and remove it
        uint256 length = _balances[from].length;
        for (uint256 i; i < length; ++i) {
            if (_balances[from][i] == tokenId) {
                _balances[from][i] = _balances[from][length - 1];
                _balances[from].pop();
                break;
            }
        }
    }
        
    if (to != zero) _balances[to].push(tokenId);
}

//internal - costs 20k