contract SingleEditionMintableCreator {
    using CountersUpgradeable for CountersUpgradeable.Counter;

    /// Counter for current contract id upgraded
    CountersUpgradeable.Counter private atContract;

    /// Address for implementation of SingleEditionMintable to clone
    address public implementation;

    /// Initializes factory with address of implementation logic
    /// @param _implementation SingleEditionMintable logic implementation contract to clone
    constructor(address _implementation) {
        implementation = _implementation;
    }

    /// Creates a new edition contract as a factory with a deterministic address
    /// Important: None of these fields (except the Url fields with the same hash) can be changed after calling
    /// @param _name Name of the edition contract
    /// @param _symbol Symbol of the edition contract
    /// @param _description Metadata: Description of the edition entry
    /// @param _animationUrl Metadata: Animation url (optional) of the edition entry
    /// @param _animationHash Metadata: SHA-256 Hash of the animation (if no animation url, can be 0x0)
    /// @param _imageUrl Metadata: Image url (semi-required) of the edition entry
    /// @param _imageHash Metadata: SHA-256 hash of the Image of the edition entry (if not image, can be 0x0)
    /// @param _editionSize Total size of the edition (number of possible editions)
    /// @param _royaltyBPS BPS amount of royalty
    function createEdition(
        string memory _name,
        string memory _symbol,
        string memory _description,
        string memory _animationUrl,
        bytes32 _animationHash,
        string memory _imageUrl,
        bytes32 _imageHash,
        uint256 _editionSize,
        uint256 _royaltyBPS
    ) external returns (uint256) {
        uint256 newId = atContract.current();
        address newContract = ClonesUpgradeable.cloneDeterministic(
            implementation,
            bytes32(abi.encodePacked(newId))
        );
        SingleEditionMintable(newContract).initialize(
            msg.sender,
            _name,
            _symbol,
            _description,
            _animationUrl,
            _animationHash,
            _imageUrl,
            _imageHash,
            _editionSize,
            _royaltyBPS
        );
        emit CreatedEdition(newId, msg.sender, _editionSize, newContract);
        // Returns the ID of the recently created minting contract
        // Also increments for the next contract creation call
        atContract.increment();
        return newId;
    }

    /// Get edition given the created ID
    /// @param editionId id of edition to get contract for
    /// @return SingleEditionMintable Edition NFT contract
    function getEditionAtId(uint256 editionId)
        external
        view
        returns (SingleEditionMintable)
    {
        return
            SingleEditionMintable(
                ClonesUpgradeable.predictDeterministicAddress(
                    implementation,
                    bytes32(abi.encodePacked(editionId)),
                    address(this)
                )
            );
    }

    /// Emitted when a edition is created reserving the corresponding token IDs.
    /// @param editionId ID of newly created edition
    event CreatedEdition(
        uint256 indexed editionId,
        address indexed creator,
        uint256 editionSize,
        address editionContractAddress
    );
}
function createEdition(
    string memory _name,
    string memory _symbol,
    string memory _description,
    string memory _animationUrl,
    bytes32 _animationHash,
    string memory _imageUrl,
    bytes32 _imageHash,
    uint256 _editionSize,
    uint256 _royaltyBPS
) external returns (uint256) {
    uint256 newId = atContract.current();
    address newContract = ClonesUpgradeable.cloneDeterministic(
        implementation,
        bytes32(abi.encodePacked(newId))
    );
    SingleEditionMintable(newContract).initialize(
        msg.sender,
        _name,
        _symbol,
        _description,
        _animationUrl,
        _animationHash,
        _imageUrl,
        _imageHash,
        _editionSize,
        _royaltyBPS
    );
    emit CreatedEdition(newId, msg.sender, _editionSize, newContract);
    // Returns the ID of the recently created minting contract
    // Also increments for the next contract creation call
    atContract.increment();
    return newId;
}

/// Creates a new edition contract as a factory with a deterministic address
/// Important: None of these fields (except the Url fields with the same hash) can be changed after calling
/// @param _name Name of the edition contract
/// @param _symbol Symbol of the edition contract
/// @param _description Metadata: Description of the edition entry
/// @param _animationUrl Metadata: Animation url (optional) of the edition entry
/// @param _animationHash Metadata: SHA-256 Hash of the animation (if no animation url, can be 0x0)
/// @param _imageUrl Metadata: Image url (semi-required) of the edition entry
/// @param _imageHash Metadata: SHA-256 hash of the Image of the edition entry (if not image, can be 0x0)
/// @param _editionSize Total size of the edition (number of possible editions)
/// @param _royaltyBPS BPS amount of royalty