contract ERC721Metadata is Context, ERC165, ERC721, IERC721Metadata {
  // Token name
  string private _name;

  // Token symbol
  string private _symbol;

  // Base URI
  string private _baseURI;

  // Optional mapping for token URIs
  mapping(uint256 => string) private _tokenURIs;

  /*
   *     bytes4(keccak256('name()')) == 0x06fdde03
   *     bytes4(keccak256('symbol()')) == 0x95d89b41
   *     bytes4(keccak256('tokenURI(uint256)')) == 0xc87b56dd
   *
   *     => 0x06fdde03 ^ 0x95d89b41 ^ 0xc87b56dd == 0x5b5e139f
   */
  bytes4 private constant _INTERFACE_ID_ERC721_METADATA = 0x5b5e139f;

  /**
   * @dev Constructor function
   */
  constructor (string memory name, string memory symbol) public {
    _name = name;
    _symbol = symbol;

    // register the supported interfaces to conform to ERC721 via ERC165
    _registerInterface(_INTERFACE_ID_ERC721_METADATA);
  }

  /**
   * @dev Gets the token name.
   * @return string representing the token name
   */
  function name() external view returns (string memory) {
    return _name;
  }

  /**
   * @dev Gets the token symbol.
   * @return string representing the token symbol
   */
  function symbol() external view returns (string memory) {
    return _symbol;
  }

  /**
   * @dev Returns the URI for a given token ID. May return an empty string.
   *
   * If the token's URI is non-empty and a base URI was set (via
   * {_setBaseURI}), it will be added to the token ID's URI as a prefix.
   *
   * Reverts if the token ID does not exist.
   */
  function tokenURI(uint256 tokenId) external view returns (string memory) {
    require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");

    string memory _tokenURI = _tokenURIs[tokenId];

    // Even if there is a base URI, it is only appended to non-empty token-specific URIs
    if (bytes(_tokenURI).length == 0) {
      return "";
    } else {
      // abi.encodePacked is being used to concatenate strings
      return string(abi.encodePacked(_baseURI, _tokenURI));
    }
  }

  /**
   * @dev Internal function to set the token URI for a given token.
   *
   * Reverts if the token ID does not exist.
   *
   * TIP: if all token IDs share a prefix (e.g. if your URIs look like
   * `http://api.myproject.com/token/<id>`), use {_setBaseURI} to store
   * it and save gas.
   */
  function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal {
    require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token");
    _tokenURIs[tokenId] = _tokenURI;
  }

  /**
   * @dev Internal function to set the base URI for all token IDs. It is
   * automatically added as a prefix to the value returned in {tokenURI}.
   *
   * _Available since v2.5.0._
   */
  function _setBaseURI(string memory baseURI) internal {
    _baseURI = baseURI;
  }

  /**
  * @dev Returns the base URI set via {_setBaseURI}. This will be
  * automatically added as a preffix in {tokenURI} to each token's URI, when
  * they are non-empty.
  *
  * _Available since v2.5.0._
  */
  function baseURI() external view returns (string memory) {
    return _baseURI;
  }

  /**
   * @dev Internal function to burn a specific token.
   * Reverts if the token does not exist.
   * Deprecated, use _burn(uint256) instead.
   * @param owner owner of the token to burn
   * @param tokenId uint256 ID of the token being burned by the msg.sender
   */
  function _burn(address owner, uint256 tokenId) internal {
    super._burn(owner, tokenId);

    // Clear metadata (if any)
    if (bytes(_tokenURIs[tokenId]).length != 0) {
      delete _tokenURIs[tokenId];
    }
  }
}
function _burn(address owner, uint256 tokenId) internal {
  super._burn(owner, tokenId);

  // Clear metadata (if any)
  if (bytes(_tokenURIs[tokenId]).length != 0) {
    delete _tokenURIs[tokenId];
  }
}

/**
 * @dev Internal function to burn a specific token.
 * Reverts if the token does not exist.
 * Deprecated, use _burn(uint256) instead.
 * @param owner owner of the token to burn
 * @param tokenId uint256 ID of the token being burned by the msg.sender
 */