// Contract: CloudDudes
// Target function: function _safeMint(
    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(   address target,
        
        bytes memory data,
        
        string memory errorMessage
    ) 
    internal returns (bytes memory) {
        
        require(isContract(target), "Address: delegate call to non-contract");

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(   bool success,
        
        bytes memory returndata,
        
        string memory errorMessage
    ) 
    internal pure returns (bytes memory) {
        
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}



// ============================================================
//                 INTERFACE IERC721RECEIVER
// ============================================================

pragma solidity ^0.8.0;

interface IERC721Receiver {
    /**
     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
     * by `operator` from `from`, this function is called.
     *
     * It must return its Solidity selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
     *
     * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
     */
    function onERC721Received(   address operator,   address from,   uint256 tokenId,
        
        bytes calldata data
    ) 
    external returns (bytes4);
}

// ============================================================
//                    INTERFACE IERC165
// ============================================================

pragma solidity ^0.8.0;

interface IERC165 {

    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

// ============================================================
//                         ERC165
// ============================================================

pragma solidity ^0.8.0;

abstract contract ERC165 is IERC165 {
    
//@dev See {IERC165-supportsInterface}.
     
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

// ============================================================
//                    INTERFACE IERC721
// ============================================================

pragma solidity ^0.8.0;

interface IERC721 is IERC165 {
   
    event Transfer(address indexed From, address indexed To, uint256 indexed tokenId);

   
    event Approval(address indexed Owner, address indexed Approved, uint256 indexed tokenId);


    event ApprovalForAll(address indexed Owner, address indexed Operator, bool Approved);

    function balanceOf(address Owner) external view returns (uint256 WalletBalance);

    
// @dev Returns the owner of the `tokenId` token.
   
    function ownerOf(uint256 tokenId) external view returns (address Owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(   address from,  address to,   uint256 tokenId,
        
        bytes calldata data
    ) 
    external;

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(   address from,   address to,   uint256 tokenId
    ) 
    external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(   address from,   address to,   uint256 tokenId
    ) 
    external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address To, uint256 tokenId) external;

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the caller.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address Operator, bool _Approved) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address Owner, address Operator) external view returns (bool);
}


// ============================================================
//                 INTERFACE IERC721ENUMERABLE
// ============================================================

pragma solidity ^0.8.0;


/**
 * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Enumerable is IERC721 {

    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns a token ID owned by `owner` at a given `index` of its token list.
     * Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
     */
    function tokenOfOwnerByIndex(address Owner, uint256 Index) external view returns (uint256);

    /**
     * @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
     * Use along with {totalSupply} to enumerate all tokens.
     */
    function tokenByIndex(uint256 index) external view returns (uint256);
}

// ============================================================
//                INTERFACE IERC721METADATA
// ============================================================

pragma solidity ^0.8.0;


/**
 * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Metadata is IERC721 {
    
    function name() external view returns (string memory);

   
    function symbol() external view returns (string memory);

//IPFS   IPFS   IPFS   IPFS   IPFS   IPFS   IPFS   IPFS   IPFS
//=============================================================   
    function tokenURI(uint256 tokenId) external view returns (string memory);
}

// ============================================================
//                     CONTRACT ERC721
// ============================================================

pragma solidity ^0.8.0;

contract ERC721A is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable {
    using Address for address;
    using Strings for uint256;

    struct TokenOwnership {
        address addr;
        uint64 startTimestamp;
    }

    struct AddressData {
        uint128 balance;
        uint128 numberMinted;
    }

    uint256 internal currentIndex = 1;

// ============================================================
//                       ABOUT TOKEN
// ============================================================
   
    // NAME
    string private _name;

    // SYMBOL
    string private _symbol;

    // Mapping from token ID to ownership details
    // An empty struct value does not necessarily mean the token is unowned. See ownershipOf implementation for details.
    mapping(uint256 => TokenOwnership) internal _ownerships;

    // Mapping owner address to address data
    mapping(address => AddressData) private _addressData;

    // Mapping from token ID to approved address
    mapping(uint256 => address) private _tokenApprovals;

    // Mapping from owner to operator approvals
    mapping(address => mapping(address => bool)) private _operatorApprovals;

    constructor(
        string memory name_, 
        string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev See {IERC721Enumerable-totalSupply}.
     */
    function totalSupply() public view override returns (uint256) {
        return currentIndex;
    }

    /**
     * @dev See {IERC721Enumerable-tokenByIndex}.
     */
    function tokenByIndex(uint256 Index) public view override returns (uint256) {
        require(Index < totalSupply(), "ERC721A: global index out of bounds Total Supply");
        return Index;
    }

    /**
     * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
     * This read function is O(totalSupply). If calling from a separate contract, be sure to test gas first.
     * It may also degrade with extremely large collection sizes (e.g >> 10000), test for your use case.
     */
    function tokenOfOwnerByIndex(address Owner, uint256 Index) public view override returns (uint256) {
        require(Index < balanceOf(Owner), "ERC721A: owner index out of bounds");
        uint256 numMintedSoFar = totalSupply();
        uint256 tokenIdsIdx;
        address OwnersAddressNow;

        unchecked {
            for (uint256 i; i < numMintedSoFar; i++) {
                TokenOwnership memory ownership = _ownerships[i];
                if (ownership.addr != address(0)) {
                    OwnersAddressNow = ownership.addr;
                }
                if (OwnersAddressNow == Owner) {
                    if (tokenIdsIdx == Index) {
                        return i;
                    }
                    tokenIdsIdx++;
                }
            }
        }

        revert("ERC721A: Error! Unable to get token of owner by index!");
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */

    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
        return
            interfaceId == type(IERC721).interfaceId ||
            interfaceId == type(IERC721Metadata).interfaceId ||
            interfaceId == type(IERC721Enumerable).interfaceId ||
            super.supportsInterface(interfaceId);
    }

    /**
     * @dev See {IERC721-balanceOf}.
     */

    function balanceOf(address Owner) public view override returns (uint256) {
        require(Owner != address(0), "ERC721A: balance query for the zero address");
        return uint256(_addressData[Owner].balance);
    }

    function _numberMinted(address Owner) internal view returns (uint256) {
        require(Owner != address(0), "ERC721A: number minted query for the zero address");
        return uint256(_addressData[Owner].numberMinted);
    }

    function ownershipOf(uint256 tokenId) internal view returns (TokenOwnership memory) {
        require(_exists(tokenId), "ERC721A: owner query for nonexistent token");

        unchecked {
            for (uint256 CloudCurr = tokenId; CloudCurr >= 0; CloudCurr--) {
                TokenOwnership memory ownership = _ownerships[CloudCurr];
                if (ownership.addr != address(0)) {
                    return ownership;
                }
            }
        }

        revert("ERC721A: Error! Unable to determine the Owner of Cloud Token");
    }

// ============================================================
//                      SOME FUNCTIONS
// ============================================================

    function ownerOf(uint256 tokenId) public view override returns (address) {
        return ownershipOf(tokenId).addr;
    }


    function name() public view virtual override returns (string memory) {
        return _name;
    }


    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

// ============================================================
//            METADATA and TOKEN URI and BASE URI
// ============================================================

//IPFS   IPFS   IPFS   IPFS   IPFS   IPFS   IPFS   IPFS   IPFS
//=============================================================    
    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent Cloud Token");

        string memory baseURI = _baseURI();
        return bytes(baseURI).length != 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : '';
    }

    /**
     * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
     * token will be the concatenation of the `baseURI` and the `tokenId`. Empty
     * by default, can be overriden in child contracts.
     */

//IPFS   IPFS   IPFS   IPFS   IPFS   IPFS   IPFS   IPFS   IPFS
//=============================================================    
    function _baseURI() internal view virtual returns (string memory) {
        return '';
    }

// ============================================================
//                     SOME FUNCTIONS
// ============================================================

    function approve(address To, uint256 tokenId) public override {
        address CloudOwner = ERC721A.ownerOf(tokenId);
        require(To != CloudOwner, "ERC721A: ERROR! Approval to current Cloud Owner");

        require(
            _msgSender() == CloudOwner || isApprovedForAll(CloudOwner, _msgSender()),
            "ERC721A: ERROR! Approve caller is not Cloud Owner nor approved for all"
        );

        _approve(To, tokenId, CloudOwner);
    }

    /**
     * @dev See {IERC721-getApproved}.
     */
    function getApproved(uint256 tokenId) public view override returns (address) {
        require(_exists(tokenId), "ERC721A: ERROR! Approved query for nonexistent Cloud Token!");

        return _tokenApprovals[tokenId];
    }

    /**
     * @dev See {IERC721-setApprovalForAll}.
     */
    function setApprovalForAll(address CloudOperator, bool Approved) public override {
        require(CloudOperator != _msgSender(), 'ERC721A: approve to caller');

        _operatorApprovals[_msgSender()][CloudOperator] = Approved;
        emit ApprovalForAll(_msgSender(), CloudOperator, Approved);
    }

    /**
     * @dev See {IERC721-isApprovedForAll}.
     */
    function isApprovedForAll(address CloudOwner, address CloudOperator) public view virtual override returns (bool) {
        return _operatorApprovals[CloudOwner][CloudOperator];
    }

// ============================================================
//                         TRANSFERS
// ============================================================
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public override {
        _transfer(from, to, tokenId);
    }

    /**
     * @dev See {IERC721-safeTransferFrom}.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public override {
        safeTransferFrom(from, to, tokenId, '');
    }

    /**
     * @dev See {IERC721-safeTransferFrom}.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes memory _data
    ) public override {
        _transfer(from, to, tokenId);
        require(
            _checkOnERC721Received(from, to, tokenId, _data),
            'ERC721A: transfer to non ERC721Receiver implementer'
        );
    }

// ============================================================
//                           MINT
// ============================================================
    
    function _exists(uint256 tokenId) internal view returns (bool) {
        return tokenId < currentIndex;
    }

    function _safeMint(address to, uint256 QuantityClouds) internal {
        _safeMint(to, QuantityClouds, '');
    }