creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "contracts/DegenerativeGames.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.21;\n\nimport { ERC721A } from \"erc721a/contracts/ERC721A.sol\";\nimport { Ownable } from \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"./IAutoglyphs.sol\";\nimport './Utils.sol';\nimport \"./Array.sol\";\nimport \"./Base64.sol\";\n\n\n/*\n@title  DegenerativeGames\n@author @marka_eth\n*/\n\ncontract DegenerativeGames is ERC721A, Ownable {\n\n    IAutoglyphs public glyphs = IAutoglyphs(0xd4e4078ca3495DE5B1d4dB434BEbc5a986197782);\n\n    uint public price = 0.083 ether;\n   \n    uint256 public constant MAX_SUPPLY = 512;\n    uint256 public constant Total_Lifetime_Blocks = 216290735; \n    uint256 internal constant Initial_Cells = 4318;\n    uint256 internal constant Cells_To_Ignore = 30;\n    uint256 internal constant Reduced_Cells = Initial_Cells - Cells_To_Ignore; \n    string internal constant _THANKYOUCONWAY = \"class Game{#e=[];#t=[];#s=!0;constructor(e){this.canvas=e,this.board=new Board(this.canvas),this.board.drawBackground(),this.launch=this.launch.bind(this),this.initBrowserEvents()}launch(){if(this.board.drawBackground(),0===this.#e.length&&this.firstGeneration(),this.#s)for(let e=0;e<this.board.size.cellNumberX;e++)for(let t=0;t<this.board.size.cellNumberY;t++)this.#e[e][t].draw();else{const e=this.serializeState();this.#t.includes(e)?(console.log('Generations:',loopCounter),this.#s=!this.#s):(loopCounter++,2===this.#t.length&&this.#t.shift(),this.#t.push(e));for(let e=0;e<this.board.size.cellNumberX;e++)for(let t=0;t<this.board.size.cellNumberY;t++)this.setCellNeighborsByCoords(e,t);for(let e=0;e<this.board.size.cellNumberX;e++)for(let t=0;t<this.board.size.cellNumberY;t++)this.#e[e][t].next()}setTimeout((()=>{requestAnimationFrame(this.launch)}),CELL_SPEED)}serializeState(){return this.#e.map((e=>e.map((e=>e.alive?'1':'0')).join(''))).join('|')}firstGeneration(){this.board.drawBackground();for(let e=0;e<this.board.size.cellNumberX;e++){this.#e[e]=[];for(let t=0;t<this.board.size.cellNumberY;t++)this.#e[e][t]=new Cell(this.board.context,e,t,this.board.size.cellSize),this.#e[e][t].alive=0,this.#e[e][t].draw()}}setCellNeighborsByCoords(e,t){let s=0;const i=[[e,t+1],[e,t-1],[e+1,t],[e-1,t],[e+1,t+1],[e-1,t-1],[e+1,t-1],[e-1,t+1]];for(const e of i){let[t,i]=e;t<0&&(t=this.board.size.cellNumberX-1),t>=this.board.size.cellNumberX&&(t=0),i<0&&(i=this.board.size.cellNumberY-1),i>=this.board.size.cellNumberY&&(i=0),this.#e[t]?.[i]?.alive&&s++}this.#e[e][t].neighbors=s}drawFromFlatArray(e){for(let t=0;t<4096;t++){let s=Math.floor(t/64)+CELL_PADDING,i=t%64+CELL_PADDING;1===e[t]&&(this.#e[i][s].alive=!0),this.#e[i][s].draw()}}stop(){loopCounter=0,CELL_SPEED=100,this.#s=!0;for(let e=0;e<this.board.size.cellNumberX;e++)for(let t=0;t<this.board.size.cellNumberY;t++)this.#e[e][t].alive=0;game.drawFromFlatArray(flatArray)}initBrowserEvents(){addEventListener('keypress',(({code:e})=>{switch(e){case'Space':case'KeyP':this.#s=!this.#s;break;case'KeyN':this.stop();break;case'KeyW':CELL_SPEED>20&&(CELL_SPEED-=20);break;case'KeyS':CELL_SPEED<1e3&&(CELL_SPEED+=20);break;case'KeyE':window.location.href=canvas.toDataURL('image/png').replace('image/png','image/octet-stream')}})),this.canvas.addEventListener('click',(()=>{this.#s=!this.#s}))}}class Board{#i=BOARD_WIDTH+2*BOARD_PADDING;#l=BOARD_HEIGHT+2*BOARD_PADDING;#a=DEFAULT_CELL_SIZE;#r='#000';constructor(e){this.canvas=e,this.ctx=this.canvas.getContext('2d'),this.canvas.width=this.#i,this.canvas.height=this.#l}drawBackground(){this.ctx.fillStyle=this.#r,this.ctx.fillRect(0,0,this.#i,this.#l)}get size(){return{cellNumberX:Math.ceil(this.#i/this.#a),cellNumberY:Math.ceil(this.#l/this.#a),cellSize:this.#a}}get context(){return this.ctx}}class Cell{#h=!0;#o=0;#c='#fff';constructor(e,t,s,i){this.ctx=e,this.x=t,this.y=s,this.cellSize=i}next(){this.#h||3!==this.#o?this.#h=this.#h&&(2===this.#o||3===this.#o):this.#h=!0,this.draw()}draw(){this.#h&&(this.ctx.fillStyle=this.#c,this.ctx.fillRect(...this.position))}get position(){return[this.x*this.cellSize,this.y*this.cellSize,this.cellSize,this.cellSize]}set alive(e){this.#h=e}get alive(){return this.#h}set neighbors(e){this.#o=e}}const canvas=document.getElementById('g'),SIZE_FACTOR=4,BOARD_WIDTH=2048,BOARD_HEIGHT=2048,BOARD_PADDING=384;let loopCounter=0;const DEFAULT_CELL_SIZE=32,CELL_PADDING=12;let CELL_SPEED=100;const game=new Game(canvas);game.launch();const pattern=/<p>.<\\\\/p>/g,matches=flatString.match(pattern),flatArray=matches.map((e=>e.includes('#')?1:0));game.drawFromFlatArray(flatArray);\";\n\n    event Infinity(uint tokenId);\n\n    bool mintEnabled;\n\n    struct DegenerativeGame {\n        uint256 num;\n        uint256 birthBlock;\n        bool infinity;\n        uint256 infinityBlock;\n    }\n\n    mapping(uint256 => DegenerativeGame) public degengames;\n\n    error MintClosed();\n    error MintedOut();\n    error NoContracts();\n    error NonceAlreadyUsed();\n    error InvalidSignature();\n    error InfinityIsInfinite();\n    error WrongPrice();\n\n    constructor() ERC721A(\"DegenerativeGames\", \"DGNRTVGMS\") Ownable(msg.sender) {\n    }\n\n    function mint() external payable {\n        \n        if (msg.sender != tx.origin) revert NoContracts();\n        if (mintEnabled == false) revert MintClosed();\n        if (totalSupply() + 1 > MAX_SUPPLY ) revert MintedOut();\n        if (msg.value != price) revert WrongPrice();\n\n        uint256 tokenId = uint256(totalSupply() + 1);\n\n        degengames[tokenId] = DegenerativeGame({\n            num: tokenId,\n            birthBlock: block.number,\n            infinity: false,\n            infinityBlock: 0\n        });\n\n        _mint(msg.sender, 1);\n    }\n\n    function promoMint(address _to, uint _count) external onlyOwner {\n        if (totalSupply() + _count > MAX_SUPPLY) revert MintedOut();\n\n        for (uint256 i = 1; i <= _count; i++) {\n\n            uint256 tokenId = uint256(totalSupply() + 1);\n\n            degengames[tokenId] = DegenerativeGame({\n                num: tokenId,\n                birthBlock: block.number,\n                infinity: false,\n                infinityBlock: 0\n            });\n\n           _mint(_to, 1);\n        }\n\n    }\n\n    /// @notice *PERMANENTLY* sets a token to Infinity mode\n    /// @dev Shout out to those that dare call their functions or contracts Infinity\n    /// @param tokenId The tokenId, from 1 to tokenCounter (max MAX_SUPPLY)\n    function enterInfinity(uint tokenId) public {\n\n        require(msg.sender == ownerOf(tokenId));\n        if ( degengames[tokenId].infinity == true) revert MintClosed();\n\n        degengames[tokenId].infinity = true;\n        degengames[tokenId].infinityBlock = block.number;\n       \n        emit Infinity(tokenId);\n    }\n\n    function tokenURI(uint256 _tokenId) public view virtual override returns (string memory) {\n        require( _exists(_tokenId), \"ERC721Metadata: URI query for nonexistent token\");\n        return buildMetadata(_tokenId);\n    }\n\n    function buildMetadata(uint256 _tokenId) internal view returns (string memory) {\n\n        DegenerativeGame memory currentDG = degengames[_tokenId];\n\n        bytes memory svg = getGlyphSVG(_tokenId);\n\n        bytes memory combinedSVG = abi.encodePacked(\n            '<svg xmlns=\"http://www.w3.org/2000/svg\" preserveAspectRatio=\"xMinYMin meet\" viewBox=\"0 0 1760 1760\" style=\"background: black;\">',\n                '<style>',\n                '@font-face{ font-family: \"markaglyph\"; font-display: block; src: url(data:application/font-woff2;charset=utf-8;base64,d09GMgABAAAAAAKMAA4AAAAABkQAAAI2AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP0ZGVE0cGhwGYACCSggEEQgKcH4LDAABNgIkAxIEIAWELgcsG1EFIJ6FsfMijAaFKizPWf3nRTxP7cfv3N193zwaYulbRjyZRCKNiCeqWCpWkk3/CdVIY+ZZNd1+mgSEvEEl/fNBRVEdCJNCacVhVDUSyeA85D8WTqrVjv/fTe6iCD7nugfdy7LegTQWxRJwAZXAmMBFkrBn3qClCB+faS4SJaleCLzfeH0R+LT55idOfiuPAcbMUVAQBK3+yCMd5U754h7tOB+sRaLohgEEAE5dqvVxtZVbqU9Uz7ghANiEoaJiHgOHyYJ5il1gQBPFVm4P+sGi/9BvCEAGCCAFBQAQUAFo4ow2lwtITwEdGEHFGCYBDcskEFpro914uzDajQxOD+Q2v4Zf3+nFL5bP/H/8AM+Dld3vQcXf9ecD6hvNVInjoIo6jo+1/Hd0nswQ+heutrK7/w2N1h/DDqPnk/UMGALGq2eUJ7IRFNgB9BbszVbMGgg6MUctiGA/F8CEJwJYUsRAjLiKgWLQYwHVDj8BzUi2YaAzmZMYGDCSK2Rpw9gLVYg5bSgm3IbqmCc0c8lAZzHeNwyYS0vFytrF1sTI2B7R9RiIwAkFNtLQsTVDSkjdyskAPvsZ9IynsQg7hdUDdGx1GgCXm3Z3jMxdrI1hLhnaGc0v6zFwxsDIwVzHFm44KwJHrSzti2/eGhkggosjIZItMZuCzxFw+mDgqCaX3diOBrTucgoJA18nwncCB31bwNQFsrUzAVhAOM4HJiQ21mDxKvddbtrKHKMAfdZBAAB0TEfhgGkAAA==) format(\"woff2\")}'\n                ' .r{ width: 1280px; height: 1300px; font-size: 26px; display: grid; box-sizing: border-box; grid-template-columns: repeat(64, 20px); grid-template-rows: repeat(64, 20px); grid-gap: 0px; justify-content: space-evenly;  }',\n                ' p{ font-family: \"markaglyph\", monospace; text-align: center; display: flex; justify-content: center; align-items: center; color: white;}',\n                '</style>',\n                '<foreignObject x=\"0\" y=\"0\" width=\"1280\" height=\"1300\" style=\"transform: translate(240px, 240px);\">',\n                    '<div xmlns=\"http://www.w3.org/1999/xhtml\" class=\"meta\">',\n                        '<div  class=\"r\">',\n                            svg,\n                        '</div>',\n                    '</div>',\n                '</foreignObject>',\n            \"</svg>\"\n        );\n\n        bytes memory combinedHTML = abi.encodePacked(\n            '<!DOCTYPE html>',\n            '<html>',\n            '<head>',\n            '</head>',\n            '<body>',\n                \"<style>html,body{height: 100%; margin: 0; padding: 0;display: flex;justify-content: center; align-items: center; background: #000;overflow: none;} #g{max-width: 100%;}</style>\",\n                \"<canvas id='g'></canvas>\",\n                '<script>',\n                    'const flatString = \\' ',\n                        svg,\n                    ' \\' ; ',\n                    _THANKYOUCONWAY,\n                    '</script>',\n            '</body>',\n            '</html>'\n        );\n\n        bytes memory name = abi.encodePacked(\n            \"DegenerativeGame #\", toString(currentDG.num)\n        );\n\n        bytes memory metadata = abi.encodePacked(\n            '{',\n                '\"name\":\"', name,'\",', \n                '\"image\": ',\n                    '\"data:image/svg+xml;base64,',\n                    Base64.encode(combinedSVG),\n                    '\",',\n                  '\"animation_url\": ',\n                    '\"data:text/html;base64,',\n                    Base64.encode(combinedHTML),\n                    '\",',\n                '\"attributes\": [', attributes(currentDG), ']',\n            '}'\n        );\n\n        return string(\n            abi.encodePacked(\n                \"data:application/json;base64,\",\n                Base64.encode(metadata)\n            )\n        );\n    }\n    \n    function getGlyphSVG( uint _tokenId ) public view returns (bytes memory svg) {\n\n        DegenerativeGame memory currentDG = degengames[_tokenId];\n        bytes memory glyphData = bytes(glyphs.tokenURI(_tokenId));\n        uint256 len = glyphData.length;\n        bytes[] memory fragments = new bytes[](len);\n\n        uint cells;\n       \n        if(currentDG.infinity) {\n            cells = calculateCurrentCells(currentDG.infinityBlock);\n        }   \n        else {\n            cells = calculateCurrentCells(currentDG.birthBlock);\n        }\n       \n        for (uint256 i = Cells_To_Ignore; i < cells; ) {\n\n            bytes1 inst = glyphData[i];\n\n            if (inst == 0x25) {\n                unchecked {\n                    i += 2;\n                }\n            } else if (inst == 0x2E) {\n                fragments[i] = abi.encodePacked('<p>', '#' , '</p>' );\n\n            } else {    \n                fragments[i] = abi.encodePacked('<p>', '.' , '</p>' ); \n            }\n\n            unchecked {\n                i++;\n            }\n        }\n\n        svg = abi.encodePacked(svg, Array.join(fragments));\n\n    }\n\n    function calculateCurrentCells(uint256 birthDate) public view returns (uint256) {\n        uint256 currentBlock = block.number; \n       \n        if (currentBlock <= birthDate) {\n            return Initial_Cells;\n        }\n\n        uint256 blocksPassed = currentBlock - birthDate;\n     \n        if (blocksPassed >= Total_Lifetime_Blocks) {\n            return 0;\n        }\n\n        uint256 reductionCount = blocksPassed * Reduced_Cells / Total_Lifetime_Blocks;\n        uint256 currentCells = Initial_Cells - reductionCount;\n\n        return currentCells;\n    }\n    \n    function attributes(DegenerativeGame memory currentDG) internal pure returns (bytes memory) {\n\n        return abi.encodePacked(\n            (currentDG.infinity == false) ? trait('Mode', 'Degenerative', ',') : trait('Mode', 'Infinity', ','),\n            (currentDG.infinity == true ) ? trait('Infinity Block', toString(currentDG.infinityBlock) , ',') : '',\n            trait('Birth Block', toString(currentDG.birthBlock) , '')\n         );\n    }\n\n    function trait(string memory traitType, string memory traitValue, string memory append) internal pure returns (string memory) {\n        return string(abi.encodePacked(\n            '{',\n                '\"trait_type\": \"', traitType, '\",'\n                '\"value\": \"', traitValue, '\"'\n            '}',\n            append\n        ));\n    }\n\n    function toString(uint value) internal pure returns (string memory) {\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint temp = value;\n        uint digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    function _startTokenId() internal view virtual override returns (uint) {\n        return 1;\n    }\n\n    function setMintOpen(bool _val) external onlyOwner {\n        mintEnabled = _val;\n    }\n\n    function withdraw() external onlyOwner {\n        (bool sent, ) = payable(owner()).call{value: address(this).balance}(\"\");\n        require(sent, \"Withdraw failed\");\n    }\n\n}"
      },
      "contracts/Base64.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.21;\n\n/// @title Base64\n/// @author Brecht Devos - <brecht@loopring.org>\n/// @notice Provides a function for encoding some bytes in base64\nlibrary Base64 {\n    string internal constant TABLE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n    function encode(bytes memory data) internal pure returns (string memory) {\n        if (data.length == 0) return '';\n        \n        // load the table into memory\n        string memory table = TABLE;\n\n        // multiply by 4/3 rounded up\n        uint256 encodedLen = 4 * ((data.length + 2) / 3);\n\n        // add some extra buffer at the end required for the writing\n        string memory result = new string(encodedLen + 32);\n\n        assembly {\n            // set the actual output length\n            mstore(result, encodedLen)\n            \n            // prepare the lookup table\n            let tablePtr := add(table, 1)\n            \n            // input ptr\n            let dataPtr := data\n            let endPtr := add(dataPtr, mload(data))\n            \n            // result ptr, jump over length\n            let resultPtr := add(result, 32)\n            \n            // run over the input, 3 bytes at a time\n            for {} lt(dataPtr, endPtr) {}\n            {\n               dataPtr := add(dataPtr, 3)\n               \n               // read 3 bytes\n               let input := mload(dataPtr)\n               \n               // write 4 characters\n               mstore(resultPtr, shl(248, mload(add(tablePtr, and(shr(18, input), 0x3F)))))\n               resultPtr := add(resultPtr, 1)\n               mstore(resultPtr, shl(248, mload(add(tablePtr, and(shr(12, input), 0x3F)))))\n               resultPtr := add(resultPtr, 1)\n               mstore(resultPtr, shl(248, mload(add(tablePtr, and(shr( 6, input), 0x3F)))))\n               resultPtr := add(resultPtr, 1)\n               mstore(resultPtr, shl(248, mload(add(tablePtr, and(        input,  0x3F)))))\n               resultPtr := add(resultPtr, 1)\n            }\n            \n            // padding with '='\n            switch mod(mload(data), 3)\n            case 1 { mstore(sub(resultPtr, 2), shl(240, 0x3d3d)) }\n            case 2 { mstore(sub(resultPtr, 1), shl(248, 0x3d)) }\n        }\n        \n        return result;\n    }\n}"
      },
      "contracts/Array.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\n/*\n * @title Arrays Utils\n * @author Clement Walter <clement0walter@gmail.com>\n *\n * @notice An attempt at implementing some of the widely used javascript's Array functions in solidity.\n */\npragma solidity ^0.8.21;\n\nerror EmptyArray();\nerror GlueOutOfBounds(uint256 length);\n\nlibrary Array {\n    \n    function join(string[] memory a, string memory glue)\n        internal\n        pure\n        returns (string memory)\n    {\n        uint256 inputPointer;\n        uint256 gluePointer;\n\n        assembly {\n            inputPointer := a\n            gluePointer := glue\n        }\n        return string(_joinReferenceType(inputPointer, gluePointer));\n    }\n\n    function join(string[] memory a) internal pure returns (string memory) {\n        return join(a, \"\");\n    }\n\n    function join(bytes[] memory a, bytes memory glue)\n        internal\n        pure\n        returns (bytes memory)\n    {\n        uint256 inputPointer;\n        uint256 gluePointer;\n\n        assembly {\n            inputPointer := a\n            gluePointer := glue\n        }\n        return _joinReferenceType(inputPointer, gluePointer);\n    }\n\n    function join(bytes[] memory a) internal pure returns (bytes memory) {\n        return join(a, bytes(\"\"));\n    }\n\n    function join(bytes2[] memory a) internal pure returns (bytes memory) {\n        uint256 pointer;\n\n        assembly {\n            pointer := a\n        }\n        return _joinValueType(pointer, 2, 0);\n    }\n\n    /// @dev Join the underlying array of bytes2 to a string.\n    function join(uint16[] memory a) internal pure returns (bytes memory) {\n        uint256 pointer;\n\n        assembly {\n            pointer := a\n        }\n        return _joinValueType(pointer, 2, 256 - 16);\n    }\n\n    function join(bytes3[] memory a) internal pure returns (bytes memory) {\n        uint256 pointer;\n\n        assembly {\n            pointer := a\n        }\n        return _joinValueType(pointer, 3, 0);\n    }\n\n    function join(bytes4[] memory a) internal pure returns (bytes memory) {\n        uint256 pointer;\n\n        assembly {\n            pointer := a\n        }\n        return _joinValueType(pointer, 4, 0);\n    }\n\n    function join(bytes8[] memory a) internal pure returns (bytes memory) {\n        uint256 pointer;\n\n        assembly {\n            pointer := a\n        }\n        return _joinValueType(pointer, 8, 0);\n    }\n\n    function join(bytes16[] memory a) internal pure returns (bytes memory) {\n        uint256 pointer;\n\n        assembly {\n            pointer := a\n        }\n        return _joinValueType(pointer, 16, 0);\n    }\n\n    function join(bytes32[] memory a) internal pure returns (bytes memory) {\n        uint256 pointer;\n\n        assembly {\n            pointer := a\n        }\n        return _joinValueType(pointer, 32, 0);\n    }\n\n    function _joinValueType(\n        uint256 a,\n        uint256 typeLength,\n        uint256 shiftLeft\n    ) private pure returns (bytes memory) {\n        bytes memory tempBytes;\n\n        assembly {\n            let inputLength := mload(a)\n            let inputData := add(a, 0x20)\n            let end := add(inputData, mul(inputLength, 0x20))\n\n            // Get a location of some free memory and store it in tempBytes as\n            // Solidity does for memory variables.\n            tempBytes := mload(0x40)\n\n            // Initialize the length of the final bytes: length is typeLength x inputLength (array of bytes4)\n            mstore(tempBytes, mul(inputLength, typeLength))\n            let memoryPointer := add(tempBytes, 0x20)\n\n            // Iterate over all bytes4\n            for {\n                let pointer := inputData\n            } lt(pointer, end) {\n                pointer := add(pointer, 0x20)\n            } {\n                let currentSlot := shl(shiftLeft, mload(pointer))\n                mstore(memoryPointer, currentSlot)\n                memoryPointer := add(memoryPointer, typeLength)\n            }\n\n            mstore(0x40, and(add(memoryPointer, 31), not(31)))\n        }\n        return tempBytes;\n    }\n\n    function _joinReferenceType(uint256 inputPointer, uint256 gluePointer)\n        internal\n        pure\n        returns (bytes memory tempBytes)\n    {\n        assembly {\n            // Get a location of some free memory and store it in tempBytes as\n            // Solidity does for memory variables.\n            tempBytes := mload(0x40)\n\n            // Skip the first 32 bytes where we will store the length of the result\n            let memoryPointer := add(tempBytes, 0x20)\n\n            // Load glue\n            let glueLength := mload(gluePointer)\n            if gt(glueLength, 0x20) {\n                revert(gluePointer, 0x20)\n            }\n            let glue := mload(add(gluePointer, 0x20))\n\n            // Load the length (first 32 bytes)\n            let inputLength := mload(inputPointer)\n            let inputData := add(inputPointer, 0x20)\n            let end := add(inputData, mul(inputLength, 0x20))\n\n            // Initialize the length of the final string\n            let stringLength := 0\n\n            // Iterate over all strings (a string is itself an array).\n            for {\n                let pointer := inputData\n            } lt(pointer, end) {\n                pointer := add(pointer, 0x20)\n            } {\n                let currentStringArray := mload(pointer)\n                let currentStringLength := mload(currentStringArray)\n                stringLength := add(stringLength, currentStringLength)\n                let currentStringBytesCount := add(\n                    div(currentStringLength, 0x20),\n                    gt(mod(currentStringLength, 0x20), 0)\n                )\n\n                let currentPointer := add(currentStringArray, 0x20)\n\n                for {\n                    let copiedBytesCount := 0\n                } lt(copiedBytesCount, currentStringBytesCount) {\n                    copiedBytesCount := add(copiedBytesCount, 1)\n                } {\n                    mstore(\n                        add(memoryPointer, mul(copiedBytesCount, 0x20)),\n                        mload(currentPointer)\n                    )\n                    currentPointer := add(currentPointer, 0x20)\n                }\n                memoryPointer := add(memoryPointer, currentStringLength)\n                mstore(memoryPointer, glue)\n                memoryPointer := add(memoryPointer, glueLength)\n            }\n\n            mstore(\n                tempBytes,\n                add(stringLength, mul(sub(inputLength, 1), glueLength))\n            )\n            mstore(0x40, and(add(memoryPointer, 31), not(31)))\n        }\n        return tempBytes;\n    }\n}"
      },
      "contracts/Utils.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.21;\n\nlibrary Utils {\n    uint256 internal constant MULTIPLIER   = 100;\n    uint256 internal constant GOLDEN_RATIO = 161803;\n\n    /**\n      * Compute the largest integer smaller than or equal to the square root of `n`\n    */\n    // function floorSqrt(uint256 n) internal pure returns (uint256) { unchecked {\n    //     if (n > 0) {\n    //         uint256 x = n / 2 + 1;\n    //         uint256 y = (x + n / x) / 2;\n    //         while (x > y) {\n    //             x = y;\n    //             y = (x + n / x) / 2;\n    //         }\n    //         return x;\n    //     }\n    //     return 0;\n    // }}\n\n    /**\n      * Compute the smallest integer larger than or equal to the square root of `n`\n    */\n    // function ceilSqrt(uint256 n) internal pure returns (uint256) { unchecked {\n    //     uint256 x = floorSqrt(n);\n    //     return x ** 2 == n ? x : x + 1;\n    // }}\n\n    // function lerp(int256 targetFrom, int256 targetTo, int256 currentFrom, int256 currentTo, int current) internal pure returns (int256) { unchecked {\n    //     int256 t = 0;\n    //     int256 divisor = currentTo - currentFrom - 1;\n        \n    //     if (divisor > 0) {\n    //         t = (current - currentFrom) * int256(MULTIPLIER) / (divisor);\n    //     }\n\n    //     return targetFrom * int256(MULTIPLIER) + t * (targetTo - targetFrom);\n    // }}\n\n    function toByteArray(bytes32 _bytes32) internal pure returns (bytes memory result) {\n        uint8 i = 0;\n        while(i < 32 && _bytes32[i] != 0) {\n            i++;\n        }\n        bytes memory bytesArray = new bytes(i);\n        for (i = 0; i < 32 && _bytes32[i] != 0; i++) {\n            bytesArray[i] = _bytes32[i];\n        }\n        return bytesArray;\n    }\n\n    function toString(bytes32 _bytes32) internal pure returns (string memory result) {\n        return string(toByteArray(_bytes32));\n    }\n\n    // todo: check this\n    function toStringBytes3(bytes3 _bytes) public pure returns (string memory) {\n        bytes memory hexChars = \"0123456789abcdef\";\n        bytes memory hexString = new bytes(6); // Since bytes3 contains 3 bytes, resulting in 6 hex characters\n\n        for (uint i = 0; i < 3; i++) {\n            hexString[i * 2] = hexChars[uint8(_bytes[i] >> 4)];\n            hexString[1 + i * 2] = hexChars[uint8(_bytes[i] & 0x0f)];\n        }\n\n        return string(hexString);\n    }\n\n\n    /*\n\n        Gas Efficient uint/int to string functions\n        Copied from: https://github.com/Vectorized/solady/blob/main/src/utils/LibString.sol\n\n    */\n\n    /// @dev Returns the base 10 decimal representation of `value`.\n    function toString(uint256 value) internal pure returns (string memory str) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // The maximum value of a uint256 contains 78 digits (1 byte per digit), but\n            // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.\n            // We will need 1 word for the trailing zeros padding, 1 word for the length,\n            // and 3 words for a maximum of 78 digits.\n            str := add(mload(0x40), 0x80)\n            // Update the free memory pointer to allocate.\n            mstore(0x40, add(str, 0x20))\n            // Zeroize the slot after the string.\n            mstore(str, 0)\n\n            // Cache the end of the memory to calculate the length later.\n            let end := str\n\n            let w := not(0) // Tsk.\n            // We write the string from rightmost digit to leftmost digit.\n            // The following is essentially a do-while loop that also handles the zero case.\n            for { let temp := value } 1 {} {\n                str := add(str, w) // `sub(str, 1)`.\n                // Write the character to the pointer.\n                // The ASCII index of the '0' character is 48.\n                mstore8(str, add(48, mod(temp, 10)))\n                // Keep dividing `temp` until zero.\n                temp := div(temp, 10)\n                if iszero(temp) { break }\n            }\n\n            let length := sub(end, str)\n            // Move the pointer 32 bytes leftwards to make room for the length.\n            str := sub(str, 0x20)\n            // Store the length.\n            mstore(str, length)\n        }\n    }\n\n    /// @dev Returns the base 10 decimal representation of `value`.\n    function toString(int256 value) internal pure returns (string memory str) {\n        if (value >= 0) {\n            return toString(uint256(value));\n        }\n        unchecked {\n            str = toString(uint256(-value));\n        }\n        /// @solidity memory-safe-assembly\n        assembly {\n            // We still have some spare memory space on the left,\n            // as we have allocated 3 words (96 bytes) for up to 78 digits.\n            let length := mload(str) // Load the string length.\n            mstore(str, 0x2d) // Store the '-' character.\n            str := sub(str, 1) // Move back the string pointer by a byte.\n            mstore(str, add(length, 1)) // Update the string length.\n        }\n    }\n\n     /// @dev Encodes `data` using the base64 encoding described in RFC 4648.\n    /// See: https://datatracker.ietf.org/doc/html/rfc4648\n    /// @param fileSafe  Whether to replace '+' with '-' and '/' with '_'.\n    /// @param noPadding Whether to strip away the padding.\n    function encode(bytes memory data, bool fileSafe, bool noPadding) internal pure returns (string memory result) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let dataLength := mload(data)\n\n            if dataLength {\n                // Multiply by 4/3 rounded up.\n                // The `shl(2, ...)` is equivalent to multiplying by 4.\n                let encodedLength := shl(2, div(add(dataLength, 2), 3))\n\n                // Set `result` to point to the start of the free memory.\n                result := mload(0x40)\n\n                // Store the table into the scratch space.\n                // Offsetted by -1 byte so that the `mload` will load the character.\n                // We will rewrite the free memory pointer at `0x40` later with\n                // the allocated size.\n                // The magic constant 0x0670 will turn \"-_\" into \"+/\".\n                mstore(0x1f, \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef\")\n                mstore(0x3f, xor(\"ghijklmnopqrstuvwxyz0123456789-_\", mul(iszero(fileSafe), 0x0670)))\n\n                // Skip the first slot, which stores the length.\n                let ptr := add(result, 0x20)\n                let end := add(ptr, encodedLength)\n\n                // Run over the input, 3 bytes at a time.\n                for {} 1 {} {\n                    data := add(data, 3) // Advance 3 bytes.\n                    let input := mload(data)\n\n                    // Write 4 bytes. Optimized for fewer stack operations.\n                    mstore8(0, mload(and(shr(18, input), 0x3F)))\n                    mstore8(1, mload(and(shr(12, input), 0x3F)))\n                    mstore8(2, mload(and(shr(6, input), 0x3F)))\n                    mstore8(3, mload(and(input, 0x3F)))\n                    mstore(ptr, mload(0x00))\n\n                    ptr := add(ptr, 4) // Advance 4 bytes.\n                    if iszero(lt(ptr, end)) { break }\n                }\n                mstore(0x40, add(end, 0x20)) // Allocate the memory.\n                // Equivalent to `o = [0, 2, 1][dataLength % 3]`.\n                let o := div(2, mod(dataLength, 3))\n                // Offset `ptr` and pad with '='. We can simply write over the end.\n                mstore(sub(ptr, o), shl(240, 0x3d3d))\n                // Set `o` to zero if there is padding.\n                o := mul(iszero(iszero(noPadding)), o)\n                mstore(sub(ptr, o), 0) // Zeroize the slot after the string.\n                mstore(result, sub(encodedLength, o)) // Store the length.\n            }\n        }\n    }\n\n    /// @dev Encodes `data` using the base64 encoding described in RFC 4648.\n    /// Equivalent to `encode(data, false, false)`.\n    function encode(bytes memory data) internal pure returns (string memory result) {\n        result = encode(data, false, false);\n    }\n\n    /// @dev Encodes `data` using the base64 encoding described in RFC 4648.\n    /// Equivalent to `encode(data, fileSafe, false)`.\n    function encode(bytes memory data, bool fileSafe) internal pure returns (string memory result) {\n        result = encode(data, fileSafe, false);\n    }\n\n   \n\n\n    // /// @dev Returns a concatenated string of `a` and `b`.\n    // /// Cheaper than `string.concat()` and does not de-align the free memory pointer.\n    // function concat(string memory a, string memory b)\n    //     internal\n    //     pure\n    //     returns (string memory result)\n    // {\n    //     /// @solidity memory-safe-assembly\n    //     assembly {\n    //         let w := not(0x1f)\n    //         result := mload(0x40)\n    //         let aLength := mload(a)\n    //         // Copy `a` one word at a time, backwards.\n    //         for { let o := and(add(aLength, 0x20), w) } 1 {} {\n    //             mstore(add(result, o), mload(add(a, o)))\n    //             o := add(o, w) // `sub(o, 0x20)`.\n    //             if iszero(o) { break }\n    //         }\n    //         let bLength := mload(b)\n    //         let output := add(result, aLength)\n    //         // Copy `b` one word at a time, backwards.\n    //         for { let o := and(add(bLength, 0x20), w) } 1 {} {\n    //             mstore(add(output, o), mload(add(b, o)))\n    //             o := add(o, w) // `sub(o, 0x20)`.\n    //             if iszero(o) { break }\n    //         }\n    //         let totalLength := add(aLength, bLength)\n    //         let last := add(add(result, 0x20), totalLength)\n    //         // Zeroize the slot after the string.\n    //         mstore(last, 0)\n    //         // Stores the length.\n    //         mstore(result, totalLength)\n    //         // Allocate memory for the length and the bytes,\n    //         // rounded up to a multiple of 32.\n    //         mstore(0x40, and(add(last, 0x1f), w))\n    //     }\n    // }\n}"
      },
      "contracts/IAutoglyphs.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.21;\n\ninterface IAutoglyphs {\n\n    function symbolScheme(uint256 index) external view returns (uint8);\n\n    function tokenURI(uint256 index) external view returns (string memory);\n\n}"
      },
      "@openzeppelin/contracts/access/Ownable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)\n\npragma solidity ^0.8.20;\n\nimport {Context} from \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * The initial owner is set to the address provided by the deployer. This can\n * later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n    address private _owner;\n\n    /**\n     * @dev The caller account is not authorized to perform an operation.\n     */\n    error OwnableUnauthorizedAccount(address account);\n\n    /**\n     * @dev The owner is not a valid owner account. (eg. `address(0)`)\n     */\n    error OwnableInvalidOwner(address owner);\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.\n     */\n    constructor(address initialOwner) {\n        if (initialOwner == address(0)) {\n            revert OwnableInvalidOwner(address(0));\n        }\n        _transferOwnership(initialOwner);\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        _checkOwner();\n        _;\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        if (owner() != _msgSender()) {\n            revert OwnableUnauthorizedAccount(_msgSender());\n        }\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby disabling any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        _transferOwnership(address(0));\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        if (newOwner == address(0)) {\n            revert OwnableInvalidOwner(address(0));\n        }\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual {\n        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n"
      },
      "erc721a/contracts/ERC721A.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// ERC721A Contracts v4.3.0\n// Creator: Chiru Labs\n\npragma solidity ^0.8.4;\n\nimport './IERC721A.sol';\n\n/**\n * @dev Interface of ERC721 token receiver.\n */\ninterface ERC721A__IERC721Receiver {\n    function onERC721Received(\n        address operator,\n        address from,\n        uint256 tokenId,\n        bytes calldata data\n    ) external returns (bytes4);\n}\n\n/**\n * @title ERC721A\n *\n * @dev Implementation of the [ERC721](https://eips.ethereum.org/EIPS/eip-721)\n * Non-Fungible Token Standard, including the Metadata extension.\n * Optimized for lower gas during batch mints.\n *\n * Token IDs are minted in sequential order (e.g. 0, 1, 2, 3, ...)\n * starting from `_startTokenId()`.\n *\n * The `_sequentialUpTo()` function can be overriden to enable spot mints\n * (i.e. non-consecutive mints) for `tokenId`s greater than `_sequentialUpTo()`.\n *\n * Assumptions:\n *\n * - An owner cannot have more than 2**64 - 1 (max value of uint64) of supply.\n * - The maximum token ID cannot exceed 2**256 - 1 (max value of uint256).\n */\ncontract ERC721A is IERC721A {\n    // Bypass for a `--via-ir` bug (https://github.com/chiru-labs/ERC721A/pull/364).\n    struct TokenApprovalRef {\n        address value;\n    }\n\n    // =============================================================\n    //                           CONSTANTS\n    // =============================================================\n\n    // Mask of an entry in packed address data.\n    uint256 private constant _BITMASK_ADDRESS_DATA_ENTRY = (1 << 64) - 1;\n\n    // The bit position of `numberMinted` in packed address data.\n    uint256 private constant _BITPOS_NUMBER_MINTED = 64;\n\n    // The bit position of `numberBurned` in packed address data.\n    uint256 private constant _BITPOS_NUMBER_BURNED = 128;\n\n    // The bit position of `aux` in packed address data.\n    uint256 private constant _BITPOS_AUX = 192;\n\n    // Mask of all 256 bits in packed address data except the 64 bits for `aux`.\n    uint256 private constant _BITMASK_AUX_COMPLEMENT = (1 << 192) - 1;\n\n    // The bit position of `startTimestamp` in packed ownership.\n    uint256 private constant _BITPOS_START_TIMESTAMP = 160;\n\n    // The bit mask of the `burned` bit in packed ownership.\n    uint256 private constant _BITMASK_BURNED = 1 << 224;\n\n    // The bit position of the `nextInitialized` bit in packed ownership.\n    uint256 private constant _BITPOS_NEXT_INITIALIZED = 225;\n\n    // The bit mask of the `nextInitialized` bit in packed ownership.\n    uint256 private constant _BITMASK_NEXT_INITIALIZED = 1 << 225;\n\n    // The bit position of `extraData` in packed ownership.\n    uint256 private constant _BITPOS_EXTRA_DATA = 232;\n\n    // Mask of all 256 bits in a packed ownership except the 24 bits for `extraData`.\n    uint256 private constant _BITMASK_EXTRA_DATA_COMPLEMENT = (1 << 232) - 1;\n\n    // The mask of the lower 160 bits for addresses.\n    uint256 private constant _BITMASK_ADDRESS = (1 << 160) - 1;\n\n    // The maximum `quantity` that can be minted with {_mintERC2309}.\n    // This limit is to prevent overflows on the address data entries.\n    // For a limit of 5000, a total of 3.689e15 calls to {_mintERC2309}\n    // is required to cause an overflow, which is unrealistic.\n    uint256 private constant _MAX_MINT_ERC2309_QUANTITY_LIMIT = 5000;\n\n    // The `Transfer` event signature is given by:\n    // `keccak256(bytes(\"Transfer(address,address,uint256)\"))`.\n    bytes32 private constant _TRANSFER_EVENT_SIGNATURE =\n        0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;\n\n    // =============================================================\n    //                            STORAGE\n    // =============================================================\n\n    // The next token ID to be minted.\n    uint256 private _currentIndex;\n\n    // The number of tokens burned.\n    uint256 private _burnCounter;\n\n    // Token name\n    string private _name;\n\n    // Token symbol\n    string private _symbol;\n\n    // Mapping from token ID to ownership details\n    // An empty struct value does not necessarily mean the token is unowned.\n    // See {_packedOwnershipOf} implementation for details.\n    //\n    // Bits Layout:\n    // - [0..159]   `addr`\n    // - [160..223] `startTimestamp`\n    // - [224]      `burned`\n    // - [225]      `nextInitialized`\n    // - [232..255] `extraData`\n    mapping(uint256 => uint256) private _packedOwnerships;\n\n    // Mapping owner address to address data.\n    //\n    // Bits Layout:\n    // - [0..63]    `balance`\n    // - [64..127]  `numberMinted`\n    // - [128..191] `numberBurned`\n    // - [192..255] `aux`\n    mapping(address => uint256) private _packedAddressData;\n\n    // Mapping from token ID to approved address.\n    mapping(uint256 => TokenApprovalRef) private _tokenApprovals;\n\n    // Mapping from owner to operator approvals\n    mapping(address => mapping(address => bool)) private _operatorApprovals;\n\n    // The amount of tokens minted above `_sequentialUpTo()`.\n    // We call these spot mints (i.e. non-sequential mints).\n    uint256 private _spotMinted;\n\n    // =============================================================\n    //                          CONSTRUCTOR\n    // =============================================================\n\n    constructor(string memory name_, string memory symbol_) {\n        _name = name_;\n        _symbol = symbol_;\n        _currentIndex = _startTokenId();\n\n        if (_sequentialUpTo() < _startTokenId()) _revert(SequentialUpToTooSmall.selector);\n    }\n\n    // =============================================================\n    //                   TOKEN COUNTING OPERATIONS\n    // =============================================================\n\n    /**\n     * @dev Returns the starting token ID for sequential mints.\n     *\n     * Override this function to change the starting token ID for sequential mints.\n     *\n     * Note: The value returned must never change after any tokens have been minted.\n     */\n    function _startTokenId() internal view virtual returns (uint256) {\n        return 0;\n    }\n\n    /**\n     * @dev Returns the maximum token ID (inclusive) for sequential mints.\n     *\n     * Override this function to return a value less than 2**256 - 1,\n     * but greater than `_startTokenId()`, to enable spot (non-sequential) mints.\n     *\n     * Note: The value returned must never change after any tokens have been minted.\n     */\n    function _sequentialUpTo() internal view virtual returns (uint256) {\n        return type(uint256).max;\n    }\n\n    /**\n     * @dev Returns the next token ID to be minted.\n     */\n    function _nextTokenId() internal view virtual returns (uint256) {\n        return _currentIndex;\n    }\n\n    /**\n     * @dev Returns the total number of tokens in existence.\n     * Burned tokens will reduce the count.\n     * To get the total number of tokens minted, please see {_totalMinted}.\n     */\n    function totalSupply() public view virtual override returns (uint256 result) {\n        // Counter underflow is impossible as `_burnCounter` cannot be incremented\n        // more than `_currentIndex + _spotMinted - _startTokenId()` times.\n        unchecked {\n            // With spot minting, the intermediate `result` can be temporarily negative,\n            // and the computation must be unchecked.\n            result = _currentIndex - _burnCounter - _startTokenId();\n            if (_sequentialUpTo() != type(uint256).max) result += _spotMinted;\n        }\n    }\n\n    /**\n     * @dev Returns the total amount of tokens minted in the contract.\n     */\n    function _totalMinted() internal view virtual returns (uint256 result) {\n        // Counter underflow is impossible as `_currentIndex` does not decrement,\n        // and it is initialized to `_startTokenId()`.\n        unchecked {\n            result = _currentIndex - _startTokenId();\n            if (_sequentialUpTo() != type(uint256).max) result += _spotMinted;\n        }\n    }\n\n    /**\n     * @dev Returns the total number of tokens burned.\n     */\n    function _totalBurned() internal view virtual returns (uint256) {\n        return _burnCounter;\n    }\n\n    /**\n     * @dev Returns the total number of tokens that are spot-minted.\n     */\n    function _totalSpotMinted() internal view virtual returns (uint256) {\n        return _spotMinted;\n    }\n\n    // =============================================================\n    //                    ADDRESS DATA OPERATIONS\n    // =============================================================\n\n    /**\n     * @dev Returns the number of tokens in `owner`'s account.\n     */\n    function balanceOf(address owner) public view virtual override returns (uint256) {\n        if (owner == address(0)) _revert(BalanceQueryForZeroAddress.selector);\n        return _packedAddressData[owner] & _BITMASK_ADDRESS_DATA_ENTRY;\n    }\n\n    /**\n     * Returns the number of tokens minted by `owner`.\n     */\n    function _numberMinted(address owner) internal view returns (uint256) {\n        return (_packedAddressData[owner] >> _BITPOS_NUMBER_MINTED) & _BITMASK_ADDRESS_DATA_ENTRY;\n    }\n\n    /**\n     * Returns the number of tokens burned by or on behalf of `owner`.\n     */\n    function _numberBurned(address owner) internal view returns (uint256) {\n        return (_packedAddressData[owner] >> _BITPOS_NUMBER_BURNED) & _BITMASK_ADDRESS_DATA_ENTRY;\n    }\n\n    /**\n     * Returns the auxiliary data for `owner`. (e.g. number of whitelist mint slots used).\n     */\n    function _getAux(address owner) internal view returns (uint64) {\n        return uint64(_packedAddressData[owner] >> _BITPOS_AUX);\n    }\n\n    /**\n     * Sets the auxiliary data for `owner`. (e.g. number of whitelist mint slots used).\n     * If there are multiple variables, please pack them into a uint64.\n     */\n    function _setAux(address owner, uint64 aux) internal virtual {\n        uint256 packed = _packedAddressData[owner];\n        uint256 auxCasted;\n        // Cast `aux` with assembly to avoid redundant masking.\n        assembly {\n            auxCasted := aux\n        }\n        packed = (packed & _BITMASK_AUX_COMPLEMENT) | (auxCasted << _BITPOS_AUX);\n        _packedAddressData[owner] = packed;\n    }\n\n    // =============================================================\n    //                            IERC165\n    // =============================================================\n\n    /**\n     * @dev Returns true if this contract implements the interface defined by\n     * `interfaceId`. See the corresponding\n     * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)\n     * to learn more about how these ids are created.\n     *\n     * This function call must use less than 30000 gas.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n        // The interface IDs are constants representing the first 4 bytes\n        // of the XOR of all function selectors in the interface.\n        // See: [ERC165](https://eips.ethereum.org/EIPS/eip-165)\n        // (e.g. `bytes4(i.functionA.selector ^ i.functionB.selector ^ ...)`)\n        return\n            interfaceId == 0x01ffc9a7 || // ERC165 interface ID for ERC165.\n            interfaceId == 0x80ac58cd || // ERC165 interface ID for ERC721.\n            interfaceId == 0x5b5e139f; // ERC165 interface ID for ERC721Metadata.\n    }\n\n    // =============================================================\n    //                        IERC721Metadata\n    // =============================================================\n\n    /**\n     * @dev Returns the token collection name.\n     */\n    function name() public view virtual override returns (string memory) {\n        return _name;\n    }\n\n    /**\n     * @dev Returns the token collection symbol.\n     */\n    function symbol() public view virtual override returns (string memory) {\n        return _symbol;\n    }\n\n    /**\n     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.\n     */\n    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {\n        if (!_exists(tokenId)) _revert(URIQueryForNonexistentToken.selector);\n\n        string memory baseURI = _baseURI();\n        return bytes(baseURI).length != 0 ? string(abi.encodePacked(baseURI, _toString(tokenId))) : '';\n    }\n\n    /**\n     * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each\n     * token will be the concatenation of the `baseURI` and the `tokenId`. Empty\n     * by default, it can be overridden in child contracts.\n     */\n    function _baseURI() internal view virtual returns (string memory) {\n        return '';\n    }\n\n    // =============================================================\n    //                     OWNERSHIPS OPERATIONS\n    // =============================================================\n\n    /**\n     * @dev Returns the owner of the `tokenId` token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function ownerOf(uint256 tokenId) public view virtual override returns (address) {\n        return address(uint160(_packedOwnershipOf(tokenId)));\n    }\n\n    /**\n     * @dev Gas spent here starts off proportional to the maximum mint batch size.\n     * It gradually moves to O(1) as tokens get transferred around over time.\n     */\n    function _ownershipOf(uint256 tokenId) internal view virtual returns (TokenOwnership memory) {\n        return _unpackedOwnership(_packedOwnershipOf(tokenId));\n    }\n\n    /**\n     * @dev Returns the unpacked `TokenOwnership` struct at `index`.\n     */\n    function _ownershipAt(uint256 index) internal view virtual returns (TokenOwnership memory) {\n        return _unpackedOwnership(_packedOwnerships[index]);\n    }\n\n    /**\n     * @dev Returns whether the ownership slot at `index` is initialized.\n     * An uninitialized slot does not necessarily mean that the slot has no owner.\n     */\n    function _ownershipIsInitialized(uint256 index) internal view virtual returns (bool) {\n        return _packedOwnerships[index] != 0;\n    }\n\n    /**\n     * @dev Initializes the ownership slot minted at `index` for efficiency purposes.\n     */\n    function _initializeOwnershipAt(uint256 index) internal virtual {\n        if (_packedOwnerships[index] == 0) {\n            _packedOwnerships[index] = _packedOwnershipOf(index);\n        }\n    }\n\n    /**\n     * @dev Returns the packed ownership data of `tokenId`.\n     */\n    function _packedOwnershipOf(uint256 tokenId) private view returns (uint256 packed) {\n        if (_startTokenId() <= tokenId) {\n            packed = _packedOwnerships[tokenId];\n\n            if (tokenId > _sequentialUpTo()) {\n                if (_packedOwnershipExists(packed)) return packed;\n                _revert(OwnerQueryForNonexistentToken.selector);\n            }\n\n            // If the data at the starting slot does not exist, start the scan.\n            if (packed == 0) {\n                if (tokenId >= _currentIndex) _revert(OwnerQueryForNonexistentToken.selector);\n                // Invariant:\n                // There will always be an initialized ownership slot\n                // (i.e. `ownership.addr != address(0) && ownership.burned == false`)\n                // before an unintialized ownership slot\n                // (i.e. `ownership.addr == address(0) && ownership.burned == false`)\n                // Hence, `tokenId` will not underflow.\n                //\n                // We can directly compare the packed value.\n                // If the address is zero, packed will be zero.\n                for (;;) {\n                    unchecked {\n                        packed = _packedOwnerships[--tokenId];\n                    }\n                    if (packed == 0) continue;\n                    if (packed & _BITMASK_BURNED == 0) return packed;\n                    // Otherwise, the token is burned, and we must revert.\n                    // This handles the case of batch burned tokens, where only the burned bit\n                    // of the starting slot is set, and remaining slots are left uninitialized.\n                    _revert(OwnerQueryForNonexistentToken.selector);\n                }\n            }\n            // Otherwise, the data exists and we can skip the scan.\n            // This is possible because we have already achieved the target condition.\n            // This saves 2143 gas on transfers of initialized tokens.\n            // If the token is not burned, return `packed`. Otherwise, revert.\n            if (packed & _BITMASK_BURNED == 0) return packed;\n        }\n        _revert(OwnerQueryForNonexistentToken.selector);\n    }\n\n    /**\n     * @dev Returns the unpacked `TokenOwnership` struct from `packed`.\n     */\n    function _unpackedOwnership(uint256 packed) private pure returns (TokenOwnership memory ownership) {\n        ownership.addr = address(uint160(packed));\n        ownership.startTimestamp = uint64(packed >> _BITPOS_START_TIMESTAMP);\n        ownership.burned = packed & _BITMASK_BURNED != 0;\n        ownership.extraData = uint24(packed >> _BITPOS_EXTRA_DATA);\n    }\n\n    /**\n     * @dev Packs ownership data into a single uint256.\n     */\n    function _packOwnershipData(address owner, uint256 flags) private view returns (uint256 result) {\n        assembly {\n            // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean.\n            owner := and(owner, _BITMASK_ADDRESS)\n            // `owner | (block.timestamp << _BITPOS_START_TIMESTAMP) | flags`.\n            result := or(owner, or(shl(_BITPOS_START_TIMESTAMP, timestamp()), flags))\n        }\n    }\n\n    /**\n     * @dev Returns the `nextInitialized` flag set if `quantity` equals 1.\n     */\n    function _nextInitializedFlag(uint256 quantity) private pure returns (uint256 result) {\n        // For branchless setting of the `nextInitialized` flag.\n        assembly {\n            // `(quantity == 1) << _BITPOS_NEXT_INITIALIZED`.\n            result := shl(_BITPOS_NEXT_INITIALIZED, eq(quantity, 1))\n        }\n    }\n\n    // =============================================================\n    //                      APPROVAL OPERATIONS\n    // =============================================================\n\n    /**\n     * @dev Gives permission to `to` to transfer `tokenId` token to another account. See {ERC721A-_approve}.\n     *\n     * Requirements:\n     *\n     * - The caller must own the token or be an approved operator.\n     */\n    function approve(address to, uint256 tokenId) public payable virtual override {\n        _approve(to, tokenId, true);\n    }\n\n    /**\n     * @dev Returns the account approved for `tokenId` token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function getApproved(uint256 tokenId) public view virtual override returns (address) {\n        if (!_exists(tokenId)) _revert(ApprovalQueryForNonexistentToken.selector);\n\n        return _tokenApprovals[tokenId].value;\n    }\n\n    /**\n     * @dev Approve or remove `operator` as an operator for the caller.\n     * Operators can call {transferFrom} or {safeTransferFrom}\n     * for any token owned by the caller.\n     *\n     * Requirements:\n     *\n     * - The `operator` cannot be the caller.\n     *\n     * Emits an {ApprovalForAll} event.\n     */\n    function setApprovalForAll(address operator, bool approved) public virtual override {\n        _operatorApprovals[_msgSenderERC721A()][operator] = approved;\n        emit ApprovalForAll(_msgSenderERC721A(), operator, approved);\n    }\n\n    /**\n     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\n     *\n     * See {setApprovalForAll}.\n     */\n    function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {\n        return _operatorApprovals[owner][operator];\n    }\n\n    /**\n     * @dev Returns whether `tokenId` exists.\n     *\n     * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.\n     *\n     * Tokens start existing when they are minted. See {_mint}.\n     */\n    function _exists(uint256 tokenId) internal view virtual returns (bool result) {\n        if (_startTokenId() <= tokenId) {\n            if (tokenId > _sequentialUpTo()) return _packedOwnershipExists(_packedOwnerships[tokenId]);\n\n            if (tokenId < _currentIndex) {\n                uint256 packed;\n                while ((packed = _packedOwnerships[tokenId]) == 0) --tokenId;\n                result = packed & _BITMASK_BURNED == 0;\n            }\n        }\n    }\n\n    /**\n     * @dev Returns whether `packed` represents a token that exists.\n     */\n    function _packedOwnershipExists(uint256 packed) private pure returns (bool result) {\n        assembly {\n            // The following is equivalent to `owner != address(0) && burned == false`.\n            // Symbolically tested.\n            result := gt(and(packed, _BITMASK_ADDRESS), and(packed, _BITMASK_BURNED))\n        }\n    }\n\n    /**\n     * @dev Returns whether `msgSender` is equal to `approvedAddress` or `owner`.\n     */\n    function _isSenderApprovedOrOwner(\n        address approvedAddress,\n        address owner,\n        address msgSender\n    ) private pure returns (bool result) {\n        assembly {\n            // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean.\n            owner := and(owner, _BITMASK_ADDRESS)\n            // Mask `msgSender` to the lower 160 bits, in case the upper bits somehow aren't clean.\n            msgSender := and(msgSender, _BITMASK_ADDRESS)\n            // `msgSender == owner || msgSender == approvedAddress`.\n            result := or(eq(msgSender, owner), eq(msgSender, approvedAddress))\n        }\n    }\n\n    /**\n     * @dev Returns the storage slot and value for the approved address of `tokenId`.\n     */\n    function _getApprovedSlotAndAddress(uint256 tokenId)\n        private\n        view\n        returns (uint256 approvedAddressSlot, address approvedAddress)\n    {\n        TokenApprovalRef storage tokenApproval = _tokenApprovals[tokenId];\n        // The following is equivalent to `approvedAddress = _tokenApprovals[tokenId].value`.\n        assembly {\n            approvedAddressSlot := tokenApproval.slot\n            approvedAddress := sload(approvedAddressSlot)\n        }\n    }\n\n    // =============================================================\n    //                      TRANSFER OPERATIONS\n    // =============================================================\n\n    /**\n     * @dev Transfers `tokenId` from `from` to `to`.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must be owned by `from`.\n     * - If the caller is not `from`, it must be approved to move this token\n     * by either {approve} or {setApprovalForAll}.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(\n        address from,\n        address to,\n        uint256 tokenId\n    ) public payable virtual override {\n        uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);\n\n        // Mask `from` to the lower 160 bits, in case the upper bits somehow aren't clean.\n        from = address(uint160(uint256(uint160(from)) & _BITMASK_ADDRESS));\n\n        if (address(uint160(prevOwnershipPacked)) != from) _revert(TransferFromIncorrectOwner.selector);\n\n        (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);\n\n        // The nested ifs save around 20+ gas over a compound boolean condition.\n        if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))\n            if (!isApprovedForAll(from, _msgSenderERC721A())) _revert(TransferCallerNotOwnerNorApproved.selector);\n\n        _beforeTokenTransfers(from, to, tokenId, 1);\n\n        // Clear approvals from the previous owner.\n        assembly {\n            if approvedAddress {\n                // This is equivalent to `delete _tokenApprovals[tokenId]`.\n                sstore(approvedAddressSlot, 0)\n            }\n        }\n\n        // Underflow of the sender's balance is impossible because we check for\n        // ownership above and the recipient's balance can't realistically overflow.\n        // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256.\n        unchecked {\n            // We can directly increment and decrement the balances.\n            --_packedAddressData[from]; // Updates: `balance -= 1`.\n            ++_packedAddressData[to]; // Updates: `balance += 1`.\n\n            // Updates:\n            // - `address` to the next owner.\n            // - `startTimestamp` to the timestamp of transfering.\n            // - `burned` to `false`.\n            // - `nextInitialized` to `true`.\n            _packedOwnerships[tokenId] = _packOwnershipData(\n                to,\n                _BITMASK_NEXT_INITIALIZED | _nextExtraData(from, to, prevOwnershipPacked)\n            );\n\n            // If the next slot may not have been initialized (i.e. `nextInitialized == false`) .\n            if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {\n                uint256 nextTokenId = tokenId + 1;\n                // If the next slot's address is zero and not burned (i.e. packed value is zero).\n                if (_packedOwnerships[nextTokenId] == 0) {\n                    // If the next slot is within bounds.\n                    if (nextTokenId != _currentIndex) {\n                        // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`.\n                        _packedOwnerships[nextTokenId] = prevOwnershipPacked;\n                    }\n                }\n            }\n        }\n\n        // Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean.\n        uint256 toMasked = uint256(uint160(to)) & _BITMASK_ADDRESS;\n        assembly {\n            // Emit the `Transfer` event.\n            log4(\n                0, // Start of data (0, since no data).\n                0, // End of data (0, since no data).\n                _TRANSFER_EVENT_SIGNATURE, // Signature.\n                from, // `from`.\n                toMasked, // `to`.\n                tokenId // `tokenId`.\n            )\n        }\n        if (toMasked == 0) _revert(TransferToZeroAddress.selector);\n\n        _afterTokenTransfers(from, to, tokenId, 1);\n    }\n\n    /**\n     * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.\n     */\n    function safeTransferFrom(\n        address from,\n        address to,\n        uint256 tokenId\n    ) public payable virtual override {\n        safeTransferFrom(from, to, tokenId, '');\n    }\n\n    /**\n     * @dev Safely transfers `tokenId` token from `from` to `to`.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must exist and be owned by `from`.\n     * - If the caller is not `from`, it must be approved to move this token\n     * by either {approve} or {setApprovalForAll}.\n     * - If `to` refers to a smart contract, it must implement\n     * {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function safeTransferFrom(\n        address from,\n        address to,\n        uint256 tokenId,\n        bytes memory _data\n    ) public payable virtual override {\n        transferFrom(from, to, tokenId);\n        if (to.code.length != 0)\n            if (!_checkContractOnERC721Received(from, to, tokenId, _data)) {\n                _revert(TransferToNonERC721ReceiverImplementer.selector);\n            }\n    }\n\n    /**\n     * @dev Hook that is called before a set of serially-ordered token IDs\n     * are about to be transferred. This includes minting.\n     * And also called before burning one token.\n     *\n     * `startTokenId` - the first token ID to be transferred.\n     * `quantity` - the amount to be transferred.\n     *\n     * Calling conditions:\n     *\n     * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be\n     * transferred to `to`.\n     * - When `from` is zero, `tokenId` will be minted for `to`.\n     * - When `to` is zero, `tokenId` will be burned by `from`.\n     * - `from` and `to` are never both zero.\n     */\n    function _beforeTokenTransfers(\n        address from,\n        address to,\n        uint256 startTokenId,\n        uint256 quantity\n    ) internal virtual {}\n\n    /**\n     * @dev Hook that is called after a set of serially-ordered token IDs\n     * have been transferred. This includes minting.\n     * And also called after one token has been burned.\n     *\n     * `startTokenId` - the first token ID to be transferred.\n     * `quantity` - the amount to be transferred.\n     *\n     * Calling conditions:\n     *\n     * - When `from` and `to` are both non-zero, `from`'s `tokenId` has been\n     * transferred to `to`.\n     * - When `from` is zero, `tokenId` has been minted for `to`.\n     * - When `to` is zero, `tokenId` has been burned by `from`.\n     * - `from` and `to` are never both zero.\n     */\n    function _afterTokenTransfers(\n        address from,\n        address to,\n        uint256 startTokenId,\n        uint256 quantity\n    ) internal virtual {}\n\n    /**\n     * @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target contract.\n     *\n     * `from` - Previous owner of the given token ID.\n     * `to` - Target address that will receive the token.\n     * `tokenId` - Token ID to be transferred.\n     * `_data` - Optional data to send along with the call.\n     *\n     * Returns whether the call correctly returned the expected magic value.\n     */\n    function _checkContractOnERC721Received(\n        address from,\n        address to,\n        uint256 tokenId,\n        bytes memory _data\n    ) private returns (bool) {\n        try ERC721A__IERC721Receiver(to).onERC721Received(_msgSenderERC721A(), from, tokenId, _data) returns (\n            bytes4 retval\n        ) {\n            return retval == ERC721A__IERC721Receiver(to).onERC721Received.selector;\n        } catch (bytes memory reason) {\n            if (reason.length == 0) {\n                _revert(TransferToNonERC721ReceiverImplementer.selector);\n            }\n            assembly {\n                revert(add(32, reason), mload(reason))\n            }\n        }\n    }\n\n    // =============================================================\n    //                        MINT OPERATIONS\n    // =============================================================\n\n    /**\n     * @dev Mints `quantity` tokens and transfers them to `to`.\n     *\n     * Requirements:\n     *\n     * - `to` cannot be the zero address.\n     * - `quantity` must be greater than 0.\n     *\n     * Emits a {Transfer} event for each mint.\n     */\n    function _mint(address to, uint256 quantity) internal virtual {\n        uint256 startTokenId = _currentIndex;\n        if (quantity == 0) _revert(MintZeroQuantity.selector);\n\n        _beforeTokenTransfers(address(0), to, startTokenId, quantity);\n\n        // Overflows are incredibly unrealistic.\n        // `balance` and `numberMinted` have a maximum limit of 2**64.\n        // `tokenId` has a maximum limit of 2**256.\n        unchecked {\n            // Updates:\n            // - `address` to the owner.\n            // - `startTimestamp` to the timestamp of minting.\n            // - `burned` to `false`.\n            // - `nextInitialized` to `quantity == 1`.\n            _packedOwnerships[startTokenId] = _packOwnershipData(\n                to,\n                _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)\n            );\n\n            // Updates:\n            // - `balance += quantity`.\n            // - `numberMinted += quantity`.\n            //\n            // We can directly add to the `balance` and `numberMinted`.\n            _packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);\n\n            // Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean.\n            uint256 toMasked = uint256(uint160(to)) & _BITMASK_ADDRESS;\n\n            if (toMasked == 0) _revert(MintToZeroAddress.selector);\n\n            uint256 end = startTokenId + quantity;\n            uint256 tokenId = startTokenId;\n\n            if (end - 1 > _sequentialUpTo()) _revert(SequentialMintExceedsLimit.selector);\n\n            do {\n                assembly {\n                    // Emit the `Transfer` event.\n                    log4(\n                        0, // Start of data (0, since no data).\n                        0, // End of data (0, since no data).\n                        _TRANSFER_EVENT_SIGNATURE, // Signature.\n                        0, // `address(0)`.\n                        toMasked, // `to`.\n                        tokenId // `tokenId`.\n                    )\n                }\n                // The `!=` check ensures that large values of `quantity`\n                // that overflows uint256 will make the loop run out of gas.\n            } while (++tokenId != end);\n\n            _currentIndex = end;\n        }\n        _afterTokenTransfers(address(0), to, startTokenId, quantity);\n    }\n\n    /**\n     * @dev Mints `quantity` tokens and transfers them to `to`.\n     *\n     * This function is intended for efficient minting only during contract creation.\n     *\n     * It emits only one {ConsecutiveTransfer} as defined in\n     * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309),\n     * instead of a sequence of {Transfer} event(s).\n     *\n     * Calling this function outside of contract creation WILL make your contract\n     * non-compliant with the ERC721 standard.\n     * For full ERC721 compliance, substituting ERC721 {Transfer} event(s) with the ERC2309\n     * {ConsecutiveTransfer} event is only permissible during contract creation.\n     *\n     * Requirements:\n     *\n     * - `to` cannot be the zero address.\n     * - `quantity` must be greater than 0.\n     *\n     * Emits a {ConsecutiveTransfer} event.\n     */\n    function _mintERC2309(address to, uint256 quantity) internal virtual {\n        uint256 startTokenId = _currentIndex;\n        if (to == address(0)) _revert(MintToZeroAddress.selector);\n        if (quantity == 0) _revert(MintZeroQuantity.selector);\n        if (quantity > _MAX_MINT_ERC2309_QUANTITY_LIMIT) _revert(MintERC2309QuantityExceedsLimit.selector);\n\n        _beforeTokenTransfers(address(0), to, startTokenId, quantity);\n\n        // Overflows are unrealistic due to the above check for `quantity` to be below the limit.\n        unchecked {\n            // Updates:\n            // - `balance += quantity`.\n            // - `numberMinted += quantity`.\n            //\n            // We can directly add to the `balance` and `numberMinted`.\n            _packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);\n\n            // Updates:\n            // - `address` to the owner.\n            // - `startTimestamp` to the timestamp of minting.\n            // - `burned` to `false`.\n            // - `nextInitialized` to `quantity == 1`.\n            _packedOwnerships[startTokenId] = _packOwnershipData(\n                to,\n                _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)\n            );\n\n            if (startTokenId + quantity - 1 > _sequentialUpTo()) _revert(SequentialMintExceedsLimit.selector);\n\n            emit ConsecutiveTransfer(startTokenId, startTokenId + quantity - 1, address(0), to);\n\n            _currentIndex = startTokenId + quantity;\n        }\n        _afterTokenTransfers(address(0), to, startTokenId, quantity);\n    }\n\n    /**\n     * @dev Safely mints `quantity` tokens and transfers them to `to`.\n     *\n     * Requirements:\n     *\n     * - If `to` refers to a smart contract, it must implement\n     * {IERC721Receiver-onERC721Received}, which is called for each safe transfer.\n     * - `quantity` must be greater than 0.\n     *\n     * See {_mint}.\n     *\n     * Emits a {Transfer} event for each mint.\n     */\n    function _safeMint(\n        address to,\n        uint256 quantity,\n        bytes memory _data\n    ) internal virtual {\n        _mint(to, quantity);\n\n        unchecked {\n            if (to.code.length != 0) {\n                uint256 end = _currentIndex;\n                uint256 index = end - quantity;\n                do {\n                    if (!_checkContractOnERC721Received(address(0), to, index++, _data)) {\n                        _revert(TransferToNonERC721ReceiverImplementer.selector);\n                    }\n                } while (index < end);\n                // This prevents reentrancy to `_safeMint`.\n                // It does not prevent reentrancy to `_safeMintSpot`.\n                if (_currentIndex != end) revert();\n            }\n        }\n    }\n\n    /**\n     * @dev Equivalent to `_safeMint(to, quantity, '')`.\n     */\n    function _safeMint(address to, uint256 quantity) internal virtual {\n        _safeMint(to, quantity, '');\n    }\n\n    /**\n     * @dev Mints a single token at `tokenId`.\n     *\n     * Note: A spot-minted `tokenId` that has been burned can be re-minted again.\n     *\n     * Requirements:\n     *\n     * - `to` cannot be the zero address.\n     * - `tokenId` must be greater than `_sequentialUpTo()`.\n     * - `tokenId` must not exist.\n     *\n     * Emits a {Transfer} event for each mint.\n     */\n    function _mintSpot(address to, uint256 tokenId) internal virtual {\n        if (tokenId <= _sequentialUpTo()) _revert(SpotMintTokenIdTooSmall.selector);\n        uint256 prevOwnershipPacked = _packedOwnerships[tokenId];\n        if (_packedOwnershipExists(prevOwnershipPacked)) _revert(TokenAlreadyExists.selector);\n\n        _beforeTokenTransfers(address(0), to, tokenId, 1);\n\n        // Overflows are incredibly unrealistic.\n        // The `numberMinted` for `to` is incremented by 1, and has a max limit of 2**64 - 1.\n        // `_spotMinted` is incremented by 1, and has a max limit of 2**256 - 1.\n        unchecked {\n            // Updates:\n            // - `address` to the owner.\n            // - `startTimestamp` to the timestamp of minting.\n            // - `burned` to `false`.\n            // - `nextInitialized` to `true` (as `quantity == 1`).\n            _packedOwnerships[tokenId] = _packOwnershipData(\n                to,\n                _nextInitializedFlag(1) | _nextExtraData(address(0), to, prevOwnershipPacked)\n            );\n\n            // Updates:\n            // - `balance += 1`.\n            // - `numberMinted += 1`.\n            //\n            // We can directly add to the `balance` and `numberMinted`.\n            _packedAddressData[to] += (1 << _BITPOS_NUMBER_MINTED) | 1;\n\n            // Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean.\n            uint256 toMasked = uint256(uint160(to)) & _BITMASK_ADDRESS;\n\n            if (toMasked == 0) _revert(MintToZeroAddress.selector);\n\n            assembly {\n                // Emit the `Transfer` event.\n                log4(\n                    0, // Start of data (0, since no data).\n                    0, // End of data (0, since no data).\n                    _TRANSFER_EVENT_SIGNATURE, // Signature.\n                    0, // `address(0)`.\n                    toMasked, // `to`.\n                    tokenId // `tokenId`.\n                )\n            }\n\n            ++_spotMinted;\n        }\n\n        _afterTokenTransfers(address(0), to, tokenId, 1);\n    }\n\n    /**\n     * @dev Safely mints a single token at `tokenId`.\n     *\n     * Note: A spot-minted `tokenId` that has been burned can be re-minted again.\n     *\n     * Requirements:\n     *\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}.\n     * - `tokenId` must be greater than `_sequentialUpTo()`.\n     * - `tokenId` must not exist.\n     *\n     * See {_mintSpot}.\n     *\n     * Emits a {Transfer} event.\n     */\n    function _safeMintSpot(\n        address to,\n        uint256 tokenId,\n        bytes memory _data\n    ) internal virtual {\n        _mintSpot(to, tokenId);\n\n        unchecked {\n            if (to.code.length != 0) {\n                uint256 currentSpotMinted = _spotMinted;\n                if (!_checkContractOnERC721Received(address(0), to, tokenId, _data)) {\n                    _revert(TransferToNonERC721ReceiverImplementer.selector);\n                }\n                // This prevents reentrancy to `_safeMintSpot`.\n                // It does not prevent reentrancy to `_safeMint`.\n                if (_spotMinted != currentSpotMinted) revert();\n            }\n        }\n    }\n\n    /**\n     * @dev Equivalent to `_safeMintSpot(to, tokenId, '')`.\n     */\n    function _safeMintSpot(address to, uint256 tokenId) internal virtual {\n        _safeMintSpot(to, tokenId, '');\n    }\n\n    // =============================================================\n    //                       APPROVAL OPERATIONS\n    // =============================================================\n\n    /**\n     * @dev Equivalent to `_approve(to, tokenId, false)`.\n     */\n    function _approve(address to, uint256 tokenId) internal virtual {\n        _approve(to, tokenId, false);\n    }\n\n    /**\n     * @dev Gives permission to `to` to transfer `tokenId` token to another account.\n     * The approval is cleared when the token is transferred.\n     *\n     * Only a single account can be approved at a time, so approving the\n     * zero address clears previous approvals.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     *\n     * Emits an {Approval} event.\n     */\n    function _approve(\n        address to,\n        uint256 tokenId,\n        bool approvalCheck\n    ) internal virtual {\n        address owner = ownerOf(tokenId);\n\n        if (approvalCheck && _msgSenderERC721A() != owner)\n            if (!isApprovedForAll(owner, _msgSenderERC721A())) {\n                _revert(ApprovalCallerNotOwnerNorApproved.selector);\n            }\n\n        _tokenApprovals[tokenId].value = to;\n        emit Approval(owner, to, tokenId);\n    }\n\n    // =============================================================\n    //                        BURN OPERATIONS\n    // =============================================================\n\n    /**\n     * @dev Equivalent to `_burn(tokenId, false)`.\n     */\n    function _burn(uint256 tokenId) internal virtual {\n        _burn(tokenId, false);\n    }\n\n    /**\n     * @dev Destroys `tokenId`.\n     * The approval is cleared when the token is burned.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     *\n     * Emits a {Transfer} event.\n     */\n    function _burn(uint256 tokenId, bool approvalCheck) internal virtual {\n        uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);\n\n        address from = address(uint160(prevOwnershipPacked));\n\n        (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);\n\n        if (approvalCheck) {\n            // The nested ifs save around 20+ gas over a compound boolean condition.\n            if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))\n                if (!isApprovedForAll(from, _msgSenderERC721A())) _revert(TransferCallerNotOwnerNorApproved.selector);\n        }\n\n        _beforeTokenTransfers(from, address(0), tokenId, 1);\n\n        // Clear approvals from the previous owner.\n        assembly {\n            if approvedAddress {\n                // This is equivalent to `delete _tokenApprovals[tokenId]`.\n                sstore(approvedAddressSlot, 0)\n            }\n        }\n\n        // Underflow of the sender's balance is impossible because we check for\n        // ownership above and the recipient's balance can't realistically overflow.\n        // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256.\n        unchecked {\n            // Updates:\n            // - `balance -= 1`.\n            // - `numberBurned += 1`.\n            //\n            // We can directly decrement the balance, and increment the number burned.\n            // This is equivalent to `packed -= 1; packed += 1 << _BITPOS_NUMBER_BURNED;`.\n            _packedAddressData[from] += (1 << _BITPOS_NUMBER_BURNED) - 1;\n\n            // Updates:\n            // - `address` to the last owner.\n            // - `startTimestamp` to the timestamp of burning.\n            // - `burned` to `true`.\n            // - `nextInitialized` to `true`.\n            _packedOwnerships[tokenId] = _packOwnershipData(\n                from,\n                (_BITMASK_BURNED | _BITMASK_NEXT_INITIALIZED) | _nextExtraData(from, address(0), prevOwnershipPacked)\n            );\n\n            // If the next slot may not have been initialized (i.e. `nextInitialized == false`) .\n            if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {\n                uint256 nextTokenId = tokenId + 1;\n                // If the next slot's address is zero and not burned (i.e. packed value is zero).\n                if (_packedOwnerships[nextTokenId] == 0) {\n                    // If the next slot is within bounds.\n                    if (nextTokenId != _currentIndex) {\n                        // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`.\n                        _packedOwnerships[nextTokenId] = prevOwnershipPacked;\n                    }\n                }\n            }\n        }\n\n        emit Transfer(from, address(0), tokenId);\n        _afterTokenTransfers(from, address(0), tokenId, 1);\n\n        // Overflow not possible, as `_burnCounter` cannot be exceed `_currentIndex + _spotMinted` times.\n        unchecked {\n            _burnCounter++;\n        }\n    }\n\n    // =============================================================\n    //                     EXTRA DATA OPERATIONS\n    // =============================================================\n\n    /**\n     * @dev Directly sets the extra data for the ownership data `index`.\n     */\n    function _setExtraDataAt(uint256 index, uint24 extraData) internal virtual {\n        uint256 packed = _packedOwnerships[index];\n        if (packed == 0) _revert(OwnershipNotInitializedForExtraData.selector);\n        uint256 extraDataCasted;\n        // Cast `extraData` with assembly to avoid redundant masking.\n        assembly {\n            extraDataCasted := extraData\n        }\n        packed = (packed & _BITMASK_EXTRA_DATA_COMPLEMENT) | (extraDataCasted << _BITPOS_EXTRA_DATA);\n        _packedOwnerships[index] = packed;\n    }\n\n    /**\n     * @dev Called during each token transfer to set the 24bit `extraData` field.\n     * Intended to be overridden by the cosumer contract.\n     *\n     * `previousExtraData` - the value of `extraData` before transfer.\n     *\n     * Calling conditions:\n     *\n     * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be\n     * transferred to `to`.\n     * - When `from` is zero, `tokenId` will be minted for `to`.\n     * - When `to` is zero, `tokenId` will be burned by `from`.\n     * - `from` and `to` are never both zero.\n     */\n    function _extraData(\n        address from,\n        address to,\n        uint24 previousExtraData\n    ) internal view virtual returns (uint24) {}\n\n    /**\n     * @dev Returns the next extra data for the packed ownership data.\n     * The returned result is shifted into position.\n     */\n    function _nextExtraData(\n        address from,\n        address to,\n        uint256 prevOwnershipPacked\n    ) private view returns (uint256) {\n        uint24 extraData = uint24(prevOwnershipPacked >> _BITPOS_EXTRA_DATA);\n        return uint256(_extraData(from, to, extraData)) << _BITPOS_EXTRA_DATA;\n    }\n\n    // =============================================================\n    //                       OTHER OPERATIONS\n    // =============================================================\n\n    /**\n     * @dev Returns the message sender (defaults to `msg.sender`).\n     *\n     * If you are writing GSN compatible contracts, you need to override this function.\n     */\n    function _msgSenderERC721A() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    /**\n     * @dev Converts a uint256 to its ASCII string decimal representation.\n     */\n    function _toString(uint256 value) internal pure virtual returns (string memory str) {\n        assembly {\n            // The maximum value of a uint256 contains 78 digits (1 byte per digit), but\n            // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.\n            // We will need 1 word for the trailing zeros padding, 1 word for the length,\n            // and 3 words for a maximum of 78 digits. Total: 5 * 0x20 = 0xa0.\n            let m := add(mload(0x40), 0xa0)\n            // Update the free memory pointer to allocate.\n            mstore(0x40, m)\n            // Assign the `str` to the end.\n            str := sub(m, 0x20)\n            // Zeroize the slot after the string.\n            mstore(str, 0)\n\n            // Cache the end of the memory to calculate the length later.\n            let end := str\n\n            // We write the string from rightmost digit to leftmost digit.\n            // The following is essentially a do-while loop that also handles the zero case.\n            // prettier-ignore\n            for { let temp := value } 1 {} {\n                str := sub(str, 1)\n                // Write the character to the pointer.\n                // The ASCII index of the '0' character is 48.\n                mstore8(str, add(48, mod(temp, 10)))\n                // Keep dividing `temp` until zero.\n                temp := div(temp, 10)\n                // prettier-ignore\n                if iszero(temp) { break }\n            }\n\n            let length := sub(end, str)\n            // Move the pointer 32 bytes leftwards to make room for the length.\n            str := sub(str, 0x20)\n            // Store the length.\n            mstore(str, length)\n        }\n    }\n\n    /**\n     * @dev For more efficient reverts.\n     */\n    function _revert(bytes4 errorSelector) internal pure {\n        assembly {\n            mstore(0x00, errorSelector)\n            revert(0x00, 0x04)\n        }\n    }\n}\n"
      },
      "erc721a/contracts/IERC721A.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// ERC721A Contracts v4.3.0\n// Creator: Chiru Labs\n\npragma solidity ^0.8.4;\n\n/**\n * @dev Interface of ERC721A.\n */\ninterface IERC721A {\n    /**\n     * The caller must own the token or be an approved operator.\n     */\n    error ApprovalCallerNotOwnerNorApproved();\n\n    /**\n     * The token does not exist.\n     */\n    error ApprovalQueryForNonexistentToken();\n\n    /**\n     * Cannot query the balance for the zero address.\n     */\n    error BalanceQueryForZeroAddress();\n\n    /**\n     * Cannot mint to the zero address.\n     */\n    error MintToZeroAddress();\n\n    /**\n     * The quantity of tokens minted must be more than zero.\n     */\n    error MintZeroQuantity();\n\n    /**\n     * The token does not exist.\n     */\n    error OwnerQueryForNonexistentToken();\n\n    /**\n     * The caller must own the token or be an approved operator.\n     */\n    error TransferCallerNotOwnerNorApproved();\n\n    /**\n     * The token must be owned by `from`.\n     */\n    error TransferFromIncorrectOwner();\n\n    /**\n     * Cannot safely transfer to a contract that does not implement the\n     * ERC721Receiver interface.\n     */\n    error TransferToNonERC721ReceiverImplementer();\n\n    /**\n     * Cannot transfer to the zero address.\n     */\n    error TransferToZeroAddress();\n\n    /**\n     * The token does not exist.\n     */\n    error URIQueryForNonexistentToken();\n\n    /**\n     * The `quantity` minted with ERC2309 exceeds the safety limit.\n     */\n    error MintERC2309QuantityExceedsLimit();\n\n    /**\n     * The `extraData` cannot be set on an unintialized ownership slot.\n     */\n    error OwnershipNotInitializedForExtraData();\n\n    /**\n     * `_sequentialUpTo()` must be greater than `_startTokenId()`.\n     */\n    error SequentialUpToTooSmall();\n\n    /**\n     * The `tokenId` of a sequential mint exceeds `_sequentialUpTo()`.\n     */\n    error SequentialMintExceedsLimit();\n\n    /**\n     * Spot minting requires a `tokenId` greater than `_sequentialUpTo()`.\n     */\n    error SpotMintTokenIdTooSmall();\n\n    /**\n     * Cannot mint over a token that already exists.\n     */\n    error TokenAlreadyExists();\n\n    /**\n     * The feature is not compatible with spot mints.\n     */\n    error NotCompatibleWithSpotMints();\n\n    // =============================================================\n    //                            STRUCTS\n    // =============================================================\n\n    struct TokenOwnership {\n        // The address of the owner.\n        address addr;\n        // Stores the start time of ownership with minimal overhead for tokenomics.\n        uint64 startTimestamp;\n        // Whether the token has been burned.\n        bool burned;\n        // Arbitrary data similar to `startTimestamp` that can be set via {_extraData}.\n        uint24 extraData;\n    }\n\n    // =============================================================\n    //                         TOKEN COUNTERS\n    // =============================================================\n\n    /**\n     * @dev Returns the total number of tokens in existence.\n     * Burned tokens will reduce the count.\n     * To get the total number of tokens minted, please see {_totalMinted}.\n     */\n    function totalSupply() external view returns (uint256);\n\n    // =============================================================\n    //                            IERC165\n    // =============================================================\n\n    /**\n     * @dev Returns true if this contract implements the interface defined by\n     * `interfaceId`. See the corresponding\n     * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)\n     * to learn more about how these ids are created.\n     *\n     * This function call must use less than 30000 gas.\n     */\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\n\n    // =============================================================\n    //                            IERC721\n    // =============================================================\n\n    /**\n     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n\n    /**\n     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\n     */\n    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\n\n    /**\n     * @dev Emitted when `owner` enables or disables\n     * (`approved`) `operator` to manage all of its assets.\n     */\n    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n    /**\n     * @dev Returns the number of tokens in `owner`'s account.\n     */\n    function balanceOf(address owner) external view returns (uint256 balance);\n\n    /**\n     * @dev Returns the owner of the `tokenId` token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function ownerOf(uint256 tokenId) external view returns (address owner);\n\n    /**\n     * @dev Safely transfers `tokenId` token from `from` to `to`,\n     * checking first that contract recipients are aware of the ERC721 protocol\n     * to prevent tokens from being forever locked.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must exist and be owned by `from`.\n     * - If the caller is not `from`, it must be have been allowed to move\n     * this token by either {approve} or {setApprovalForAll}.\n     * - If `to` refers to a smart contract, it must implement\n     * {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function safeTransferFrom(\n        address from,\n        address to,\n        uint256 tokenId,\n        bytes calldata data\n    ) external payable;\n\n    /**\n     * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.\n     */\n    function safeTransferFrom(\n        address from,\n        address to,\n        uint256 tokenId\n    ) external payable;\n\n    /**\n     * @dev Transfers `tokenId` from `from` to `to`.\n     *\n     * WARNING: Usage of this method is discouraged, use {safeTransferFrom}\n     * whenever possible.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must be owned by `from`.\n     * - If the caller is not `from`, it must be approved to move this token\n     * by either {approve} or {setApprovalForAll}.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(\n        address from,\n        address to,\n        uint256 tokenId\n    ) external payable;\n\n    /**\n     * @dev Gives permission to `to` to transfer `tokenId` token to another account.\n     * The approval is cleared when the token is transferred.\n     *\n     * Only a single account can be approved at a time, so approving the\n     * zero address clears previous approvals.\n     *\n     * Requirements:\n     *\n     * - The caller must own the token or be an approved operator.\n     * - `tokenId` must exist.\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address to, uint256 tokenId) external payable;\n\n    /**\n     * @dev Approve or remove `operator` as an operator for the caller.\n     * Operators can call {transferFrom} or {safeTransferFrom}\n     * for any token owned by the caller.\n     *\n     * Requirements:\n     *\n     * - The `operator` cannot be the caller.\n     *\n     * Emits an {ApprovalForAll} event.\n     */\n    function setApprovalForAll(address operator, bool _approved) external;\n\n    /**\n     * @dev Returns the account approved for `tokenId` token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function getApproved(uint256 tokenId) external view returns (address operator);\n\n    /**\n     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\n     *\n     * See {setApprovalForAll}.\n     */\n    function isApprovedForAll(address owner, address operator) external view returns (bool);\n\n    // =============================================================\n    //                        IERC721Metadata\n    // =============================================================\n\n    /**\n     * @dev Returns the token collection name.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the token collection symbol.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.\n     */\n    function tokenURI(uint256 tokenId) external view returns (string memory);\n\n    // =============================================================\n    //                           IERC2309\n    // =============================================================\n\n    /**\n     * @dev Emitted when tokens in `fromTokenId` to `toTokenId`\n     * (inclusive) is transferred from `from` to `to`, as defined in the\n     * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309) standard.\n     *\n     * See {_mintERC2309} for more details.\n     */\n    event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to);\n}\n"
      },
      "@openzeppelin/contracts/utils/Context.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n\n    function _contextSuffixLength() internal view virtual returns (uint256) {\n        return 0;\n    }\n}\n"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": false,
        "runs": 200
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      }
    }
  }}