ETH Price: $2,157.27 (-1.65%)

Contract

0xf514A2E88C19f6C4E57ce31cE4de2C2be4556174
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Set Approval For...241194302025-12-29 16:14:5980 days ago1767024899IN
0xf514A2E8...be4556174
0 ETH0.000001310.02828562
Set Approval For...239078402025-11-30 0:16:11110 days ago1764461771IN
0xf514A2E8...be4556174
0 ETH0.000004640.1
Set Approval For...239075692025-11-29 23:21:23110 days ago1764458483IN
0xf514A2E8...be4556174
0 ETH0.000001820.0392554
Set Approval For...234545072025-09-27 13:02:11173 days ago1758978131IN
0xf514A2E8...be4556174
0 ETH0.000032751.33384266
Set Approval For...232499732025-08-29 23:09:35202 days ago1756508975IN
0xf514A2E8...be4556174
0 ETH0.000008270.1780731
Set Approval For...232098562025-08-24 8:48:59207 days ago1756025339IN
0xf514A2E8...be4556174
0 ETH0.000014320.3083408
Set Approval For...231946752025-08-22 5:58:59209 days ago1755842339IN
0xf514A2E8...be4556174
0 ETH0.000099872.14931168
Set Approval For...231349672025-08-13 21:59:23218 days ago1755122363IN
0xf514A2E8...be4556174
0 ETH0.000143573.08972178
Safe Transfer Fr...229038932025-07-12 15:10:35250 days ago1752333035IN
0xf514A2E8...be4556174
0 ETH0.000110261.79132938
Set Approval For...221541862025-03-29 17:55:47355 days ago1743270947IN
0xf514A2E8...be4556174
0 ETH0.000027011.1
Set Approval For...220901222025-03-20 19:19:11364 days ago1742498351IN
0xf514A2E8...be4556174
0 ETH0.000034870.74922145
Set Approval For...219155272025-02-24 10:16:35388 days ago1740392195IN
0xf514A2E8...be4556174
0 ETH0.000051621.11097763
Set Approval For...218624512025-02-17 0:11:47396 days ago1739751107IN
0xf514A2E8...be4556174
0 ETH0.000060071.29289268
Set Approval For...216038112025-01-11 21:05:23432 days ago1736629523IN
0xf514A2E8...be4556174
0 ETH0.000196644.23187784
Set Approval For...216005122025-01-11 10:02:11432 days ago1736589731IN
0xf514A2E8...be4556174
0 ETH0.000059972.44237109
Set Approval For...216004592025-01-11 9:51:35432 days ago1736589095IN
0xf514A2E8...be4556174
0 ETH0.000114622.46685596
Set Approval For...213311502024-12-04 19:13:23470 days ago1733339603IN
0xf514A2E8...be4556174
0 ETH0.0014632531.4326339
Set Approval For...208671492024-10-01 0:46:23535 days ago1727743583IN
0xf514A2E8...be4556174
0 ETH0.000168066.32600542
Set Approval For...208671462024-10-01 0:45:47535 days ago1727743547IN
0xf514A2E8...be4556174
0 ETH0.000291256.26777221
Set Approval For...207687482024-09-17 7:10:23548 days ago1726557023IN
0xf514A2E8...be4556174
0 ETH0.000066082.69115322
Set Approval For...198241202024-05-08 8:21:59680 days ago1715156519IN
0xf514A2E8...be4556174
0 ETH0.000246925.31393227
Set Approval For...197585542024-04-29 4:22:35689 days ago1714364555IN
0xf514A2E8...be4556174
0 ETH0.000257215.53526608
Set Approval For...197444182024-04-27 4:53:47691 days ago1714193627IN
0xf514A2E8...be4556174
0 ETH0.000220524.73727796
Set Approval For...195779582024-04-03 21:34:23715 days ago1712180063IN
0xf514A2E8...be4556174
0 ETH0.001425930.68584768
Safe Transfer Fr...192983862024-02-24 15:37:47754 days ago1708789067IN
0xf514A2E8...be4556174
0 ETH0.0021467132.69036043
View all transactions

Latest 9 internal transactions

Advanced mode:
Parent Transaction Hash Method Block
From
To
Transfer166228312023-02-13 22:30:591130 days ago1676327459
0xf514A2E8...be4556174
9.75 ETH
Transfer166228312023-02-13 22:30:591130 days ago1676327459
0xf514A2E8...be4556174
9.75 ETH
Transfer165872172023-02-08 23:07:591135 days ago1675897679
0xf514A2E8...be4556174
1.3125 ETH
Transfer165872172023-02-08 23:07:591135 days ago1675897679
0xf514A2E8...be4556174
1.3125 ETH
Transfer157966032022-10-21 12:52:231245 days ago1666356743
0xf514A2E8...be4556174
0.85 ETH
Transfer157966032022-10-21 12:52:231245 days ago1666356743
0xf514A2E8...be4556174
0.85 ETH
Transfer157830482022-10-19 15:28:351247 days ago1666193315
0xf514A2E8...be4556174
0.0125 ETH
Transfer157830482022-10-19 15:28:351247 days ago1666193315
0xf514A2E8...be4556174
0.0125 ETH
0x611a1780157827402022-10-19 14:26:351247 days ago1666189595
0xf514A2E8...be4556174
 Contract Creation0 ETH
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
DefaultPunks

Compiler Version
v0.8.15+commit.e14f2714

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0 <0.9.0;
pragma abicoder v2;
import "@openzeppelin/contracts/access/Ownable.sol";
import "../inactive_contracts/lib/ERC721r.sol";
import "solady/src/utils/DynamicBufferLib.sol";
import "solady/src/utils/LibString.sol";
import "solady/src/utils/SafeTransferLib.sol";
import "solady/src/utils/Base64.sol";
import "solady/src/utils/SSTORE2.sol";
import "./utils/DynamicBuffer.sol";


import "hardhat/console.sol";

interface PunkDataInterface {
    function punkImage(uint16 index) external view returns (bytes memory);
}

interface ExtendedPunkDataInterface {
    enum PunkAttributeType {SEX, HAIR, EYES, BEARD, EARS, LIPS, MOUTH,
                                FACE, EMOTION, NECK, NOSE, CHEEKS, TEETH}
    
    enum PunkAttributeValue {NONE, ALIEN, APE, BANDANA, BEANIE, BIG_BEARD, BIG_SHADES, BLACK_LIPSTICK, BLONDE_BOB, BLONDE_SHORT, BLUE_EYE_SHADOW, BUCK_TEETH, CAP, CAP_FORWARD, CHINSTRAP, CHOKER, CIGARETTE, CLASSIC_SHADES, CLOWN_EYES_BLUE, CLOWN_EYES_GREEN, CLOWN_HAIR_GREEN, CLOWN_NOSE, COWBOY_HAT, CRAZY_HAIR, DARK_HAIR, DO_RAG, EARRING, EYE_MASK, EYE_PATCH, FEDORA, FEMALE, FRONT_BEARD, FRONT_BEARD_DARK, FROWN, FRUMPY_HAIR, GOAT, GOLD_CHAIN, GREEN_EYE_SHADOW, HALF_SHAVED, HANDLEBARS, HEADBAND, HOODIE, HORNED_RIM_GLASSES, HOT_LIPSTICK, KNITTED_CAP, LUXURIOUS_BEARD, MALE, MEDICAL_MASK, MESSY_HAIR, MOHAWK, MOHAWK_DARK, MOHAWK_THIN, MOLE, MUSTACHE, MUTTONCHOPS, NERD_GLASSES, NORMAL_BEARD, NORMAL_BEARD_BLACK, ORANGE_SIDE, PEAK_SPIKE, PIGTAILS, PILOT_HELMET, PINK_WITH_HAT, PIPE, POLICE_CAP, PURPLE_EYE_SHADOW, PURPLE_HAIR, PURPLE_LIPSTICK, RED_MOHAWK, REGULAR_SHADES, ROSY_CHEEKS, SHADOW_BEARD, SHAVED_HEAD, SILVER_CHAIN, SMALL_SHADES, SMILE, SPOTS, STRAIGHT_HAIR, STRAIGHT_HAIR_BLONDE, STRAIGHT_HAIR_DARK, STRINGY_HAIR, TASSLE_HAT, THREE_D_GLASSES, TIARA, TOP_HAT, VAMPIRE_HAIR, VAPE, VR, WELDING_GOGGLES, WILD_BLONDE, WILD_HAIR, WILD_WHITE_HAIR, ZOMBIE}
    
    function attrStringToEnumMapping(string memory) external view returns (ExtendedPunkDataInterface.PunkAttributeValue);
    function attrEnumToStringMapping(PunkAttributeValue) external view returns (string memory);
    function attrValueToTypeEnumMapping(PunkAttributeValue) external view returns (ExtendedPunkDataInterface.PunkAttributeType);
}

contract DefaultPunks is Ownable, ERC721r {
    using LibString for *;
    using SafeTransferLib for *;
    using DynamicBufferLib for DynamicBufferLib.DynamicBuffer;
    using DynamicBuffer for bytes;
    
    enum PunkAttributeType {SEX, HAIR, EYES, BEARD, EARS, LIPS, MOUTH,
                                FACE, EMOTION, NECK, NOSE, CHEEKS, TEETH}
    
    enum PunkAttributeValue {NONE, ALIEN, APE, BANDANA, BEANIE, BIG_BEARD, BIG_SHADES, BLACK_LIPSTICK, BLONDE_BOB, BLONDE_SHORT, BLUE_EYE_SHADOW, BUCK_TEETH, CAP, CAP_FORWARD, CHINSTRAP, CHOKER, CIGARETTE, CLASSIC_SHADES, CLOWN_EYES_BLUE, CLOWN_EYES_GREEN, CLOWN_HAIR_GREEN, CLOWN_NOSE, COWBOY_HAT, CRAZY_HAIR, DARK_HAIR, DO_RAG, EARRING, EYE_MASK, EYE_PATCH, FEDORA, FEMALE, FRONT_BEARD, FRONT_BEARD_DARK, FROWN, FRUMPY_HAIR, GOAT, GOLD_CHAIN, GREEN_EYE_SHADOW, HALF_SHAVED, HANDLEBARS, HEADBAND, HOODIE, HORNED_RIM_GLASSES, HOT_LIPSTICK, KNITTED_CAP, LUXURIOUS_BEARD, MALE, MEDICAL_MASK, MESSY_HAIR, MOHAWK, MOHAWK_DARK, MOHAWK_THIN, MOLE, MUSTACHE, MUTTONCHOPS, NERD_GLASSES, NORMAL_BEARD, NORMAL_BEARD_BLACK, ORANGE_SIDE, PEAK_SPIKE, PIGTAILS, PILOT_HELMET, PINK_WITH_HAT, PIPE, POLICE_CAP, PURPLE_EYE_SHADOW, PURPLE_HAIR, PURPLE_LIPSTICK, RED_MOHAWK, REGULAR_SHADES, ROSY_CHEEKS, SHADOW_BEARD, SHAVED_HEAD, SILVER_CHAIN, SMALL_SHADES, SMILE, SPOTS, STRAIGHT_HAIR, STRAIGHT_HAIR_BLONDE, STRAIGHT_HAIR_DARK, STRINGY_HAIR, TASSLE_HAT, THREE_D_GLASSES, TIARA, TOP_HAT, VAMPIRE_HAIR, VAPE, VR, WELDING_GOGGLES, WILD_BLONDE, WILD_HAIR, WILD_WHITE_HAIR, ZOMBIE}
    
    struct DefaultPunk {
        PunkAttributeValue sex;
        PunkAttributeValue hair;
        PunkAttributeValue eyes;
        PunkAttributeValue beard;
        PunkAttributeValue ears;
        PunkAttributeValue lips;
        PunkAttributeValue mouth;
        PunkAttributeValue face;
        PunkAttributeValue emotion;
        PunkAttributeValue neck;
        PunkAttributeValue nose;
        PunkAttributeValue cheeks;
        PunkAttributeValue teeth;
    }
    
    struct ContractConfig {
        bool isMintActive;
        bool contractSealed;
        string name;
        string nameSingular;
        string symbol;
        string externalLink;
        string tokenDescription;
        string baseImageUri;
        uint costPerToken;
        uint64 maxSupply;
    }
    
    ContractConfig public config;
    
    PunkDataInterface public immutable punkDataContract;
    ExtendedPunkDataInterface public immutable extendedPunkDataContract;
    
    function name() public view virtual override returns (string memory) {
        return config.name;
    }

    function symbol() public view virtual override returns (string memory) {
        return config.symbol;
    }
    
    function setContractConfig(ContractConfig calldata _config) external onlyOwner unsealed {
        config = _config;
    }
    
    uint16[954] private defaultPunks;
    
    function setDefaultPunks(uint16[954] calldata _defaultPunks) external onlyOwner unsealed {
        defaultPunks = _defaultPunks;
    }
    
    uint16[954] private defaultPunkCounts;
    
    function setDefaultPunkCounts(uint16[954] calldata _defaultPunkCounts) external onlyOwner unsealed {
        defaultPunkCounts = _defaultPunkCounts;
    }
    
    address private defaultPunkAttributesBytes;
    
    function setDefaultPunkAttributesBytes(bytes calldata _defaultPunkAttributesBytes) external onlyOwner unsealed {
        defaultPunkAttributesBytes = SSTORE2.write(_defaultPunkAttributesBytes);
    }
    
    function defaultAttributesForPunkId(uint16 punkId) public view returns (PunkAttributeValue[] memory) {
        bytes memory arrayAsBytes = SSTORE2.read(defaultPunkAttributesBytes);
        uint maxNumberAttributes = 7;
        uint bytesPerAttribute = 1;
        
        uint startingByteIndex = punkId * maxNumberAttributes * bytesPerAttribute;
        
        PunkAttributeValue[] memory attributes = new PunkAttributeValue[](maxNumberAttributes);
        
        for (uint i; i < maxNumberAttributes; ++i) {
            uint8 attributeValue = uint8(arrayAsBytes[startingByteIndex + i]);
            
            attributes[i] = PunkAttributeValue(attributeValue);
        }
        
        return attributes;
    }
    
    modifier unsealed() {
        require(!config.contractSealed, "Contract sealed.");
        _;
    }
    
    function setTokenDescription(string calldata _tokenDescription) external onlyOwner unsealed {
        config.tokenDescription = _tokenDescription;
    }
    
    function sealContract() external onlyOwner unsealed {
        config.contractSealed = true;
    }
    
    function flipMintState() external onlyOwner {
        config.isMintActive = !config.isMintActive;
    }
    
    constructor(address punkDataContractAddress, address extendedPunkDataContractAddress, ContractConfig memory _config)
        ERC721r("", "", _config.maxSupply) {
        config = _config;
        punkDataContract = PunkDataInterface(punkDataContractAddress);
        extendedPunkDataContract = ExtendedPunkDataInterface(extendedPunkDataContractAddress);
    }
    
    function _internalMint(address toAddress, uint numTokens) private {
        require(msg.value == totalMintCost(numTokens), "Need exact payment");
        require(config.isMintActive, "Mint is not active");
        
        _mintRandom(toAddress, numTokens);
    }
    
    function airdrop(address toAddress, uint numTokens) external payable {
        _internalMint(toAddress, numTokens);
    }
    
    function mintPublic(uint numTokens) external payable {
        _internalMint(msg.sender, numTokens);
    }
    
    function exists(uint tokenId) external view returns (bool) {
        return _exists(tokenId);
    }
    
    function tokenURI(uint256 id) public view override returns (string memory) {
        require(_exists(id), "Token does not exist");

        return constructTokenURI(uint16(id));
    }
    
    function constructTokenURI(uint16 tokenId) private view returns (string memory) {
        bytes memory title = abi.encodePacked(config.nameSingular, " #", tokenId.toString());
        string memory html = tokenHTMLPage(tokenId);
        string memory b64Html = Base64.encode(bytes(html));

        bytes memory imageUri = abi.encodePacked(config.baseImageUri, tokenId.toString(), ".png");

        return
            string(
                abi.encodePacked(
                    "data:application/json;base64,",
                    Base64.encode(
                        bytes(
                            abi.encodePacked(
                                '{',
                                '"name":"', title, '",'
                                '"description":"', config.tokenDescription.escapeJSON(), '",'
                                '"image":"', imageUri,'",'
                                '"external_url":"', config.externalLink, '",'
                                '"html":"data:text/html;charset=utf-8;base64,', b64Html, '",'
                                '"attributes": ',
                                    punkAttributesAsJSON(tokenId),
                                '}'
                            )
                        )
                    )
                )
            );
    }
    
    bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
    
    function tokenImage(uint16 tokenId) public view returns (string memory) {
        uint16 punkId = defaultPunks[tokenId];
        bytes memory pixels = punkDataContract.punkImage(punkId);
        DynamicBufferLib.DynamicBuffer memory svgBytes;
        
        svgBytes.append('<svg width="1200" height="1200" shape-rendering="crispEdges" xmlns="http://www.w3.org/2000/svg" version="1.2" viewBox="0 0 24 24"><style>rect{width:1px;height:1px}</style>');
        
        svgBytes.append('<g><rect x="0" y="0" style="width:100%;height:100%" fill="#d6dde4" />');
        
        bytes memory buffer = new bytes(8);
        for (uint256 y = 0; y < 24; y++) {
            for (uint256 x = 0; x < 24; x++) {
                uint256 p = (y * 24 + x) * 4;
                if (uint8(pixels[p + 3]) > 0) {
                    for (uint256 i = 0; i < 4; i++) {
                        uint8 value = uint8(pixels[p + i]);
                        
                        buffer[i * 2 + 1] = _HEX_SYMBOLS[value & 0xf];
                        value >>= 4;
                        buffer[i * 2] = _HEX_SYMBOLS[value & 0xf];
                    }
                    
                    string memory oldColor = string(buffer);
                    string memory newColor;
                    
                    if (oldColor.endsWith("00")) {
                        newColor = "d6dde4";
                    } else {
                        newColor = "788a97";
                    }
                    
                    svgBytes.append(
                        abi.encodePacked(
                            '<rect x="',
                            x.toString(),
                            '" y="',
                            y.toString(),
                            '" fill="#',
                            newColor,
                            '"/>'
                        )
                    );
                }
            }
        }
        
        svgBytes.append('</g>');
        svgBytes.append('</svg>');
        return string(svgBytes.data);
    }
    
    function tokenHTMLPage(uint16 tokenId) public view returns (string memory) {
        bytes memory HTMLBytes = DynamicBuffer.allocate(1024 * 128);
    
        string memory image = tokenImage(tokenId);
        
        HTMLBytes.appendSafe('<!DOCTYPE html><html lang="en">');
        HTMLBytes.appendSafe(abi.encodePacked('<body><style>*{box-sizing:border-box;margin:0;padding:0;border:0;transform-origin: center} svg{background:#638596;left: 50%;top: 50%;transform: translate(-50%, -50%);position: fixed;aspect-ratio: 1 / 1;max-width: 100vmin;max-height: 100vmin;width: 100%; height: 100%;}</style>'));
        
        HTMLBytes.appendSafe(bytes(image));
        
        HTMLBytes.appendSafe('</body></html>');

        return string(HTMLBytes);
    }
    
    address constant pivAddress = 0xf98537696e2Cf486F8F32604B2Ca2CDa120DBBa8;
    address constant middleAddress = 0xC2172a6315c1D7f6855768F843c420EbB36eDa97;
    
    function withdraw() external {
        require(address(this).balance > 0, "Nothing to withdraw");
        
        uint total = address(this).balance;
        uint half = total / 2;
        
        Address.sendValue(payable(middleAddress), half);
        Address.sendValue(payable(pivAddress), total - half);
    }
    
    function totalMintCost(uint numTokens) public view returns (uint) {
        return numTokens * config.costPerToken;
    }
    
    function initializePunkWithPunkAttributeValueArray(uint16 tokenId) private view returns (DefaultPunk memory) {
        PunkAttributeValue[] memory punkAttributes = defaultAttributesForPunkId(tokenId);
        DefaultPunk memory punk = DefaultPunk({
            sex: PunkAttributeValue.NONE,
            hair: PunkAttributeValue.NONE,
            eyes: PunkAttributeValue.NONE,
            beard: PunkAttributeValue.NONE,
            ears: PunkAttributeValue.NONE,
            lips: PunkAttributeValue.NONE,
            mouth: PunkAttributeValue.NONE,
            face: PunkAttributeValue.NONE,
            emotion: PunkAttributeValue.NONE,
            neck: PunkAttributeValue.NONE,
            nose: PunkAttributeValue.NONE,
            cheeks: PunkAttributeValue.NONE,
            teeth: PunkAttributeValue.NONE
        });
        
        for (uint i = 0; i < punkAttributes.length; i++) {
            PunkAttributeValue attrValue = punkAttributes[i];
            PunkAttributeType attrType = PunkAttributeType(uint(extendedPunkDataContract.attrValueToTypeEnumMapping(ExtendedPunkDataInterface.PunkAttributeValue(uint(attrValue)))));
            
            if (attrValue == PunkAttributeValue.NONE) {
                continue;
            }
            
            if (attrType == PunkAttributeType.SEX) {
                punk.sex = attrValue;
            } else if (attrType == PunkAttributeType.HAIR) {
                punk.hair = attrValue;
            } else if (attrType == PunkAttributeType.EYES) {
                punk.eyes = attrValue;
            } else if (attrType == PunkAttributeType.BEARD) {
                punk.beard = attrValue;
            } else if (attrType == PunkAttributeType.EARS) {
                punk.ears = attrValue;
            } else if (attrType == PunkAttributeType.LIPS) {
                punk.lips = attrValue;
            } else if (attrType == PunkAttributeType.MOUTH) {
                punk.mouth = attrValue;
            } else if (attrType == PunkAttributeType.FACE) {
                punk.face = attrValue;
            } else if (attrType == PunkAttributeType.EMOTION) {
                punk.emotion = attrValue;
            } else if (attrType == PunkAttributeType.NECK) {
                punk.neck = attrValue;
            } else if (attrType == PunkAttributeType.NOSE) {
                punk.nose = attrValue;
            } else if (attrType == PunkAttributeType.CHEEKS) {
                punk.cheeks = attrValue;
            } else if (attrType == PunkAttributeType.TEETH) {
                punk.teeth = attrValue;
            }
        }
        
        return punk;
    }
    
    function punkAttributeCount(DefaultPunk memory phunk) internal pure returns (uint totalCount) {
        PunkAttributeValue[13] memory attrArray = [
            phunk.sex,
            phunk.hair,
            phunk.eyes,
            phunk.beard,
            phunk.ears,
            phunk.lips,
            phunk.mouth,
            phunk.face,
            phunk.emotion,
            phunk.neck,
            phunk.nose,
            phunk.cheeks,
            phunk.teeth
        ];
        
        for (uint i = 0; i < 13; ++i) {
            if (attrArray[i] != PunkAttributeValue.NONE) {
                totalCount++;
            }
        }
    }
    
    function punkAttributesAsJSON(uint16 tokenId) public view returns (string memory json) {
        DefaultPunk memory phunk = initializePunkWithPunkAttributeValueArray(tokenId);
        
        PunkAttributeValue none = PunkAttributeValue.NONE;
        
        bytes memory outputBytes = DynamicBuffer.allocate(1024 * 64);

        outputBytes.appendSafe("[");
        
        PunkAttributeValue[13] memory attrArray = [
            phunk.sex,
            phunk.hair,
            phunk.eyes,
            phunk.beard,
            phunk.ears,
            phunk.lips,
            phunk.mouth,
            phunk.face,
            phunk.emotion,
            phunk.neck,
            phunk.nose,
            phunk.cheeks,
            phunk.teeth
        ];
        
        uint attrCount = punkAttributeCount(phunk);
        uint attrsCounted;
        
        outputBytes.appendSafe(abi.encodePacked(
            '{"trait_type":"CryptoPunks With Matching Silhouette", "display_type": "number", "max_value": 496, "value":', defaultPunkCounts[tokenId].toString(), '},'
        ));
        
        if (defaultPunkCounts[tokenId] == 1) {
            outputBytes.appendSafe(abi.encodePacked(
                '{"trait_type":"Unique Silhouette", "value": "Yes"},'
            ));
        }
        
        for (uint i; i < 13; ++i) {
            PunkAttributeValue attrVal = attrArray[i];
            
            if (attrVal != none) {
                attrsCounted++;
                outputBytes.appendSafe(bytes(punkAttributeAsJSON(attrVal)));
                
                if (attrsCounted < attrCount) {
                    outputBytes.appendSafe(",");
                }
            }
        }
        
        return string(abi.encodePacked(outputBytes, "]"));
    }
    
    function punkAttributeAsJSON(PunkAttributeValue attribute) internal view returns (string memory json) {
        require(attribute != PunkAttributeValue.NONE);
        
        string memory attributeAsString = extendedPunkDataContract.attrEnumToStringMapping(ExtendedPunkDataInterface.PunkAttributeValue(uint(attribute)));
        string memory attributeTypeAsString;
        
        PunkAttributeType attrType = PunkAttributeType(
            uint(
                extendedPunkDataContract.attrValueToTypeEnumMapping(
                    ExtendedPunkDataInterface.PunkAttributeValue(
                        uint(
                            attribute
                        )))));

        
        if (attrType == PunkAttributeType.SEX) {
            attributeTypeAsString = "Sex";
        } else if (attrType == PunkAttributeType.HAIR) {
            attributeTypeAsString = "Hair";
        } else if (attrType == PunkAttributeType.EYES) {
            attributeTypeAsString = "Eyes";
        } else if (attrType == PunkAttributeType.BEARD) {
            attributeTypeAsString = "Beard";
        } else if (attrType == PunkAttributeType.EARS) {
            attributeTypeAsString = "Ears";
        } else if (attrType == PunkAttributeType.LIPS) {
            attributeTypeAsString = "Lips";
        } else if (attrType == PunkAttributeType.MOUTH) {
            attributeTypeAsString = "Mouth";
        } else if (attrType == PunkAttributeType.FACE) {
            attributeTypeAsString = "Face";
        } else if (attrType == PunkAttributeType.EMOTION) {
            attributeTypeAsString = "Emotion";
        } else if (attrType == PunkAttributeType.NECK) {
            attributeTypeAsString = "Neck";
        } else if (attrType == PunkAttributeType.NOSE) {
            attributeTypeAsString = "Nose";
        } else if (attrType == PunkAttributeType.CHEEKS) {
            attributeTypeAsString = "Cheeks";
        } else if (attrType == PunkAttributeType.TEETH) {
            attributeTypeAsString = "Teeth";
        }
        
        return string(abi.encodePacked('{"trait_type":"', attributeTypeAsString, '", "value":"', attributeAsString, '"}'));
    }
    
    function walletOfOwner(address _owner)
        external
        view
        returns (uint16[] memory)
    {
        uint ownerTokenCount = balanceOf(_owner);
        uint16[] memory ownedTokenIds = new uint16[](ownerTokenCount);
        uint currentTokenId = 0;
        uint ownedTokenIndex = 0;

        while (ownedTokenIndex < ownerTokenCount && currentTokenId < maxSupply()) {
            address currentTokenOwner = _exists(currentTokenId) ? ownerOf(currentTokenId) : address(0);

            if (currentTokenOwner == _owner) {
                ownedTokenIds[ownedTokenIndex] = uint16(currentTokenId);

                ownedTokenIndex++;
            }

            currentTokenId++;
        }

        return ownedTokenIds;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/utils/introspection/ERC165.sol";

/**
 * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
 * the Metadata extension, but not including the Enumerable extension. This does random batch minting.
 */
contract ERC721r is Context, ERC165, IERC721, IERC721Metadata {
    using Address for address;
    using Strings for uint256;

    // Token name
    string private _name;

    // Token symbol
    string private _symbol;
    
    mapping(uint => uint) private _availableTokens;
    uint256 private _numAvailableTokens;
    uint256 immutable _maxSupply;
    // Mapping from token ID to owner address
    mapping(uint256 => address) private _owners;

    // Mapping owner address to token count
    mapping(address => uint256) private _balances;

    // Mapping from token ID to approved address
    mapping(uint256 => address) private _tokenApprovals;

    // Mapping from owner to operator approvals
    mapping(address => mapping(address => bool)) private _operatorApprovals;

    /**
     * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
     */
    constructor(string memory name_, string memory symbol_, uint maxSupply_) {
        _name = name_;
        _symbol = symbol_;
        _maxSupply = maxSupply_;
        _numAvailableTokens = maxSupply_;
    }
    
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
        return
            interfaceId == type(IERC721).interfaceId ||
            interfaceId == type(IERC721Metadata).interfaceId ||
            super.supportsInterface(interfaceId);
    }
    
    function totalSupply() public view virtual returns (uint256) {
        return _maxSupply - _numAvailableTokens;
    }
    
    function maxSupply() public view virtual returns (uint256) {
        return _maxSupply;
    }

    /**
     * @dev See {IERC721-balanceOf}.
     */
    function balanceOf(address owner) public view virtual override returns (uint256) {
        require(owner != address(0), "ERC721: balance query for the zero address");
        return _balances[owner];
    }

    /**
     * @dev See {IERC721-ownerOf}.
     */
    function ownerOf(uint256 tokenId) public view virtual override returns (address) {
        address owner = _owners[tokenId];
        require(owner != address(0), "ERC721: owner query for nonexistent token");
        return owner;
    }

    /**
     * @dev See {IERC721Metadata-name}.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev See {IERC721Metadata-symbol}.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev See {IERC721Metadata-tokenURI}.
     */
    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");

        string memory baseURI = _baseURI();
        return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
    }

    /**
     * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
     * token will be the concatenation of the `baseURI` and the `tokenId`. Empty
     * by default, can be overridden in child contracts.
     */
    function _baseURI() internal view virtual returns (string memory) {
        return "";
    }

    /**
     * @dev See {IERC721-approve}.
     */
    function approve(address to, uint256 tokenId) public virtual override {
        address owner = ERC721r.ownerOf(tokenId);
        require(to != owner, "ERC721: approval to current owner");

        require(
            _msgSender() == owner || isApprovedForAll(owner, _msgSender()),
            "ERC721: approve caller is not owner nor approved for all"
        );

        _approve(to, tokenId);
    }

    /**
     * @dev See {IERC721-getApproved}.
     */
    function getApproved(uint256 tokenId) public view virtual override returns (address) {
        require(_exists(tokenId), "ERC721: approved query for nonexistent token");

        return _tokenApprovals[tokenId];
    }

    /**
     * @dev See {IERC721-setApprovalForAll}.
     */
    function setApprovalForAll(address operator, bool approved) public virtual override {
        _setApprovalForAll(_msgSender(), operator, approved);
    }

    /**
     * @dev See {IERC721-isApprovedForAll}.
     */
    function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
        return _operatorApprovals[owner][operator];
    }

    /**
     * @dev See {IERC721-transferFrom}.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {
        //solhint-disable-next-line max-line-length
        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");

        _transfer(from, to, tokenId);
    }

    /**
     * @dev See {IERC721-safeTransferFrom}.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {
        safeTransferFrom(from, to, tokenId, "");
    }

    /**
     * @dev See {IERC721-safeTransferFrom}.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes memory _data
    ) public virtual override {
        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
        _safeTransfer(from, to, tokenId, _data);
    }

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * `_data` is additional data, it has no specified format and it is sent in call to `to`.
     *
     * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
     * implement alternative mechanisms to perform token transfer, such as signature-based.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function _safeTransfer(
        address from,
        address to,
        uint256 tokenId,
        bytes memory _data
    ) internal virtual {
        _transfer(from, to, tokenId);
        require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
    }

    /**
     * @dev Returns whether `tokenId` exists.
     *
     * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
     *
     * Tokens start existing when they are minted (`_mint`),
     * and stop existing when they are burned (`_burn`).
     */
    function _exists(uint256 tokenId) internal view virtual returns (bool) {
        return _owners[tokenId] != address(0);
    }

    /**
     * @dev Returns whether `spender` is allowed to manage `tokenId`.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
        require(_exists(tokenId), "ERC721: operator query for nonexistent token");
        address owner = ERC721r.ownerOf(tokenId);
        return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
    }

    function _mintIdWithoutBalanceUpdate(address to, uint256 tokenId) private {
        _beforeTokenTransfer(address(0), to, tokenId);
        
        _owners[tokenId] = to;
        
        emit Transfer(address(0), to, tokenId);
        
        _afterTokenTransfer(address(0), to, tokenId);
    }

    function _mintRandom(address to, uint _numToMint) internal virtual {
        require(_msgSender() == tx.origin, "Contracts cannot mint");
        require(to != address(0), "ERC721: mint to the zero address");
        require(_numToMint > 0, "ERC721r: need to mint at least one token");
        
        // TODO: Probably don't need this as it will underflow and revert automatically in this case
        require(_numAvailableTokens >= _numToMint, "ERC721r: minting more tokens than available");
        
        uint updatedNumAvailableTokens = _numAvailableTokens;
        for (uint256 i; i < _numToMint; ++i) { // Do this ++ unchecked?
            uint256 tokenId = getRandomAvailableTokenId(to, updatedNumAvailableTokens);
            
            _mintIdWithoutBalanceUpdate(to, tokenId);
            
            --updatedNumAvailableTokens;
        }
        
        _numAvailableTokens = updatedNumAvailableTokens;
        _balances[to] += _numToMint;
    }
        
    function getRandomAvailableTokenId(address to, uint updatedNumAvailableTokens)
        internal
        returns (uint256)
    {
        uint256 randomNum = uint256(
            keccak256(
                abi.encode(
                    to,
                    tx.gasprice,
                    block.number,
                    block.timestamp,
                    block.difficulty,
                    blockhash(block.number - 1),
                    address(this),
                    updatedNumAvailableTokens
                )
            )
        );
        uint256 randomIndex = randomNum % updatedNumAvailableTokens;
        return getAvailableTokenAtIndex(randomIndex, updatedNumAvailableTokens);
    }

    // Implements https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle. Code taken from CryptoPhunksV2
    function getAvailableTokenAtIndex(uint256 indexToUse, uint updatedNumAvailableTokens)
        internal
        returns (uint256)
    {
        uint256 valAtIndex = _availableTokens[indexToUse];
        uint256 result;
        if (valAtIndex == 0) {
            // This means the index itself is still an available token
            result = indexToUse;
        } else {
            // This means the index itself is not an available token, but the val at that index is.
            result = valAtIndex;
        }

        uint256 lastIndex = updatedNumAvailableTokens - 1;
        if (indexToUse != lastIndex) {
            // Replace the value at indexToUse, now that it's been used.
            // Replace it with the data from the last index in the array, since we are going to decrease the array size afterwards.
            uint256 lastValInArray = _availableTokens[lastIndex];
            if (lastValInArray == 0) {
                // This means the index itself is still an available token
                _availableTokens[indexToUse] = lastIndex;
            } else {
                // This means the index itself is not an available token, but the val at that index is.
                _availableTokens[indexToUse] = lastValInArray;
                // Gas refund courtsey of @dievardump
                delete _availableTokens[lastIndex];
            }
        }
        
        return result;
    }
    
    // Not as good as minting a specific tokenId, but will behave the same at the start
    // allowing you to explicitly mint some tokens at launch.
    function _mintAtIndex(address to, uint index) internal virtual {
        require(_msgSender() == tx.origin, "Contracts cannot mint");
        require(to != address(0), "ERC721: mint to the zero address");
        require(_numAvailableTokens >= 1, "ERC721r: minting more tokens than available");
        
        uint tokenId = getAvailableTokenAtIndex(index, _numAvailableTokens);
        --_numAvailableTokens;
        
        _mintIdWithoutBalanceUpdate(to, tokenId);
        
        _balances[to] += 1;
    }

    /**
     * @dev Transfers `tokenId` from `from` to `to`.
     *  As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     *
     * Emits a {Transfer} event.
     */
    function _transfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual {
        require(ERC721r.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner");
        require(to != address(0), "ERC721: transfer to the zero address");

        _beforeTokenTransfer(from, to, tokenId);

        // Clear approvals from the previous owner
        _approve(address(0), tokenId);

        _balances[from] -= 1;
        _balances[to] += 1;
        _owners[tokenId] = to;

        emit Transfer(from, to, tokenId);

        _afterTokenTransfer(from, to, tokenId);
    }

    /**
     * @dev Approve `to` to operate on `tokenId`
     *
     * Emits a {Approval} event.
     */
    function _approve(address to, uint256 tokenId) internal virtual {
        _tokenApprovals[tokenId] = to;
        emit Approval(ERC721r.ownerOf(tokenId), to, tokenId);
    }

    /**
     * @dev Approve `operator` to operate on all of `owner` tokens
     *
     * Emits a {ApprovalForAll} event.
     */
    function _setApprovalForAll(
        address owner,
        address operator,
        bool approved
    ) internal virtual {
        require(owner != operator, "ERC721: approve to caller");
        _operatorApprovals[owner][operator] = approved;
        emit ApprovalForAll(owner, operator, approved);
    }

    /**
     * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
     * The call is not executed if the target address is not a contract.
     *
     * @param from address representing the previous owner of the given token ID
     * @param to target address that will receive the tokens
     * @param tokenId uint256 ID of the token to be transferred
     * @param _data bytes optional data to send along with the call
     * @return bool whether the call correctly returned the expected magic value
     */
    function _checkOnERC721Received(
        address from,
        address to,
        uint256 tokenId,
        bytes memory _data
    ) private returns (bool) {
        if (to.isContract()) {
            try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) {
                return retval == IERC721Receiver.onERC721Received.selector;
            } catch (bytes memory reason) {
                if (reason.length == 0) {
                    revert("ERC721: transfer to non ERC721Receiver implementer");
                } else {
                    assembly {
                        revert(add(32, reason), mload(reason))
                    }
                }
            }
        } else {
            return true;
        }
    }

    /**
     * @dev Hook that is called before any token transfer. This includes minting
     * and burning.
     *
     * Calling conditions:
     *
     * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be
     * transferred to `to`.
     * - When `from` is zero, `tokenId` will be minted for `to`.
     * - When `to` is zero, ``from``'s `tokenId` will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual {}

    /**
     * @dev Hook that is called after any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _afterTokenTransfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual {}
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Library for dynamic buffers
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/DynamicBuffer.sol)
/// @author Modified from cozyco (https://github.com/samkingco/cozyco/blob/main/contracts/utils/DynamicBuffer.sol)
library DynamicBufferLib {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                          STRUCTS                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Type to represent a dynamic buffer in memory.
    /// You can directly assign to `data`, and the `append` function will
    /// take care of the memory allocation.
    struct DynamicBuffer {
        bytes data;
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         OPERATIONS                         */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Appends `data` to `buffer`.
    function append(DynamicBuffer memory buffer, bytes memory data) internal pure {
        assembly {
            if mload(data) {
                let bufferData := mload(buffer)
                let bufferDataLength := mload(bufferData)
                let newBufferDataLength := add(mload(data), bufferDataLength)
                // Some random prime number to multiply `capacity`, so that
                // we know that the `capacity` is for a dynamic buffer.
                // Selected to be larger than any memory pointer realistically.
                let prime := 1621250193422201
                let capacity := mload(sub(bufferData, 0x20))

                // Extract `capacity`, and set it to 0
                // if it is not a multiple of `prime`.
                capacity := mul(div(capacity, prime), iszero(mod(capacity, prime)))

                // Expand / Reallocate memory if required.
                // prettier-ignore
                for {} iszero(lt(newBufferDataLength, capacity)) {} {
                    // Approximately double the memory with a heuristic,
                    // ensuring more than enough space for the combined data,
                    // rounding up to the next multiple of 32.
                    let newCapacity := and(add(capacity, add(or(capacity, newBufferDataLength), 32)), not(31))

                    // If next slot after current buffer is not eligible for use.
                    if iszero(eq(mload(0x40), add(bufferData, add(0x40, capacity)))) {
                        // Set the `newBufferData` to point to the slot after capacity.
                        let newBufferData := add(mload(0x40), 0x20)
                        // Reallocate the memory.
                        mstore(0x40, add(newBufferData, add(0x40, newCapacity)))
                        // Store the `newBufferData`.
                        mstore(buffer, newBufferData)
                        // Copy `bufferData` one word at a time, backwards.
                        // prettier-ignore
                        for { let o := and(add(bufferDataLength, 32), not(31)) } 1 {} {
                            mstore(add(newBufferData, o), mload(add(bufferData, o)))
                            o := sub(o, 0x20)
                            // prettier-ignore
                            if iszero(o) { break }
                        }
                        // Store the `capacity` multiplied by `prime` in the slot before the `length`.
                        mstore(sub(newBufferData, 0x20), mul(prime, newCapacity))
                        // Assign `newBufferData` to `bufferData`.
                        bufferData := newBufferData
                        break
                    }
                    // Expand the memory.
                    mstore(0x40, add(bufferData, add(0x40, newCapacity)))
                    // Store the `capacity` multiplied by `prime` in the slot before the `length`.
                    mstore(sub(bufferData, 0x20), mul(prime, newCapacity))
                    break
                }
                // Initalize `output` to the next empty position in `bufferData`.
                let output := add(bufferData, bufferDataLength)
                // Copy `data` one word at a time, backwards.
                // prettier-ignore
                for { let o := and(add(mload(data), 32), not(31)) } 1 {} {
                    mstore(add(output, o), mload(add(data, o)))
                    o := sub(o, 0x20)
                    // prettier-ignore
                    if iszero(o) { break }
                }
                // Zeroize the slot after the buffer.
                mstore(add(add(bufferData, 0x20), newBufferDataLength), 0)
                // Store the `newBufferDataLength`.
                mstore(bufferData, newBufferDataLength)
            }
        }
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Library for converting numbers into strings and other string operations.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol)
library LibString {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                        CUSTOM ERRORS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The `length` of the output is too small to contain all the hex digits.
    error HexLengthInsufficient();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The constant returned when the `search` is not found in the string.
    uint256 internal constant NOT_FOUND = uint256(int256(-1));

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     DECIMAL OPERATIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the base 10 decimal representation of `value`.
    function toString(uint256 value) internal pure returns (string memory str) {
        assembly {
            // The maximum value of a uint256 contains 78 digits (1 byte per digit), but
            // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.
            // We will need 1 word for the trailing zeros padding, 1 word for the length,
            // and 3 words for a maximum of 78 digits. Total: 5 * 0x20 = 0xa0.
            let m := add(mload(0x40), 0xa0)
            // Update the free memory pointer to allocate.
            mstore(0x40, m)
            // Assign the `str` to the end.
            str := sub(m, 0x20)
            // Zeroize the slot after the string.
            mstore(str, 0)

            // Cache the end of the memory to calculate the length later.
            let end := str

            // We write the string from rightmost digit to leftmost digit.
            // The following is essentially a do-while loop that also handles the zero case.
            // prettier-ignore
            for { let temp := value } 1 {} {
                str := sub(str, 1)
                // Write the character to the pointer.
                // The ASCII index of the '0' character is 48.
                mstore8(str, add(48, mod(temp, 10)))
                // Keep dividing `temp` until zero.
                temp := div(temp, 10)
                // prettier-ignore
                if iszero(temp) { break }
            }

            let length := sub(end, str)
            // Move the pointer 32 bytes leftwards to make room for the length.
            str := sub(str, 0x20)
            // Store the length.
            mstore(str, length)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   HEXADECIMAL OPERATIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the hexadecimal representation of `value`,
    /// left-padded to an input length of `length` bytes.
    /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte,
    /// giving a total length of `length * 2 + 2` bytes.
    /// Reverts if `length` is too small for the output to contain all the digits.
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory str) {
        assembly {
            let start := mload(0x40)
            // We need 0x20 bytes for the trailing zeros padding, `length * 2` bytes
            // for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length.
            // We add 0x20 to the total and round down to a multiple of 0x20.
            // (0x20 + 0x20 + 0x02 + 0x20) = 0x62.
            let m := add(start, and(add(shl(1, length), 0x62), not(0x1f)))
            // Allocate the memory.
            mstore(0x40, m)
            // Assign the `str` to the end.
            str := sub(m, 0x20)
            // Zeroize the slot after the string.
            mstore(str, 0)

            // Cache the end to calculate the length later.
            let end := str
            // Store "0123456789abcdef" in scratch space.
            mstore(0x0f, 0x30313233343536373839616263646566)

            let temp := value
            // We write the string from rightmost digit to leftmost digit.
            // The following is essentially a do-while loop that also handles the zero case.
            // prettier-ignore
            for {} 1 {} {
                str := sub(str, 2)
                mstore8(add(str, 1), mload(and(temp, 15)))
                mstore8(str, mload(and(shr(4, temp), 15)))
                temp := shr(8, temp)
                length := sub(length, 1)
                // prettier-ignore
                if iszero(length) { break }
            }

            if temp {
                // Store the function selector of `HexLengthInsufficient()`.
                mstore(0x00, 0x2194895a)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }

            // Compute the string's length.
            let strLength := add(sub(end, str), 2)
            // Move the pointer and write the "0x" prefix.
            str := sub(str, 0x20)
            mstore(str, 0x3078)
            // Move the pointer and write the length.
            str := sub(str, 2)
            mstore(str, strLength)
        }
    }

    /// @dev Returns the hexadecimal representation of `value`.
    /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte.
    /// As address are 20 bytes long, the output will left-padded to have
    /// a length of `20 * 2 + 2` bytes.
    function toHexString(uint256 value) internal pure returns (string memory str) {
        assembly {
            let start := mload(0x40)
            // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,
            // 0x02 bytes for the prefix, and 0x40 bytes for the digits.
            // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0.
            let m := add(start, 0xa0)
            // Allocate the memory.
            mstore(0x40, m)
            // Assign the `str` to the end.
            str := sub(m, 0x20)
            // Zeroize the slot after the string.
            mstore(str, 0)

            // Cache the end to calculate the length later.
            let end := str
            // Store "0123456789abcdef" in scratch space.
            mstore(0x0f, 0x30313233343536373839616263646566)

            // We write the string from rightmost digit to leftmost digit.
            // The following is essentially a do-while loop that also handles the zero case.
            // prettier-ignore
            for { let temp := value } 1 {} {
                str := sub(str, 2)
                mstore8(add(str, 1), mload(and(temp, 15)))
                mstore8(str, mload(and(shr(4, temp), 15)))
                temp := shr(8, temp)
                // prettier-ignore
                if iszero(temp) { break }
            }

            // Compute the string's length.
            let strLength := add(sub(end, str), 2)
            // Move the pointer and write the "0x" prefix.
            str := sub(str, 0x20)
            mstore(str, 0x3078)
            // Move the pointer and write the length.
            str := sub(str, 2)
            mstore(str, strLength)
        }
    }

    /// @dev Returns the hexadecimal representation of `value`.
    /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte.
    function toHexString(address value) internal pure returns (string memory str) {
        assembly {
            let start := mload(0x40)
            // We need 0x20 bytes for the length, 0x02 bytes for the prefix,
            // and 0x28 bytes for the digits.
            // The next multiple of 0x20 above (0x20 + 0x02 + 0x28) is 0x60.
            str := add(start, 0x60)

            // Allocate the memory.
            mstore(0x40, str)
            // Store "0123456789abcdef" in scratch space.
            mstore(0x0f, 0x30313233343536373839616263646566)

            let length := 20
            // We write the string from rightmost digit to leftmost digit.
            // The following is essentially a do-while loop that also handles the zero case.
            // prettier-ignore
            for { let temp := value } 1 {} {
                str := sub(str, 2)
                mstore8(add(str, 1), mload(and(temp, 15)))
                mstore8(str, mload(and(shr(4, temp), 15)))
                temp := shr(8, temp)
                length := sub(length, 1)
                // prettier-ignore
                if iszero(length) { break }
            }

            // Move the pointer and write the "0x" prefix.
            str := sub(str, 32)
            mstore(str, 0x3078)
            // Move the pointer and write the length.
            str := sub(str, 2)
            mstore(str, 42)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   OTHER STRING OPERATIONS                  */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // For performance and bytecode compactness, all indices of the following operations
    // are byte (ASCII) offsets, not UTF character offsets.

    /// @dev Returns `subject` all occurrences of `search` replaced with `replacement`.
    function replace(
        string memory subject,
        string memory search,
        string memory replacement
    ) internal pure returns (string memory result) {
        assembly {
            let subjectLength := mload(subject)
            let searchLength := mload(search)
            let replacementLength := mload(replacement)

            subject := add(subject, 0x20)
            search := add(search, 0x20)
            replacement := add(replacement, 0x20)
            result := add(mload(0x40), 0x20)

            let subjectEnd := add(subject, subjectLength)
            if iszero(gt(searchLength, subjectLength)) {
                let subjectSearchEnd := add(sub(subjectEnd, searchLength), 1)
                let h := 0
                if iszero(lt(searchLength, 32)) {
                    h := keccak256(search, searchLength)
                }
                let m := shl(3, sub(32, and(searchLength, 31)))
                let s := mload(search)
                // prettier-ignore
                for {} 1 {} {
                    let t := mload(subject)
                    // Whether the first `searchLength % 32` bytes of 
                    // `subject` and `search` matches.
                    if iszero(shr(m, xor(t, s))) {
                        if h {
                            if iszero(eq(keccak256(subject, searchLength), h)) {
                                mstore(result, t)
                                result := add(result, 1)
                                subject := add(subject, 1)
                                // prettier-ignore
                                if iszero(lt(subject, subjectSearchEnd)) { break }
                                continue
                            }
                        }
                        // Copy the `replacement` one word at a time.
                        // prettier-ignore
                        for { let o := 0 } 1 {} {
                            mstore(add(result, o), mload(add(replacement, o)))
                            o := add(o, 0x20)
                            // prettier-ignore
                            if iszero(lt(o, replacementLength)) { break }
                        }
                        result := add(result, replacementLength)
                        subject := add(subject, searchLength)
                        if searchLength {
                            // prettier-ignore
                            if iszero(lt(subject, subjectSearchEnd)) { break }
                            continue
                        }
                    }
                    mstore(result, t)
                    result := add(result, 1)
                    subject := add(subject, 1)
                    // prettier-ignore
                    if iszero(lt(subject, subjectSearchEnd)) { break }
                }
            }

            let resultRemainder := result
            result := add(mload(0x40), 0x20)
            let k := add(sub(resultRemainder, result), sub(subjectEnd, subject))
            // Copy the rest of the string one word at a time.
            // prettier-ignore
            for {} lt(subject, subjectEnd) {} {
                mstore(resultRemainder, mload(subject))
                resultRemainder := add(resultRemainder, 0x20)
                subject := add(subject, 0x20)
            }
            result := sub(result, 0x20)
            // Zeroize the slot after the string.
            let last := add(add(result, 0x20), k)
            mstore(last, 0)
            // Allocate memory for the length and the bytes,
            // rounded up to a multiple of 32.
            mstore(0x40, and(add(last, 31), not(31)))
            // Store the length of the result.
            mstore(result, k)
        }
    }

    /// @dev Returns the byte index of the first location of `search` in `subject`,
    /// searching from left to right, starting from `from`.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
    function indexOf(
        string memory subject,
        string memory search,
        uint256 from
    ) internal pure returns (uint256 result) {
        assembly {
            // prettier-ignore
            for { let subjectLength := mload(subject) } 1 {} {
                if iszero(mload(search)) {
                    // `result = min(from, subjectLength)`.
                    result := xor(from, mul(xor(from, subjectLength), lt(subjectLength, from)))
                    break
                }
                let searchLength := mload(search)
                let subjectStart := add(subject, 0x20)    
                
                result := not(0) // Initialize to `NOT_FOUND`.

                subject := add(subjectStart, from)
                let subjectSearchEnd := add(sub(add(subjectStart, subjectLength), searchLength), 1)

                let m := shl(3, sub(32, and(searchLength, 31)))
                let s := mload(add(search, 0x20))

                // prettier-ignore
                if iszero(lt(subject, subjectSearchEnd)) { break }

                if iszero(lt(searchLength, 32)) {
                    // prettier-ignore
                    for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} {
                        if iszero(shr(m, xor(mload(subject), s))) {
                            if eq(keccak256(subject, searchLength), h) {
                                result := sub(subject, subjectStart)
                                break
                            }
                        }
                        subject := add(subject, 1)
                        // prettier-ignore
                        if iszero(lt(subject, subjectSearchEnd)) { break }
                    }
                    break
                }
                // prettier-ignore
                for {} 1 {} {
                    if iszero(shr(m, xor(mload(subject), s))) {
                        result := sub(subject, subjectStart)
                        break
                    }
                    subject := add(subject, 1)
                    // prettier-ignore
                    if iszero(lt(subject, subjectSearchEnd)) { break }
                }
                break
            }
        }
    }

    /// @dev Returns the byte index of the first location of `search` in `subject`,
    /// searching from left to right.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
    function indexOf(string memory subject, string memory search) internal pure returns (uint256 result) {
        result = indexOf(subject, search, 0);
    }

    /// @dev Returns the byte index of the first location of `search` in `subject`,
    /// searching from right to left, starting from `from`.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
    function lastIndexOf(
        string memory subject,
        string memory search,
        uint256 from
    ) internal pure returns (uint256 result) {
        assembly {
            // prettier-ignore
            for {} 1 {} {
                let searchLength := mload(search)
                let fromMax := sub(mload(subject), searchLength)
                if iszero(gt(fromMax, from)) {
                    from := fromMax
                }
                if iszero(mload(search)) {
                    result := from
                    break
                }
                result := not(0) // Initialize to `NOT_FOUND`.

                let subjectSearchEnd := sub(add(subject, 0x20), 1)

                subject := add(add(subject, 0x20), from)
                // prettier-ignore
                if iszero(gt(subject, subjectSearchEnd)) { break }
                // As this function is not too often used,
                // we shall simply use keccak256 for smaller bytecode size.
                // prettier-ignore
                for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} {
                    if eq(keccak256(subject, searchLength), h) {
                        result := sub(subject, add(subjectSearchEnd, 1))
                        break
                    }
                    subject := sub(subject, 1)
                    // prettier-ignore
                    if iszero(gt(subject, subjectSearchEnd)) { break }
                }
                break
            }
        }
    }

    /// @dev Returns the byte index of the first location of `search` in `subject`,
    /// searching from right to left.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
    function lastIndexOf(string memory subject, string memory search) internal pure returns (uint256 result) {
        result = lastIndexOf(subject, search, uint256(int256(-1)));
    }

    /// @dev Returns whether `subject` starts with `search`.
    function startsWith(string memory subject, string memory search) internal pure returns (bool result) {
        assembly {
            let searchLength := mload(search)
            // Just using keccak256 directly is actually cheaper.
            result := and(
                iszero(gt(searchLength, mload(subject))),
                eq(keccak256(add(subject, 0x20), searchLength), keccak256(add(search, 0x20), searchLength))
            )
        }
    }

    /// @dev Returns whether `subject` ends with `search`.
    function endsWith(string memory subject, string memory search) internal pure returns (bool result) {
        assembly {
            let searchLength := mload(search)
            let subjectLength := mload(subject)
            // Whether `search` is not longer than `subject`.
            let withinRange := iszero(gt(searchLength, subjectLength))
            // Just using keccak256 directly is actually cheaper.
            result := and(
                withinRange,
                eq(
                    keccak256(
                        // `subject + 0x20 + max(subjectLength - searchLength, 0)`.
                        add(add(subject, 0x20), mul(withinRange, sub(subjectLength, searchLength))),
                        searchLength
                    ),
                    keccak256(add(search, 0x20), searchLength)
                )
            )
        }
    }

    /// @dev Returns `subject` repeated `times`.
    function repeat(string memory subject, uint256 times) internal pure returns (string memory result) {
        assembly {
            let subjectLength := mload(subject)
            if iszero(or(iszero(times), iszero(subjectLength))) {
                subject := add(subject, 0x20)
                result := mload(0x40)
                let output := add(result, 0x20)
                // prettier-ignore
                for {} 1 {} {
                    // Copy the `subject` one word at a time.
                    // prettier-ignore
                    for { let o := 0 } 1 {} {
                        mstore(add(output, o), mload(add(subject, o)))
                        o := add(o, 0x20)
                        // prettier-ignore
                        if iszero(lt(o, subjectLength)) { break }
                    }
                    output := add(output, subjectLength)
                    times := sub(times, 1)
                    // prettier-ignore
                    if iszero(times) { break }
                }
                // Zeroize the slot after the string.
                mstore(output, 0)
                // Store the length.
                let resultLength := sub(output, add(result, 0x20))
                mstore(result, resultLength)
                // Allocate memory for the length and the bytes,
                // rounded up to a multiple of 32.
                mstore(0x40, add(result, and(add(resultLength, 63), not(31))))
            }
        }
    }

    /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive).
    /// `start` and `end` are byte offsets.
    function slice(
        string memory subject,
        uint256 start,
        uint256 end
    ) internal pure returns (string memory result) {
        assembly {
            let subjectLength := mload(subject)
            if iszero(gt(subjectLength, end)) {
                end := subjectLength
            }
            if iszero(gt(subjectLength, start)) {
                start := subjectLength
            }
            if lt(start, end) {
                result := mload(0x40)
                let resultLength := sub(end, start)
                mstore(result, resultLength)
                subject := add(subject, start)
                // Copy the `subject` one word at a time, backwards.
                // prettier-ignore
                for { let o := and(add(resultLength, 31), not(31)) } 1 {} {
                    mstore(add(result, o), mload(add(subject, o)))
                    o := sub(o, 0x20)
                    // prettier-ignore
                    if iszero(o) { break }
                }
                // Zeroize the slot after the string.
                mstore(add(add(result, 0x20), resultLength), 0)
                // Allocate memory for the length and the bytes,
                // rounded up to a multiple of 32.
                mstore(0x40, add(result, and(add(resultLength, 63), not(31))))
            }
        }
    }

    /// @dev Returns a copy of `subject` sliced from `start` to the end of the string.
    /// `start` is a byte offset.
    function slice(string memory subject, uint256 start) internal pure returns (string memory result) {
        result = slice(subject, start, uint256(int256(-1)));
    }

    /// @dev Returns all the indices of `search` in `subject`.
    /// The indices are byte offsets.
    function indicesOf(string memory subject, string memory search) internal pure returns (uint256[] memory result) {
        assembly {
            let subjectLength := mload(subject)
            let searchLength := mload(search)

            if iszero(gt(searchLength, subjectLength)) {
                subject := add(subject, 0x20)
                search := add(search, 0x20)
                result := add(mload(0x40), 0x20)

                let subjectStart := subject
                let subjectSearchEnd := add(sub(add(subject, subjectLength), searchLength), 1)
                let h := 0
                if iszero(lt(searchLength, 32)) {
                    h := keccak256(search, searchLength)
                }
                let m := shl(3, sub(32, and(searchLength, 31)))
                let s := mload(search)
                // prettier-ignore
                for {} 1 {} {
                    let t := mload(subject)
                    // Whether the first `searchLength % 32` bytes of 
                    // `subject` and `search` matches.
                    if iszero(shr(m, xor(t, s))) {
                        if h {
                            if iszero(eq(keccak256(subject, searchLength), h)) {
                                subject := add(subject, 1)
                                // prettier-ignore
                                if iszero(lt(subject, subjectSearchEnd)) { break }
                                continue
                            }
                        }
                        // Append to `result`.
                        mstore(result, sub(subject, subjectStart))
                        result := add(result, 0x20)
                        // Advance `subject` by `searchLength`.
                        subject := add(subject, searchLength)
                        if searchLength {
                            // prettier-ignore
                            if iszero(lt(subject, subjectSearchEnd)) { break }
                            continue
                        }
                    }
                    subject := add(subject, 1)
                    // prettier-ignore
                    if iszero(lt(subject, subjectSearchEnd)) { break }
                }
                let resultEnd := result
                // Assign `result` to the free memory pointer.
                result := mload(0x40)
                // Store the length of `result`.
                mstore(result, shr(5, sub(resultEnd, add(result, 0x20))))
                // Allocate memory for result.
                // We allocate one more word, so this array can be recycled for {split}.
                mstore(0x40, add(resultEnd, 0x20))
            }
        }
    }

    /// @dev Returns a arrays of strings based on the `delimiter` inside of the `subject` string.
    function split(string memory subject, string memory delimiter) internal pure returns (string[] memory result) {
        uint256[] memory indices = indicesOf(subject, delimiter);
        assembly {
            let indexPtr := add(indices, 0x20)
            let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1)))
            mstore(sub(indicesEnd, 0x20), mload(subject))
            mstore(indices, add(mload(indices), 1))
            let prevIndex := 0
            // prettier-ignore
            for {} 1 {} {
                let index := mload(indexPtr)
                mstore(indexPtr, 0x60)                        
                if iszero(eq(index, prevIndex)) {
                    let element := mload(0x40)
                    let elementLength := sub(index, prevIndex)
                    mstore(element, elementLength)
                    // Copy the `subject` one word at a time, backwards.
                    // prettier-ignore
                    for { let o := and(add(elementLength, 31), not(31)) } 1 {} {
                        mstore(add(element, o), mload(add(add(subject, prevIndex), o)))
                        o := sub(o, 0x20)
                        // prettier-ignore
                        if iszero(o) { break }
                    }
                    // Zeroize the slot after the string.
                    mstore(add(add(element, 0x20), elementLength), 0)
                    // Allocate memory for the length and the bytes,
                    // rounded up to a multiple of 32.
                    mstore(0x40, add(element, and(add(elementLength, 63), not(31))))
                    // Store the `element` into the array.
                    mstore(indexPtr, element)                        
                }
                prevIndex := add(index, mload(delimiter))
                indexPtr := add(indexPtr, 0x20)
                // prettier-ignore
                if iszero(lt(indexPtr, indicesEnd)) { break }
            }
            result := indices
            if iszero(mload(delimiter)) {
                result := add(indices, 0x20)
                mstore(result, sub(mload(indices), 2))
            }
        }
    }

    /// @dev Returns a concatenated string of `a` and `b`.
    /// Cheaper than `string.concat()` and does not de-align the free memory pointer.
    function concat(string memory a, string memory b) internal pure returns (string memory result) {
        assembly {
            result := mload(0x40)
            let aLength := mload(a)
            // Copy `a` one word at a time, backwards.
            // prettier-ignore
            for { let o := and(add(mload(a), 32), not(31)) } 1 {} {
                mstore(add(result, o), mload(add(a, o)))
                o := sub(o, 0x20)
                // prettier-ignore
                if iszero(o) { break }
            }
            let bLength := mload(b)
            let output := add(result, mload(a))
            // Copy `b` one word at a time, backwards.
            // prettier-ignore
            for { let o := and(add(bLength, 32), not(31)) } 1 {} {
                mstore(add(output, o), mload(add(b, o)))
                o := sub(o, 0x20)
                // prettier-ignore
                if iszero(o) { break }
            }
            let totalLength := add(aLength, bLength)
            let last := add(add(result, 0x20), totalLength)
            // Zeroize the slot after the string.
            mstore(last, 0)
            // Stores the length.
            mstore(result, totalLength)
            // Allocate memory for the length and the bytes,
            // rounded up to a multiple of 32.
            mstore(0x40, and(add(last, 31), not(31)))
        }
    }

    /// @dev Escapes the string to be used within HTML tags.
    function escapeHTML(string memory s) internal pure returns (string memory result) {
        assembly {
            // prettier-ignore
            for {
                let end := add(s, mload(s))
                result := add(mload(0x40), 0x20)
                // Store the bytes of the packed offsets and strides into the scratch space.
                // `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6.
                mstore(0x1f, 0x900094)
                mstore(0x08, 0xc0000000a6ab)
                // Store "&quot;&amp;&#39;&lt;&gt;" into the scratch space.
                mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b))
            } iszero(eq(s, end)) {} {
                s := add(s, 1)
                let c := and(mload(s), 0xff)
                // Not in `["\"","'","&","<",">"]`.
                if iszero(and(shl(c, 1), 0x500000c400000000)) { 
                    mstore8(result, c)
                    result := add(result, 1)
                    continue    
                }
                let t := shr(248, mload(c))
                mstore(result, mload(and(t, 31)))
                result := add(result, shr(5, t))
            }
            let last := result
            // Zeroize the slot after the string.
            mstore(last, 0)
            // Restore the result to the start of the free memory.
            result := mload(0x40)
            // Store the length of the result.
            mstore(result, sub(last, add(result, 0x20)))
            // Allocate memory for the length and the bytes,
            // rounded up to a multiple of 32.
            mstore(0x40, and(add(last, 31), not(31)))
        }
    }

    /// @dev Escapes the string to be used within double-quotes in a JSON.
    function escapeJSON(string memory s) internal pure returns (string memory result) {
        assembly {
            // prettier-ignore
            for {
                let end := add(s, mload(s))
                result := add(mload(0x40), 0x20)
                // Store "\\u0000" in scratch space.
                // Store "0123456789abcdef" in scratch space.
                // Also, store `{0x08:"b", 0x09:"t", 0x0a:"n", 0x0c:"f", 0x0d:"r"}`.
                // into the scratch space.
                mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672)
                // Bitmask for detecting `["\"","\\"]`.
                let e := or(shl(0x22, 1), shl(0x5c, 1))
            } iszero(eq(s, end)) {} {
                s := add(s, 1)
                let c := and(mload(s), 0xff)
                if iszero(lt(c, 0x20)) {
                    if iszero(and(shl(c, 1), e)) { // Not in `["\"","\\"]`.
                        mstore8(result, c)
                        result := add(result, 1)
                        continue    
                    }
                    mstore8(result, 0x5c) // "\\".
                    mstore8(add(result, 1), c) 
                    result := add(result, 2)
                    continue
                }
                if iszero(and(shl(c, 1), 0x3700)) { // Not in `["\b","\t","\n","\f","\d"]`.
                    mstore8(0x1d, mload(shr(4, c))) // Hex value.
                    mstore8(0x1e, mload(and(c, 15))) // Hex value.
                    mstore(result, mload(0x19)) // "\\u00XX".
                    result := add(result, 6)    
                    continue
                }
                mstore8(result, 0x5c) // "\\".
                mstore8(add(result, 1), mload(add(c, 8)))
                result := add(result, 2)
            }
            let last := result
            // Zeroize the slot after the string.
            mstore(last, 0)
            // Restore the result to the start of the free memory.
            result := mload(0x40)
            // Store the length of the result.
            mstore(result, sub(last, add(result, 0x20)))
            // Allocate memory for the length and the bytes,
            // rounded up to a multiple of 32.
            mstore(0x40, and(add(last, 31), not(31)))
        }
    }

    /// @dev Packs a single string with its length into a single word.
    /// Returns `bytes32(0)` if the length is zero or greater than 31.
    function packOne(string memory a) internal pure returns (bytes32 result) {
        assembly {
            // We don't need to zero right pad the string,
            // since this is our own custom non-standard packing scheme.
            result := mul(
                // Load the length and the bytes.
                mload(add(a, 0x1f)),
                // `length != 0 && length < 32`. Abuses underflow.
                // Assumes that the length is valid and within the block gas limit.
                lt(sub(mload(a), 1), 0x1f)
            )
        }
    }

    /// @dev Unpacks a string packed using {packOne}.
    /// Returns the empty string if `packed` is `bytes32(0)`.
    /// If `packed` is not an output of {packOne}, the output behaviour is undefined.
    function unpackOne(bytes32 packed) internal pure returns (string memory result) {
        assembly {
            // Grab the free memory pointer.
            result := mload(0x40)
            // Allocate 2 words (1 for the length, 1 for the bytes).
            mstore(0x40, add(result, 0x40))
            // Zeroize the length slot.
            mstore(result, 0)
            // Store the length and bytes.
            mstore(add(result, 0x1f), packed)
            // Right pad with zeroes.
            mstore(add(add(result, 0x20), mload(result)), 0)
        }
    }

    /// @dev Packs two strings with their lengths into a single word.
    /// Returns `bytes32(0)` if combined length is zero or greater than 30.
    function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) {
        assembly {
            let aLength := mload(a)
            // We don't need to zero right pad the strings,
            // since this is our own custom non-standard packing scheme.
            result := mul(
                // Load the length and the bytes of `a` and `b`.
                or(shl(shl(3, sub(0x1f, aLength)), mload(add(a, aLength))), mload(sub(add(b, 0x1e), aLength))),
                // `totalLength != 0 && totalLength < 31`. Abuses underflow.
                // Assumes that the lengths are valid and within the block gas limit.
                lt(sub(add(aLength, mload(b)), 1), 0x1e)
            )
        }
    }

    /// @dev Unpacks strings packed using {packTwo}.
    /// Returns the empty strings if `packed` is `bytes32(0)`.
    /// If `packed` is not an output of {packTwo}, the output behaviour is undefined.
    function unpackTwo(bytes32 packed) internal pure returns (string memory resultA, string memory resultB) {
        assembly {
            // Grab the free memory pointer.
            resultA := mload(0x40)
            resultB := add(resultA, 0x40)
            // Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words.
            mstore(0x40, add(resultB, 0x40))
            // Zeroize the length slots.
            mstore(resultA, 0)
            mstore(resultB, 0)
            // Store the lengths and bytes.
            mstore(add(resultA, 0x1f), packed)
            mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA))))
            // Right pad with zeroes.
            mstore(add(add(resultA, 0x20), mload(resultA)), 0)
            mstore(add(add(resultB, 0x20), mload(resultB)), 0)
        }
    }

    /// @dev Directly returns `a` without copying.
    function directReturn(string memory a) internal pure {
        assembly {
            // Right pad with zeroes. Just in case the string is produced
            // by a method that doesn't zero right pad.
            mstore(add(add(a, 0x20), mload(a)), 0)
            // Store the return offset.
            // Assumes that the string does not start from the scratch space.
            mstore(sub(a, 0x20), 0x20)
            // End the transaction, returning the string.
            return(sub(a, 0x20), add(mload(a), 0x40))
        }
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Caution! This library won't check that a token has code, responsibility is delegated to the caller.
library SafeTransferLib {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The ETH transfer has failed.
    error ETHTransferFailed();

    /// @dev The ERC20 `transferFrom` has failed.
    error TransferFromFailed();

    /// @dev The ERC20 `transfer` has failed.
    error TransferFailed();

    /// @dev The ERC20 `approve` has failed.
    error ApproveFailed();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Suggested gas stipend for contract receiving ETH
    /// that disallows any storage writes.
    uint256 internal constant _GAS_STIPEND_NO_STORAGE_WRITES = 2300;

    /// @dev Suggested gas stipend for contract receiving ETH to perform a few
    /// storage reads and writes, but low enough to prevent griefing.
    /// Multiply by a small constant (e.g. 2), if needed.
    uint256 internal constant _GAS_STIPEND_NO_GRIEF = 100000;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       ETH OPERATIONS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Sends `amount` (in wei) ETH to `to`.
    /// Reverts upon failure.
    function safeTransferETH(address to, uint256 amount) internal {
        assembly {
            // Transfer the ETH and check if it succeeded or not.
            if iszero(call(gas(), to, amount, 0, 0, 0, 0)) {
                // Store the function selector of `ETHTransferFailed()`.
                mstore(0x00, 0xb12d13eb)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
    /// The `gasStipend` can be set to a low enough value to prevent
    /// storage writes or gas griefing.
    ///
    /// If sending via the normal procedure fails, force sends the ETH by
    /// creating a temporary contract which uses `SELFDESTRUCT` to force send the ETH.
    ///
    /// Reverts if the current contract has insufficient balance.
    function forceSafeTransferETH(
        address to,
        uint256 amount,
        uint256 gasStipend
    ) internal {
        assembly {
            // If insufficient balance, revert.
            if lt(selfbalance(), amount) {
                // Store the function selector of `ETHTransferFailed()`.
                mstore(0x00, 0xb12d13eb)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
            // Transfer the ETH and check if it succeeded or not.
            if iszero(call(gasStipend, to, amount, 0, 0, 0, 0)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                // We can directly use `SELFDESTRUCT` in the contract creation.
                // We don't check and revert upon failure here, just in case
                // `SELFDESTRUCT`'s behavior is changed some day in the future.
                // (If that ever happens, we will riot, and port the code to use WETH).
                pop(create(amount, 0x0b, 0x16))
            }
        }
    }

    /// @dev Force sends `amount` (in wei) ETH to `to`, with a gas stipend
    /// equal to `_GAS_STIPEND_NO_GRIEF`. This gas stipend is a reasonable default
    /// for 99% of cases and can be overriden with the three-argument version of this
    /// function if necessary.
    ///
    /// If sending via the normal procedure fails, force sends the ETH by
    /// creating a temporary contract which uses `SELFDESTRUCT` to force send the ETH.
    ///
    /// Reverts if the current contract has insufficient balance.
    function forceSafeTransferETH(address to, uint256 amount) internal {
        // Manually inlined because the compiler doesn't inline functions with branches.
        assembly {
            // If insufficient balance, revert.
            if lt(selfbalance(), amount) {
                // Store the function selector of `ETHTransferFailed()`.
                mstore(0x00, 0xb12d13eb)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
            // Transfer the ETH and check if it succeeded or not.
            if iszero(call(_GAS_STIPEND_NO_GRIEF, to, amount, 0, 0, 0, 0)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                // We can directly use `SELFDESTRUCT` in the contract creation.
                // We don't check and revert upon failure here, just in case
                // `SELFDESTRUCT`'s behavior is changed some day in the future.
                // (If that ever happens, we will riot, and port the code to use WETH).
                pop(create(amount, 0x0b, 0x16))
            }
        }
    }

    /// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
    /// The `gasStipend` can be set to a low enough value to prevent
    /// storage writes or gas griefing.
    ///
    /// Simply use `gasleft()` for `gasStipend` if you don't need a gas stipend.
    ///
    /// Note: Does NOT revert upon failure.
    /// Returns whether the transfer of ETH is successful instead.
    function trySafeTransferETH(
        address to,
        uint256 amount,
        uint256 gasStipend
    ) internal returns (bool success) {
        assembly {
            // Transfer the ETH and check if it succeeded or not.
            success := call(gasStipend, to, amount, 0, 0, 0, 0)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      ERC20 OPERATIONS                      */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
    /// Reverts upon failure.
    ///
    /// The `from` account must have at least `amount` approved for
    /// the current contract to manage.
    function safeTransferFrom(
        address token,
        address from,
        address to,
        uint256 amount
    ) internal {
        assembly {
            // We'll write our calldata to this slot below, but restore it later.
            let memPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(0x00, 0x23b872dd)
            mstore(0x20, from) // Append the "from" argument.
            mstore(0x40, to) // Append the "to" argument.
            mstore(0x60, amount) // Append the "amount" argument.

            if iszero(
                and(
                    // Set success to whether the call reverted, if not we check it either
                    // returned exactly 1 (can't just be non-zero data), or had no return data.
                    or(eq(mload(0x00), 1), iszero(returndatasize())),
                    // We use 0x64 because that's the total length of our calldata (0x04 + 0x20 * 3)
                    // Counterintuitively, this call() must be positioned after the or() in the
                    // surrounding and() because and() evaluates its arguments from right to left.
                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
                )
            ) {
                // Store the function selector of `TransferFromFailed()`.
                mstore(0x00, 0x7939f424)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }

            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, memPointer) // Restore the memPointer.
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from the current contract to `to`.
    /// Reverts upon failure.
    function safeTransfer(
        address token,
        address to,
        uint256 amount
    ) internal {
        assembly {
            // We'll write our calldata to this slot below, but restore it later.
            let memPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(0x00, 0xa9059cbb)
            mstore(0x20, to) // Append the "to" argument.
            mstore(0x40, amount) // Append the "amount" argument.

            if iszero(
                and(
                    // Set success to whether the call reverted, if not we check it either
                    // returned exactly 1 (can't just be non-zero data), or had no return data.
                    or(eq(mload(0x00), 1), iszero(returndatasize())),
                    // We use 0x44 because that's the total length of our calldata (0x04 + 0x20 * 2)
                    // Counterintuitively, this call() must be positioned after the or() in the
                    // surrounding and() because and() evaluates its arguments from right to left.
                    call(gas(), token, 0, 0x1c, 0x44, 0x00, 0x20)
                )
            ) {
                // Store the function selector of `TransferFailed()`.
                mstore(0x00, 0x90b8ec18)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }

            mstore(0x40, memPointer) // Restore the memPointer.
        }
    }

    /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
    /// Reverts upon failure.
    function safeApprove(
        address token,
        address to,
        uint256 amount
    ) internal {
        assembly {
            // We'll write our calldata to this slot below, but restore it later.
            let memPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(0x00, 0x095ea7b3)
            mstore(0x20, to) // Append the "to" argument.
            mstore(0x40, amount) // Append the "amount" argument.

            if iszero(
                and(
                    // Set success to whether the call reverted, if not we check it either
                    // returned exactly 1 (can't just be non-zero data), or had no return data.
                    or(eq(mload(0x00), 1), iszero(returndatasize())),
                    // We use 0x44 because that's the total length of our calldata (0x04 + 0x20 * 2)
                    // Counterintuitively, this call() must be positioned after the or() in the
                    // surrounding and() because and() evaluates its arguments from right to left.
                    call(gas(), token, 0, 0x1c, 0x44, 0x00, 0x20)
                )
            ) {
                // Store the function selector of `ApproveFailed()`.
                mstore(0x00, 0x3e3f8f73)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }

            mstore(0x40, memPointer) // Restore the memPointer.
        }
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Library to encode strings in Base64.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/Base64.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/Base64.sol)
/// @author Modified from (https://github.com/Brechtpd/base64/blob/main/base64.sol) by Brecht Devos - <brecht@loopring.org>.
library Base64 {
    /// @dev Encodes `data` using the base64 encoding described in RFC 4648.
    /// See: https://datatracker.ietf.org/doc/html/rfc4648
    /// @param fileSafe  Whether to replace '+' with '-' and '/' with '_'.
    /// @param noPadding Whether to strip away the padding.
    function encode(
        bytes memory data,
        bool fileSafe,
        bool noPadding
    ) internal pure returns (string memory result) {
        assembly {
            let dataLength := mload(data)

            if dataLength {
                // Multiply by 4/3 rounded up.
                // The `shl(2, ...)` is equivalent to multiplying by 4.
                let encodedLength := shl(2, div(add(dataLength, 2), 3))

                // Set `result` to point to the start of the free memory.
                result := mload(0x40)

                // Store the table into the scratch space.
                // Offsetted by -1 byte so that the `mload` will load the character.
                // We will rewrite the free memory pointer at `0x40` later with
                // the allocated size.
                // The magic constant 0x0230 will translate "-_" + "+/".
                mstore(0x1f, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef")
                mstore(0x3f, sub("ghijklmnopqrstuvwxyz0123456789-_", mul(iszero(fileSafe), 0x0230)))

                // Skip the first slot, which stores the length.
                let ptr := add(result, 0x20)
                let end := add(ptr, encodedLength)

                // Run over the input, 3 bytes at a time.
                // prettier-ignore
                for {} 1 {} {
                    data := add(data, 3) // Advance 3 bytes.
                    let input := mload(data)

                    // Write 4 bytes. Optimized for fewer stack operations.
                    mstore8(    ptr    , mload(and(shr(18, input), 0x3F)))
                    mstore8(add(ptr, 1), mload(and(shr(12, input), 0x3F)))
                    mstore8(add(ptr, 2), mload(and(shr( 6, input), 0x3F)))
                    mstore8(add(ptr, 3), mload(and(        input , 0x3F)))
                    
                    ptr := add(ptr, 4) // Advance 4 bytes.
                    // prettier-ignore
                    if iszero(lt(ptr, end)) { break }
                }

                let r := mod(dataLength, 3)

                switch noPadding
                case 0 {
                    // Offset `ptr` and pad with '='. We can simply write over the end.
                    mstore8(sub(ptr, iszero(iszero(r))), 0x3d) // Pad at `ptr - 1` if `r > 0`.
                    mstore8(sub(ptr, shl(1, eq(r, 1))), 0x3d) // Pad at `ptr - 2` if `r == 1`.
                    // Write the length of the string.
                    mstore(result, encodedLength)
                }
                default {
                    // Write the length of the string.
                    mstore(result, sub(encodedLength, add(iszero(iszero(r)), eq(r, 1))))
                }

                // Allocate the memory for the string.
                // Add 31 and mask with `not(31)` to round the
                // free memory pointer up the next multiple of 32.
                mstore(0x40, and(add(end, 31), not(31)))
            }
        }
    }

    /// @dev Encodes `data` using the base64 encoding described in RFC 4648.
    /// Equivalent to `encode(data, false, false)`.
    function encode(bytes memory data) internal pure returns (string memory result) {
        result = encode(data, false, false);
    }

    /// @dev Encodes `data` using the base64 encoding described in RFC 4648.
    /// Equivalent to `encode(data, fileSafe, false)`.
    function encode(bytes memory data, bool fileSafe) internal pure returns (string memory result) {
        result = encode(data, fileSafe, false);
    }

    /// @dev Encodes base64 encoded `data`.
    ///
    /// Supports:
    /// - RFC 4648 (both standard and file-safe mode).
    /// - RFC 3501 (63: ',').
    ///
    /// Does not support:
    /// - Line breaks.
    ///
    /// Note: For performance reasons,
    /// this function will NOT revert on invalid `data` inputs.
    /// Outputs for invalid inputs will simply be undefined behaviour.
    /// It is the user's responsibility to ensure that the `data`
    /// is a valid base64 encoded string.
    function decode(string memory data) internal pure returns (bytes memory result) {
        assembly {
            let dataLength := mload(data)

            if dataLength {
                let end := add(data, dataLength)
                let decodedLength := mul(shr(2, dataLength), 3)

                switch and(dataLength, 3)
                case 0 {
                    // If padded.
                    decodedLength := sub(
                        decodedLength,
                        add(eq(and(mload(end), 0xFF), 0x3d), eq(and(mload(end), 0xFFFF), 0x3d3d))
                    )
                }
                default {
                    // If non-padded.
                    decodedLength := add(decodedLength, sub(and(dataLength, 3), 1))
                }

                result := mload(0x40)

                // Write the length of the string.
                mstore(result, decodedLength)

                // Skip the first slot, which stores the length.
                let ptr := add(result, 0x20)

                // Load the table into the scratch space.
                // Constants are optimized for smaller bytecode with zero gas overhead.
                // `m` also doubles as the mask of the upper 6 bits.
                let m := 0xfc000000fc00686c7074787c8084888c9094989ca0a4a8acb0b4b8bcc0c4c8cc
                mstore(0x5b, m)
                mstore(0x3b, 0x04080c1014181c2024282c3034383c4044484c5054585c6064)
                mstore(0x1a, 0xf8fcf800fcd0d4d8dce0e4e8ecf0f4)

                // prettier-ignore
                for {} 1 {} {
                    // Read 4 bytes.
                    data := add(data, 4)
                    let input := mload(data)

                    // Write 3 bytes.
                    mstore(ptr, or(
                        and(m, mload(byte(28, input))),
                        shr(6, or(
                            and(m, mload(byte(29, input))),
                            shr(6, or(
                                and(m, mload(byte(30, input))),
                                shr(6, mload(byte(31, input)))
                            ))
                        ))
                    ))

                    ptr := add(ptr, 3)
                    
                    // prettier-ignore
                    if iszero(lt(data, end)) { break }
                }

                // Allocate the memory for the string.
                // Add 32 + 31 and mask with `not(31)` to round the
                // free memory pointer up the next multiple of 32.
                mstore(0x40, and(add(add(result, decodedLength), 63), not(31)))

                // Restore the zero slot.
                mstore(0x60, 0)
            }
        }
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Read and write to persistent storage at a fraction of the cost.
/// @author Solady (https://github.com/vectorized/solmady/blob/main/src/utils/SSTORE2.sol)
/// @author Saw-mon-and-Natalie (https://github.com/Saw-mon-and-Natalie)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SSTORE2.sol)
/// @author Modified from 0xSequence (https://github.com/0xSequence/sstore2/blob/master/contracts/SSTORE2.sol)
library SSTORE2 {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                        CUSTOM ERRORS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Unable to deploy the storage contract.
    error DeploymentFailed();

    /// @dev The storage contract address is invalid.
    error InvalidPointer();

    /// @dev Attempt to read outside of the storage contract's bytecode bounds.
    error ReadOutOfBounds();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         WRITE LOGIC                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Writes `data` into the bytecode of a storage contract and returns its address.
    function write(bytes memory data) internal returns (address pointer) {
        // Note: The assembly block below does not expand the memory.
        assembly {
            let originalDataLength := mload(data)

            // Add 1 to data size since we are prefixing it with a STOP opcode.
            let dataSize := add(originalDataLength, 1)

            /**
             * ------------------------------------------------------------------------------+
             * Opcode      | Mnemonic        | Stack                   | Memory              |
             * ------------------------------------------------------------------------------|
             * 61 codeSize | PUSH2 codeSize  | codeSize                |                     |
             * 80          | DUP1            | codeSize codeSize       |                     |
             * 60 0xa      | PUSH1 0xa       | 0xa codeSize codeSize   |                     |
             * 3D          | RETURNDATASIZE  | 0 0xa codeSize codeSize |                     |
             * 39          | CODECOPY        | codeSize                | [0..codeSize): code |
             * 3D          | RETURNDATASZIE  | 0 codeSize              | [0..codeSize): code |
             * F3          | RETURN          |                         | [0..codeSize): code |
             * 00          | STOP            |                         |                     |
             * ------------------------------------------------------------------------------+
             * @dev Prefix the bytecode with a STOP opcode to ensure it cannot be called.
             * Also PUSH2 is used since max contract size cap is 24,576 bytes which is less than 2 ** 16.
             */
            mstore(
                data,
                or(
                    0x61000080600a3d393df300,
                    // Left shift `dataSize` by 64 so that it lines up with the 0000 after PUSH2.
                    shl(0x40, dataSize)
                )
            )

            // Deploy a new contract with the generated creation code.
            pointer := create(0, add(data, 0x15), add(dataSize, 0xa))

            // If `pointer` is zero, revert.
            if iszero(pointer) {
                // Store the function selector of `DeploymentFailed()`.
                mstore(0x00, 0x30116425)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }

            // Restore original length of the variable size `data`.
            mstore(data, originalDataLength)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         READ LOGIC                         */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns all the `data` from the bytecode of the storage contract at `pointer`.
    function read(address pointer) internal view returns (bytes memory data) {
        assembly {
            let pointerCodesize := extcodesize(pointer)
            if iszero(pointerCodesize) {
                // Store the function selector of `InvalidPointer()`.
                mstore(0x00, 0x11052bb4)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
            // Offset all indices by 1 to skip the STOP opcode.
            let size := sub(pointerCodesize, 1)

            // Get the pointer to the free memory and allocate
            // enough 32-byte words for the data and the length of the data,
            // then copy the code to the allocated memory.
            // Masking with 0xffe0 will suffice, since contract size is less than 16 bits.
            data := mload(0x40)
            mstore(0x40, add(data, and(add(size, 0x3f), 0xffe0)))
            mstore(data, size)
            extcodecopy(pointer, add(data, 0x20), 1, size)
        }
    }

    /// @dev Returns the `data` from the bytecode of the storage contract at `pointer`,
    /// from the byte at `start`, to the end of the data stored.
    function read(address pointer, uint256 start) internal view returns (bytes memory data) {
        assembly {
            let pointerCodesize := extcodesize(pointer)
            if iszero(pointerCodesize) {
                // Store the function selector of `InvalidPointer()`.
                mstore(0x00, 0x11052bb4)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }

            // If `!(pointer.code.size > start)`, reverts.
            // This also handles the case where `start + 1` overflows.
            if iszero(gt(pointerCodesize, start)) {
                // Store the function selector of `ReadOutOfBounds()`.
                mstore(0x00, 0x84eb0dd1)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
            let size := sub(pointerCodesize, add(start, 1))

            // Get the pointer to the free memory and allocate
            // enough 32-byte words for the data and the length of the data,
            // then copy the code to the allocated memory.
            // Masking with 0xffe0 will suffice, since contract size is less than 16 bits.
            data := mload(0x40)
            mstore(0x40, add(data, and(add(size, 0x3f), 0xffe0)))
            mstore(data, size)
            extcodecopy(pointer, add(data, 0x20), add(start, 1), size)
        }
    }

    /// @dev Returns the `data` from the bytecode of the storage contract at `pointer`,
    /// from the byte at `start`, to the byte at `end` (exclusive) of the data stored.
    function read(
        address pointer,
        uint256 start,
        uint256 end
    ) internal view returns (bytes memory data) {
        assembly {
            let pointerCodesize := extcodesize(pointer)
            if iszero(pointerCodesize) {
                // Store the function selector of `InvalidPointer()`.
                mstore(0x00, 0x11052bb4)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }

            // If `!(pointer.code.size > end) || (start > end)`, revert.
            // This also handles the cases where `end + 1` or `start + 1` overflow.
            if iszero(
                and(
                    gt(pointerCodesize, end), // Within bounds.
                    iszero(gt(start, end)) // Valid range.
                )
            ) {
                // Store the function selector of `ReadOutOfBounds()`.
                mstore(0x00, 0x84eb0dd1)
                // Revert with (offset, size).
                revert(0x1c, 0x04)
            }
            let size := sub(end, start)

            // Get the pointer to the free memory and allocate
            // enough 32-byte words for the data and the length of the data,
            // then copy the code to the allocated memory.
            // Masking with 0xffe0 will suffice, since contract size is less than 16 bits.
            data := mload(0x40)
            mstore(0x40, add(data, and(add(size, 0x3f), 0xffe0)))
            mstore(data, size)
            extcodecopy(pointer, add(data, 0x20), add(start, 1), size)
        }
    }
}

// SPDX-License-Identifier: MIT
// Copyright (c) 2021 the ethier authors (github.com/divergencetech/ethier)

pragma solidity >=0.8.0;

/// @title DynamicBuffer
/// @author David Huber (@cxkoda) and Simon Fremaux (@dievardump). See also
///         https://raw.githubusercontent.com/dievardump/solidity-dynamic-buffer
/// @notice This library is used to allocate a big amount of container memory
//          which will be subsequently filled without needing to reallocate
///         memory.
/// @dev First, allocate memory.
///      Then use `buffer.appendUnchecked(theBytes)` or `appendSafe()` if
///      bounds checking is required.
library DynamicBuffer {
    /// @notice Allocates container space for the DynamicBuffer
    /// @param capacity The intended max amount of bytes in the buffer
    /// @return buffer The memory location of the buffer
    /// @dev Allocates `capacity + 0x60` bytes of space
    ///      The buffer array starts at the first container data position,
    ///      (i.e. `buffer = container + 0x20`)
    function allocate(uint256 capacity)
        internal
        pure
        returns (bytes memory buffer)
    {
        assembly {
            // Get next-free memory address
            let container := mload(0x40)

            // Allocate memory by setting a new next-free address
            {
                // Add 2 x 32 bytes in size for the two length fields
                // Add 32 bytes safety space for 32B chunked copy
                let size := add(capacity, 0x60)
                let newNextFree := add(container, size)
                mstore(0x40, newNextFree)
            }

            // Set the correct container length
            {
                let length := add(capacity, 0x40)
                mstore(container, length)
            }

            // The buffer starts at idx 1 in the container (0 is length)
            buffer := add(container, 0x20)

            // Init content with length 0
            mstore(buffer, 0)
        }

        return buffer;
    }

    /// @notice Appends data to buffer, and update buffer length
    /// @param buffer the buffer to append the data to
    /// @param data the data to append
    /// @dev Does not perform out-of-bound checks (container capacity)
    ///      for efficiency.
    function appendUnchecked(bytes memory buffer, bytes memory data)
        internal
        pure
    {
        assembly {
            let length := mload(data)
            for {
                data := add(data, 0x20)
                let dataEnd := add(data, length)
                let copyTo := add(buffer, add(mload(buffer), 0x20))
            } lt(data, dataEnd) {
                data := add(data, 0x20)
                copyTo := add(copyTo, 0x20)
            } {
                // Copy 32B chunks from data to buffer.
                // This may read over data array boundaries and copy invalid
                // bytes, which doesn't matter in the end since we will
                // later set the correct buffer length, and have allocated an
                // additional word to avoid buffer overflow.
                mstore(copyTo, mload(data))
            }

            // Update buffer length
            mstore(buffer, add(mload(buffer), length))
        }
    }

    /// @notice Appends data to buffer, and update buffer length
    /// @param buffer the buffer to append the data to
    /// @param data the data to append
    /// @dev Performs out-of-bound checks and calls `appendUnchecked`.
    function appendSafe(bytes memory buffer, bytes memory data) internal pure {
        uint256 capacity;
        uint256 length;
        assembly {
            capacity := sub(mload(sub(buffer, 0x20)), 0x40)
            length := mload(buffer)
        }

        require(
            length + data.length <= capacity,
            "DynamicBuffer: Appending out of bounds."
        );
        appendUnchecked(buffer, data);
    }
}

File 10 of 18 : console.sol
// SPDX-License-Identifier: MIT
pragma solidity >= 0.4.22 <0.9.0;

library console {
	address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67);

	function _sendLogPayload(bytes memory payload) private view {
		uint256 payloadLength = payload.length;
		address consoleAddress = CONSOLE_ADDRESS;
		assembly {
			let payloadStart := add(payload, 32)
			let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0)
		}
	}

	function log() internal view {
		_sendLogPayload(abi.encodeWithSignature("log()"));
	}

	function logInt(int p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(int)", p0));
	}

	function logUint(uint p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint)", p0));
	}

	function logString(string memory p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string)", p0));
	}

	function logBool(bool p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
	}

	function logAddress(address p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address)", p0));
	}

	function logBytes(bytes memory p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes)", p0));
	}

	function logBytes1(bytes1 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0));
	}

	function logBytes2(bytes2 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0));
	}

	function logBytes3(bytes3 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0));
	}

	function logBytes4(bytes4 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0));
	}

	function logBytes5(bytes5 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0));
	}

	function logBytes6(bytes6 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0));
	}

	function logBytes7(bytes7 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0));
	}

	function logBytes8(bytes8 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0));
	}

	function logBytes9(bytes9 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0));
	}

	function logBytes10(bytes10 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0));
	}

	function logBytes11(bytes11 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0));
	}

	function logBytes12(bytes12 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0));
	}

	function logBytes13(bytes13 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0));
	}

	function logBytes14(bytes14 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0));
	}

	function logBytes15(bytes15 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0));
	}

	function logBytes16(bytes16 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0));
	}

	function logBytes17(bytes17 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0));
	}

	function logBytes18(bytes18 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0));
	}

	function logBytes19(bytes19 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0));
	}

	function logBytes20(bytes20 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0));
	}

	function logBytes21(bytes21 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0));
	}

	function logBytes22(bytes22 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0));
	}

	function logBytes23(bytes23 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0));
	}

	function logBytes24(bytes24 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0));
	}

	function logBytes25(bytes25 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0));
	}

	function logBytes26(bytes26 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0));
	}

	function logBytes27(bytes27 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0));
	}

	function logBytes28(bytes28 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0));
	}

	function logBytes29(bytes29 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0));
	}

	function logBytes30(bytes30 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0));
	}

	function logBytes31(bytes31 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0));
	}

	function logBytes32(bytes32 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0));
	}

	function log(uint p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint)", p0));
	}

	function log(string memory p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string)", p0));
	}

	function log(bool p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
	}

	function log(address p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address)", p0));
	}

	function log(uint p0, uint p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,uint)", p0, p1));
	}

	function log(uint p0, string memory p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,string)", p0, p1));
	}

	function log(uint p0, bool p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,bool)", p0, p1));
	}

	function log(uint p0, address p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,address)", p0, p1));
	}

	function log(string memory p0, uint p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint)", p0, p1));
	}

	function log(string memory p0, string memory p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1));
	}

	function log(string memory p0, bool p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1));
	}

	function log(string memory p0, address p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1));
	}

	function log(bool p0, uint p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint)", p0, p1));
	}

	function log(bool p0, string memory p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1));
	}

	function log(bool p0, bool p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1));
	}

	function log(bool p0, address p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1));
	}

	function log(address p0, uint p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint)", p0, p1));
	}

	function log(address p0, string memory p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1));
	}

	function log(address p0, bool p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1));
	}

	function log(address p0, address p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1));
	}

	function log(uint p0, uint p1, uint p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint)", p0, p1, p2));
	}

	function log(uint p0, uint p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,uint,string)", p0, p1, p2));
	}

	function log(uint p0, uint p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool)", p0, p1, p2));
	}

	function log(uint p0, uint p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,uint,address)", p0, p1, p2));
	}

	function log(uint p0, string memory p1, uint p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,string,uint)", p0, p1, p2));
	}

	function log(uint p0, string memory p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,string,string)", p0, p1, p2));
	}

	function log(uint p0, string memory p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,string,bool)", p0, p1, p2));
	}

	function log(uint p0, string memory p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,string,address)", p0, p1, p2));
	}

	function log(uint p0, bool p1, uint p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint)", p0, p1, p2));
	}

	function log(uint p0, bool p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,bool,string)", p0, p1, p2));
	}

	function log(uint p0, bool p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool)", p0, p1, p2));
	}

	function log(uint p0, bool p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,bool,address)", p0, p1, p2));
	}

	function log(uint p0, address p1, uint p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,address,uint)", p0, p1, p2));
	}

	function log(uint p0, address p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,address,string)", p0, p1, p2));
	}

	function log(uint p0, address p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,address,bool)", p0, p1, p2));
	}

	function log(uint p0, address p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,address,address)", p0, p1, p2));
	}

	function log(string memory p0, uint p1, uint p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint,uint)", p0, p1, p2));
	}

	function log(string memory p0, uint p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint,string)", p0, p1, p2));
	}

	function log(string memory p0, uint p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint,bool)", p0, p1, p2));
	}

	function log(string memory p0, uint p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint,address)", p0, p1, p2));
	}

	function log(string memory p0, string memory p1, uint p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,uint)", p0, p1, p2));
	}

	function log(string memory p0, string memory p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2));
	}

	function log(string memory p0, string memory p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2));
	}

	function log(string memory p0, string memory p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2));
	}

	function log(string memory p0, bool p1, uint p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,uint)", p0, p1, p2));
	}

	function log(string memory p0, bool p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2));
	}

	function log(string memory p0, bool p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2));
	}

	function log(string memory p0, bool p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2));
	}

	function log(string memory p0, address p1, uint p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,uint)", p0, p1, p2));
	}

	function log(string memory p0, address p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2));
	}

	function log(string memory p0, address p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2));
	}

	function log(string memory p0, address p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2));
	}

	function log(bool p0, uint p1, uint p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint)", p0, p1, p2));
	}

	function log(bool p0, uint p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint,string)", p0, p1, p2));
	}

	function log(bool p0, uint p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool)", p0, p1, p2));
	}

	function log(bool p0, uint p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint,address)", p0, p1, p2));
	}

	function log(bool p0, string memory p1, uint p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,uint)", p0, p1, p2));
	}

	function log(bool p0, string memory p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2));
	}

	function log(bool p0, string memory p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2));
	}

	function log(bool p0, string memory p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2));
	}

	function log(bool p0, bool p1, uint p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint)", p0, p1, p2));
	}

	function log(bool p0, bool p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2));
	}

	function log(bool p0, bool p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2));
	}

	function log(bool p0, bool p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2));
	}

	function log(bool p0, address p1, uint p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,uint)", p0, p1, p2));
	}

	function log(bool p0, address p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2));
	}

	function log(bool p0, address p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2));
	}

	function log(bool p0, address p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2));
	}

	function log(address p0, uint p1, uint p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint,uint)", p0, p1, p2));
	}

	function log(address p0, uint p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint,string)", p0, p1, p2));
	}

	function log(address p0, uint p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint,bool)", p0, p1, p2));
	}

	function log(address p0, uint p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint,address)", p0, p1, p2));
	}

	function log(address p0, string memory p1, uint p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,uint)", p0, p1, p2));
	}

	function log(address p0, string memory p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2));
	}

	function log(address p0, string memory p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2));
	}

	function log(address p0, string memory p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2));
	}

	function log(address p0, bool p1, uint p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,uint)", p0, p1, p2));
	}

	function log(address p0, bool p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2));
	}

	function log(address p0, bool p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2));
	}

	function log(address p0, bool p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2));
	}

	function log(address p0, address p1, uint p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,uint)", p0, p1, p2));
	}

	function log(address p0, address p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2));
	}

	function log(address p0, address p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2));
	}

	function log(address p0, address p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2));
	}

	function log(uint p0, uint p1, uint p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,uint)", p0, p1, p2, p3));
	}

	function log(uint p0, uint p1, uint p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,string)", p0, p1, p2, p3));
	}

	function log(uint p0, uint p1, uint p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,bool)", p0, p1, p2, p3));
	}

	function log(uint p0, uint p1, uint p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,address)", p0, p1, p2, p3));
	}

	function log(uint p0, uint p1, string memory p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,uint)", p0, p1, p2, p3));
	}

	function log(uint p0, uint p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,string)", p0, p1, p2, p3));
	}

	function log(uint p0, uint p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,bool)", p0, p1, p2, p3));
	}

	function log(uint p0, uint p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,address)", p0, p1, p2, p3));
	}

	function log(uint p0, uint p1, bool p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,uint)", p0, p1, p2, p3));
	}

	function log(uint p0, uint p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,string)", p0, p1, p2, p3));
	}

	function log(uint p0, uint p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,bool)", p0, p1, p2, p3));
	}

	function log(uint p0, uint p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,address)", p0, p1, p2, p3));
	}

	function log(uint p0, uint p1, address p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,uint)", p0, p1, p2, p3));
	}

	function log(uint p0, uint p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,string)", p0, p1, p2, p3));
	}

	function log(uint p0, uint p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,bool)", p0, p1, p2, p3));
	}

	function log(uint p0, uint p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,address)", p0, p1, p2, p3));
	}

	function log(uint p0, string memory p1, uint p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,uint)", p0, p1, p2, p3));
	}

	function log(uint p0, string memory p1, uint p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,string)", p0, p1, p2, p3));
	}

	function log(uint p0, string memory p1, uint p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,bool)", p0, p1, p2, p3));
	}

	function log(uint p0, string memory p1, uint p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,address)", p0, p1, p2, p3));
	}

	function log(uint p0, string memory p1, string memory p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,string,string,uint)", p0, p1, p2, p3));
	}

	function log(uint p0, string memory p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,string,string,string)", p0, p1, p2, p3));
	}

	function log(uint p0, string memory p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,string,string,bool)", p0, p1, p2, p3));
	}

	function log(uint p0, string memory p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,string,string,address)", p0, p1, p2, p3));
	}

	function log(uint p0, string memory p1, bool p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,uint)", p0, p1, p2, p3));
	}

	function log(uint p0, string memory p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,string)", p0, p1, p2, p3));
	}

	function log(uint p0, string memory p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,bool)", p0, p1, p2, p3));
	}

	function log(uint p0, string memory p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,address)", p0, p1, p2, p3));
	}

	function log(uint p0, string memory p1, address p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,string,address,uint)", p0, p1, p2, p3));
	}

	function log(uint p0, string memory p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,string,address,string)", p0, p1, p2, p3));
	}

	function log(uint p0, string memory p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,string,address,bool)", p0, p1, p2, p3));
	}

	function log(uint p0, string memory p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,string,address,address)", p0, p1, p2, p3));
	}

	function log(uint p0, bool p1, uint p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,uint)", p0, p1, p2, p3));
	}

	function log(uint p0, bool p1, uint p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,string)", p0, p1, p2, p3));
	}

	function log(uint p0, bool p1, uint p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,bool)", p0, p1, p2, p3));
	}

	function log(uint p0, bool p1, uint p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,address)", p0, p1, p2, p3));
	}

	function log(uint p0, bool p1, string memory p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,uint)", p0, p1, p2, p3));
	}

	function log(uint p0, bool p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,string)", p0, p1, p2, p3));
	}

	function log(uint p0, bool p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,bool)", p0, p1, p2, p3));
	}

	function log(uint p0, bool p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,address)", p0, p1, p2, p3));
	}

	function log(uint p0, bool p1, bool p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,uint)", p0, p1, p2, p3));
	}

	function log(uint p0, bool p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,string)", p0, p1, p2, p3));
	}

	function log(uint p0, bool p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,bool)", p0, p1, p2, p3));
	}

	function log(uint p0, bool p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,address)", p0, p1, p2, p3));
	}

	function log(uint p0, bool p1, address p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,uint)", p0, p1, p2, p3));
	}

	function log(uint p0, bool p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,string)", p0, p1, p2, p3));
	}

	function log(uint p0, bool p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,bool)", p0, p1, p2, p3));
	}

	function log(uint p0, bool p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,address)", p0, p1, p2, p3));
	}

	function log(uint p0, address p1, uint p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,uint)", p0, p1, p2, p3));
	}

	function log(uint p0, address p1, uint p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,string)", p0, p1, p2, p3));
	}

	function log(uint p0, address p1, uint p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,bool)", p0, p1, p2, p3));
	}

	function log(uint p0, address p1, uint p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,address)", p0, p1, p2, p3));
	}

	function log(uint p0, address p1, string memory p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,address,string,uint)", p0, p1, p2, p3));
	}

	function log(uint p0, address p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,address,string,string)", p0, p1, p2, p3));
	}

	function log(uint p0, address p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,address,string,bool)", p0, p1, p2, p3));
	}

	function log(uint p0, address p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,address,string,address)", p0, p1, p2, p3));
	}

	function log(uint p0, address p1, bool p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,uint)", p0, p1, p2, p3));
	}

	function log(uint p0, address p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,string)", p0, p1, p2, p3));
	}

	function log(uint p0, address p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,bool)", p0, p1, p2, p3));
	}

	function log(uint p0, address p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,address)", p0, p1, p2, p3));
	}

	function log(uint p0, address p1, address p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,address,address,uint)", p0, p1, p2, p3));
	}

	function log(uint p0, address p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,address,address,string)", p0, p1, p2, p3));
	}

	function log(uint p0, address p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,address,address,bool)", p0, p1, p2, p3));
	}

	function log(uint p0, address p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint,address,address,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint p1, uint p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,uint)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint p1, uint p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint p1, uint p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint p1, uint p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint p1, string memory p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint,string,uint)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint,string,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint,string,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint,string,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint p1, bool p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,uint)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint p1, address p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint,address,uint)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint,address,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint,address,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint,address,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, uint p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,uint,uint)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, uint p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,uint,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, uint p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,uint,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, uint p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,uint,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, string memory p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, bool p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, address p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, uint p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,uint)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, uint p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, uint p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, uint p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, string memory p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, bool p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, address p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, uint p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,uint,uint)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, uint p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,uint,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, uint p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,uint,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, uint p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,uint,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, string memory p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, bool p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, address p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3));
	}

	function log(bool p0, uint p1, uint p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,uint)", p0, p1, p2, p3));
	}

	function log(bool p0, uint p1, uint p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,string)", p0, p1, p2, p3));
	}

	function log(bool p0, uint p1, uint p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, uint p1, uint p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,address)", p0, p1, p2, p3));
	}

	function log(bool p0, uint p1, string memory p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,uint)", p0, p1, p2, p3));
	}

	function log(bool p0, uint p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,string)", p0, p1, p2, p3));
	}

	function log(bool p0, uint p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, uint p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,address)", p0, p1, p2, p3));
	}

	function log(bool p0, uint p1, bool p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,uint)", p0, p1, p2, p3));
	}

	function log(bool p0, uint p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,string)", p0, p1, p2, p3));
	}

	function log(bool p0, uint p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, uint p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,address)", p0, p1, p2, p3));
	}

	function log(bool p0, uint p1, address p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,uint)", p0, p1, p2, p3));
	}

	function log(bool p0, uint p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,string)", p0, p1, p2, p3));
	}

	function log(bool p0, uint p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, uint p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,address)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, uint p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,uint)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, uint p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,string)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, uint p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, uint p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,address)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, string memory p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, bool p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, address p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, uint p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,uint)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, uint p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,string)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, uint p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, uint p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,address)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, string memory p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, bool p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, address p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, uint p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,uint)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, uint p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,string)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, uint p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, uint p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,address)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, string memory p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, bool p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, address p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3));
	}

	function log(address p0, uint p1, uint p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,uint)", p0, p1, p2, p3));
	}

	function log(address p0, uint p1, uint p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,string)", p0, p1, p2, p3));
	}

	function log(address p0, uint p1, uint p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,bool)", p0, p1, p2, p3));
	}

	function log(address p0, uint p1, uint p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,address)", p0, p1, p2, p3));
	}

	function log(address p0, uint p1, string memory p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint,string,uint)", p0, p1, p2, p3));
	}

	function log(address p0, uint p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint,string,string)", p0, p1, p2, p3));
	}

	function log(address p0, uint p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint,string,bool)", p0, p1, p2, p3));
	}

	function log(address p0, uint p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint,string,address)", p0, p1, p2, p3));
	}

	function log(address p0, uint p1, bool p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,uint)", p0, p1, p2, p3));
	}

	function log(address p0, uint p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,string)", p0, p1, p2, p3));
	}

	function log(address p0, uint p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,bool)", p0, p1, p2, p3));
	}

	function log(address p0, uint p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,address)", p0, p1, p2, p3));
	}

	function log(address p0, uint p1, address p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint,address,uint)", p0, p1, p2, p3));
	}

	function log(address p0, uint p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint,address,string)", p0, p1, p2, p3));
	}

	function log(address p0, uint p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint,address,bool)", p0, p1, p2, p3));
	}

	function log(address p0, uint p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint,address,address)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, uint p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,uint,uint)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, uint p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,uint,string)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, uint p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,uint,bool)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, uint p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,uint,address)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, string memory p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, bool p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, address p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, uint p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,uint)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, uint p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,string)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, uint p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,bool)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, uint p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,address)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, string memory p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, bool p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, address p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, uint p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,uint,uint)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, uint p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,uint,string)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, uint p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,uint,bool)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, uint p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,uint,address)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, string memory p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, bool p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, address p2, uint p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3));
	}

}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes calldata data
    ) external;

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the caller.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool _approved) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);
}

File 13 of 18 : IERC721Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)

pragma solidity ^0.8.0;

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
interface IERC721Receiver {
    /**
     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
     * by `operator` from `from`, this function is called.
     *
     * It must return its Solidity selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
     *
     * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
     */
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC721.sol";

/**
 * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Metadata is IERC721 {
    /**
     * @dev Returns the token collection name.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the token collection symbol.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
     */
    function tokenURI(uint256 tokenId) external view returns (string memory);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly
                /// @solidity memory-safe-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
    uint8 private constant _ADDRESS_LENGTH = 20;

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return "0x00";
        }
        uint256 temp = value;
        uint256 length = 0;
        while (temp != 0) {
            length++;
            temp >>= 8;
        }
        return toHexString(value, length);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _HEX_SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;

import "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200,
    "details": {
      "yul": false
    }
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "metadata": {
    "useLiteralContent": true
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"punkDataContractAddress","type":"address"},{"internalType":"address","name":"extendedPunkDataContractAddress","type":"address"},{"components":[{"internalType":"bool","name":"isMintActive","type":"bool"},{"internalType":"bool","name":"contractSealed","type":"bool"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"nameSingular","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"string","name":"externalLink","type":"string"},{"internalType":"string","name":"tokenDescription","type":"string"},{"internalType":"string","name":"baseImageUri","type":"string"},{"internalType":"uint256","name":"costPerToken","type":"uint256"},{"internalType":"uint64","name":"maxSupply","type":"uint64"}],"internalType":"struct DefaultPunks.ContractConfig","name":"_config","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"toAddress","type":"address"},{"internalType":"uint256","name":"numTokens","type":"uint256"}],"name":"airdrop","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"config","outputs":[{"internalType":"bool","name":"isMintActive","type":"bool"},{"internalType":"bool","name":"contractSealed","type":"bool"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"nameSingular","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"string","name":"externalLink","type":"string"},{"internalType":"string","name":"tokenDescription","type":"string"},{"internalType":"string","name":"baseImageUri","type":"string"},{"internalType":"uint256","name":"costPerToken","type":"uint256"},{"internalType":"uint64","name":"maxSupply","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"punkId","type":"uint16"}],"name":"defaultAttributesForPunkId","outputs":[{"internalType":"enum DefaultPunks.PunkAttributeValue[]","name":"","type":"uint8[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"exists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"extendedPunkDataContract","outputs":[{"internalType":"contract ExtendedPunkDataInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"flipMintState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"numTokens","type":"uint256"}],"name":"mintPublic","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"tokenId","type":"uint16"}],"name":"punkAttributesAsJSON","outputs":[{"internalType":"string","name":"json","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"punkDataContract","outputs":[{"internalType":"contract PunkDataInterface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sealContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bool","name":"isMintActive","type":"bool"},{"internalType":"bool","name":"contractSealed","type":"bool"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"nameSingular","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"string","name":"externalLink","type":"string"},{"internalType":"string","name":"tokenDescription","type":"string"},{"internalType":"string","name":"baseImageUri","type":"string"},{"internalType":"uint256","name":"costPerToken","type":"uint256"},{"internalType":"uint64","name":"maxSupply","type":"uint64"}],"internalType":"struct DefaultPunks.ContractConfig","name":"_config","type":"tuple"}],"name":"setContractConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_defaultPunkAttributesBytes","type":"bytes"}],"name":"setDefaultPunkAttributesBytes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16[954]","name":"_defaultPunkCounts","type":"uint16[954]"}],"name":"setDefaultPunkCounts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16[954]","name":"_defaultPunks","type":"uint16[954]"}],"name":"setDefaultPunks","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_tokenDescription","type":"string"}],"name":"setTokenDescription","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"tokenId","type":"uint16"}],"name":"tokenHTMLPage","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"tokenId","type":"uint16"}],"name":"tokenImage","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"numTokens","type":"uint256"}],"name":"totalMintCost","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"walletOfOwner","outputs":[{"internalType":"uint16[]","name":"","type":"uint16[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60e06040523480156200001157600080fd5b5060405162005bfd38038062005bfd833981016040819052620000349162000569565b60405180602001604052806000815250604051806020016040528060008152508261012001516001600160401b03166200007d62000077620001a760201b60201c565b620001ab565b60016200008b8482620006da565b5060026200009a8382620006da565b5060808190526004555050805160098054602084015115156101000261ff00199315159390931661ffff19909116179190911781556040820151829190600a90620000e69082620006da565b5060608201516002820190620000fd9082620006da565b5060808201516003820190620001149082620006da565b5060a082015160048201906200012b9082620006da565b5060c08201516005820190620001429082620006da565b5060e08201516006820190620001599082620006da565b50610100820151600782015561012090910151600890910180546001600160401b0319166001600160401b03909216919091179055506001600160a01b0391821660a0521660c052620007aa565b3390565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60006001600160a01b0382165b92915050565b6200021981620001fb565b81146200022557600080fd5b50565b805162000208816200020e565b634e487b7160e01b600052604160045260246000fd5b601f19601f83011681018181106001600160401b038211171562000273576200027362000235565b6040525050565b60006200028660405190565b90506200029482826200024b565b919050565b80151562000219565b8051620002088162000299565b60006001600160401b03821115620002cb57620002cb62000235565b601f19601f83011660200192915050565b60005b83811015620002f9578181015183820152602001620002df565b8381111562000309576000848401525b50505050565b6000620003266200032084620002af565b6200027a565b905082815260208101848484011115620003435762000343600080fd5b62000350848285620002dc565b509392505050565b600082601f8301126200036e576200036e600080fd5b8151620003808482602086016200030f565b949350505050565b8062000219565b8051620002088162000388565b6001600160401b03811662000219565b805162000208816200039c565b60006101408284031215620003d157620003d1600080fd5b620003de6101406200027a565b90506000620003ee8484620002a2565b82525060206200040184848301620002a2565b60208301525060408201516001600160401b03811115620004255762000425600080fd5b620004338482850162000358565b60408301525060608201516001600160401b03811115620004575762000457600080fd5b620004658482850162000358565b60608301525060808201516001600160401b03811115620004895762000489600080fd5b620004978482850162000358565b60808301525060a08201516001600160401b03811115620004bb57620004bb600080fd5b620004c98482850162000358565b60a08301525060c08201516001600160401b03811115620004ed57620004ed600080fd5b620004fb8482850162000358565b60c08301525060e08201516001600160401b038111156200051f576200051f600080fd5b6200052d8482850162000358565b60e08301525061010062000544848285016200038f565b610100830152506101206200055c84828501620003ac565b6101208301525092915050565b600080600060608486031215620005835762000583600080fd5b600062000591868662000228565b9350506020620005a48682870162000228565b92505060408401516001600160401b03811115620005c557620005c5600080fd5b620005d386828701620003b9565b9150509250925092565b634e487b7160e01b600052602260045260246000fd5b6002810460018216806200060857607f821691505b6020821081036200061d576200061d620005dd565b50919050565b600062000208620006318381565b90565b6200063f8362000623565b81546008840282811b60001990911b908116901990911617825550505050565b60006200066e81848462000634565b505050565b818110156200069257620006896000826200065f565b60010162000673565b5050565b601f8211156200066e576000818152602090206020601f85010481016020851015620006bf5750805b620006d36020601f86010483018262000673565b5050505050565b81516001600160401b03811115620006f657620006f662000235565b620007028254620005f3565b6200070f82828562000696565b6020601f8311600181146200074657600084156200072d5750858201515b600019600886021c1981166002860217865550620007a2565b600085815260208120601f198616915b8281101562000778578885015182556020948501946001909201910162000756565b86831015620007955784890151600019601f89166008021c191682555b6001600288020188555050505b505050505050565b60805160a05160c0516153f9620008046000396000818161038f01528181611dff0152818161250001526125b901526000818161034e01526115f801526000818161069401528181610d900152610ee801526153f96000f3fe6080604052600436106102235760003560e01c806368bd580e11610123578063b804c4ff116100ab578063d5abeb011161006f578063d5abeb0114610685578063df5dfc63146106b8578063e985e9c5146106d8578063efd0cbf9146106f8578063f2fde38b1461070b57600080fd5b8063b804c4ff146105d8578063b88d4fde146105f8578063c87b56dd14610618578063cb41715514610638578063ce22f7db1461065857600080fd5b80638ba4cc3c116100f25780638ba4cc3c146105525780638da5cb5b1461056557806395d89b41146105835780639896ed1114610598578063a22cb465146105b857600080fd5b806368bd580e146104dd57806370a08231146104f2578063715018a61461051257806379502c551461052757600080fd5b806318160ddd116101b15780634f558e79116101755780634f558e79146104485780635291b6061461046857806359c74f29146104885780636352211e1461049d57806368260a72146104bd57600080fd5b806318160ddd146103b157806323b872dd146103c65780633ccfd60b146103e657806342842e0e146103fb578063438b63001461041b57600080fd5b806306fdde03116101f857806306fdde03146102da578063081812fc146102ef578063095ea7b31461031c5780630f5a9f891461033c578063137fee321461037d57600080fd5b806270cb3214610228578062d5da021461025e57806301ffc9a714610280578063023abe2b146102ad575b600080fd5b34801561023457600080fd5b5061024861024336600461371c565b61072b565b6040516102559190613745565b60405180910390f35b34801561026a57600080fd5b5061027e6102793660046137a4565b610741565b005b34801561028c57600080fd5b506102a061029b366004613806565b61078c565b604051610255919061382f565b3480156102b957600080fd5b506102cd6102c8366004613852565b6107dc565b60405161025591906138d1565b3480156102e657600080fd5b506102cd610c24565b3480156102fb57600080fd5b5061030f61030a36600461371c565b610cb9565b6040516102559190613903565b34801561032857600080fd5b5061027e610337366004613925565b610d09565b34801561034857600080fd5b506103707f000000000000000000000000000000000000000000000000000000000000000081565b60405161025591906139a4565b34801561038957600080fd5b506103707f000000000000000000000000000000000000000000000000000000000000000081565b3480156103bd57600080fd5b50610248610d89565b3480156103d257600080fd5b5061027e6103e13660046139b2565b610dbe565b3480156103f257600080fd5b5061027e610def565b34801561040757600080fd5b5061027e6104163660046139b2565b610e68565b34801561042757600080fd5b5061043b610436366004613a02565b610e83565b6040516102559190613a8a565b34801561045457600080fd5b506102a061046336600461371c565b610fa7565b34801561047457600080fd5b5061027e6104833660046137a4565b610fc6565b34801561049457600080fd5b5061027e611059565b3480156104a957600080fd5b5061030f6104b836600461371c565b611075565b3480156104c957600080fd5b506102cd6104d8366004613852565b6110aa565b3480156104e957600080fd5b5061027e611187565b3480156104fe57600080fd5b5061024861050d366004613a02565b6111c8565b34801561051e57600080fd5b5061027e61120c565b34801561053357600080fd5b5061053c611220565b6040516102559a99989796959493929190613aaa565b61027e610560366004613925565b6115a0565b34801561057157600080fd5b506000546001600160a01b031661030f565b34801561058f57600080fd5b506102cd6115aa565b3480156105a457600080fd5b506102cd6105b3366004613852565b6115bc565b3480156105c457600080fd5b5061027e6105d3366004613b7c565b6119e2565b3480156105e457600080fd5b5061027e6105f3366004613bc4565b6119ed565b34801561060457600080fd5b5061027e610613366004613cd7565b611a2b565b34801561062457600080fd5b506102cd61063336600461371c565b611a63565b34801561064457600080fd5b5061027e610653366004613d71565b611aa3565b34801561066457600080fd5b50610678610673366004613852565b611ae0565b6040516102559190613e39565b34801561069157600080fd5b507f0000000000000000000000000000000000000000000000000000000000000000610248565b3480156106c457600080fd5b5061027e6106d3366004613bc4565b611c06565b3480156106e457600080fd5b506102a06106f3366004613e4a565b611c44565b61027e61070636600461371c565b611c72565b34801561071757600080fd5b5061027e610726366004613a02565b611c7f565b60105460009061073b9083613e93565b92915050565b610749611cb6565b600954610100900460ff161561077a5760405162461bcd60e51b815260040161077190613edc565b60405180910390fd5b600e610787828483613fc5565b505050565b60006001600160e01b031982166380ac58cd60e01b14806107bd57506001600160e01b03198216635b5e139f60e01b145b8061073b57506301ffc9a760e01b6001600160e01b031983161461073b565b606060006107e983611ce0565b604080516201006081019091526201004081526000602090910181815291925090610836604051806040016040528060018152602001605b60f81b815250826121a490919063ffffffff16565b6000604051806101a001604052808560000151605c81111561085a5761085a613dab565b605c81111561086b5761086b613dab565b81526020018560200151605c81111561088657610886613dab565b605c81111561089757610897613dab565b81526020018560400151605c8111156108b2576108b2613dab565b605c8111156108c3576108c3613dab565b81526020018560600151605c8111156108de576108de613dab565b605c8111156108ef576108ef613dab565b81526020018560800151605c81111561090a5761090a613dab565b605c81111561091b5761091b613dab565b81526020018560a00151605c81111561093657610936613dab565b605c81111561094757610947613dab565b81526020018560c00151605c81111561096257610962613dab565b605c81111561097357610973613dab565b81526020018560e00151605c81111561098e5761098e613dab565b605c81111561099f5761099f613dab565b8152602001856101000151605c8111156109bb576109bb613dab565b605c8111156109cc576109cc613dab565b8152602001856101200151605c8111156109e8576109e8613dab565b605c8111156109f9576109f9613dab565b8152602001856101400151605c811115610a1557610a15613dab565b605c811115610a2657610a26613dab565b8152602001856101600151605c811115610a4257610a42613dab565b605c811115610a5357610a53613dab565b8152602001856101800151605c811115610a6f57610a6f613dab565b605c811115610a8057610a80613dab565b905290506000610a8f856121e9565b90506000610afb610ad4604e8a61ffff166103ba8110610ab157610ab1614088565b601091828204019190066002029054906101000a900461ffff1661ffff16612498565b604051602001610ae491906140d2565b60408051601f1981840301815291905285906121a4565b604e8861ffff166103ba8110610b1357610b13614088565b601091828204019190066002029054906101000a900461ffff1661ffff16600103610b4a57610b4a604051602001610ae49061416e565b60005b600d811015610bf65760008482600d8110610b6a57610b6a614088565b6020020151905086605c811115610b8357610b83613dab565b81605c811115610b9557610b95613dab565b14610be55782610ba4816141b8565b935050610bba610bb3826124dc565b87906121a4565b83831015610be5576040805180820190915260018152600b60fa1b6020820152610be59087906121a4565b50610bef816141b8565b9050610b4d565b5083604051602001610c0891906141e0565b6040516020818303038152906040529650505050505050919050565b606060096001018054610c3690613f02565b80601f0160208091040260200160405190810160405280929190818152602001828054610c6290613f02565b8015610caf5780601f10610c8457610100808354040283529160200191610caf565b820191906000526020600020905b815481529060010190602001808311610c9257829003601f168201915b5050505050905090565b6000818152600560205260408120546001600160a01b0316610ced5760405162461bcd60e51b815260040161077190614243565b506000908152600760205260409020546001600160a01b031690565b6000610d1482611075565b9050806001600160a01b0316836001600160a01b031603610d475760405162461bcd60e51b815260040161077190614291565b336001600160a01b0382161480610d635750610d638133611c44565b610d7f5760405162461bcd60e51b8152600401610771906142fb565b61078783836129d2565b60006004547f0000000000000000000000000000000000000000000000000000000000000000610db9919061430b565b905090565b610dc83382612a40565b610de45760405162461bcd60e51b815260040161077190614370565b610787838383612ad2565b60004711610e0f5760405162461bcd60e51b8152600401610771906143aa565b476000610e1d6002836143d0565b9050610e3d73c2172a6315c1d7f6855768f843c420ebb36eda9782612bf4565b610e6473f98537696e2cf486f8f32604b2ca2cda120dbba8610e5f838561430b565b612bf4565b5050565b61078783838360405180602001604052806000815250611a2b565b60606000610e90836111c8565b90506000816001600160401b03811115610eac57610eac613be6565b604051908082528060200260200182016040528015610ed5578160200160208202803683370190505b5090506000805b8381108015610f0a57507f000000000000000000000000000000000000000000000000000000000000000082105b15610f9d576000828152600560205260408120546001600160a01b0316610f32576000610f3b565b610f3b83611075565b9050866001600160a01b0316816001600160a01b031603610f8a5782848381518110610f6957610f69614088565b61ffff9092166020928302919091019091015281610f86816141b8565b9250505b82610f94816141b8565b93505050610edc565b5090949350505050565b6000818152600560205260408120546001600160a01b0316151561073b565b610fce611cb6565b600954610100900460ff1615610ff65760405162461bcd60e51b815260040161077190613edc565b61103582828080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612c9092505050565b608a80546001600160a01b0319166001600160a01b03929092169190911790555050565b611061611cb6565b6009805460ff19811660ff90911615179055565b6000818152600560205260408120546001600160a01b03168061073b5760405162461bcd60e51b81526004016107719061442a565b60408051620200608101909152620200408152600060209091018181526060916110d3846115bc565b905061111d6040518060400160405280601f81526020017f3c21444f43545950452068746d6c3e3c68746d6c206c616e673d22656e223e00815250836121a490919063ffffffff16565b61114660405160200161112f9061443a565b60408051601f1981840301815291905283906121a4565b61115082826121a4565b60408051808201909152600e81526d1e17b137b23c9f1e17b43a36b61f60911b60208201526111809083906121a4565b5092915050565b61118f611cb6565b600954610100900460ff16156111b75760405162461bcd60e51b815260040161077190613edc565b6009805461ff001916610100179055565b60006001600160a01b0382166111f05760405162461bcd60e51b8152600401610771906145d8565b506001600160a01b031660009081526006602052604090205490565b611214611cb6565b61121e6000612cd2565b565b60098054600a805460ff808416946101009094041692919061124190613f02565b80601f016020809104026020016040519081016040528092919081815260200182805461126d90613f02565b80156112ba5780601f1061128f576101008083540402835291602001916112ba565b820191906000526020600020905b81548152906001019060200180831161129d57829003601f168201915b5050505050908060020180546112cf90613f02565b80601f01602080910402602001604051908101604052809291908181526020018280546112fb90613f02565b80156113485780601f1061131d57610100808354040283529160200191611348565b820191906000526020600020905b81548152906001019060200180831161132b57829003601f168201915b50505050509080600301805461135d90613f02565b80601f016020809104026020016040519081016040528092919081815260200182805461138990613f02565b80156113d65780601f106113ab576101008083540402835291602001916113d6565b820191906000526020600020905b8154815290600101906020018083116113b957829003601f168201915b5050505050908060040180546113eb90613f02565b80601f016020809104026020016040519081016040528092919081815260200182805461141790613f02565b80156114645780601f1061143957610100808354040283529160200191611464565b820191906000526020600020905b81548152906001019060200180831161144757829003601f168201915b50505050509080600501805461147990613f02565b80601f01602080910402602001604051908101604052809291908181526020018280546114a590613f02565b80156114f25780601f106114c7576101008083540402835291602001916114f2565b820191906000526020600020905b8154815290600101906020018083116114d557829003601f168201915b50505050509080600601805461150790613f02565b80601f016020809104026020016040519081016040528092919081815260200182805461153390613f02565b80156115805780601f1061155557610100808354040283529160200191611580565b820191906000526020600020905b81548152906001019060200180831161156357829003601f168201915b5050505060078301546008909301549192916001600160401b031690508a565b610e648282612d22565b606060096003018054610c3690613f02565b6060600060128361ffff166103ba81106115d8576115d8614088565b601091828204019190066002029054906101000a900461ffff16905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633e5e0a96836040518263ffffffff1660e01b815260040161164291906145e8565b600060405180830381865afa15801561165f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611687919081019061464e565b905061169f6040518060200160405280606081525090565b6116c26040518060e0016040528060ab815260200161531960ab91398290612d75565b6116e56040518060800160405280604581526020016152d4604591398290612d75565b60408051600880825281830190925260009160208201818036833701905050905060005b60188110156119895760005b60188110156119765760008161172c846018613e93565b6117369190614688565b611741906004613e93565b9050600086611751836003614688565b8151811061176157611761614088565b016020015160f81c11156119635760005b6004811015611882576000876117888385614688565b8151811061179857611798614088565b016020015160f81c90506f181899199a1a9b1b9c1cb0b131b232b360811b600f8216601081106117ca576117ca614088565b1a60f81b866117da846002613e93565b6117e5906001614688565b815181106117f5576117f5614088565b60200101906001600160f81b031916908160001a90535060041c600f166f181899199a1a9b1b9c1cb0b131b232b360811b816010811061183757611837614088565b1a60f81b86611847846002613e93565b8151811061185757611857614088565b60200101906001600160f81b031916908160001a90535050808061187a906141b8565b915050611772565b5060408051808201909152600280825261030360f41b602092830152855180821115600119909101810287019092012085916060917fe3f0ae350ee09657933cd8202a4dd563c5af941f8054e6d7191e3246be3782901416156119025750604080518082019091526006815265190d9919194d60d21b6020820152611921565b5060408051808201909152600681526537383861393760d01b60208201525b61196061192d85612498565b61193687612498565b83604051602001611949939291906146cf565b60408051601f198184030181529190528890612d75565b50505b508061196e816141b8565b915050611715565b5080611981816141b8565b915050611709565b506040805180820190915260048152631e17b39f60e11b60208201526119b0908390612d75565b6040805180820190915260068152651e17b9bb339f60d11b60208201526119d8908390612d75565b5051949350505050565b610e64338383612e3f565b6119f5611cb6565b600954610100900460ff1615611a1d5760405162461bcd60e51b815260040161077190613edc565b610e646012826103ba613655565b611a353383612a40565b611a515760405162461bcd60e51b815260040161077190614370565b611a5d84848484612ee1565b50505050565b6000818152600560205260409020546060906001600160a01b0316611a9a5760405162461bcd60e51b815260040161077190614756565b61073b82612f14565b611aab611cb6565b600954610100900460ff1615611ad35760405162461bcd60e51b815260040161077190613edc565b80600961078782826149fa565b608a54606090600090611afb906001600160a01b0316613090565b905060076001600081611b128461ffff8916613e93565b611b1c9190613e93565b90506000836001600160401b03811115611b3857611b38613be6565b604051908082528060200260200182016040528015611b61578160200160208202803683370190505b50905060005b84811015611bfb57600086611b7c8386614688565b81518110611b8c57611b8c614088565b016020015160f81c905080605c811115611ba857611ba8613dab565b838381518110611bba57611bba614088565b6020026020010190605c811115611bd357611bd3613dab565b9081605c811115611be657611be6613dab565b905250611bf49050816141b8565b9050611b67565b509695505050505050565b611c0e611cb6565b600954610100900460ff1615611c365760405162461bcd60e51b815260040161077190613edc565b610e64604e826103ba613655565b6001600160a01b03918216600090815260086020908152604080832093909416825291909152205460ff1690565b611c7c3382612d22565b50565b611c87611cb6565b6001600160a01b038116611cad5760405162461bcd60e51b815260040161077190614a47565b611c7c81612cd2565b6000546001600160a01b0316331461121e5760405162461bcd60e51b815260040161077190614a89565b611d4b604080516101a08101909152806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000905290565b6000611d5683611ae0565b90506000604051806101a001604052806000605c811115611d7957611d79613dab565b8152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160009052905060005b825181101561219c576000838281518110611df157611df1614088565b6020026020010151905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663683375c483605c811115611e3e57611e3e613dab565b605c811115611e4f57611e4f613dab565b6040518263ffffffff1660e01b8152600401611e6b9190614a99565b602060405180830381865afa158015611e88573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eac9190614abf565b600c811115611ebd57611ebd613dab565b600c811115611ece57611ece613dab565b9050600082605c811115611ee457611ee4613dab565b03611ef057505061218a565b600081600c811115611f0457611f04613dab565b03611f37578382605c811115611f1c57611f1c613dab565b9081605c811115611f2f57611f2f613dab565b905250612187565b600181600c811115611f4b57611f4b613dab565b03611f66576020840182605c811115611f1c57611f1c613dab565b600281600c811115611f7a57611f7a613dab565b03611f95576040840182605c811115611f1c57611f1c613dab565b600381600c811115611fa957611fa9613dab565b03611fc4576060840182605c811115611f1c57611f1c613dab565b600481600c811115611fd857611fd8613dab565b03611ff3576080840182605c811115611f1c57611f1c613dab565b600581600c81111561200757612007613dab565b036120225760a0840182605c811115611f1c57611f1c613dab565b600681600c81111561203657612036613dab565b036120515760c0840182605c811115611f1c57611f1c613dab565b600781600c81111561206557612065613dab565b036120805760e0840182605c811115611f1c57611f1c613dab565b600881600c81111561209457612094613dab565b036120b057610100840182605c811115611f1c57611f1c613dab565b600981600c8111156120c4576120c4613dab565b036120e057610120840182605c811115611f1c57611f1c613dab565b600a81600c8111156120f4576120f4613dab565b0361211057610140840182605c811115611f1c57611f1c613dab565b600b81600c81111561212457612124613dab565b0361214057610160840182605c811115611f1c57611f1c613dab565b600c81600c81111561215457612154613dab565b0361218757610180840182605c81111561217057612170613dab565b9081605c81111561218357612183613dab565b9052505b50505b80612194816141b8565b915050611dd4565b509392505050565b601f1982015182518251603f199092019182906121c19083614688565b11156121df5760405162461bcd60e51b815260040161077190614b24565b611a5d84846130d0565b600080604051806101a001604052808460000151605c81111561220e5761220e613dab565b605c81111561221f5761221f613dab565b81526020018460200151605c81111561223a5761223a613dab565b605c81111561224b5761224b613dab565b81526020018460400151605c81111561226657612266613dab565b605c81111561227757612277613dab565b81526020018460600151605c81111561229257612292613dab565b605c8111156122a3576122a3613dab565b81526020018460800151605c8111156122be576122be613dab565b605c8111156122cf576122cf613dab565b81526020018460a00151605c8111156122ea576122ea613dab565b605c8111156122fb576122fb613dab565b81526020018460c00151605c81111561231657612316613dab565b605c81111561232757612327613dab565b81526020018460e00151605c81111561234257612342613dab565b605c81111561235357612353613dab565b8152602001846101000151605c81111561236f5761236f613dab565b605c81111561238057612380613dab565b8152602001846101200151605c81111561239c5761239c613dab565b605c8111156123ad576123ad613dab565b8152602001846101400151605c8111156123c9576123c9613dab565b605c8111156123da576123da613dab565b8152602001846101600151605c8111156123f6576123f6613dab565b605c81111561240757612407613dab565b8152602001846101800151605c81111561242357612423613dab565b605c81111561243457612434613dab565b9052905060005b600d8110156124915760008282600d811061245857612458614088565b6020020151605c81111561246e5761246e613dab565b14612481578261247d816141b8565b9350505b61248a816141b8565b905061243b565b5050919050565b606060a060405101806040526020810391506000825281835b600184039350600a81066030018453600a9004806124b15750829003601f1990920191825250919050565b6060600082605c8111156124f2576124f2613dab565b036124fc57600080fd5b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663fc9faca584605c81111561253f5761253f613dab565b605c81111561255057612550613dab565b6040518263ffffffff1660e01b815260040161256c9190614a99565b600060405180830381865afa158015612589573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526125b1919081019061464e565b9050606060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663683375c486605c8111156125f8576125f8613dab565b605c81111561260957612609613dab565b6040518263ffffffff1660e01b81526004016126259190614a99565b602060405180830381865afa158015612642573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126669190614abf565b600c81111561267757612677613dab565b600c81111561268857612688613dab565b9050600081600c81111561269e5761269e613dab565b036126c657604051806040016040528060038152602001620a6caf60eb1b81525091506129a6565b600181600c8111156126da576126da613dab565b0361270357604051806040016040528060048152602001632430b4b960e11b81525091506129a6565b600281600c81111561271757612717613dab565b0361274057604051806040016040528060048152602001634579657360e01b81525091506129a6565b600381600c81111561275457612754613dab565b0361277e57604051806040016040528060058152602001641099585c9960da1b81525091506129a6565b600481600c81111561279257612792613dab565b036127bb57604051806040016040528060048152602001634561727360e01b81525091506129a6565b600581600c8111156127cf576127cf613dab565b036127f857604051806040016040528060048152602001634c69707360e01b81525091506129a6565b600681600c81111561280c5761280c613dab565b03612836576040518060400160405280600581526020016409adeeae8d60db1b81525091506129a6565b600781600c81111561284a5761284a613dab565b0361287357604051806040016040528060048152602001634661636560e01b81525091506129a6565b600881600c81111561288757612887613dab565b036128b3576040518060400160405280600781526020016622b6b7ba34b7b760c91b81525091506129a6565b600981600c8111156128c7576128c7613dab565b036128f057604051806040016040528060048152602001634e65636b60e01b81525091506129a6565b600a81600c81111561290457612904613dab565b0361292d57604051806040016040528060048152602001634e6f736560e01b81525091506129a6565b600b81600c81111561294157612941613dab565b0361296c5760405180604001604052806006815260200165436865656b7360d01b81525091506129a6565b600c81600c81111561298057612980613dab565b036129a657604051806040016040528060058152602001640a8cacae8d60db1b81525091505b81836040516020016129b9929190614b43565b6040516020818303038152906040529350505050919050565b600081815260076020526040902080546001600160a01b0319166001600160a01b0384169081179091558190612a0782611075565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6000818152600560205260408120546001600160a01b0316612a745760405162461bcd60e51b815260040161077190614bdc565b6000612a7f83611075565b9050806001600160a01b0316846001600160a01b03161480612aba5750836001600160a01b0316612aaf84610cb9565b6001600160a01b0316145b80612aca5750612aca8185611c44565b949350505050565b826001600160a01b0316612ae582611075565b6001600160a01b031614612b0b5760405162461bcd60e51b815260040161077190614c2e565b6001600160a01b038216612b315760405162461bcd60e51b815260040161077190614c7f565b612b3c6000826129d2565b6001600160a01b0383166000908152600660205260408120805460019290612b6590849061430b565b90915550506001600160a01b0382166000908152600660205260408120805460019290612b93908490614688565b909155505060008181526005602052604080822080546001600160a01b0319166001600160a01b0386811691821790925591518493918716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b80471015612c145760405162461bcd60e51b815260040161077190614cc3565b6000826001600160a01b031682604051612c2d90614cd3565b60006040518083038185875af1925050503d8060008114612c6a576040519150601f19603f3d011682016040523d82523d6000602084013e612c6f565b606091505b50509050806107875760405162461bcd60e51b815260040161077190614d38565b60008151600181018060401b6a61000080600a3d393df300178452600a8101601585016000f0925082612ccb5763301164256000526004601cfd5b5090915290565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b612d2b8161072b565b3414612d495760405162461bcd60e51b815260040161077190614d71565b60095460ff16612d6b5760405162461bcd60e51b815260040161077190614daa565b610e648282613106565b805115610e645781518051808351016605c284b9def779602084035181810615828204029050808310612e0c57601f1960208483170182011681604001860160405114612df957602060405101816040018101604052808952601f1960208701165b8781015182820152601f190180612dd75750908302601f198201529450612e0c565b8060400186016040528083026020870352505b838501601f196020885101165b8781015182820152601f190180612e195750506000858401602001525050909152505050565b816001600160a01b0316836001600160a01b031603612e705760405162461bcd60e51b815260040161077190614dee565b6001600160a01b0383811660008181526008602090815260408083209487168084529490915290819020805460ff1916851515179055517f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3190612ed490859061382f565b60405180910390a3505050565b612eec848484612ad2565b612ef884848484613208565b611a5d5760405162461bcd60e51b815260040161077190614e4d565b60606000600b612f2761ffff8516612498565b604051602001612f38929190614ede565b60405160208183030381529060405290506000612f54846110aa565b90506000612f6182613309565b90506000600f612f7461ffff8816612498565b604051602001612f85929190614f01565b60405160208183030381529060405290506130668461303060096005018054612fad90613f02565b80601f0160208091040260200160405190810160405280929190818152602001828054612fd990613f02565b80156130265780601f10612ffb57610100808354040283529160200191613026565b820191906000526020600020905b81548152906001019060200180831161300957829003601f168201915b5050505050613317565b83600d8661303d8c6107dc565b60405160200161305296959493929190614f4a565b604051602081830303815290604052613309565b6040516020016130769190615064565b604051602081830303815290604052945050505050919050565b6060813b806130a7576311052bb46000526004601cfd5b60018103604051925061ffe0603f820116830160405280835280600160208501863c5050919050565b8051602082019150808201602084510184015b818410156130fb5783518152602093840193016130e3565b505082510190915250565b3332146131255760405162461bcd60e51b8152600401610771906150c2565b6001600160a01b03821661314b5760405162461bcd60e51b815260040161077190615104565b6000811161316b5760405162461bcd60e51b815260040161077190615159565b80600454101561318d5760405162461bcd60e51b8152600401610771906151b1565b60045460005b828110156131d05760006131a78584613403565b90506131b3858261346b565b6131bc836151c1565b925050806131c9906141b8565b9050613193565b5060048190556001600160a01b038316600090815260066020526040812080548492906131fe908490614688565b9091555050505050565b60006001600160a01b0384163b156132fe57604051630a85bd0160e11b81526001600160a01b0385169063150b7a029061324c9033908990889088906004016151d8565b6020604051808303816000875af1925050508015613287575060408051601f3d908101601f1916820190925261328491810190615227565b60015b6132e4573d8080156132b5576040519150601f19603f3d011682016040523d82523d6000602084013e6132ba565b606091505b5080516000036132dc5760405162461bcd60e51b815260040161077190614e4d565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050612aca565b506001949350505050565b606061073b826000806134c4565b80516040517b5c75303030303031323334353637383961626364656662746e0066726015526020019082016b1000000000000004000000005b8184146133e05760018401935060ff8451166020811061339957816001821b166133835780845360018401935050613350565b605c845380600185015360028401935050613350565b6137006001821b166133c6578060041c51601d53600f811651601e53601951845260068401935050613350565b605c84536008810151600185015360028401935050613350565b50506000815260408051601f1981840381018252601f9093019092169052919050565b600080833a43424461341660018461430b565b403089604051602001613430989796959493929190615248565b60408051601f1981840301815291905280516020909101209050600061345684836152bf565b905061346281856135cd565b95945050505050565b60008181526005602052604080822080546001600160a01b0319166001600160a01b03861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b60608351801561219c576003600282010460021b60405192507f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f526102308515027f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f03603f52602083018181015b6003880197508751603f8160121c16518353603f81600c1c16516001840153603f8160061c16516002840153603f811651600384015360048301925081831061357d5750613583565b50613534565b6003840686801561359f576001821482151501850387526135b7565b603d821515850353603d6001831460011b8503538487525b5050601f01601f19166040525050509392505050565b600082815260036020526040812054818181036135eb5750836135ee565b50805b60006135fb60018661430b565b905080861461364c576000818152600360205260408120549081900361363157600087815260036020526040902082905561364a565b6000878152600360205260408082208390558382528120555b505b50949350505050565b603c830191839082156136df5791602002820160005b838211156136af57833561ffff1683826101000a81548161ffff021916908361ffff160217905550926020019260020160208160010104928301926001030261366b565b80156136dd5782816101000a81549061ffff02191690556002016020816001010492830192600103026136af565b505b506136eb9291506136ef565b5090565b5b808211156136eb57600081556001016136f0565b805b8114611c7c57600080fd5b803561073b81613704565b60006020828403121561373157613731600080fd5b6000612aca8484613711565b805b82525050565b6020810161073b828461373d565b60008083601f84011261376857613768600080fd5b5081356001600160401b0381111561378257613782600080fd5b60208301915083600182028301111561379d5761379d600080fd5b9250929050565b600080602083850312156137ba576137ba600080fd5b82356001600160401b038111156137d3576137d3600080fd5b6137df85828601613753565b92509250509250929050565b6001600160e01b03198116613706565b803561073b816137eb565b60006020828403121561381b5761381b600080fd5b6000612aca84846137fb565b80151561373f565b6020810161073b8284613827565b61ffff8116613706565b803561073b8161383d565b60006020828403121561386757613867600080fd5b6000612aca8484613847565b60005b8381101561388e578181015183820152602001613876565b83811115611a5d5750506000910152565b60006138a9825190565b8084526020840193506138c0818560208601613873565b601f01601f19169290920192915050565b602080825281016138e2818461389f565b9392505050565b60006001600160a01b03821661073b565b61373f816138e9565b6020810161073b82846138fa565b613706816138e9565b803561073b81613911565b6000806040838503121561393b5761393b600080fd5b6000613947858561391a565b925050602061395885828601613711565b9150509250929050565b600061073b6001600160a01b038316613979565b90565b6001600160a01b031690565b600061073b82613962565b600061073b82613985565b61373f81613990565b6020810161073b828461399b565b6000806000606084860312156139ca576139ca600080fd5b60006139d6868661391a565b93505060206139e78682870161391a565b92505060406139f886828701613711565b9150509250925092565b600060208284031215613a1757613a17600080fd5b6000612aca848461391a565b61ffff811661373f565b6000613a398383613a23565b505060200190565b6000613a4b825190565b80845260209384019383018060005b83811015613a7f578151613a6e8882613a2d565b975060208301925050600101613a5a565b509495945050505050565b602080825281016138e28184613a41565b6001600160401b03811661373f565b6101408101613ab9828d613827565b613ac6602083018c613827565b8181036040830152613ad8818b61389f565b90508181036060830152613aec818a61389f565b90508181036080830152613b00818961389f565b905081810360a0830152613b14818861389f565b905081810360c0830152613b28818761389f565b905081810360e0830152613b3c818661389f565b9050613b4c61010083018561373d565b613b5a610120830184613a9b565b9b9a5050505050505050505050565b801515613706565b803561073b81613b69565b60008060408385031215613b9257613b92600080fd5b6000613b9e858561391a565b925050602061395885828601613b71565b80617740810183101561073b5761073b600080fd5b60006177408284031215613bda57613bda600080fd5b6000612aca8484613baf565b634e487b7160e01b600052604160045260246000fd5b601f19601f83011681018181106001600160401b0382111715613c2157613c21613be6565b6040525050565b6000613c3360405190565b9050613c3f8282613bfc565b919050565b60006001600160401b03821115613c5d57613c5d613be6565b601f19601f83011660200192915050565b82818337506000910152565b6000613c8d613c8884613c44565b613c28565b905082815260208101848484011115613ca857613ca8600080fd5b61219c848285613c6e565b600082601f830112613cc757613cc7600080fd5b8135612aca848260208601613c7a565b60008060008060808587031215613cf057613cf0600080fd5b6000613cfc878761391a565b9450506020613d0d8782880161391a565b9350506040613d1e87828801613711565b92505060608501356001600160401b03811115613d3d57613d3d600080fd5b613d4987828801613cb3565b91505092959194509250565b60006101408284031215613d6b57613d6b600080fd5b50919050565b600060208284031215613d8657613d86600080fd5b81356001600160401b03811115613d9f57613d9f600080fd5b612aca84828501613d55565b634e487b7160e01b600052602160045260246000fd5b605d8110611c7c57611c7c613dab565b80613c3f81613dc1565b600061073b82613dd1565b61373f81613ddb565b6000613a398383613de6565b6000613e05825190565b80845260209384019383018060005b83811015613a7f578151613e288882613def565b975060208301925050600101613e14565b602080825281016138e28184613dfb565b60008060408385031215613e6057613e60600080fd5b6000613e6c858561391a565b92505060206139588582860161391a565b634e487b7160e01b600052601160045260246000fd5b6000816000190483118215151615613ead57613ead613e7d565b500290565b601081526000602082016f21b7b73a3930b1ba1039b2b0b632b21760811b815291505b5060200190565b6020808252810161073b81613eb2565b634e487b7160e01b600052602260045260246000fd5b600281046001821680613f1657607f821691505b602082108103613d6b57613d6b613eec565b600061073b6139768381565b613f3d83613f28565b81546008840282811b60001990911b908116901990911617825550505050565b6000610787818484613f34565b81811015610e6457613f7d600082613f5d565b600101613f6a565b601f821115610787576000818152602090206020601f85010481016020851015613fac5750805b613fbe6020601f860104830182613f6a565b5050505050565b826001600160401b03811115613fdd57613fdd613be6565b613fe78254613f02565b613ff2828285613f85565b6000601f831160018114614026576000841561400e5750858201355b600019600886021c198116600286021786555061407f565b600085815260208120601f198616915b828110156140565788850135825560209485019460019092019101614036565b8683101561407257600019601f88166008021c19858a01351682555b6001600288020188555050505b50505050505050565b634e487b7160e01b600052603260045260246000fd5b60006140a8825190565b6140b6818560208601613873565b9290920192915050565b611f4b60f21b815260005b5060020190565b7f7b2274726169745f74797065223a2243727970746f50756e6b7320576974682081527f4d61746368696e672053696c686f7565747465222c2022646973706c61795f7460208201527f797065223a20226e756d626572222c20226d61785f76616c7565223a203439366040820152691610113b30b63ab2911d60b11b6060820152606a016000614163828461409e565b91506138e2826140c0565b7f7b2274726169745f74797065223a22556e697175652053696c686f7565747465815272088b08089d985b1d59488e880896595cc89f4b606a1b602082015260006033820161073b565b600060001982036141cb576141cb613e7d565b5060010190565b605d60f81b815260006141cb565b60006141ec828461409e565b91506138e2826141d2565b602c81526000602082017f4552433732313a20617070726f76656420717565727920666f72206e6f6e657881526b34b9ba32b73a103a37b5b2b760a11b602082015291505b5060400190565b6020808252810161073b816141f7565b602181526000602082017f4552433732313a20617070726f76616c20746f2063757272656e74206f776e658152603960f91b6020820152915061423c565b6020808252810161073b81614253565b603881526000602082017f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f7781527f6e6572206e6f7220617070726f76656420666f7220616c6c00000000000000006020820152915061423c565b6020808252810161073b816142a1565b60008282101561431d5761431d613e7d565b500390565b603181526000602082017f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f8152701ddb995c881b9bdc88185c1c1c9bdd9959607a1b6020820152915061423c565b6020808252810161073b81614322565b60138152600060208201724e6f7468696e6720746f20776974686472617760681b81529150613ed5565b6020808252810161073b81614380565b634e487b7160e01b600052601260045260246000fd5b6000826143df576143df6143ba565b500490565b602981526000602082017f4552433732313a206f776e657220717565727920666f72206e6f6e657869737481526832b73a103a37b5b2b760b91b6020820152915061423c565b6020808252810161073b816143e4565b7f3c626f64793e3c7374796c653e2a7b626f782d73697a696e673a626f7264657281527f2d626f783b6d617267696e3a303b70616464696e673a303b626f726465723a3060208201527f3b7472616e73666f726d2d6f726967696e3a2063656e7465727d207376677b6260408201527f61636b67726f756e643a233633383539363b6c6566743a203530253b746f703a60608201527f203530253b7472616e73666f726d3a207472616e736c617465282d3530252c2060808201527f2d353025293b706f736974696f6e3a2066697865643b6173706563742d72617460a08201527f696f3a2031202f20313b6d61782d77696474683a20313030766d696e3b6d617860c08201527f2d6865696768743a20313030766d696e3b77696474683a20313030253b20686560e08201527334b3b43a1d10189818129dbe9e17b9ba3cb6329f60611b6101008201526000610114820161073b565b602a81526000602082017f4552433732313a2062616c616e636520717565727920666f7220746865207a65815269726f206164647265737360b01b6020820152915061423c565b6020808252810161073b81614591565b6020810161073b8284613a23565b6000614604613c8884613c44565b90508281526020810184848401111561461f5761461f600080fd5b61219c848285613873565b600082601f83011261463e5761463e600080fd5b8151612aca8482602086016145f6565b60006020828403121561466357614663600080fd5b81516001600160401b0381111561467c5761467c600080fd5b612aca8482850161462a565b6000821982111561469b5761469b613e7d565b500190565b681e3932b1ba103c1e9160b91b815260005b5060090190565b68222066696c6c3d222360b81b815260006146b2565b60006146da826146a0565b91506146e6828661409e565b6411103c9e9160d91b81526005019150614700828561409e565b915061470b826146b9565b9150614717828461409e565b6211179f60e91b8152915060038201613462565b6014815260006020820173151bdad95b88191bd95cc81b9bdd08195e1a5cdd60621b81529150613ed5565b6020808252810161073b8161472b565b6000813561073b81613b69565b600060ff835b81169019929092169190911792915050565b600081151561073b565b61479e8261478b565b6147a9818354614773565b8255505050565b600061ff006147798460081b90565b6147c88261478b565b6147a98183546147b0565b6000808335601e19368590030181126147ee576147ee600080fd5b8084019250823591506001600160401b0382111561480e5761480e600080fd5b60208301925060018202360383131561482957614829600080fd5b509250929050565b610787838383613fc5565b6000813561073b81613704565b600060001983614779565b61485d82613f28565b6147a9818354614849565b6001600160401b038116613706565b6000813561073b81614868565b60006001600160401b0383614779565b60006001600160401b03821661073b565b6148ae82614894565b6147a9818354614884565b8082806148c581614766565b90506148d18184614795565b508291505060208301806148e481614766565b90506148f081846147bf565b505050600181016040830161490581856147d3565b614910818386614831565b50505050600281016060830161492681856147d3565b614931818386614831565b50505050600381016080830161494781856147d3565b614952818386614831565b505050506004810160a0830161496881856147d3565b614973818386614831565b505050506005810160c0830161498981856147d3565b614994818386614831565b505050506006810160e083016149aa81856147d3565b6149b5818386614831565b50505050600781016101008301806149cc8161483c565b90506149d88184614854565b505050600881016101208301806149ee81614877565b9050613fbe81846148a5565b610e6482826148b9565b602681526000602082017f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181526564647265737360d01b6020820152915061423c565b6020808252810161073b81614a04565b60208082527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657291019081526000613ed5565b6020808252810161073b81614a57565b6020810161073b8284613de6565b600d8110611c7c57600080fd5b805161073b81614aa7565b600060208284031215614ad457614ad4600080fd5b6000612aca8484614ab4565b602781526000602082017f44796e616d69634275666665723a20417070656e64696e67206f7574206f66208152663137bab732399760c91b6020820152915061423c565b6020808252810161073b81614ae0565b61227d60f01b815260006140cb565b6e3d913a3930b4ba2fba3cb832911d1160891b8152600f016000614b67828561409e565b6b111610113b30b63ab2911d1160a11b8152600c019150614b88828461409e565b9150612aca82614b34565b602c81526000602082017f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657881526b34b9ba32b73a103a37b5b2b760a11b6020820152915061423c565b6020808252810161073b81614b93565b602581526000602082017f4552433732313a207472616e736665722066726f6d20696e636f72726563742081526437bbb732b960d91b6020820152915061423c565b6020808252810161073b81614bec565b602481526000602082017f4552433732313a207472616e7366657220746f20746865207a65726f206164648152637265737360e01b6020820152915061423c565b6020808252810161073b81614c3e565b601d81526000602082017f416464726573733a20696e73756666696369656e742062616c616e636500000081529150613ed5565b6020808252810161073b81614c8f565b600061073b82613976565b603a81526000602082017f416464726573733a20756e61626c6520746f2073656e642076616c75652c207281527f6563697069656e74206d617920686176652072657665727465640000000000006020820152915061423c565b6020808252810161073b81614cde565b60128152600060208201711399595908195e1858dd081c185e5b595b9d60721b81529150613ed5565b6020808252810161073b81614d48565b60128152600060208201714d696e74206973206e6f742061637469766560701b81529150613ed5565b6020808252810161073b81614d81565b601981526000602082017f4552433732313a20617070726f766520746f2063616c6c65720000000000000081529150613ed5565b6020808252810161073b81614dba565b603281526000602082017f4552433732313a207472616e7366657220746f206e6f6e20455243373231526581527131b2b4bb32b91034b6b83632b6b2b73a32b960711b6020820152915061423c565b6020808252810161073b81614dfe565b60008154614e6a81613f02565b600182168015614e815760018114614e9657614ec6565b60ff1983168652811515820286019350614ec6565b60008581526020902060005b83811015614ebe57815488820152600190910190602001614ea2565b838801955050505b50505092915050565b61202360f01b815260006140cb565b6000614eea8285614e5d565b9150614ef582614ecf565b9150612aca828461409e565b6000614f0d8285614e5d565b9150614f19828461409e565b632e706e6760e01b8152915060048201612aca565b607b60f81b815260006141cb565b607d60f81b815260006141cb565b6000614f5582614f2e565b67113730b6b2911d1160c11b81526008019150614f72828961409e565b701116113232b9b1b934b83a34b7b7111d1160791b81526011019150614f98828861409e565b6a11161134b6b0b3b2911d1160a91b8152600b019150614fb8828761409e565b7111161132bc3a32b93730b62fbab936111d1160711b81526012019150614fdf8286614e5d565b7f222c2268746d6c223a22646174613a746578742f68746d6c3b6368617273657481526d0f5d5d198b4e0ed8985cd94d8d0b60921b6020820152602e019150615028828561409e565b6f011161130ba3a3934b13aba32b9911d160851b8152601001915061504d828461409e565b915061505882614f3c565b98975050505050505050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c0000008152601d0160006138e2828461409e565b601581526000602082017410dbdb9d1c9858dd1cc818d85b9b9bdd081b5a5b9d605a1b81529150613ed5565b6020808252810161073b81615096565b60208082527f4552433732313a206d696e7420746f20746865207a65726f206164647265737391019081526000613ed5565b6020808252810161073b816150d2565b602881526000602082017f455243373231723a206e65656420746f206d696e74206174206c65617374206f8152673732903a37b5b2b760c11b6020820152915061423c565b6020808252810161073b81615114565b602b81526000602082017f455243373231723a206d696e74696e67206d6f726520746f6b656e732074686181526a6e20617661696c61626c6560a81b6020820152915061423c565b6020808252810161073b81615169565b6000816151d0576151d0613e7d565b506000190190565b608081016151e682876138fa565b6151f360208301866138fa565b615200604083018561373d565b8181036060830152615212818461389f565b9695505050505050565b805161073b816137eb565b60006020828403121561523c5761523c600080fd5b6000612aca848461521c565b6101008101615257828b6138fa565b615264602083018a61373d565b615271604083018961373d565b61527e606083018861373d565b61528b608083018761373d565b61529860a083018661373d565b6152a560c08301856138fa565b6152b260e083018461373d565b9998505050505050505050565b6000826152ce576152ce6143ba565b50069056fe3c673e3c7265637420783d22302220793d223022207374796c653d2277696474683a313030253b6865696768743a31303025222066696c6c3d222364366464653422202f3e3c7376672077696474683d223132303022206865696768743d2231323030222073686170652d72656e646572696e673d22637269737045646765732220786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323030302f737667222076657273696f6e3d22312e32222076696577426f783d22302030203234203234223e3c7374796c653e726563747b77696474683a3170783b6865696768743a3170787d3c2f7374796c653ea26469706673582212207baedc415aa254266fecfa588ab3dde352ed81350e03a3d1376c12a45119b82364736f6c634300080f003300000000000000000000000016f5a35647d6f03d5d3da7b35409d65ba03af3b2000000000000000000000000f03e345bb89dc9cfaf8fda381a9e4417bfb46e7a0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000004c00000000000000000000000000000000000000000000000000058d15e1762800000000000000000000000000000000000000000000000000000000000000003ba000000000000000000000000000000000000000000000000000000000000000d44656661756c742050756e6b7300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c44656661756c742050756e6b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000744454641554c5400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002f68747470733a2f2f63617073756c6532312e636f6d2f636f6c6c656374696f6e732f64656661756c742d70756e6b73000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002374f6e65206f662039353420746f6b656e7320696e207468652044656661756c742050756e6b7320636f6c6c656374696f6e2e205468697320504e47207761732067656e6572617465642062792072756e6e696e67207468652062656c6f77204a61766173637269707420636f6465207769746820746865206068746d6c602070726f706572747920696e2060746f6b656e555249602061732069747320696e7075742e0a0a6060606a6176617363726970740a2f2f205573652076657273696f6e2031372e312e330a636f6e737420707570706574656572203d2072657175697265282770757070657465657227293b0a0a636f6e7374206d61696e203d206173796e63202868746d6c2c206f75747075745061746829203d3e207b0a2020636f6e73742062726f77736572203d206177616974207075707065746565722e6c61756e6368287b686561646c6573733a20276368726f6d65277d293b0a2020636f6e73742070616765203d2061776169742062726f777365722e6e65775061676528293b0a0a2020617761697420706167652e73657456696577706f7274287b2077696474683a20313230302c206865696768743a2031323030207d293b0a0a2020617761697420706167652e736574436f6e74656e742868746d6c293b0a20200a2020617761697420706167652e73637265656e73686f74287b20706174683a206f757470757450617468207d293b0a202061776169742062726f777365722e636c6f736528293b0a7d0a0a6d61696e28290a606060000000000000000000000000000000000000000000000000000000000000000000000000000000005768747470733a2f2f6d6964646c656d617263682e6d7970696e6174612e636c6f75642f697066732f516d5463326a614b544e7a336745696e6b6856594a626537525a6653366276565a704a646f667954525a6e626b4a2f000000000000000000

Deployed Bytecode

0x6080604052600436106102235760003560e01c806368bd580e11610123578063b804c4ff116100ab578063d5abeb011161006f578063d5abeb0114610685578063df5dfc63146106b8578063e985e9c5146106d8578063efd0cbf9146106f8578063f2fde38b1461070b57600080fd5b8063b804c4ff146105d8578063b88d4fde146105f8578063c87b56dd14610618578063cb41715514610638578063ce22f7db1461065857600080fd5b80638ba4cc3c116100f25780638ba4cc3c146105525780638da5cb5b1461056557806395d89b41146105835780639896ed1114610598578063a22cb465146105b857600080fd5b806368bd580e146104dd57806370a08231146104f2578063715018a61461051257806379502c551461052757600080fd5b806318160ddd116101b15780634f558e79116101755780634f558e79146104485780635291b6061461046857806359c74f29146104885780636352211e1461049d57806368260a72146104bd57600080fd5b806318160ddd146103b157806323b872dd146103c65780633ccfd60b146103e657806342842e0e146103fb578063438b63001461041b57600080fd5b806306fdde03116101f857806306fdde03146102da578063081812fc146102ef578063095ea7b31461031c5780630f5a9f891461033c578063137fee321461037d57600080fd5b806270cb3214610228578062d5da021461025e57806301ffc9a714610280578063023abe2b146102ad575b600080fd5b34801561023457600080fd5b5061024861024336600461371c565b61072b565b6040516102559190613745565b60405180910390f35b34801561026a57600080fd5b5061027e6102793660046137a4565b610741565b005b34801561028c57600080fd5b506102a061029b366004613806565b61078c565b604051610255919061382f565b3480156102b957600080fd5b506102cd6102c8366004613852565b6107dc565b60405161025591906138d1565b3480156102e657600080fd5b506102cd610c24565b3480156102fb57600080fd5b5061030f61030a36600461371c565b610cb9565b6040516102559190613903565b34801561032857600080fd5b5061027e610337366004613925565b610d09565b34801561034857600080fd5b506103707f00000000000000000000000016f5a35647d6f03d5d3da7b35409d65ba03af3b281565b60405161025591906139a4565b34801561038957600080fd5b506103707f000000000000000000000000f03e345bb89dc9cfaf8fda381a9e4417bfb46e7a81565b3480156103bd57600080fd5b50610248610d89565b3480156103d257600080fd5b5061027e6103e13660046139b2565b610dbe565b3480156103f257600080fd5b5061027e610def565b34801561040757600080fd5b5061027e6104163660046139b2565b610e68565b34801561042757600080fd5b5061043b610436366004613a02565b610e83565b6040516102559190613a8a565b34801561045457600080fd5b506102a061046336600461371c565b610fa7565b34801561047457600080fd5b5061027e6104833660046137a4565b610fc6565b34801561049457600080fd5b5061027e611059565b3480156104a957600080fd5b5061030f6104b836600461371c565b611075565b3480156104c957600080fd5b506102cd6104d8366004613852565b6110aa565b3480156104e957600080fd5b5061027e611187565b3480156104fe57600080fd5b5061024861050d366004613a02565b6111c8565b34801561051e57600080fd5b5061027e61120c565b34801561053357600080fd5b5061053c611220565b6040516102559a99989796959493929190613aaa565b61027e610560366004613925565b6115a0565b34801561057157600080fd5b506000546001600160a01b031661030f565b34801561058f57600080fd5b506102cd6115aa565b3480156105a457600080fd5b506102cd6105b3366004613852565b6115bc565b3480156105c457600080fd5b5061027e6105d3366004613b7c565b6119e2565b3480156105e457600080fd5b5061027e6105f3366004613bc4565b6119ed565b34801561060457600080fd5b5061027e610613366004613cd7565b611a2b565b34801561062457600080fd5b506102cd61063336600461371c565b611a63565b34801561064457600080fd5b5061027e610653366004613d71565b611aa3565b34801561066457600080fd5b50610678610673366004613852565b611ae0565b6040516102559190613e39565b34801561069157600080fd5b507f00000000000000000000000000000000000000000000000000000000000003ba610248565b3480156106c457600080fd5b5061027e6106d3366004613bc4565b611c06565b3480156106e457600080fd5b506102a06106f3366004613e4a565b611c44565b61027e61070636600461371c565b611c72565b34801561071757600080fd5b5061027e610726366004613a02565b611c7f565b60105460009061073b9083613e93565b92915050565b610749611cb6565b600954610100900460ff161561077a5760405162461bcd60e51b815260040161077190613edc565b60405180910390fd5b600e610787828483613fc5565b505050565b60006001600160e01b031982166380ac58cd60e01b14806107bd57506001600160e01b03198216635b5e139f60e01b145b8061073b57506301ffc9a760e01b6001600160e01b031983161461073b565b606060006107e983611ce0565b604080516201006081019091526201004081526000602090910181815291925090610836604051806040016040528060018152602001605b60f81b815250826121a490919063ffffffff16565b6000604051806101a001604052808560000151605c81111561085a5761085a613dab565b605c81111561086b5761086b613dab565b81526020018560200151605c81111561088657610886613dab565b605c81111561089757610897613dab565b81526020018560400151605c8111156108b2576108b2613dab565b605c8111156108c3576108c3613dab565b81526020018560600151605c8111156108de576108de613dab565b605c8111156108ef576108ef613dab565b81526020018560800151605c81111561090a5761090a613dab565b605c81111561091b5761091b613dab565b81526020018560a00151605c81111561093657610936613dab565b605c81111561094757610947613dab565b81526020018560c00151605c81111561096257610962613dab565b605c81111561097357610973613dab565b81526020018560e00151605c81111561098e5761098e613dab565b605c81111561099f5761099f613dab565b8152602001856101000151605c8111156109bb576109bb613dab565b605c8111156109cc576109cc613dab565b8152602001856101200151605c8111156109e8576109e8613dab565b605c8111156109f9576109f9613dab565b8152602001856101400151605c811115610a1557610a15613dab565b605c811115610a2657610a26613dab565b8152602001856101600151605c811115610a4257610a42613dab565b605c811115610a5357610a53613dab565b8152602001856101800151605c811115610a6f57610a6f613dab565b605c811115610a8057610a80613dab565b905290506000610a8f856121e9565b90506000610afb610ad4604e8a61ffff166103ba8110610ab157610ab1614088565b601091828204019190066002029054906101000a900461ffff1661ffff16612498565b604051602001610ae491906140d2565b60408051601f1981840301815291905285906121a4565b604e8861ffff166103ba8110610b1357610b13614088565b601091828204019190066002029054906101000a900461ffff1661ffff16600103610b4a57610b4a604051602001610ae49061416e565b60005b600d811015610bf65760008482600d8110610b6a57610b6a614088565b6020020151905086605c811115610b8357610b83613dab565b81605c811115610b9557610b95613dab565b14610be55782610ba4816141b8565b935050610bba610bb3826124dc565b87906121a4565b83831015610be5576040805180820190915260018152600b60fa1b6020820152610be59087906121a4565b50610bef816141b8565b9050610b4d565b5083604051602001610c0891906141e0565b6040516020818303038152906040529650505050505050919050565b606060096001018054610c3690613f02565b80601f0160208091040260200160405190810160405280929190818152602001828054610c6290613f02565b8015610caf5780601f10610c8457610100808354040283529160200191610caf565b820191906000526020600020905b815481529060010190602001808311610c9257829003601f168201915b5050505050905090565b6000818152600560205260408120546001600160a01b0316610ced5760405162461bcd60e51b815260040161077190614243565b506000908152600760205260409020546001600160a01b031690565b6000610d1482611075565b9050806001600160a01b0316836001600160a01b031603610d475760405162461bcd60e51b815260040161077190614291565b336001600160a01b0382161480610d635750610d638133611c44565b610d7f5760405162461bcd60e51b8152600401610771906142fb565b61078783836129d2565b60006004547f00000000000000000000000000000000000000000000000000000000000003ba610db9919061430b565b905090565b610dc83382612a40565b610de45760405162461bcd60e51b815260040161077190614370565b610787838383612ad2565b60004711610e0f5760405162461bcd60e51b8152600401610771906143aa565b476000610e1d6002836143d0565b9050610e3d73c2172a6315c1d7f6855768f843c420ebb36eda9782612bf4565b610e6473f98537696e2cf486f8f32604b2ca2cda120dbba8610e5f838561430b565b612bf4565b5050565b61078783838360405180602001604052806000815250611a2b565b60606000610e90836111c8565b90506000816001600160401b03811115610eac57610eac613be6565b604051908082528060200260200182016040528015610ed5578160200160208202803683370190505b5090506000805b8381108015610f0a57507f00000000000000000000000000000000000000000000000000000000000003ba82105b15610f9d576000828152600560205260408120546001600160a01b0316610f32576000610f3b565b610f3b83611075565b9050866001600160a01b0316816001600160a01b031603610f8a5782848381518110610f6957610f69614088565b61ffff9092166020928302919091019091015281610f86816141b8565b9250505b82610f94816141b8565b93505050610edc565b5090949350505050565b6000818152600560205260408120546001600160a01b0316151561073b565b610fce611cb6565b600954610100900460ff1615610ff65760405162461bcd60e51b815260040161077190613edc565b61103582828080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612c9092505050565b608a80546001600160a01b0319166001600160a01b03929092169190911790555050565b611061611cb6565b6009805460ff19811660ff90911615179055565b6000818152600560205260408120546001600160a01b03168061073b5760405162461bcd60e51b81526004016107719061442a565b60408051620200608101909152620200408152600060209091018181526060916110d3846115bc565b905061111d6040518060400160405280601f81526020017f3c21444f43545950452068746d6c3e3c68746d6c206c616e673d22656e223e00815250836121a490919063ffffffff16565b61114660405160200161112f9061443a565b60408051601f1981840301815291905283906121a4565b61115082826121a4565b60408051808201909152600e81526d1e17b137b23c9f1e17b43a36b61f60911b60208201526111809083906121a4565b5092915050565b61118f611cb6565b600954610100900460ff16156111b75760405162461bcd60e51b815260040161077190613edc565b6009805461ff001916610100179055565b60006001600160a01b0382166111f05760405162461bcd60e51b8152600401610771906145d8565b506001600160a01b031660009081526006602052604090205490565b611214611cb6565b61121e6000612cd2565b565b60098054600a805460ff808416946101009094041692919061124190613f02565b80601f016020809104026020016040519081016040528092919081815260200182805461126d90613f02565b80156112ba5780601f1061128f576101008083540402835291602001916112ba565b820191906000526020600020905b81548152906001019060200180831161129d57829003601f168201915b5050505050908060020180546112cf90613f02565b80601f01602080910402602001604051908101604052809291908181526020018280546112fb90613f02565b80156113485780601f1061131d57610100808354040283529160200191611348565b820191906000526020600020905b81548152906001019060200180831161132b57829003601f168201915b50505050509080600301805461135d90613f02565b80601f016020809104026020016040519081016040528092919081815260200182805461138990613f02565b80156113d65780601f106113ab576101008083540402835291602001916113d6565b820191906000526020600020905b8154815290600101906020018083116113b957829003601f168201915b5050505050908060040180546113eb90613f02565b80601f016020809104026020016040519081016040528092919081815260200182805461141790613f02565b80156114645780601f1061143957610100808354040283529160200191611464565b820191906000526020600020905b81548152906001019060200180831161144757829003601f168201915b50505050509080600501805461147990613f02565b80601f01602080910402602001604051908101604052809291908181526020018280546114a590613f02565b80156114f25780601f106114c7576101008083540402835291602001916114f2565b820191906000526020600020905b8154815290600101906020018083116114d557829003601f168201915b50505050509080600601805461150790613f02565b80601f016020809104026020016040519081016040528092919081815260200182805461153390613f02565b80156115805780601f1061155557610100808354040283529160200191611580565b820191906000526020600020905b81548152906001019060200180831161156357829003601f168201915b5050505060078301546008909301549192916001600160401b031690508a565b610e648282612d22565b606060096003018054610c3690613f02565b6060600060128361ffff166103ba81106115d8576115d8614088565b601091828204019190066002029054906101000a900461ffff16905060007f00000000000000000000000016f5a35647d6f03d5d3da7b35409d65ba03af3b26001600160a01b0316633e5e0a96836040518263ffffffff1660e01b815260040161164291906145e8565b600060405180830381865afa15801561165f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611687919081019061464e565b905061169f6040518060200160405280606081525090565b6116c26040518060e0016040528060ab815260200161531960ab91398290612d75565b6116e56040518060800160405280604581526020016152d4604591398290612d75565b60408051600880825281830190925260009160208201818036833701905050905060005b60188110156119895760005b60188110156119765760008161172c846018613e93565b6117369190614688565b611741906004613e93565b9050600086611751836003614688565b8151811061176157611761614088565b016020015160f81c11156119635760005b6004811015611882576000876117888385614688565b8151811061179857611798614088565b016020015160f81c90506f181899199a1a9b1b9c1cb0b131b232b360811b600f8216601081106117ca576117ca614088565b1a60f81b866117da846002613e93565b6117e5906001614688565b815181106117f5576117f5614088565b60200101906001600160f81b031916908160001a90535060041c600f166f181899199a1a9b1b9c1cb0b131b232b360811b816010811061183757611837614088565b1a60f81b86611847846002613e93565b8151811061185757611857614088565b60200101906001600160f81b031916908160001a90535050808061187a906141b8565b915050611772565b5060408051808201909152600280825261030360f41b602092830152855180821115600119909101810287019092012085916060917fe3f0ae350ee09657933cd8202a4dd563c5af941f8054e6d7191e3246be3782901416156119025750604080518082019091526006815265190d9919194d60d21b6020820152611921565b5060408051808201909152600681526537383861393760d01b60208201525b61196061192d85612498565b61193687612498565b83604051602001611949939291906146cf565b60408051601f198184030181529190528890612d75565b50505b508061196e816141b8565b915050611715565b5080611981816141b8565b915050611709565b506040805180820190915260048152631e17b39f60e11b60208201526119b0908390612d75565b6040805180820190915260068152651e17b9bb339f60d11b60208201526119d8908390612d75565b5051949350505050565b610e64338383612e3f565b6119f5611cb6565b600954610100900460ff1615611a1d5760405162461bcd60e51b815260040161077190613edc565b610e646012826103ba613655565b611a353383612a40565b611a515760405162461bcd60e51b815260040161077190614370565b611a5d84848484612ee1565b50505050565b6000818152600560205260409020546060906001600160a01b0316611a9a5760405162461bcd60e51b815260040161077190614756565b61073b82612f14565b611aab611cb6565b600954610100900460ff1615611ad35760405162461bcd60e51b815260040161077190613edc565b80600961078782826149fa565b608a54606090600090611afb906001600160a01b0316613090565b905060076001600081611b128461ffff8916613e93565b611b1c9190613e93565b90506000836001600160401b03811115611b3857611b38613be6565b604051908082528060200260200182016040528015611b61578160200160208202803683370190505b50905060005b84811015611bfb57600086611b7c8386614688565b81518110611b8c57611b8c614088565b016020015160f81c905080605c811115611ba857611ba8613dab565b838381518110611bba57611bba614088565b6020026020010190605c811115611bd357611bd3613dab565b9081605c811115611be657611be6613dab565b905250611bf49050816141b8565b9050611b67565b509695505050505050565b611c0e611cb6565b600954610100900460ff1615611c365760405162461bcd60e51b815260040161077190613edc565b610e64604e826103ba613655565b6001600160a01b03918216600090815260086020908152604080832093909416825291909152205460ff1690565b611c7c3382612d22565b50565b611c87611cb6565b6001600160a01b038116611cad5760405162461bcd60e51b815260040161077190614a47565b611c7c81612cd2565b6000546001600160a01b0316331461121e5760405162461bcd60e51b815260040161077190614a89565b611d4b604080516101a08101909152806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000905290565b6000611d5683611ae0565b90506000604051806101a001604052806000605c811115611d7957611d79613dab565b8152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160009052905060005b825181101561219c576000838281518110611df157611df1614088565b6020026020010151905060007f000000000000000000000000f03e345bb89dc9cfaf8fda381a9e4417bfb46e7a6001600160a01b031663683375c483605c811115611e3e57611e3e613dab565b605c811115611e4f57611e4f613dab565b6040518263ffffffff1660e01b8152600401611e6b9190614a99565b602060405180830381865afa158015611e88573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eac9190614abf565b600c811115611ebd57611ebd613dab565b600c811115611ece57611ece613dab565b9050600082605c811115611ee457611ee4613dab565b03611ef057505061218a565b600081600c811115611f0457611f04613dab565b03611f37578382605c811115611f1c57611f1c613dab565b9081605c811115611f2f57611f2f613dab565b905250612187565b600181600c811115611f4b57611f4b613dab565b03611f66576020840182605c811115611f1c57611f1c613dab565b600281600c811115611f7a57611f7a613dab565b03611f95576040840182605c811115611f1c57611f1c613dab565b600381600c811115611fa957611fa9613dab565b03611fc4576060840182605c811115611f1c57611f1c613dab565b600481600c811115611fd857611fd8613dab565b03611ff3576080840182605c811115611f1c57611f1c613dab565b600581600c81111561200757612007613dab565b036120225760a0840182605c811115611f1c57611f1c613dab565b600681600c81111561203657612036613dab565b036120515760c0840182605c811115611f1c57611f1c613dab565b600781600c81111561206557612065613dab565b036120805760e0840182605c811115611f1c57611f1c613dab565b600881600c81111561209457612094613dab565b036120b057610100840182605c811115611f1c57611f1c613dab565b600981600c8111156120c4576120c4613dab565b036120e057610120840182605c811115611f1c57611f1c613dab565b600a81600c8111156120f4576120f4613dab565b0361211057610140840182605c811115611f1c57611f1c613dab565b600b81600c81111561212457612124613dab565b0361214057610160840182605c811115611f1c57611f1c613dab565b600c81600c81111561215457612154613dab565b0361218757610180840182605c81111561217057612170613dab565b9081605c81111561218357612183613dab565b9052505b50505b80612194816141b8565b915050611dd4565b509392505050565b601f1982015182518251603f199092019182906121c19083614688565b11156121df5760405162461bcd60e51b815260040161077190614b24565b611a5d84846130d0565b600080604051806101a001604052808460000151605c81111561220e5761220e613dab565b605c81111561221f5761221f613dab565b81526020018460200151605c81111561223a5761223a613dab565b605c81111561224b5761224b613dab565b81526020018460400151605c81111561226657612266613dab565b605c81111561227757612277613dab565b81526020018460600151605c81111561229257612292613dab565b605c8111156122a3576122a3613dab565b81526020018460800151605c8111156122be576122be613dab565b605c8111156122cf576122cf613dab565b81526020018460a00151605c8111156122ea576122ea613dab565b605c8111156122fb576122fb613dab565b81526020018460c00151605c81111561231657612316613dab565b605c81111561232757612327613dab565b81526020018460e00151605c81111561234257612342613dab565b605c81111561235357612353613dab565b8152602001846101000151605c81111561236f5761236f613dab565b605c81111561238057612380613dab565b8152602001846101200151605c81111561239c5761239c613dab565b605c8111156123ad576123ad613dab565b8152602001846101400151605c8111156123c9576123c9613dab565b605c8111156123da576123da613dab565b8152602001846101600151605c8111156123f6576123f6613dab565b605c81111561240757612407613dab565b8152602001846101800151605c81111561242357612423613dab565b605c81111561243457612434613dab565b9052905060005b600d8110156124915760008282600d811061245857612458614088565b6020020151605c81111561246e5761246e613dab565b14612481578261247d816141b8565b9350505b61248a816141b8565b905061243b565b5050919050565b606060a060405101806040526020810391506000825281835b600184039350600a81066030018453600a9004806124b15750829003601f1990920191825250919050565b6060600082605c8111156124f2576124f2613dab565b036124fc57600080fd5b60007f000000000000000000000000f03e345bb89dc9cfaf8fda381a9e4417bfb46e7a6001600160a01b031663fc9faca584605c81111561253f5761253f613dab565b605c81111561255057612550613dab565b6040518263ffffffff1660e01b815260040161256c9190614a99565b600060405180830381865afa158015612589573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526125b1919081019061464e565b9050606060007f000000000000000000000000f03e345bb89dc9cfaf8fda381a9e4417bfb46e7a6001600160a01b031663683375c486605c8111156125f8576125f8613dab565b605c81111561260957612609613dab565b6040518263ffffffff1660e01b81526004016126259190614a99565b602060405180830381865afa158015612642573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126669190614abf565b600c81111561267757612677613dab565b600c81111561268857612688613dab565b9050600081600c81111561269e5761269e613dab565b036126c657604051806040016040528060038152602001620a6caf60eb1b81525091506129a6565b600181600c8111156126da576126da613dab565b0361270357604051806040016040528060048152602001632430b4b960e11b81525091506129a6565b600281600c81111561271757612717613dab565b0361274057604051806040016040528060048152602001634579657360e01b81525091506129a6565b600381600c81111561275457612754613dab565b0361277e57604051806040016040528060058152602001641099585c9960da1b81525091506129a6565b600481600c81111561279257612792613dab565b036127bb57604051806040016040528060048152602001634561727360e01b81525091506129a6565b600581600c8111156127cf576127cf613dab565b036127f857604051806040016040528060048152602001634c69707360e01b81525091506129a6565b600681600c81111561280c5761280c613dab565b03612836576040518060400160405280600581526020016409adeeae8d60db1b81525091506129a6565b600781600c81111561284a5761284a613dab565b0361287357604051806040016040528060048152602001634661636560e01b81525091506129a6565b600881600c81111561288757612887613dab565b036128b3576040518060400160405280600781526020016622b6b7ba34b7b760c91b81525091506129a6565b600981600c8111156128c7576128c7613dab565b036128f057604051806040016040528060048152602001634e65636b60e01b81525091506129a6565b600a81600c81111561290457612904613dab565b0361292d57604051806040016040528060048152602001634e6f736560e01b81525091506129a6565b600b81600c81111561294157612941613dab565b0361296c5760405180604001604052806006815260200165436865656b7360d01b81525091506129a6565b600c81600c81111561298057612980613dab565b036129a657604051806040016040528060058152602001640a8cacae8d60db1b81525091505b81836040516020016129b9929190614b43565b6040516020818303038152906040529350505050919050565b600081815260076020526040902080546001600160a01b0319166001600160a01b0384169081179091558190612a0782611075565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6000818152600560205260408120546001600160a01b0316612a745760405162461bcd60e51b815260040161077190614bdc565b6000612a7f83611075565b9050806001600160a01b0316846001600160a01b03161480612aba5750836001600160a01b0316612aaf84610cb9565b6001600160a01b0316145b80612aca5750612aca8185611c44565b949350505050565b826001600160a01b0316612ae582611075565b6001600160a01b031614612b0b5760405162461bcd60e51b815260040161077190614c2e565b6001600160a01b038216612b315760405162461bcd60e51b815260040161077190614c7f565b612b3c6000826129d2565b6001600160a01b0383166000908152600660205260408120805460019290612b6590849061430b565b90915550506001600160a01b0382166000908152600660205260408120805460019290612b93908490614688565b909155505060008181526005602052604080822080546001600160a01b0319166001600160a01b0386811691821790925591518493918716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b80471015612c145760405162461bcd60e51b815260040161077190614cc3565b6000826001600160a01b031682604051612c2d90614cd3565b60006040518083038185875af1925050503d8060008114612c6a576040519150601f19603f3d011682016040523d82523d6000602084013e612c6f565b606091505b50509050806107875760405162461bcd60e51b815260040161077190614d38565b60008151600181018060401b6a61000080600a3d393df300178452600a8101601585016000f0925082612ccb5763301164256000526004601cfd5b5090915290565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b612d2b8161072b565b3414612d495760405162461bcd60e51b815260040161077190614d71565b60095460ff16612d6b5760405162461bcd60e51b815260040161077190614daa565b610e648282613106565b805115610e645781518051808351016605c284b9def779602084035181810615828204029050808310612e0c57601f1960208483170182011681604001860160405114612df957602060405101816040018101604052808952601f1960208701165b8781015182820152601f190180612dd75750908302601f198201529450612e0c565b8060400186016040528083026020870352505b838501601f196020885101165b8781015182820152601f190180612e195750506000858401602001525050909152505050565b816001600160a01b0316836001600160a01b031603612e705760405162461bcd60e51b815260040161077190614dee565b6001600160a01b0383811660008181526008602090815260408083209487168084529490915290819020805460ff1916851515179055517f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3190612ed490859061382f565b60405180910390a3505050565b612eec848484612ad2565b612ef884848484613208565b611a5d5760405162461bcd60e51b815260040161077190614e4d565b60606000600b612f2761ffff8516612498565b604051602001612f38929190614ede565b60405160208183030381529060405290506000612f54846110aa565b90506000612f6182613309565b90506000600f612f7461ffff8816612498565b604051602001612f85929190614f01565b60405160208183030381529060405290506130668461303060096005018054612fad90613f02565b80601f0160208091040260200160405190810160405280929190818152602001828054612fd990613f02565b80156130265780601f10612ffb57610100808354040283529160200191613026565b820191906000526020600020905b81548152906001019060200180831161300957829003601f168201915b5050505050613317565b83600d8661303d8c6107dc565b60405160200161305296959493929190614f4a565b604051602081830303815290604052613309565b6040516020016130769190615064565b604051602081830303815290604052945050505050919050565b6060813b806130a7576311052bb46000526004601cfd5b60018103604051925061ffe0603f820116830160405280835280600160208501863c5050919050565b8051602082019150808201602084510184015b818410156130fb5783518152602093840193016130e3565b505082510190915250565b3332146131255760405162461bcd60e51b8152600401610771906150c2565b6001600160a01b03821661314b5760405162461bcd60e51b815260040161077190615104565b6000811161316b5760405162461bcd60e51b815260040161077190615159565b80600454101561318d5760405162461bcd60e51b8152600401610771906151b1565b60045460005b828110156131d05760006131a78584613403565b90506131b3858261346b565b6131bc836151c1565b925050806131c9906141b8565b9050613193565b5060048190556001600160a01b038316600090815260066020526040812080548492906131fe908490614688565b9091555050505050565b60006001600160a01b0384163b156132fe57604051630a85bd0160e11b81526001600160a01b0385169063150b7a029061324c9033908990889088906004016151d8565b6020604051808303816000875af1925050508015613287575060408051601f3d908101601f1916820190925261328491810190615227565b60015b6132e4573d8080156132b5576040519150601f19603f3d011682016040523d82523d6000602084013e6132ba565b606091505b5080516000036132dc5760405162461bcd60e51b815260040161077190614e4d565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050612aca565b506001949350505050565b606061073b826000806134c4565b80516040517b5c75303030303031323334353637383961626364656662746e0066726015526020019082016b1000000000000004000000005b8184146133e05760018401935060ff8451166020811061339957816001821b166133835780845360018401935050613350565b605c845380600185015360028401935050613350565b6137006001821b166133c6578060041c51601d53600f811651601e53601951845260068401935050613350565b605c84536008810151600185015360028401935050613350565b50506000815260408051601f1981840381018252601f9093019092169052919050565b600080833a43424461341660018461430b565b403089604051602001613430989796959493929190615248565b60408051601f1981840301815291905280516020909101209050600061345684836152bf565b905061346281856135cd565b95945050505050565b60008181526005602052604080822080546001600160a01b0319166001600160a01b03861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b60608351801561219c576003600282010460021b60405192507f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f526102308515027f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f03603f52602083018181015b6003880197508751603f8160121c16518353603f81600c1c16516001840153603f8160061c16516002840153603f811651600384015360048301925081831061357d5750613583565b50613534565b6003840686801561359f576001821482151501850387526135b7565b603d821515850353603d6001831460011b8503538487525b5050601f01601f19166040525050509392505050565b600082815260036020526040812054818181036135eb5750836135ee565b50805b60006135fb60018661430b565b905080861461364c576000818152600360205260408120549081900361363157600087815260036020526040902082905561364a565b6000878152600360205260408082208390558382528120555b505b50949350505050565b603c830191839082156136df5791602002820160005b838211156136af57833561ffff1683826101000a81548161ffff021916908361ffff160217905550926020019260020160208160010104928301926001030261366b565b80156136dd5782816101000a81549061ffff02191690556002016020816001010492830192600103026136af565b505b506136eb9291506136ef565b5090565b5b808211156136eb57600081556001016136f0565b805b8114611c7c57600080fd5b803561073b81613704565b60006020828403121561373157613731600080fd5b6000612aca8484613711565b805b82525050565b6020810161073b828461373d565b60008083601f84011261376857613768600080fd5b5081356001600160401b0381111561378257613782600080fd5b60208301915083600182028301111561379d5761379d600080fd5b9250929050565b600080602083850312156137ba576137ba600080fd5b82356001600160401b038111156137d3576137d3600080fd5b6137df85828601613753565b92509250509250929050565b6001600160e01b03198116613706565b803561073b816137eb565b60006020828403121561381b5761381b600080fd5b6000612aca84846137fb565b80151561373f565b6020810161073b8284613827565b61ffff8116613706565b803561073b8161383d565b60006020828403121561386757613867600080fd5b6000612aca8484613847565b60005b8381101561388e578181015183820152602001613876565b83811115611a5d5750506000910152565b60006138a9825190565b8084526020840193506138c0818560208601613873565b601f01601f19169290920192915050565b602080825281016138e2818461389f565b9392505050565b60006001600160a01b03821661073b565b61373f816138e9565b6020810161073b82846138fa565b613706816138e9565b803561073b81613911565b6000806040838503121561393b5761393b600080fd5b6000613947858561391a565b925050602061395885828601613711565b9150509250929050565b600061073b6001600160a01b038316613979565b90565b6001600160a01b031690565b600061073b82613962565b600061073b82613985565b61373f81613990565b6020810161073b828461399b565b6000806000606084860312156139ca576139ca600080fd5b60006139d6868661391a565b93505060206139e78682870161391a565b92505060406139f886828701613711565b9150509250925092565b600060208284031215613a1757613a17600080fd5b6000612aca848461391a565b61ffff811661373f565b6000613a398383613a23565b505060200190565b6000613a4b825190565b80845260209384019383018060005b83811015613a7f578151613a6e8882613a2d565b975060208301925050600101613a5a565b509495945050505050565b602080825281016138e28184613a41565b6001600160401b03811661373f565b6101408101613ab9828d613827565b613ac6602083018c613827565b8181036040830152613ad8818b61389f565b90508181036060830152613aec818a61389f565b90508181036080830152613b00818961389f565b905081810360a0830152613b14818861389f565b905081810360c0830152613b28818761389f565b905081810360e0830152613b3c818661389f565b9050613b4c61010083018561373d565b613b5a610120830184613a9b565b9b9a5050505050505050505050565b801515613706565b803561073b81613b69565b60008060408385031215613b9257613b92600080fd5b6000613b9e858561391a565b925050602061395885828601613b71565b80617740810183101561073b5761073b600080fd5b60006177408284031215613bda57613bda600080fd5b6000612aca8484613baf565b634e487b7160e01b600052604160045260246000fd5b601f19601f83011681018181106001600160401b0382111715613c2157613c21613be6565b6040525050565b6000613c3360405190565b9050613c3f8282613bfc565b919050565b60006001600160401b03821115613c5d57613c5d613be6565b601f19601f83011660200192915050565b82818337506000910152565b6000613c8d613c8884613c44565b613c28565b905082815260208101848484011115613ca857613ca8600080fd5b61219c848285613c6e565b600082601f830112613cc757613cc7600080fd5b8135612aca848260208601613c7a565b60008060008060808587031215613cf057613cf0600080fd5b6000613cfc878761391a565b9450506020613d0d8782880161391a565b9350506040613d1e87828801613711565b92505060608501356001600160401b03811115613d3d57613d3d600080fd5b613d4987828801613cb3565b91505092959194509250565b60006101408284031215613d6b57613d6b600080fd5b50919050565b600060208284031215613d8657613d86600080fd5b81356001600160401b03811115613d9f57613d9f600080fd5b612aca84828501613d55565b634e487b7160e01b600052602160045260246000fd5b605d8110611c7c57611c7c613dab565b80613c3f81613dc1565b600061073b82613dd1565b61373f81613ddb565b6000613a398383613de6565b6000613e05825190565b80845260209384019383018060005b83811015613a7f578151613e288882613def565b975060208301925050600101613e14565b602080825281016138e28184613dfb565b60008060408385031215613e6057613e60600080fd5b6000613e6c858561391a565b92505060206139588582860161391a565b634e487b7160e01b600052601160045260246000fd5b6000816000190483118215151615613ead57613ead613e7d565b500290565b601081526000602082016f21b7b73a3930b1ba1039b2b0b632b21760811b815291505b5060200190565b6020808252810161073b81613eb2565b634e487b7160e01b600052602260045260246000fd5b600281046001821680613f1657607f821691505b602082108103613d6b57613d6b613eec565b600061073b6139768381565b613f3d83613f28565b81546008840282811b60001990911b908116901990911617825550505050565b6000610787818484613f34565b81811015610e6457613f7d600082613f5d565b600101613f6a565b601f821115610787576000818152602090206020601f85010481016020851015613fac5750805b613fbe6020601f860104830182613f6a565b5050505050565b826001600160401b03811115613fdd57613fdd613be6565b613fe78254613f02565b613ff2828285613f85565b6000601f831160018114614026576000841561400e5750858201355b600019600886021c198116600286021786555061407f565b600085815260208120601f198616915b828110156140565788850135825560209485019460019092019101614036565b8683101561407257600019601f88166008021c19858a01351682555b6001600288020188555050505b50505050505050565b634e487b7160e01b600052603260045260246000fd5b60006140a8825190565b6140b6818560208601613873565b9290920192915050565b611f4b60f21b815260005b5060020190565b7f7b2274726169745f74797065223a2243727970746f50756e6b7320576974682081527f4d61746368696e672053696c686f7565747465222c2022646973706c61795f7460208201527f797065223a20226e756d626572222c20226d61785f76616c7565223a203439366040820152691610113b30b63ab2911d60b11b6060820152606a016000614163828461409e565b91506138e2826140c0565b7f7b2274726169745f74797065223a22556e697175652053696c686f7565747465815272088b08089d985b1d59488e880896595cc89f4b606a1b602082015260006033820161073b565b600060001982036141cb576141cb613e7d565b5060010190565b605d60f81b815260006141cb565b60006141ec828461409e565b91506138e2826141d2565b602c81526000602082017f4552433732313a20617070726f76656420717565727920666f72206e6f6e657881526b34b9ba32b73a103a37b5b2b760a11b602082015291505b5060400190565b6020808252810161073b816141f7565b602181526000602082017f4552433732313a20617070726f76616c20746f2063757272656e74206f776e658152603960f91b6020820152915061423c565b6020808252810161073b81614253565b603881526000602082017f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f7781527f6e6572206e6f7220617070726f76656420666f7220616c6c00000000000000006020820152915061423c565b6020808252810161073b816142a1565b60008282101561431d5761431d613e7d565b500390565b603181526000602082017f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f8152701ddb995c881b9bdc88185c1c1c9bdd9959607a1b6020820152915061423c565b6020808252810161073b81614322565b60138152600060208201724e6f7468696e6720746f20776974686472617760681b81529150613ed5565b6020808252810161073b81614380565b634e487b7160e01b600052601260045260246000fd5b6000826143df576143df6143ba565b500490565b602981526000602082017f4552433732313a206f776e657220717565727920666f72206e6f6e657869737481526832b73a103a37b5b2b760b91b6020820152915061423c565b6020808252810161073b816143e4565b7f3c626f64793e3c7374796c653e2a7b626f782d73697a696e673a626f7264657281527f2d626f783b6d617267696e3a303b70616464696e673a303b626f726465723a3060208201527f3b7472616e73666f726d2d6f726967696e3a2063656e7465727d207376677b6260408201527f61636b67726f756e643a233633383539363b6c6566743a203530253b746f703a60608201527f203530253b7472616e73666f726d3a207472616e736c617465282d3530252c2060808201527f2d353025293b706f736974696f6e3a2066697865643b6173706563742d72617460a08201527f696f3a2031202f20313b6d61782d77696474683a20313030766d696e3b6d617860c08201527f2d6865696768743a20313030766d696e3b77696474683a20313030253b20686560e08201527334b3b43a1d10189818129dbe9e17b9ba3cb6329f60611b6101008201526000610114820161073b565b602a81526000602082017f4552433732313a2062616c616e636520717565727920666f7220746865207a65815269726f206164647265737360b01b6020820152915061423c565b6020808252810161073b81614591565b6020810161073b8284613a23565b6000614604613c8884613c44565b90508281526020810184848401111561461f5761461f600080fd5b61219c848285613873565b600082601f83011261463e5761463e600080fd5b8151612aca8482602086016145f6565b60006020828403121561466357614663600080fd5b81516001600160401b0381111561467c5761467c600080fd5b612aca8482850161462a565b6000821982111561469b5761469b613e7d565b500190565b681e3932b1ba103c1e9160b91b815260005b5060090190565b68222066696c6c3d222360b81b815260006146b2565b60006146da826146a0565b91506146e6828661409e565b6411103c9e9160d91b81526005019150614700828561409e565b915061470b826146b9565b9150614717828461409e565b6211179f60e91b8152915060038201613462565b6014815260006020820173151bdad95b88191bd95cc81b9bdd08195e1a5cdd60621b81529150613ed5565b6020808252810161073b8161472b565b6000813561073b81613b69565b600060ff835b81169019929092169190911792915050565b600081151561073b565b61479e8261478b565b6147a9818354614773565b8255505050565b600061ff006147798460081b90565b6147c88261478b565b6147a98183546147b0565b6000808335601e19368590030181126147ee576147ee600080fd5b8084019250823591506001600160401b0382111561480e5761480e600080fd5b60208301925060018202360383131561482957614829600080fd5b509250929050565b610787838383613fc5565b6000813561073b81613704565b600060001983614779565b61485d82613f28565b6147a9818354614849565b6001600160401b038116613706565b6000813561073b81614868565b60006001600160401b0383614779565b60006001600160401b03821661073b565b6148ae82614894565b6147a9818354614884565b8082806148c581614766565b90506148d18184614795565b508291505060208301806148e481614766565b90506148f081846147bf565b505050600181016040830161490581856147d3565b614910818386614831565b50505050600281016060830161492681856147d3565b614931818386614831565b50505050600381016080830161494781856147d3565b614952818386614831565b505050506004810160a0830161496881856147d3565b614973818386614831565b505050506005810160c0830161498981856147d3565b614994818386614831565b505050506006810160e083016149aa81856147d3565b6149b5818386614831565b50505050600781016101008301806149cc8161483c565b90506149d88184614854565b505050600881016101208301806149ee81614877565b9050613fbe81846148a5565b610e6482826148b9565b602681526000602082017f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181526564647265737360d01b6020820152915061423c565b6020808252810161073b81614a04565b60208082527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657291019081526000613ed5565b6020808252810161073b81614a57565b6020810161073b8284613de6565b600d8110611c7c57600080fd5b805161073b81614aa7565b600060208284031215614ad457614ad4600080fd5b6000612aca8484614ab4565b602781526000602082017f44796e616d69634275666665723a20417070656e64696e67206f7574206f66208152663137bab732399760c91b6020820152915061423c565b6020808252810161073b81614ae0565b61227d60f01b815260006140cb565b6e3d913a3930b4ba2fba3cb832911d1160891b8152600f016000614b67828561409e565b6b111610113b30b63ab2911d1160a11b8152600c019150614b88828461409e565b9150612aca82614b34565b602c81526000602082017f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657881526b34b9ba32b73a103a37b5b2b760a11b6020820152915061423c565b6020808252810161073b81614b93565b602581526000602082017f4552433732313a207472616e736665722066726f6d20696e636f72726563742081526437bbb732b960d91b6020820152915061423c565b6020808252810161073b81614bec565b602481526000602082017f4552433732313a207472616e7366657220746f20746865207a65726f206164648152637265737360e01b6020820152915061423c565b6020808252810161073b81614c3e565b601d81526000602082017f416464726573733a20696e73756666696369656e742062616c616e636500000081529150613ed5565b6020808252810161073b81614c8f565b600061073b82613976565b603a81526000602082017f416464726573733a20756e61626c6520746f2073656e642076616c75652c207281527f6563697069656e74206d617920686176652072657665727465640000000000006020820152915061423c565b6020808252810161073b81614cde565b60128152600060208201711399595908195e1858dd081c185e5b595b9d60721b81529150613ed5565b6020808252810161073b81614d48565b60128152600060208201714d696e74206973206e6f742061637469766560701b81529150613ed5565b6020808252810161073b81614d81565b601981526000602082017f4552433732313a20617070726f766520746f2063616c6c65720000000000000081529150613ed5565b6020808252810161073b81614dba565b603281526000602082017f4552433732313a207472616e7366657220746f206e6f6e20455243373231526581527131b2b4bb32b91034b6b83632b6b2b73a32b960711b6020820152915061423c565b6020808252810161073b81614dfe565b60008154614e6a81613f02565b600182168015614e815760018114614e9657614ec6565b60ff1983168652811515820286019350614ec6565b60008581526020902060005b83811015614ebe57815488820152600190910190602001614ea2565b838801955050505b50505092915050565b61202360f01b815260006140cb565b6000614eea8285614e5d565b9150614ef582614ecf565b9150612aca828461409e565b6000614f0d8285614e5d565b9150614f19828461409e565b632e706e6760e01b8152915060048201612aca565b607b60f81b815260006141cb565b607d60f81b815260006141cb565b6000614f5582614f2e565b67113730b6b2911d1160c11b81526008019150614f72828961409e565b701116113232b9b1b934b83a34b7b7111d1160791b81526011019150614f98828861409e565b6a11161134b6b0b3b2911d1160a91b8152600b019150614fb8828761409e565b7111161132bc3a32b93730b62fbab936111d1160711b81526012019150614fdf8286614e5d565b7f222c2268746d6c223a22646174613a746578742f68746d6c3b6368617273657481526d0f5d5d198b4e0ed8985cd94d8d0b60921b6020820152602e019150615028828561409e565b6f011161130ba3a3934b13aba32b9911d160851b8152601001915061504d828461409e565b915061505882614f3c565b98975050505050505050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c0000008152601d0160006138e2828461409e565b601581526000602082017410dbdb9d1c9858dd1cc818d85b9b9bdd081b5a5b9d605a1b81529150613ed5565b6020808252810161073b81615096565b60208082527f4552433732313a206d696e7420746f20746865207a65726f206164647265737391019081526000613ed5565b6020808252810161073b816150d2565b602881526000602082017f455243373231723a206e65656420746f206d696e74206174206c65617374206f8152673732903a37b5b2b760c11b6020820152915061423c565b6020808252810161073b81615114565b602b81526000602082017f455243373231723a206d696e74696e67206d6f726520746f6b656e732074686181526a6e20617661696c61626c6560a81b6020820152915061423c565b6020808252810161073b81615169565b6000816151d0576151d0613e7d565b506000190190565b608081016151e682876138fa565b6151f360208301866138fa565b615200604083018561373d565b8181036060830152615212818461389f565b9695505050505050565b805161073b816137eb565b60006020828403121561523c5761523c600080fd5b6000612aca848461521c565b6101008101615257828b6138fa565b615264602083018a61373d565b615271604083018961373d565b61527e606083018861373d565b61528b608083018761373d565b61529860a083018661373d565b6152a560c08301856138fa565b6152b260e083018461373d565b9998505050505050505050565b6000826152ce576152ce6143ba565b50069056fe3c673e3c7265637420783d22302220793d223022207374796c653d2277696474683a313030253b6865696768743a31303025222066696c6c3d222364366464653422202f3e3c7376672077696474683d223132303022206865696768743d2231323030222073686170652d72656e646572696e673d22637269737045646765732220786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323030302f737667222076657273696f6e3d22312e32222076696577426f783d22302030203234203234223e3c7374796c653e726563747b77696474683a3170783b6865696768743a3170787d3c2f7374796c653ea26469706673582212207baedc415aa254266fecfa588ab3dde352ed81350e03a3d1376c12a45119b82364736f6c634300080f0033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

00000000000000000000000016f5a35647d6f03d5d3da7b35409d65ba03af3b2000000000000000000000000f03e345bb89dc9cfaf8fda381a9e4417bfb46e7a0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000004c00000000000000000000000000000000000000000000000000058d15e1762800000000000000000000000000000000000000000000000000000000000000003ba000000000000000000000000000000000000000000000000000000000000000d44656661756c742050756e6b7300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c44656661756c742050756e6b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000744454641554c5400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002f68747470733a2f2f63617073756c6532312e636f6d2f636f6c6c656374696f6e732f64656661756c742d70756e6b73000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002374f6e65206f662039353420746f6b656e7320696e207468652044656661756c742050756e6b7320636f6c6c656374696f6e2e205468697320504e47207761732067656e6572617465642062792072756e6e696e67207468652062656c6f77204a61766173637269707420636f6465207769746820746865206068746d6c602070726f706572747920696e2060746f6b656e555249602061732069747320696e7075742e0a0a6060606a6176617363726970740a2f2f205573652076657273696f6e2031372e312e330a636f6e737420707570706574656572203d2072657175697265282770757070657465657227293b0a0a636f6e7374206d61696e203d206173796e63202868746d6c2c206f75747075745061746829203d3e207b0a2020636f6e73742062726f77736572203d206177616974207075707065746565722e6c61756e6368287b686561646c6573733a20276368726f6d65277d293b0a2020636f6e73742070616765203d2061776169742062726f777365722e6e65775061676528293b0a0a2020617761697420706167652e73657456696577706f7274287b2077696474683a20313230302c206865696768743a2031323030207d293b0a0a2020617761697420706167652e736574436f6e74656e742868746d6c293b0a20200a2020617761697420706167652e73637265656e73686f74287b20706174683a206f757470757450617468207d293b0a202061776169742062726f777365722e636c6f736528293b0a7d0a0a6d61696e28290a606060000000000000000000000000000000000000000000000000000000000000000000000000000000005768747470733a2f2f6d6964646c656d617263682e6d7970696e6174612e636c6f75642f697066732f516d5463326a614b544e7a336745696e6b6856594a626537525a6653366276565a704a646f667954525a6e626b4a2f000000000000000000

-----Decoded View---------------
Arg [0] : punkDataContractAddress (address): 0x16F5A35647D6F03D5D3da7b35409D65ba03aF3B2
Arg [1] : extendedPunkDataContractAddress (address): 0xf03e345bB89Dc9cFaf8Fda381a9E4417BFB46e7A
Arg [2] : _config (tuple):
Arg [1] : isMintActive (bool): False
Arg [2] : contractSealed (bool): False
Arg [3] : name (string): Default Punks
Arg [4] : nameSingular (string): Default Punk
Arg [5] : symbol (string): DEFAULT
Arg [6] : externalLink (string): https://capsule21.com/collections/default-punks
Arg [7] : tokenDescription (string): One of 954 tokens in the Default Punks collection. This PNG was generated by running the below Javascript code with the `html` property in `tokenURI` as its input. ```javascript // Use version 17.1.3 const puppeteer = require('puppeteer'); const main = async (html, outputPath) => { const browser = await puppeteer.launch({headless: 'chrome'}); const page = await browser.newPage(); await page.setViewport({ width: 1200, height: 1200 }); await page.setContent(html); await page.screenshot({ path: outputPath }); await browser.close(); } main() ```
Arg [8] : baseImageUri (string): https://middlemarch.mypinata.cloud/ipfs/QmTc2jaKTNz3gEinkhVYJbe7RZfS6bvVZpJdofyTRZnbkJ/
Arg [9] : costPerToken (uint256): 25000000000000000
Arg [10] : maxSupply (uint64): 954


-----Encoded View---------------
45 Constructor Arguments found :
Arg [0] : 00000000000000000000000016f5a35647d6f03d5d3da7b35409d65ba03af3b2
Arg [1] : 000000000000000000000000f03e345bb89dc9cfaf8fda381a9e4417bfb46e7a
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000060
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000140
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000180
Arg [7] : 00000000000000000000000000000000000000000000000000000000000001c0
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000200
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000260
Arg [10] : 00000000000000000000000000000000000000000000000000000000000004c0
Arg [11] : 0000000000000000000000000000000000000000000000000058d15e17628000
Arg [12] : 00000000000000000000000000000000000000000000000000000000000003ba
Arg [13] : 000000000000000000000000000000000000000000000000000000000000000d
Arg [14] : 44656661756c742050756e6b7300000000000000000000000000000000000000
Arg [15] : 000000000000000000000000000000000000000000000000000000000000000c
Arg [16] : 44656661756c742050756e6b0000000000000000000000000000000000000000
Arg [17] : 0000000000000000000000000000000000000000000000000000000000000007
Arg [18] : 44454641554c5400000000000000000000000000000000000000000000000000
Arg [19] : 000000000000000000000000000000000000000000000000000000000000002f
Arg [20] : 68747470733a2f2f63617073756c6532312e636f6d2f636f6c6c656374696f6e
Arg [21] : 732f64656661756c742d70756e6b730000000000000000000000000000000000
Arg [22] : 0000000000000000000000000000000000000000000000000000000000000237
Arg [23] : 4f6e65206f662039353420746f6b656e7320696e207468652044656661756c74
Arg [24] : 2050756e6b7320636f6c6c656374696f6e2e205468697320504e472077617320
Arg [25] : 67656e6572617465642062792072756e6e696e67207468652062656c6f77204a
Arg [26] : 61766173637269707420636f6465207769746820746865206068746d6c602070
Arg [27] : 726f706572747920696e2060746f6b656e555249602061732069747320696e70
Arg [28] : 75742e0a0a6060606a6176617363726970740a2f2f205573652076657273696f
Arg [29] : 6e2031372e312e330a636f6e737420707570706574656572203d207265717569
Arg [30] : 7265282770757070657465657227293b0a0a636f6e7374206d61696e203d2061
Arg [31] : 73796e63202868746d6c2c206f75747075745061746829203d3e207b0a202063
Arg [32] : 6f6e73742062726f77736572203d206177616974207075707065746565722e6c
Arg [33] : 61756e6368287b686561646c6573733a20276368726f6d65277d293b0a202063
Arg [34] : 6f6e73742070616765203d2061776169742062726f777365722e6e6577506167
Arg [35] : 6528293b0a0a2020617761697420706167652e73657456696577706f7274287b
Arg [36] : 2077696474683a20313230302c206865696768743a2031323030207d293b0a0a
Arg [37] : 2020617761697420706167652e736574436f6e74656e742868746d6c293b0a20
Arg [38] : 200a2020617761697420706167652e73637265656e73686f74287b2070617468
Arg [39] : 3a206f757470757450617468207d293b0a202061776169742062726f77736572
Arg [40] : 2e636c6f736528293b0a7d0a0a6d61696e28290a606060000000000000000000
Arg [41] : 0000000000000000000000000000000000000000000000000000000000000057
Arg [42] : 68747470733a2f2f6d6964646c656d617263682e6d7970696e6174612e636c6f
Arg [43] : 75642f697066732f516d5463326a614b544e7a336745696e6b6856594a626537
Arg [44] : 525a6653366276565a704a646f667954525a6e626b4a2f000000000000000000


Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.