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

   // Token symbol
   string private _symbol;

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


   //Optional mapping for IPFS link to canonical image file
   mapping(uint256 => string) private _tokenIPFSHashes;

   mapping(uint256 => string) private _niftyTypeName;

    //Optional mapping for IPFS link to canonical image file by  Nifty type
   mapping(uint256 => string) private _niftyTypeIPFSHashes;

   //Token name
   mapping(uint256 => string) private _tokenName;

   /*
    *     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;
   }

      //master builder - ONLY DOES STATIC CALLS
   address public masterBuilderContract = 0x6EFB06cF568253a53C7511BD3c31AB28BecB0192;

   /**
    * @dev Returns an URI for a given token ID.
    * Throws if the token ID does not exist. May return an empty string.
    * @param tokenId uint256 ID of the token to query
    */
   function tokenURI(uint256 tokenId) external view returns (string memory) {
       require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
       return _tokenURIs[tokenId];
   }


     /**
    * @dev Returns an IPFS Hash for a given token ID.
    * Throws if the token ID does not exist. May return an empty string.
    * @param tokenId uint256 ID of the token to query
    */
   function tokenIPFSHash(uint256 tokenId) external view returns (string memory) {
       require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
        //master for static calls
       BuilderMaster bm = BuilderMaster(masterBuilderContract);
       uint nifty_type = bm.getNiftyTypeId(tokenId);
       return _niftyTypeIPFSHashes[nifty_type];
   }

        /**
    * @dev Returns an URI for a given token ID.
    * Throws if the token ID does not exist. May return an empty string.
    * @param tokenId uint256 ID of the token to query
    */
   function tokenName(uint256 tokenId) external view returns (string memory) {
       require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
        //master for static calls
       BuilderMaster bm = BuilderMaster(masterBuilderContract);
       uint nifty_type = bm.getNiftyTypeId(tokenId);
       return _niftyTypeName[nifty_type];
   }

   /**
    * @dev Internal function to set the token URI for a given token.
    * Reverts if the token ID does not exist.
    * @param tokenId uint256 ID of the token to set its URI
    * @param uri string URI to assign
    */
   function _setTokenURI(uint256 tokenId, string memory uri) internal {
       require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token");
       _tokenURIs[tokenId] = uri;
   }

      /**
    * @dev Internal function to set the token IPFS hash for a given token.
    * Reverts if the token ID does not exist.
    * @param tokenId uint256 ID of the token to set its URI
    * @param ipfs_hash string IPFS link to assign
    */
   function _setTokenIPFSHash(uint256 tokenId, string memory ipfs_hash) internal {
       require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token");
       _tokenIPFSHashes[tokenId] = ipfs_hash;
   }

            /**
    * @dev Internal function to set the token IPFS hash for a given token.
    * Reverts if the token ID does not exist.
    * @param niftyType uint256 ID of the token to set its URI
    * @param ipfs_hash string IPFS link to assign
    */
   function _setTokenIPFSHashNiftyType(uint256 niftyType, string memory ipfs_hash) internal {
    //   require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token");
       _niftyTypeIPFSHashes[niftyType] = ipfs_hash;
   }

         /**
    * @dev Internal function to set the token IPFS hash for a given token.
    * Reverts if the token ID does not exist.
    * @param nifty_type uint256 of nifty type name to be set
    * @param nifty_type_name name of nifty type
    */
   function _setNiftyTypeName(uint256 nifty_type, string memory nifty_type_name) internal {
       _niftyTypeName[nifty_type] = nifty_type_name;
   }



   /**
    * @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 tokenURI(uint256 tokenId) external view returns (string memory) {
    require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
    return _tokenURIs[tokenId];
}

/**
 * @dev Returns an URI for a given token ID.
 * Throws if the token ID does not exist. May return an empty string.
 * @param tokenId uint256 ID of the token to query
 */