contract NFTFactory {
    // address of creator => NFT contract address
    mapping(address => NFT[]) nftMap;
    // number of NFTs issued from factory
    uint256 public nftCount;
    // return addresses of deployed NFTs
    NFT[] public nfts;
    // emits when new NFT issued
    event CreateNFT(address indexed newNFT);
    
    /**
     * @dev Creates a new NFT.
     * @param owner Base account (owner[0]) starts with admin and minter role; others, NFT grants.
     * @param name The name of NFT.
     * @param symbol The symbol of NFT.
     * @param baseURI The base URI metadata for NFT.
     * @param tokenId The `tokenId` for initial NFT minted to owner(s). 
     * @param tokenURI The `tokenURI` for initial NFT minted to owner(s). 
     * 
     * Requirements:
     *
     * - array lengths must match.
     */
    function createNFT(
        address[] calldata owner, 
        string calldata name, 
        string calldata symbol, 
        string calldata baseURI, 
        uint256[] calldata tokenId, 
        string[] calldata tokenURI
    ) external {
        require(owner.length == tokenId.length && owner.length == tokenURI.length, "!owner/tokenId/tokenURI");
        // new NFT
        NFT nft = new NFT(
            owner, 
            name,
            symbol,
            baseURI,
            tokenId,
            tokenURI);
            
        // push into mapping of NFTs by base owner (owner[0])
        nftMap[owner[0]].push(nft);
        // push into array to get NFTs in order
        nfts.push(nft);
        // increment NFT count
        nftCount++;

        emit CreateNFT(address(nft));
    }

    /**
     * @dev owner is the base owner of the NFT. 
     */
    function getNFTByAddress(address owner) external view returns (NFT[] memory) {
        return nftMap[owner];
    }
}
/**
 * @dev {ERC721} token factory ("NFTFactory"), including:
 *  
 *  - ability for holders to burn (destroy) their tokens
 *  - an admin role that allows for role management
 *  - a minter role that allows for token minting (creation)
 */
function createNFT(
    address[] calldata owner, 
    string calldata name, 
    string calldata symbol, 
    string calldata baseURI, 
    uint256[] calldata tokenId, 
    string[] calldata tokenURI
) external {
    require(owner.length == tokenId.length && owner.length == tokenURI.length, "!owner/tokenId/tokenURI");
    // new NFT
    NFT nft = new NFT(
        owner, 
        name,
        symbol,
        baseURI,
        tokenId,
        tokenURI);
            
    // push into mapping of NFTs by base owner (owner[0])
    nftMap[owner[0]].push(nft);
    // push into array to get NFTs in order
    nfts.push(nft);
    // increment NFT count
    nftCount++;

    emit CreateNFT(address(nft));
}

/**
 * @dev Creates a new NFT.
 * @param owner Base account (owner[0]) starts with admin and minter role; others, NFT grants.
 * @param name The name of NFT.
 * @param symbol The symbol of NFT.
 * @param baseURI The base URI metadata for NFT.
 * @param tokenId The `tokenId` for initial NFT minted to owner(s). 
 * @param tokenURI The `tokenURI` for initial NFT minted to owner(s). 
 * 
 * Requirements:
 *
 * - array lengths must match.
 */