// Contract: NFTSprites
// Target function: function _removeNFToken(address _from, uint256 _tokenId) internal virtual
c31070eEdff0e192176251a3Fb;
    sprites[13].currentlyForSale = false;
    sprites[13].price = 13**2 * (10**15)*5;
    sprites[13].timesSold = 1;
    idToOwner[13] = 0xB117a08963Db62c31070eEdff0e192176251a3Fb;
    spriteOwners[0xB117a08963Db62c31070eEdff0e192176251a3Fb].push(13);
    
    sprites[14].owner = 0x375D4DE9c37B3b93e4C0af0E58D54F7DFF06cC16;
    sprites[14].currentlyForSale = false;
    sprites[14].price = 14**2 * (10**15)*5;
    sprites[14].timesSold = 1;
    idToOwner[14] = 0x375D4DE9c37B3b93e4C0af0E58D54F7DFF06cC16;
    spriteOwners[0x375D4DE9c37B3b93e4C0af0E58D54F7DFF06cC16].push(14);
    
    sprites[15].owner = 0x070DcB7ba170091F84783b224489aA8B280c1A30; // original owner was 0xd9c3415Bf8600f007A1b4199DF967C25A3E00EeA, who later transferred it to this new owner: https://etherscan.io/tx/0xe2427b79bb545188468cba61a8ffc8a1f69ce1ce60f66a4ac18ac9f883336d22
    sprites[15].currentlyForSale = false;
    sprites[15].price = 15**2 * (10**15)*5;
    sprites[15].timesSold = 1;
    idToOwner[15] = 0x070DcB7ba170091F84783b224489aA8B280c1A30;
    spriteOwners[0x070DcB7ba170091F84783b224489aA8B280c1A30].push(15);
    
    sprites[16].owner = 0x172d894dB40435D04A099e081eade6492D3E71a8;
    sprites[16].currentlyForSale = false;
    sprites[16].price = 16**2 * (10**15)*5;
    sprites[16].timesSold = 1;
    idToOwner[16] = 0x172d894dB40435D04A099e081eade6492D3E71a8;
    spriteOwners[0x172d894dB40435D04A099e081eade6492D3E71a8].push(16);
    
    sprites[17].owner = 0xe4446D52e2bdB3E31470643Ab1753a4c2aEee3eA;
    sprites[17].currentlyForSale = false;
    sprites[17].price = 17**2 * (10**15)*5;
    sprites[17].timesSold = 1;
    idToOwner[17] = 0xe4446D52e2bdB3E31470643Ab1753a4c2aEee3eA;
    spriteOwners[0xe4446D52e2bdB3E31470643Ab1753a4c2aEee3eA].push(17);
    
    sprites[18].owner = 0xe4446D52e2bdB3E31470643Ab1753a4c2aEee3eA;
    sprites[18].currentlyForSale = false;
    sprites[18].price = 18**2 * (10**15)*5;
    sprites[18].timesSold = 1;
    idToOwner[18] = 0xe4446D52e2bdB3E31470643Ab1753a4c2aEee3eA;
    spriteOwners[0xe4446D52e2bdB3E31470643Ab1753a4c2aEee3eA].push(18);
    
    sprites[19].owner = 0x4202C5Aa18c934B96Bc4aEDB3DA4593c44076618;
    sprites[19].currentlyForSale = false;
    sprites[19].price = 19**2 * (10**15)*5;
    sprites[19].timesSold = 1;
    idToOwner[19] = 0x4202C5Aa18c934B96Bc4aEDB3DA4593c44076618;
    spriteOwners[0x4202C5Aa18c934B96Bc4aEDB3DA4593c44076618].push(19);
    
    sprites[20].owner = 0x7B167965d0449D27476eF236a8B6A02d5ABd27C4;
    sprites[20].currentlyForSale = false;
    sprites[20].price = 20**2 * (10**15)*5;
    sprites[20].timesSold = 1;
    idToOwner[20] = 0x7B167965d0449D27476eF236a8B6A02d5ABd27C4;
    spriteOwners[0x7B167965d0449D27476eF236a8B6A02d5ABd27C4].push(20);
    
    sprites[21].owner = 0x40D80168B6663700B6AE55d71a8c2Cf61d0C1225;
    sprites[21].currentlyForSale = false;
    sprites[21].price = 21**2 * (10**15)*5;
    sprites[21].timesSold = 1;
    idToOwner[21] = 0x40D80168B6663700B6AE55d71a8c2Cf61d0C1225;
    spriteOwners[0x40D80168B6663700B6AE55d71a8c2Cf61d0C1225].push(21);
    
    sprites[22].owner = 0x6747B33F4293fB4fD1bEaa5D7935F85d5958b684; // original owner was 0x9e4a9b4334f3167bc7dd35f48f2238c73f532baf, who later transferred it to this new owner: https://etherscan.io/tx/0x85f5486c54ae8fd9b6bd73ed524835a0517f816d50f40273e74e1df706309db2
    sprites[22].currentlyForSale = false;
    sprites[22].price = 22**2 * (10**15)*5;
    sprites[22].timesSold = 1;
    idToOwner[22] = 0x6747B33F4293fB4fD1bEaa5D7935F85d5958b684;
    spriteOwners[0x6747B33F4293fB4fD1bEaa5D7935F85d5958b684].push(22);
    
    latestNewSpriteForSale = 23;
    
    sprites[23].currentlyForSale = true;
    sprites[23].price = 23**2 * (10**15)*5;
    
    owner = msg.sender;
  }
    
  function buySprite (uint spriteNumber) public payable {
    require(sprites[spriteNumber].currentlyForSale == true);
    require(msg.value == sprites[spriteNumber].price);
    require(spriteNumber < 100);
    sprites[spriteNumber].timesSold++;
    spriteOwners[msg.sender].push(spriteNumber);
    sprites[spriteNumber].currentlyForSale = false;
    if (spriteNumber != latestNewSpriteForSale) {
        // buying sprite that is already owned from someone
        // give existing sprite owner their money
        address currentSpriteOwner = getSpriteOwner(spriteNumber);
        payable(currentSpriteOwner).transfer(msg.value);
        // have to approve msg.sender for NFT to be transferred
        idToApproval[spriteNumber] = msg.sender;
        // _safeTransferFrom calls _transfer which updates the sprite owner to msg.sender and clears approvals
        _safeTransferFrom(currentSpriteOwner, msg.sender, spriteNumber, "");
    } else {
        // buying brand new latest sprite
        sprites[spriteNumber].owner = msg.sender;
        if (latestNewSpriteForSale != 99) {
            latestNewSpriteForSale++;
            sprites[latestNewSpriteForSale].price = latestNewSpriteForSale**2 * (10**15)*5;
            sprites[latestNewSpriteForSale].currentlyForSale = true;
        }
        _mint(msg.sender, spriteNumber);
    }
  }
  
  function sellSprite (uint spriteNumber, uint price) public {
    require(msg.sender == sprites[spriteNumber].owner);
    require(price > 0);
    sprites[spriteNumber].price = price;
    sprites[spriteNumber].currentlyForSale = true;
  }
  
  function dontSellSprite (uint spriteNumber) public {
    require(msg.sender == sprites[spriteNumber].owner);
    sprites[spriteNumber].currentlyForSale = false;
  }
  
  function giftSprite (uint spriteNumber, address receiver) public {
    require(msg.sender == sprites[spriteNumber].owner);
    require(receiver != address(0), ZERO_ADDRESS);
    spriteOwners[receiver].push(spriteNumber);
    _safeTransferFrom(msg.sender, receiver, spriteNumber, "");
  }
  
  function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes calldata _data) external override {
    _safeTransferFrom(_from, _to, _tokenId, _data);
  }
  
  /**
   * @dev Transfers the ownership of an NFT from one address to another address. This function can
   * be changed to payable.
   * @notice This works identically to the other function with an extra data parameter, except this
   * function just sets data to ""
   * @param _from The current owner of the NFT.
   * @param _to The new owner.
   * @param _tokenId The NFT to transfer.
   */
  function safeTransferFrom(address _from, address _to, uint256 _tokenId) external override {
    _safeTransferFrom(_from, _to, _tokenId, "");
  }

  /**
   * @dev Set or reaffirm the approved address for an NFT. This function can be changed to payable.
   * @notice The zero address indicates there is no approved address. Throws unless `msg.sender` is
   * the current NFT owner, or an authorized operator of the current owner.
   * @param _approved Address to be approved for the given NFT ID.
   * @param _tokenId ID of the token to be approved.
   */
  function approve(address _approved, uint256 _tokenId) external override canOperate(_tokenId) validNFToken(_tokenId) {
    address tokenOwner = idToOwner[_tokenId];
    require(_approved != tokenOwner, IS_OWNER);

    idToApproval[_tokenId] = _approved;
    emit Approval(tokenOwner, _approved, _tokenId);
  }

  /**
   * @dev Enables or disables approval for a third party ("operator") to manage all of
   * `msg.sender`'s assets. It also emits the ApprovalForAll event.
   * @notice This works even if sender doesn't own any tokens at the time.
   * @param _operator Address to add to the set of authorized operators.
   * @param _approved True if the operators is approved, false to revoke approval.
   */
  function setApprovalForAll(address _operator, bool _approved) external override {
    ownerToOperators[msg.sender][_operator] = _approved;
    emit ApprovalForAll(msg.sender, _operator, _approved);
  }

  /**
   * @dev Returns the number of NFTs owned by `_owner`. NFTs assigned to the zero address are
   * considered invalid, and this function throws for queries about the zero address.
   * @param _owner Address for whom to query the balance.
   * @return Balance of _owner.
   */
  function balanceOf(address _owner) external override view returns (uint256) {
    require(_owner != address(0), ZERO_ADDRESS);
    return _getOwnerNFTCount(_owner);
  }

  /**
   * @dev Returns the address of the owner of the NFT. NFTs assigned to zero address are considered
   * invalid, and queries about them do throw.
   * @param _tokenId The identifier for an NFT.
   * @return _owner Address of _tokenId owner.
   */
  function ownerOf(uint256 _tokenId) external override view returns (address _owner) {
    _owner = idToOwner[_tokenId];
    require(_owner != address(0), NOT_VALID_NFT);
  }

  /**
   * @dev Get the approved address for a single NFT.
   * @notice Throws if `_tokenId` is not a valid NFT.
   * @param _tokenId ID of the NFT to query the approval of.
   * @return Address that _tokenId is approved for.
   */
  function getApproved(uint256 _tokenId) external override view validNFToken(_tokenId) returns (address) {
    return idToApproval[_tokenId];
  }

  /**
   * @dev Checks if `_operator` is an approved operator for `_owner`.
   * @param _owner The address that owns the NFTs.
   * @param _operator The address that acts on behalf of the owner.
   * @return True if approved for all, false otherwise.
   */
  function isApprovedForAll(address _owner, address _operator) external override view returns (bool) {
    return ownerToOperators[_owner][_operator];
  }

  /**
   * @dev Actually preforms the transfer.
   * @notice Does NO checks.
   * @param _to Address of a new owner.
   * @param _tokenId The NFT that is being transferred.
   */
  function _transfer(address _to, uint256 _tokenId) internal {
    address from = idToOwner[_tokenId];
    _clearApproval(_tokenId);

    _removeNFToken(from, _tokenId);
    _addNFToken(_to, _tokenId);
    
    sprites[_tokenId].owner = _to;

    emit Transfer(from, _to, _tokenId);
  }

  /**
   * @dev Mints a new NFT.
   * @notice This is an internal function which should be called from user-implemented external
   * mint function. Its purpose is to show and properly initialize data structures when using this
   * implementation.
   * @param _to The address that will own the minted NFT.
   * @param _tokenId of the NFT to be minted by the msg.sender.
   */
  function _mint(address _to, uint256 _tokenId) internal virtual {
    require(_to != address(0), ZERO_ADDRESS);
    require(idToOwner[_tokenId] == address(0), NFT_ALREADY_EXISTS);

    _addNFToken(_to, _tokenId);

    emit Transfer(address(0), _to, _tokenId);
  }

  /**
   * @dev Burns a NFT.
   * @notice This is an internal function which should be called from user-implemented external burn
   * function. Its purpose is to show and properly initialize data structures when using this
   * implementation. Also, note that this burn implementation allows the minter to re-mint a burned
   * NFT.
   * @param _tokenId ID of the NFT to be burned.
   */
  function _burn(uint256 _tokenId) internal virtual validNFToken(_tokenId) {
    address tokenOwner = idToOwner[_tokenId];
    _clearApproval(_tokenId);
    _removeNFToken(tokenOwner, _tokenId);
    emit Transfer(tokenOwner, address(0), _tokenId);
  }