ETH Price: $3,374.11 (+5.73%)
Gas: 16 Gwei

Tamagogi Pets (TAMAGOGI)
 

Overview

TokenID

344

Total Transfers

-

Market

Onchain Market Cap

$0.00

Circulating Supply Market Cap

-
Loading...
Loading
Loading...
Loading
Loading...
Loading

OVERVIEW

First released by bandai in 1996, tamagotchi is the world's first virtual pet. In September 2022, we build tamagogi on the Ethereum blockchain as a tribute to bandai.

# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
Tamagogi

Compiler Version
v0.8.7+commit.e28d00a7

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 13 : tamagogi.sol
// SPDX-License-Identifier: MIT

//  ___             __  __  __   
//   |  /\ |\/| /\ / _ /  \/ _ | 
//   | /--\|  |/--\\__)\__/\__)| 
// 
//  Tamagogi is a fully onchain tamagotchi dapp.
//  https://tamagogi.xyz 

pragma solidity ^0.8.7;

import "https://github.com/RollaProject/solidity-datetime/blob/master/contracts/DateTimeContract.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "erc721a/contracts/ERC721A.sol";
import "base64-sol/base64.sol";
import "./tamagogi_drawer.sol";


contract Tamagogi is Ownable, ERC721A, ReentrancyGuard, TamagogiDrawer {
    struct TMGG {
        string name;
        uint lastFeed;
        uint lastPlay;
        uint lastHit;
        uint birthhash;
    }

    struct PetMdata {
        uint tokenId;
        uint seed;
        uint hunger;
        uint bored;
        uint unhappiness;
        bool isMaster;
        bool rerollable;
    }

    struct Config {
        uint price;
        uint propMaxSupply;
        uint petMaxSupply;
        uint[3] hungerRate;
        uint[3] boredRate;
        uint[3] hitRate;
        uint[3] hitRasing;
        uint[5] reactionRate;
        bool revealProp;
        bool revealPet;
        MintStage mintStage;
    }

    //@@@ enum
    enum MintStage {
        PAUSED,
        PROPS,
        PETS_MERKLE,
        PETS
    }

    //@@@ event
    event EPlay(
       uint tokenId,
       address sender
    );
    event EHit(
       uint tokenId,
       address sender
    );
    event EFeed(
       uint tokenId,
       address sender
    );

    constructor() ERC721A("Tamagogi Pets", "TAMAGOGI") {
        config.price = 0;
        config.propMaxSupply = 2000;
        config.petMaxSupply = 1825;
        config.mintStage = MintStage.PAUSED;
        config.hungerRate = [8,40,120];
        config.boredRate = [6,30,90];
        config.hitRate = [4,20,60];
        config.hitRasing = [9,3,1];
        config.reactionRate = [0,10,20,30,40];
        config.revealProp = false;
        config.revealPet = false;
    }
    
    DateTimeContract private dateTimeContract = new DateTimeContract();
    bytes32 public rootHash = 0x0;

    Config public config;

    mapping(uint => uint) public seeds;
    mapping(uint => TMGG) public TMGGs;
    mapping(uint => bool) public rerollTable;
    mapping(string => bool) public nameTable;
    mapping(address => bool) public propMinted;
    mapping(address => bool) public petMinted;

    uint private bornTimestamp = 1640995201;
    uint private bornIdx = 0;
    uint private airdropId = 1;
    uint public airdropProgress = 0;
    uint public airdropReceivers = 947;

    //@@@ modifier
    modifier validToken(uint tokenId) {
        require(tokenId >= _startTokenId() && tokenId <= _totalMinted(), "Not valid id");
        _;
    }

    modifier validOwner(uint tokenId) {
        require(ownerOf(tokenId) == msg.sender, "You are not token's owner");
        _;
    }

    modifier revealPetOnly() {
        require(config.revealPet, "Not reveal");
        _;
    }

    modifier petOnly(uint tokenId) {
        require(tokenId > config.propMaxSupply && tokenId <= config.petMaxSupply + config.propMaxSupply, "Not valid pet id");
        _;
    }

    //@@@ mint
    function _getProp(address _address, uint quantity) private {
        for (uint i = 0; i < quantity; i ++) {
            uint seed = _getRandom(airdropId);
            seeds[airdropId] = seed;
            airdropId++;
        }

        _safeMint(_address, quantity);
    }

    function airdrop(address[] calldata addresses, uint256[] calldata quantity) external onlyOwner {
        require(airdropProgress + addresses.length <= airdropReceivers, "Exceed the limit");
        for (uint i = 0; i < addresses.length; i ++) {
            _getProp(addresses[i], quantity[i]);
        }
        airdropProgress += addresses.length;
    }

    function hatchEgg() external payable {
        require(config.mintStage == MintStage.PETS, "Not in stage to mint TMGG");
        require(_totalMinted() < config.petMaxSupply + config.propMaxSupply, "No pet left");
        require(!petMinted[msg.sender], "Max to 1");
        require(1 * config.price <= msg.value,"No enough eth.");
        _hatchEgg();
    }

    function allowlistHatchEgg(bytes32[] calldata _proof) external payable {
        require(config.mintStage == MintStage.PETS_MERKLE, "Not in stage to mint merkle TMGG");
        require(_totalMinted() < config.petMaxSupply + config.propMaxSupply, "No pet left");
        require(!petMinted[msg.sender], "Max to 1");
        require(1 * config.price <= msg.value,"No enough eth.");

        bytes32 leaf = keccak256(abi.encodePacked(msg.sender));
        require(MerkleProof.verify(_proof, rootHash, leaf), "invalid proof");
        _hatchEgg();
    }

    function _hatchEgg() private {
        uint mintId = _startTokenId() + _totalMinted();
        if (bornIdx == 5) {
            bornIdx = 0;
            bornTimestamp = dateTimeContract.addDays(bornTimestamp, 1);
        }

        TMGG memory preBornTMGG = TMGG('', block.timestamp, block.timestamp, 0, bornTimestamp);
        TMGGs[mintId] = preBornTMGG;
        bornIdx++;
        
        uint seed = _getRandom(mintId);
        seeds[mintId] = seed;

        _safeMint(msg.sender, 1);
        petMinted[msg.sender] = true;
    }
    
    //@@@ pet function

    function setName(uint tokenId, string calldata name) external validOwner(tokenId) revealPetOnly() petOnly(tokenId) {
        require(nameTable[name] == false, "Name exist");

        uint nameLength = utfStringLength(name);

        require(nameLength > 1 && nameLength < 18, "Not valid name");
        TMGGs[tokenId].name = name;
        nameTable[name] = true;
    }

    // everyone can call these function to feed, hit or play with any pet
    function play(uint tokenId) external revealPetOnly() petOnly(tokenId) {
        TMGGs[tokenId].lastPlay = block.timestamp;
        emit EPlay(tokenId, msg.sender);
    }

    function feed(uint tokenId) external revealPetOnly() petOnly(tokenId) {
        TMGGs[tokenId].lastFeed = block.timestamp;
        emit EFeed(tokenId, msg.sender);
    }

    function hit(uint tokenId) external revealPetOnly() petOnly(tokenId) {
        TMGGs[tokenId].lastHit = block.timestamp;
        emit EHit(tokenId, msg.sender);
    }

    function reroll(uint tokenId) external validOwner(tokenId) revealPetOnly() petOnly(tokenId) {
        require(!rerollTable[tokenId], "Not available");
        seeds[tokenId] = _getRandom(tokenId);
        rerollTable[tokenId] = true;
    }
    
    function isBirthdate(uint tokenId) public view petOnly(tokenId) returns (bool) {
        TMGG memory tmgg = TMGGs[tokenId];
        uint _now = block.timestamp;
        
        uint seed = seeds[tokenId];
        uint offset = seed % 31536000;

        return dateTimeContract.getDay(_now) == dateTimeContract.getDay(tmgg.birthhash + offset) && dateTimeContract.getMonth(_now) == dateTimeContract.getMonth(tmgg.birthhash + offset);
    }

    function getBirthdate(uint tokenId) public view petOnly(tokenId) returns (uint month, uint day) {
        TMGG memory tmgg = TMGGs[tokenId];

        uint seed = seeds[tokenId];
        uint offset = seed % 31536000;

        uint _month = dateTimeContract.getMonth(tmgg.birthhash + offset);
        uint _day = dateTimeContract.getDay(tmgg.birthhash + offset);

        return (_month, _day);
    }

    function getPetUnhappinessAndProp(uint tokenId) public view revealPetOnly() petOnly(tokenId) returns(uint, bool, bool ,bool) {
        uint _now = block.timestamp;
        TMGG memory tmgg = TMGGs[tokenId];
        uint hunger = dateTimeContract.diffHours(tmgg.lastFeed, _now);
        uint bored = dateTimeContract.diffHours(tmgg.lastPlay, _now);
        uint _baseHit = tmgg.lastHit == 0 ? 0 : (_now - tmgg.lastHit) / 60;

        uint hitVal = 0;
        if (_baseHit <= config.hitRate[0]) {
            hitVal = _baseHit * config.hitRasing[0];
        } else if (_baseHit < config.hitRate[1]) {
            hitVal = _baseHit * config.hitRasing[1];
        } else if (_baseHit < config.hitRate[2]) {
            hitVal = _baseHit * config.hitRasing[2];
        } else {
            hitVal = _baseHit * 0;
        }

        uint[] memory ownerTokens = tokensOfOwner(ownerOf(tokenId));
        bool ownFood = false;
        bool ownToy = false;
        bool ownShield = false;

        for(uint i = 0; i < ownerTokens.length; i++) {
            uint id = ownerTokens[i];

            if (id <= config.propMaxSupply) {
                uint seed = seeds[id];
                uint propNumber = propOdds[seed % propOdds.length];

                if (propNumber == 0) { // own food
                    hunger = 0;
                    ownFood = true;
                } else if (propNumber == 1) { // own toy
                    bored = 0;
                    ownToy = true;
                } else if (propNumber == 2) { // own shiled
                    hitVal = 0;
                    ownShield = true;
                }
            }
        }

        uint _unhappiness = hunger + bored + hitVal;

        return (_unhappiness, ownFood, ownToy, ownShield);
    }

    function getPetHungerAndBored(uint tokenId) public view revealPetOnly() petOnly(tokenId) returns(uint, uint) {
        uint _now = block.timestamp;
        TMGG memory tmgg = TMGGs[tokenId];
        uint hunger = dateTimeContract.diffHours(tmgg.lastFeed, _now);
        uint bored = dateTimeContract.diffHours(tmgg.lastPlay, _now);

        uint[] memory ownerTokens = tokensOfOwner(ownerOf(tokenId));
        for(uint i = 0; i < ownerTokens.length; i++) {
            uint id = ownerTokens[i];

            if (id <= config.propMaxSupply) {
                uint seed = seeds[id];
                uint propNumber = propOdds[seed % propOdds.length];

                if (propNumber == 0) { // own food
                    hunger = 0;
                } else if (propNumber == 1) { // own toy
                    bored = 0;
                }
            }
        }

        return (hunger, bored);
    }

    function _getReactionTraitIndex(uint _unhappiness) private view returns (uint) {
        if (_unhappiness <= config.reactionRate[0]) {
            return reaction[3];
        } else if (_unhappiness < config.reactionRate[1]) {
            return reaction[0];
        } else if (_unhappiness < config.reactionRate[2]) {
            return reaction[1];
        } else if (_unhappiness < config.reactionRate[3]) {
            return reaction[2];
        } else {
            return reaction[4];
        }
    }

    function _getPetTraits(PetMdata memory petMeta) private pure returns (string memory) {
        string memory attr = string(abi.encodePacked(
            '{ "trait_type": "hunger", "display_type": "number", "value": ',Strings.toString(petMeta.hunger),'},',
            '{ "trait_type": "bored", "display_type": "number", "value": ',Strings.toString(petMeta.bored),'},'
        ));

        return attr;
    }

    function _getPetStyleTraits(PetMdata memory petMeta) private view returns (string memory) {
        string memory masterLabel = petMeta.isMaster ? "yes" : "no";
        string memory rerolled = petMeta.rerollable ? "yes" : "no";
        string memory attr = string(abi.encodePacked(
            '{ "trait_type": "type", "value": "pets"},',
            '{ "trait_type": "master", "value": "',masterLabel,'"},',
            '{ "trait_type": "rerolled", "value": "',rerolled,'"},',
            '{ "trait_type": "unhappiness", "display_type": "number", "value": ',Strings.toString(petMeta.unhappiness),'},',
            _getPetReactionTraits(petMeta),
            _getPetEarTraits(petMeta),
            _getPetHeadTraits(petMeta),
            _getPetBodyTraits(petMeta)
        ));

        return attr;
    }
    
    function _getPetReactionTraits(PetMdata memory petMeta) private view returns (string memory) {
        string memory attr = string(abi.encodePacked(
            '{ "trait_type": "reaction", "value": "',reactionTraits[_getReactionTraitIndex(petMeta.unhappiness)],'"},'
        ));

        return attr;
    }

    function _getPetEarTraits(PetMdata memory petMeta) private view returns (string memory) {
        string memory attr = string(abi.encodePacked(
            '{ "trait_type": "ear", "value": "',earTraits[ear[(petMeta.seed / 2) % ear.length]],'"},'
        ));

        return attr;
    }

    function _getPetHeadTraits(PetMdata memory petMeta) private view returns (string memory) {
        string memory attr = string(abi.encodePacked(
            '{ "trait_type": "head", "value": "',headTraits[head[(petMeta.seed / 3) % head.length]],'"},'
        ));

        return attr;
    }

    function _getPetBodyTraits(PetMdata memory petMeta) private view returns (string memory) {
        string memory attr = string(abi.encodePacked(
            '{ "trait_type": "body", "value": "',bodyTraits[body[(petMeta.seed / 4) % body.length]],'"},'
        ));

        return attr;
    }

    function _getPetsName(PetMdata memory petMeta) private view returns (string memory) {
        (uint month, uint day) = getBirthdate(petMeta.tokenId);
        TMGG memory tmgg = TMGGs[petMeta.tokenId];
        string memory name = utfStringLength(tmgg.name) > 1 ? string(abi.encodePacked(tmgg.name, " / ")) : "";

        return string(abi.encodePacked(
            '{"name": "',name,'#',Strings.toString(petMeta.tokenId),' Tamagogi (',Strings.toString(month),'/',Strings.toString(day),')','",'
        ));
    }

    function _getPetsBirthTrait(PetMdata memory petMeta) private view returns (string memory) {
        (uint month, uint day) = getBirthdate(petMeta.tokenId);

        return string(abi.encodePacked(
            '{ "trait_type": "birthdate", "value": "',Strings.toString(month),'/',Strings.toString(day),'"}'
        ));
    }

    function _getPetsMetadata(uint tokenId) private view returns (string memory) {
        (uint unhappiness, bool ownFood, bool ownToy, bool ownShield) = getPetUnhappinessAndProp(tokenId);
        (uint hunger, uint bored) = getPetHungerAndBored(tokenId);
        bool hbd = isBirthdate(tokenId);
        bool isMaster = ownFood && ownToy && ownShield || hbd ? true : false;
        uint reactionId = _getReactionTraitIndex(unhappiness);
        PetMdata memory petMeta = PetMdata(tokenId, seeds[tokenId], hunger, bored, unhappiness, isMaster, rerollTable[tokenId]);
        string memory _svgString = drawReveal(seeds[tokenId], reactionId, isMaster);

        string memory json = 
                string(
                    abi.encodePacked(
                        _getPetsName(petMeta),
                        '"description": "Tamagogi is a Tamagotchi Dapp and fully generated on-chain. The contract interaction and time will affect the status and reaction of the pet. If you collect other items, the pet will show love!",', 
                        '"attributes": [',
                            _getPetTraits(petMeta),
                            _getPetStyleTraits(petMeta),
                            _getPetsBirthTrait(petMeta),
                        '],'
                        '"image": "data:image/svg+xml;base64,', Base64.encode(bytes(drawSVG(_svgString))), '"}' 
                        )
                    );

        return Base64.encode(
            bytes(
                string(json)
                )
            );
    }

    function _getPetsUnrevealMetadata(uint tokenId) private view returns (string memory) {
        (uint month, uint day) = getBirthdate(tokenId);
        uint _seed = seeds[tokenId];

        string memory json = Base64.encode(
            bytes(
                string(
                    abi.encodePacked(
                        '{"name": "#',Strings.toString(tokenId),' Tamagogi Egg (',Strings.toString(month),'/',Strings.toString(day),')','", "description": "Unbroken Tamagogi eggs...",',
                        '"attributes": [',
                            '{ "trait_type": "type", "value": "pets"},',
                            '{ "trait_type": "birthdate", "value": "',Strings.toString(month),'/',Strings.toString(day),'"}',
                        '],',
                        '"image": "ipfs://QmW1tccYqBmSLQFTfN8rWw8JHXxx7hZS4MiiwWWDN5tvG8/',Strings.toString(eggs[_seed % eggs.length]),'.gif"}' 
                        )
                    )
                )
            );

        return json;
    }

    function _getPropsMetadata(uint tokenId) private view returns (string memory) {
        uint _seed = seeds[tokenId];
        uint _propIndex = propOdds[_seed % propOdds.length];
        string memory _desc = propDesc[_propIndex];
        string memory _traitName = propTraits[_propIndex];

        string memory json = Base64.encode(
            bytes(
                string(
                    abi.encodePacked(
                        '{"name": "#',Strings.toString(tokenId),' Tamagogi (',_traitName,')", "description": "',_desc,'",',
                        '"attributes": [',
                            '{ "trait_type": "type", "value": "props"},',
                            '{ "trait_type": "usage", "value": "',_traitName,'"}'
                        '],',
                        '"image": "ipfs://QmVxCDfmwgY2psAh7wti8aLCykkj99snygGQ89p2zkfAtf/',_traitName,'.gif"}' 
                    )
                )
            )
        );

        return json;
    }

    function _getPropsUnrevealMetadata(uint tokenId) private pure returns (string memory) {
        string memory json = Base64.encode(
            bytes(
                string(
                    abi.encodePacked(
                        '{"name": "#',Strings.toString(tokenId),' Tamagogi (Unreveal Props)", "description": "Unreveal Props",',
                        '"attributes": [',
                            '{ "trait_type": "type", "value": "props"}',
                        '],',
                        '"image": "ipfs://QmTbB6DD2w8t36zLPvBEdoWo62RFMyJi9EXcj99ZixPrxC"}' 
                    )
                )
            )
        );

        return json;
    }

    //@@@ override
    function _tokenURI(uint256 tokenId) private view validToken(tokenId) returns (string memory) {
        string memory json = tokenId <= config.propMaxSupply ? config.revealProp ? _getPropsMetadata(tokenId) : _getPropsUnrevealMetadata(tokenId) : config.revealPet ? _getPetsMetadata(tokenId) : _getPetsUnrevealMetadata(tokenId);

        return string(abi.encodePacked('data:application/json;base64,', json));
    }

    function tokenURI(uint256 tokenId) override (ERC721A) public view returns (string memory) {
        return _tokenURI(tokenId);
    }

    function _startTokenId() override internal pure virtual returns (uint256) {
        return 1;
    }

    //@@@ admin

    function setMintStage(uint _stage) external onlyOwner {
        config.mintStage = MintStage(_stage);
    }
    function setHungerRate(uint[3] calldata _rate) external onlyOwner {
        config.hungerRate = _rate;
    }
    function setBoredRate(uint[3] calldata _rate) external onlyOwner {
        config.boredRate = _rate;
    }
    function setHitRate(uint[3] calldata _rate) external onlyOwner {
        config.hitRate = _rate;
    }
    function setReactionRate(uint[5] calldata _rate) external onlyOwner {
        config.reactionRate = _rate;
    }
    function setHitRasing(uint[3] calldata _rate) external onlyOwner {
        config.hitRasing = _rate;
    }
    function setRevealPet() external onlyOwner {
        config.revealPet = true;
    }
    function setRevealProp() external onlyOwner {
        config.revealProp = true;
    }
    function setPrice(uint _price) external onlyOwner {
        config.price = _price;
    }
    function setMerkle(bytes32 _hash) external onlyOwner {
        rootHash = _hash;
    }

    //@@@ others

    // ERC721AQueryable.sol
    function tokensOfOwner(address owner) public view virtual returns (uint256[] memory) {
        unchecked {
            uint256 tokenIdsIdx;
            address currOwnershipAddr;
            uint256 tokenIdsLength = balanceOf(owner);
            uint256[] memory tokenIds = new uint256[](tokenIdsLength);
            TokenOwnership memory ownership;
            for (uint256 i = _startTokenId(); tokenIdsIdx != tokenIdsLength; ++i) {
                ownership = _ownershipAt(i);
                if (ownership.burned) {
                    continue;
                }
                if (ownership.addr != address(0)) {
                    currOwnershipAddr = ownership.addr;
                }
                if (currOwnershipAddr == owner) {
                    tokenIds[tokenIdsIdx++] = i;
                }
            }
            return tokenIds;
        }
    }

    // https://ethereum.stackexchange.com/questions/13862/is-it-possible-to-check-string-variables-length-inside-the-contract
    function utfStringLength(string memory str) pure internal returns (uint length) {
        uint i=0;
        bytes memory string_rep = bytes(str);

        while (i<string_rep.length)
        {
            if (string_rep[i]>>7==0)
                i+=1;
            else if (string_rep[i]>>5==bytes1(uint8(0x6)))
                i+=2;
            else if (string_rep[i]>>4==bytes1(uint8(0xE)))
                i+=3;
            else if (string_rep[i]>>3==bytes1(uint8(0x1E)))
                i+=4;
            else
                //For safety
                i+=1;

            length++;
        }
    }
    
    function _getRandom(uint tokenId) private view returns (uint) {
        uint randomlize = uint(keccak256(abi.encodePacked(blockhash(block.number - 1), tokenId, msg.sender)));
        return randomlize;
    }
}

File 2 of 13 : tamagogi_drawer.sol
pragma solidity ^0.8.7;
import "base64-sol/base64.sol";
import "./tamagogi_data.sol";
// SPDX-License-Identifier: MIT

contract TamagogiDrawer is TamagogiData {
    function drawImage(bytes memory trait) private pure returns (string memory) {
      return string(abi.encodePacked(
        '<image x="0" y="0" width="32" height="32" image-rendering="pixelated" preserveAspectRatio="xMidYMid" xlink:href="data:image/png;base64,',Base64.encode(bytes(trait)),'"/>'
      ));
    }

    function drawReveal(uint seed, uint reactionId, bool isMaster) internal view returns (string memory) {
        bytes memory bodyImageData = bodyBytes[(seed / 4) % body.length];
        bytes memory headImageData = headBytes[(seed / 3) % head.length];
        bytes memory earImageData = earBytes[(seed / 2) % ear.length];
        bytes memory reactionImageData = reactionBytes[reactionId];

        string memory imgString = string(abi.encodePacked(
            drawImage(bodyImageData),
            drawImage(headImageData),
            drawImage(reactionImageData),
            drawImage(earImageData)
          ));

        if (isMaster) { //master
          imgString = string(abi.encodePacked(
              imgString,
              drawImage(masterBytes[0])
          ));
        }

        return imgString;
    }

    function drawSVG(string memory svgString) internal pure returns (string memory) {
        return string(abi.encodePacked(
          '<svg width="960" height="960" version="1.1" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">',
          '<rect width="100%" height="100%" fill="#aad999" />',
          svgString,
          "</svg>"
        ));
    }
}

File 3 of 13 : base64.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0;

/// @title Base64
/// @author Brecht Devos - <[email protected]>
/// @notice Provides functions for encoding/decoding base64
library Base64 {
    string internal constant TABLE_ENCODE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
    bytes  internal constant TABLE_DECODE = hex"0000000000000000000000000000000000000000000000000000000000000000"
                                            hex"00000000000000000000003e0000003f3435363738393a3b3c3d000000000000"
                                            hex"00000102030405060708090a0b0c0d0e0f101112131415161718190000000000"
                                            hex"001a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132330000000000";

    function encode(bytes memory data) internal pure returns (string memory) {
        if (data.length == 0) return '';

        // load the table into memory
        string memory table = TABLE_ENCODE;

        // multiply by 4/3 rounded up
        uint256 encodedLen = 4 * ((data.length + 2) / 3);

        // add some extra buffer at the end required for the writing
        string memory result = new string(encodedLen + 32);

        assembly {
            // set the actual output length
            mstore(result, encodedLen)

            // prepare the lookup table
            let tablePtr := add(table, 1)

            // input ptr
            let dataPtr := data
            let endPtr := add(dataPtr, mload(data))

            // result ptr, jump over length
            let resultPtr := add(result, 32)

            // run over the input, 3 bytes at a time
            for {} lt(dataPtr, endPtr) {}
            {
                // read 3 bytes
                dataPtr := add(dataPtr, 3)
                let input := mload(dataPtr)

                // write 4 characters
                mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F))))
                resultPtr := add(resultPtr, 1)
                mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F))))
                resultPtr := add(resultPtr, 1)
                mstore8(resultPtr, mload(add(tablePtr, and(shr( 6, input), 0x3F))))
                resultPtr := add(resultPtr, 1)
                mstore8(resultPtr, mload(add(tablePtr, and(        input,  0x3F))))
                resultPtr := add(resultPtr, 1)
            }

            // padding with '='
            switch mod(mload(data), 3)
            case 1 { mstore(sub(resultPtr, 2), shl(240, 0x3d3d)) }
            case 2 { mstore(sub(resultPtr, 1), shl(248, 0x3d)) }
        }

        return result;
    }

    function decode(string memory _data) internal pure returns (bytes memory) {
        bytes memory data = bytes(_data);

        if (data.length == 0) return new bytes(0);
        require(data.length % 4 == 0, "invalid base64 decoder input");

        // load the table into memory
        bytes memory table = TABLE_DECODE;

        // every 4 characters represent 3 bytes
        uint256 decodedLen = (data.length / 4) * 3;

        // add some extra buffer at the end required for the writing
        bytes memory result = new bytes(decodedLen + 32);

        assembly {
            // padding with '='
            let lastBytes := mload(add(data, mload(data)))
            if eq(and(lastBytes, 0xFF), 0x3d) {
                decodedLen := sub(decodedLen, 1)
                if eq(and(lastBytes, 0xFFFF), 0x3d3d) {
                    decodedLen := sub(decodedLen, 1)
                }
            }

            // set the actual output length
            mstore(result, decodedLen)

            // prepare the lookup table
            let tablePtr := add(table, 1)

            // input ptr
            let dataPtr := data
            let endPtr := add(dataPtr, mload(data))

            // result ptr, jump over length
            let resultPtr := add(result, 32)

            // run over the input, 4 characters at a time
            for {} lt(dataPtr, endPtr) {}
            {
               // read 4 characters
               dataPtr := add(dataPtr, 4)
               let input := mload(dataPtr)

               // write 3 bytes
               let output := add(
                   add(
                       shl(18, and(mload(add(tablePtr, and(shr(24, input), 0xFF))), 0xFF)),
                       shl(12, and(mload(add(tablePtr, and(shr(16, input), 0xFF))), 0xFF))),
                   add(
                       shl( 6, and(mload(add(tablePtr, and(shr( 8, input), 0xFF))), 0xFF)),
                               and(mload(add(tablePtr, and(        input , 0xFF))), 0xFF)
                    )
                )
                mstore(resultPtr, shl(232, output))
                resultPtr := add(resultPtr, 3)
            }
        }

        return result;
    }
}

File 4 of 13 : ERC721A.sol
// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.2.2
// Creator: Chiru Labs

pragma solidity ^0.8.4;

import './IERC721A.sol';

/**
 * @dev Interface of ERC721 token receiver.
 */
interface ERC721A__IERC721Receiver {
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}

/**
 * @title ERC721A
 *
 * @dev Implementation of the [ERC721](https://eips.ethereum.org/EIPS/eip-721)
 * Non-Fungible Token Standard, including the Metadata extension.
 * Optimized for lower gas during batch mints.
 *
 * Token IDs are minted in sequential order (e.g. 0, 1, 2, 3, ...)
 * starting from `_startTokenId()`.
 *
 * Assumptions:
 *
 * - An owner cannot have more than 2**64 - 1 (max value of uint64) of supply.
 * - The maximum token ID cannot exceed 2**256 - 1 (max value of uint256).
 */
contract ERC721A is IERC721A {
    // Reference type for token approval.
    struct TokenApprovalRef {
        address value;
    }

    // =============================================================
    //                           CONSTANTS
    // =============================================================

    // Mask of an entry in packed address data.
    uint256 private constant _BITMASK_ADDRESS_DATA_ENTRY = (1 << 64) - 1;

    // The bit position of `numberMinted` in packed address data.
    uint256 private constant _BITPOS_NUMBER_MINTED = 64;

    // The bit position of `numberBurned` in packed address data.
    uint256 private constant _BITPOS_NUMBER_BURNED = 128;

    // The bit position of `aux` in packed address data.
    uint256 private constant _BITPOS_AUX = 192;

    // Mask of all 256 bits in packed address data except the 64 bits for `aux`.
    uint256 private constant _BITMASK_AUX_COMPLEMENT = (1 << 192) - 1;

    // The bit position of `startTimestamp` in packed ownership.
    uint256 private constant _BITPOS_START_TIMESTAMP = 160;

    // The bit mask of the `burned` bit in packed ownership.
    uint256 private constant _BITMASK_BURNED = 1 << 224;

    // The bit position of the `nextInitialized` bit in packed ownership.
    uint256 private constant _BITPOS_NEXT_INITIALIZED = 225;

    // The bit mask of the `nextInitialized` bit in packed ownership.
    uint256 private constant _BITMASK_NEXT_INITIALIZED = 1 << 225;

    // The bit position of `extraData` in packed ownership.
    uint256 private constant _BITPOS_EXTRA_DATA = 232;

    // Mask of all 256 bits in a packed ownership except the 24 bits for `extraData`.
    uint256 private constant _BITMASK_EXTRA_DATA_COMPLEMENT = (1 << 232) - 1;

    // The mask of the lower 160 bits for addresses.
    uint256 private constant _BITMASK_ADDRESS = (1 << 160) - 1;

    // The maximum `quantity` that can be minted with {_mintERC2309}.
    // This limit is to prevent overflows on the address data entries.
    // For a limit of 5000, a total of 3.689e15 calls to {_mintERC2309}
    // is required to cause an overflow, which is unrealistic.
    uint256 private constant _MAX_MINT_ERC2309_QUANTITY_LIMIT = 5000;

    // The `Transfer` event signature is given by:
    // `keccak256(bytes("Transfer(address,address,uint256)"))`.
    bytes32 private constant _TRANSFER_EVENT_SIGNATURE =
        0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;

    // =============================================================
    //                            STORAGE
    // =============================================================

    // The next token ID to be minted.
    uint256 private _currentIndex;

    // The number of tokens burned.
    uint256 private _burnCounter;

    // Token name
    string private _name;

    // Token symbol
    string private _symbol;

    // Mapping from token ID to ownership details
    // An empty struct value does not necessarily mean the token is unowned.
    // See {_packedOwnershipOf} implementation for details.
    //
    // Bits Layout:
    // - [0..159]   `addr`
    // - [160..223] `startTimestamp`
    // - [224]      `burned`
    // - [225]      `nextInitialized`
    // - [232..255] `extraData`
    mapping(uint256 => uint256) private _packedOwnerships;

    // Mapping owner address to address data.
    //
    // Bits Layout:
    // - [0..63]    `balance`
    // - [64..127]  `numberMinted`
    // - [128..191] `numberBurned`
    // - [192..255] `aux`
    mapping(address => uint256) private _packedAddressData;

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

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

    // =============================================================
    //                          CONSTRUCTOR
    // =============================================================

    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
        _currentIndex = _startTokenId();
    }

    // =============================================================
    //                   TOKEN COUNTING OPERATIONS
    // =============================================================

    /**
     * @dev Returns the starting token ID.
     * To change the starting token ID, please override this function.
     */
    function _startTokenId() internal view virtual returns (uint256) {
        return 0;
    }

    /**
     * @dev Returns the next token ID to be minted.
     */
    function _nextTokenId() internal view virtual returns (uint256) {
        return _currentIndex;
    }

    /**
     * @dev Returns the total number of tokens in existence.
     * Burned tokens will reduce the count.
     * To get the total number of tokens minted, please see {_totalMinted}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        // Counter underflow is impossible as _burnCounter cannot be incremented
        // more than `_currentIndex - _startTokenId()` times.
        unchecked {
            return _currentIndex - _burnCounter - _startTokenId();
        }
    }

    /**
     * @dev Returns the total amount of tokens minted in the contract.
     */
    function _totalMinted() internal view virtual returns (uint256) {
        // Counter underflow is impossible as `_currentIndex` does not decrement,
        // and it is initialized to `_startTokenId()`.
        unchecked {
            return _currentIndex - _startTokenId();
        }
    }

    /**
     * @dev Returns the total number of tokens burned.
     */
    function _totalBurned() internal view virtual returns (uint256) {
        return _burnCounter;
    }

    // =============================================================
    //                    ADDRESS DATA OPERATIONS
    // =============================================================

    /**
     * @dev Returns the number of tokens in `owner`'s account.
     */
    function balanceOf(address owner) public view virtual override returns (uint256) {
        if (owner == address(0)) revert BalanceQueryForZeroAddress();
        return _packedAddressData[owner] & _BITMASK_ADDRESS_DATA_ENTRY;
    }

    /**
     * Returns the number of tokens minted by `owner`.
     */
    function _numberMinted(address owner) internal view returns (uint256) {
        return (_packedAddressData[owner] >> _BITPOS_NUMBER_MINTED) & _BITMASK_ADDRESS_DATA_ENTRY;
    }

    /**
     * Returns the number of tokens burned by or on behalf of `owner`.
     */
    function _numberBurned(address owner) internal view returns (uint256) {
        return (_packedAddressData[owner] >> _BITPOS_NUMBER_BURNED) & _BITMASK_ADDRESS_DATA_ENTRY;
    }

    /**
     * Returns the auxiliary data for `owner`. (e.g. number of whitelist mint slots used).
     */
    function _getAux(address owner) internal view returns (uint64) {
        return uint64(_packedAddressData[owner] >> _BITPOS_AUX);
    }

    /**
     * Sets the auxiliary data for `owner`. (e.g. number of whitelist mint slots used).
     * If there are multiple variables, please pack them into a uint64.
     */
    function _setAux(address owner, uint64 aux) internal virtual {
        uint256 packed = _packedAddressData[owner];
        uint256 auxCasted;
        // Cast `aux` with assembly to avoid redundant masking.
        assembly {
            auxCasted := aux
        }
        packed = (packed & _BITMASK_AUX_COMPLEMENT) | (auxCasted << _BITPOS_AUX);
        _packedAddressData[owner] = packed;
    }

    // =============================================================
    //                            IERC165
    // =============================================================

    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30000 gas.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        // The interface IDs are constants representing the first 4 bytes
        // of the XOR of all function selectors in the interface.
        // See: [ERC165](https://eips.ethereum.org/EIPS/eip-165)
        // (e.g. `bytes4(i.functionA.selector ^ i.functionB.selector ^ ...)`)
        return
            interfaceId == 0x01ffc9a7 || // ERC165 interface ID for ERC165.
            interfaceId == 0x80ac58cd || // ERC165 interface ID for ERC721.
            interfaceId == 0x5b5e139f; // ERC165 interface ID for ERC721Metadata.
    }

    // =============================================================
    //                        IERC721Metadata
    // =============================================================

    /**
     * @dev Returns the token collection name.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the token collection symbol.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
     */
    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        if (!_exists(tokenId)) revert URIQueryForNonexistentToken();

        string memory baseURI = _baseURI();
        return bytes(baseURI).length != 0 ? string(abi.encodePacked(baseURI, _toString(tokenId))) : '';
    }

    /**
     * @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, it can be overridden in child contracts.
     */
    function _baseURI() internal view virtual returns (string memory) {
        return '';
    }

    // =============================================================
    //                     OWNERSHIPS OPERATIONS
    // =============================================================

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) public view virtual override returns (address) {
        return address(uint160(_packedOwnershipOf(tokenId)));
    }

    /**
     * @dev Gas spent here starts off proportional to the maximum mint batch size.
     * It gradually moves to O(1) as tokens get transferred around over time.
     */
    function _ownershipOf(uint256 tokenId) internal view virtual returns (TokenOwnership memory) {
        return _unpackedOwnership(_packedOwnershipOf(tokenId));
    }

    /**
     * @dev Returns the unpacked `TokenOwnership` struct at `index`.
     */
    function _ownershipAt(uint256 index) internal view virtual returns (TokenOwnership memory) {
        return _unpackedOwnership(_packedOwnerships[index]);
    }

    /**
     * @dev Initializes the ownership slot minted at `index` for efficiency purposes.
     */
    function _initializeOwnershipAt(uint256 index) internal virtual {
        if (_packedOwnerships[index] == 0) {
            _packedOwnerships[index] = _packedOwnershipOf(index);
        }
    }

    /**
     * Returns the packed ownership data of `tokenId`.
     */
    function _packedOwnershipOf(uint256 tokenId) private view returns (uint256) {
        uint256 curr = tokenId;

        unchecked {
            if (_startTokenId() <= curr)
                if (curr < _currentIndex) {
                    uint256 packed = _packedOwnerships[curr];
                    // If not burned.
                    if (packed & _BITMASK_BURNED == 0) {
                        // Invariant:
                        // There will always be an initialized ownership slot
                        // (i.e. `ownership.addr != address(0) && ownership.burned == false`)
                        // before an unintialized ownership slot
                        // (i.e. `ownership.addr == address(0) && ownership.burned == false`)
                        // Hence, `curr` will not underflow.
                        //
                        // We can directly compare the packed value.
                        // If the address is zero, packed will be zero.
                        while (packed == 0) {
                            packed = _packedOwnerships[--curr];
                        }
                        return packed;
                    }
                }
        }
        revert OwnerQueryForNonexistentToken();
    }

    /**
     * @dev Returns the unpacked `TokenOwnership` struct from `packed`.
     */
    function _unpackedOwnership(uint256 packed) private pure returns (TokenOwnership memory ownership) {
        ownership.addr = address(uint160(packed));
        ownership.startTimestamp = uint64(packed >> _BITPOS_START_TIMESTAMP);
        ownership.burned = packed & _BITMASK_BURNED != 0;
        ownership.extraData = uint24(packed >> _BITPOS_EXTRA_DATA);
    }

    /**
     * @dev Packs ownership data into a single uint256.
     */
    function _packOwnershipData(address owner, uint256 flags) private view returns (uint256 result) {
        assembly {
            // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean.
            owner := and(owner, _BITMASK_ADDRESS)
            // `owner | (block.timestamp << _BITPOS_START_TIMESTAMP) | flags`.
            result := or(owner, or(shl(_BITPOS_START_TIMESTAMP, timestamp()), flags))
        }
    }

    /**
     * @dev Returns the `nextInitialized` flag set if `quantity` equals 1.
     */
    function _nextInitializedFlag(uint256 quantity) private pure returns (uint256 result) {
        // For branchless setting of the `nextInitialized` flag.
        assembly {
            // `(quantity == 1) << _BITPOS_NEXT_INITIALIZED`.
            result := shl(_BITPOS_NEXT_INITIALIZED, eq(quantity, 1))
        }
    }

    // =============================================================
    //                      APPROVAL OPERATIONS
    // =============================================================

    /**
     * @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) public virtual override {
        address owner = ownerOf(tokenId);

        if (_msgSenderERC721A() != owner)
            if (!isApprovedForAll(owner, _msgSenderERC721A())) {
                revert ApprovalCallerNotOwnerNorApproved();
            }

        _tokenApprovals[tokenId].value = to;
        emit Approval(owner, to, tokenId);
    }

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) public view virtual override returns (address) {
        if (!_exists(tokenId)) revert ApprovalQueryForNonexistentToken();

        return _tokenApprovals[tokenId].value;
    }

    /**
     * @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) public virtual override {
        if (operator == _msgSenderERC721A()) revert ApproveToCaller();

        _operatorApprovals[_msgSenderERC721A()][operator] = approved;
        emit ApprovalForAll(_msgSenderERC721A(), operator, approved);
    }

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

    /**
     * @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. See {_mint}.
     */
    function _exists(uint256 tokenId) internal view virtual returns (bool) {
        return
            _startTokenId() <= tokenId &&
            tokenId < _currentIndex && // If within bounds,
            _packedOwnerships[tokenId] & _BITMASK_BURNED == 0; // and not burned.
    }

    /**
     * @dev Returns whether `msgSender` is equal to `approvedAddress` or `owner`.
     */
    function _isSenderApprovedOrOwner(
        address approvedAddress,
        address owner,
        address msgSender
    ) private pure returns (bool result) {
        assembly {
            // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean.
            owner := and(owner, _BITMASK_ADDRESS)
            // Mask `msgSender` to the lower 160 bits, in case the upper bits somehow aren't clean.
            msgSender := and(msgSender, _BITMASK_ADDRESS)
            // `msgSender == owner || msgSender == approvedAddress`.
            result := or(eq(msgSender, owner), eq(msgSender, approvedAddress))
        }
    }

    /**
     * @dev Returns the storage slot and value for the approved address of `tokenId`.
     */
    function _getApprovedSlotAndAddress(uint256 tokenId)
        private
        view
        returns (uint256 approvedAddressSlot, address approvedAddress)
    {
        TokenApprovalRef storage tokenApproval = _tokenApprovals[tokenId];
        // The following is equivalent to `approvedAddress = _tokenApprovals[tokenId]`.
        assembly {
            approvedAddressSlot := tokenApproval.slot
            approvedAddress := sload(approvedAddressSlot)
        }
    }

    // =============================================================
    //                      TRANSFER OPERATIONS
    // =============================================================

    /**
     * @dev Transfers `tokenId` from `from` to `to`.
     *
     * 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
    ) public virtual override {
        uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);

        if (address(uint160(prevOwnershipPacked)) != from) revert TransferFromIncorrectOwner();

        (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);

        // The nested ifs save around 20+ gas over a compound boolean condition.
        if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))
            if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved();

        if (to == address(0)) revert TransferToZeroAddress();

        _beforeTokenTransfers(from, to, tokenId, 1);

        // Clear approvals from the previous owner.
        assembly {
            if approvedAddress {
                // This is equivalent to `delete _tokenApprovals[tokenId]`.
                sstore(approvedAddressSlot, 0)
            }
        }

        // Underflow of the sender's balance is impossible because we check for
        // ownership above and the recipient's balance can't realistically overflow.
        // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256.
        unchecked {
            // We can directly increment and decrement the balances.
            --_packedAddressData[from]; // Updates: `balance -= 1`.
            ++_packedAddressData[to]; // Updates: `balance += 1`.

            // Updates:
            // - `address` to the next owner.
            // - `startTimestamp` to the timestamp of transfering.
            // - `burned` to `false`.
            // - `nextInitialized` to `true`.
            _packedOwnerships[tokenId] = _packOwnershipData(
                to,
                _BITMASK_NEXT_INITIALIZED | _nextExtraData(from, to, prevOwnershipPacked)
            );

            // If the next slot may not have been initialized (i.e. `nextInitialized == false`) .
            if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
                uint256 nextTokenId = tokenId + 1;
                // If the next slot's address is zero and not burned (i.e. packed value is zero).
                if (_packedOwnerships[nextTokenId] == 0) {
                    // If the next slot is within bounds.
                    if (nextTokenId != _currentIndex) {
                        // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`.
                        _packedOwnerships[nextTokenId] = prevOwnershipPacked;
                    }
                }
            }
        }

        emit Transfer(from, to, tokenId);
        _afterTokenTransfers(from, to, tokenId, 1);
    }

    /**
     * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {
        safeTransferFrom(from, to, tokenId, '');
    }

    /**
     * @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 memory _data
    ) public virtual override {
        transferFrom(from, to, tokenId);
        if (to.code.length != 0)
            if (!_checkContractOnERC721Received(from, to, tokenId, _data)) {
                revert TransferToNonERC721ReceiverImplementer();
            }
    }

    /**
     * @dev Hook that is called before a set of serially-ordered token IDs
     * are about to be transferred. This includes minting.
     * And also called before burning one token.
     *
     * `startTokenId` - the first token ID to be transferred.
     * `quantity` - the amount to be transferred.
     *
     * 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, `tokenId` will be burned by `from`.
     * - `from` and `to` are never both zero.
     */
    function _beforeTokenTransfers(
        address from,
        address to,
        uint256 startTokenId,
        uint256 quantity
    ) internal virtual {}

    /**
     * @dev Hook that is called after a set of serially-ordered token IDs
     * have been transferred. This includes minting.
     * And also called after one token has been burned.
     *
     * `startTokenId` - the first token ID to be transferred.
     * `quantity` - the amount to be transferred.
     *
     * Calling conditions:
     *
     * - When `from` and `to` are both non-zero, `from`'s `tokenId` has been
     * transferred to `to`.
     * - When `from` is zero, `tokenId` has been minted for `to`.
     * - When `to` is zero, `tokenId` has been burned by `from`.
     * - `from` and `to` are never both zero.
     */
    function _afterTokenTransfers(
        address from,
        address to,
        uint256 startTokenId,
        uint256 quantity
    ) internal virtual {}

    /**
     * @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target contract.
     *
     * `from` - Previous owner of the given token ID.
     * `to` - Target address that will receive the token.
     * `tokenId` - Token ID to be transferred.
     * `_data` - Optional data to send along with the call.
     *
     * Returns whether the call correctly returned the expected magic value.
     */
    function _checkContractOnERC721Received(
        address from,
        address to,
        uint256 tokenId,
        bytes memory _data
    ) private returns (bool) {
        try ERC721A__IERC721Receiver(to).onERC721Received(_msgSenderERC721A(), from, tokenId, _data) returns (
            bytes4 retval
        ) {
            return retval == ERC721A__IERC721Receiver(to).onERC721Received.selector;
        } catch (bytes memory reason) {
            if (reason.length == 0) {
                revert TransferToNonERC721ReceiverImplementer();
            } else {
                assembly {
                    revert(add(32, reason), mload(reason))
                }
            }
        }
    }

    // =============================================================
    //                        MINT OPERATIONS
    // =============================================================

    /**
     * @dev Mints `quantity` tokens and transfers them to `to`.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `quantity` must be greater than 0.
     *
     * Emits a {Transfer} event for each mint.
     */
    function _mint(address to, uint256 quantity) internal virtual {
        uint256 startTokenId = _currentIndex;
        if (quantity == 0) revert MintZeroQuantity();

        _beforeTokenTransfers(address(0), to, startTokenId, quantity);

        // Overflows are incredibly unrealistic.
        // `balance` and `numberMinted` have a maximum limit of 2**64.
        // `tokenId` has a maximum limit of 2**256.
        unchecked {
            // Updates:
            // - `balance += quantity`.
            // - `numberMinted += quantity`.
            //
            // We can directly add to the `balance` and `numberMinted`.
            _packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);

            // Updates:
            // - `address` to the owner.
            // - `startTimestamp` to the timestamp of minting.
            // - `burned` to `false`.
            // - `nextInitialized` to `quantity == 1`.
            _packedOwnerships[startTokenId] = _packOwnershipData(
                to,
                _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)
            );

            uint256 toMasked;
            uint256 end = startTokenId + quantity;

            // Use assembly to loop and emit the `Transfer` event for gas savings.
            assembly {
                // Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean.
                toMasked := and(to, _BITMASK_ADDRESS)
                // Emit the `Transfer` event.
                log4(
                    0, // Start of data (0, since no data).
                    0, // End of data (0, since no data).
                    _TRANSFER_EVENT_SIGNATURE, // Signature.
                    0, // `address(0)`.
                    toMasked, // `to`.
                    startTokenId // `tokenId`.
                )

                for {
                    let tokenId := add(startTokenId, 1)
                } iszero(eq(tokenId, end)) {
                    tokenId := add(tokenId, 1)
                } {
                    // Emit the `Transfer` event. Similar to above.
                    log4(0, 0, _TRANSFER_EVENT_SIGNATURE, 0, toMasked, tokenId)
                }
            }
            if (toMasked == 0) revert MintToZeroAddress();

            _currentIndex = end;
        }
        _afterTokenTransfers(address(0), to, startTokenId, quantity);
    }

    /**
     * @dev Mints `quantity` tokens and transfers them to `to`.
     *
     * This function is intended for efficient minting only during contract creation.
     *
     * It emits only one {ConsecutiveTransfer} as defined in
     * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309),
     * instead of a sequence of {Transfer} event(s).
     *
     * Calling this function outside of contract creation WILL make your contract
     * non-compliant with the ERC721 standard.
     * For full ERC721 compliance, substituting ERC721 {Transfer} event(s) with the ERC2309
     * {ConsecutiveTransfer} event is only permissible during contract creation.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `quantity` must be greater than 0.
     *
     * Emits a {ConsecutiveTransfer} event.
     */
    function _mintERC2309(address to, uint256 quantity) internal virtual {
        uint256 startTokenId = _currentIndex;
        if (to == address(0)) revert MintToZeroAddress();
        if (quantity == 0) revert MintZeroQuantity();
        if (quantity > _MAX_MINT_ERC2309_QUANTITY_LIMIT) revert MintERC2309QuantityExceedsLimit();

        _beforeTokenTransfers(address(0), to, startTokenId, quantity);

        // Overflows are unrealistic due to the above check for `quantity` to be below the limit.
        unchecked {
            // Updates:
            // - `balance += quantity`.
            // - `numberMinted += quantity`.
            //
            // We can directly add to the `balance` and `numberMinted`.
            _packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);

            // Updates:
            // - `address` to the owner.
            // - `startTimestamp` to the timestamp of minting.
            // - `burned` to `false`.
            // - `nextInitialized` to `quantity == 1`.
            _packedOwnerships[startTokenId] = _packOwnershipData(
                to,
                _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)
            );

            emit ConsecutiveTransfer(startTokenId, startTokenId + quantity - 1, address(0), to);

            _currentIndex = startTokenId + quantity;
        }
        _afterTokenTransfers(address(0), to, startTokenId, quantity);
    }

    /**
     * @dev Safely mints `quantity` tokens and transfers them to `to`.
     *
     * Requirements:
     *
     * - If `to` refers to a smart contract, it must implement
     * {IERC721Receiver-onERC721Received}, which is called for each safe transfer.
     * - `quantity` must be greater than 0.
     *
     * See {_mint}.
     *
     * Emits a {Transfer} event for each mint.
     */
    function _safeMint(
        address to,
        uint256 quantity,
        bytes memory _data
    ) internal virtual {
        _mint(to, quantity);

        unchecked {
            if (to.code.length != 0) {
                uint256 end = _currentIndex;
                uint256 index = end - quantity;
                do {
                    if (!_checkContractOnERC721Received(address(0), to, index++, _data)) {
                        revert TransferToNonERC721ReceiverImplementer();
                    }
                } while (index < end);
                // Reentrancy protection.
                if (_currentIndex != end) revert();
            }
        }
    }

    /**
     * @dev Equivalent to `_safeMint(to, quantity, '')`.
     */
    function _safeMint(address to, uint256 quantity) internal virtual {
        _safeMint(to, quantity, '');
    }

    // =============================================================
    //                        BURN OPERATIONS
    // =============================================================

    /**
     * @dev Equivalent to `_burn(tokenId, false)`.
     */
    function _burn(uint256 tokenId) internal virtual {
        _burn(tokenId, false);
    }

    /**
     * @dev Destroys `tokenId`.
     * The approval is cleared when the token is burned.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     *
     * Emits a {Transfer} event.
     */
    function _burn(uint256 tokenId, bool approvalCheck) internal virtual {
        uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);

        address from = address(uint160(prevOwnershipPacked));

        (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);

        if (approvalCheck) {
            // The nested ifs save around 20+ gas over a compound boolean condition.
            if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))
                if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved();
        }

        _beforeTokenTransfers(from, address(0), tokenId, 1);

        // Clear approvals from the previous owner.
        assembly {
            if approvedAddress {
                // This is equivalent to `delete _tokenApprovals[tokenId]`.
                sstore(approvedAddressSlot, 0)
            }
        }

        // Underflow of the sender's balance is impossible because we check for
        // ownership above and the recipient's balance can't realistically overflow.
        // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256.
        unchecked {
            // Updates:
            // - `balance -= 1`.
            // - `numberBurned += 1`.
            //
            // We can directly decrement the balance, and increment the number burned.
            // This is equivalent to `packed -= 1; packed += 1 << _BITPOS_NUMBER_BURNED;`.
            _packedAddressData[from] += (1 << _BITPOS_NUMBER_BURNED) - 1;

            // Updates:
            // - `address` to the last owner.
            // - `startTimestamp` to the timestamp of burning.
            // - `burned` to `true`.
            // - `nextInitialized` to `true`.
            _packedOwnerships[tokenId] = _packOwnershipData(
                from,
                (_BITMASK_BURNED | _BITMASK_NEXT_INITIALIZED) | _nextExtraData(from, address(0), prevOwnershipPacked)
            );

            // If the next slot may not have been initialized (i.e. `nextInitialized == false`) .
            if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
                uint256 nextTokenId = tokenId + 1;
                // If the next slot's address is zero and not burned (i.e. packed value is zero).
                if (_packedOwnerships[nextTokenId] == 0) {
                    // If the next slot is within bounds.
                    if (nextTokenId != _currentIndex) {
                        // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`.
                        _packedOwnerships[nextTokenId] = prevOwnershipPacked;
                    }
                }
            }
        }

        emit Transfer(from, address(0), tokenId);
        _afterTokenTransfers(from, address(0), tokenId, 1);

        // Overflow not possible, as _burnCounter cannot be exceed _currentIndex times.
        unchecked {
            _burnCounter++;
        }
    }

    // =============================================================
    //                     EXTRA DATA OPERATIONS
    // =============================================================

    /**
     * @dev Directly sets the extra data for the ownership data `index`.
     */
    function _setExtraDataAt(uint256 index, uint24 extraData) internal virtual {
        uint256 packed = _packedOwnerships[index];
        if (packed == 0) revert OwnershipNotInitializedForExtraData();
        uint256 extraDataCasted;
        // Cast `extraData` with assembly to avoid redundant masking.
        assembly {
            extraDataCasted := extraData
        }
        packed = (packed & _BITMASK_EXTRA_DATA_COMPLEMENT) | (extraDataCasted << _BITPOS_EXTRA_DATA);
        _packedOwnerships[index] = packed;
    }

    /**
     * @dev Called during each token transfer to set the 24bit `extraData` field.
     * Intended to be overridden by the cosumer contract.
     *
     * `previousExtraData` - the value of `extraData` before transfer.
     *
     * 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, `tokenId` will be burned by `from`.
     * - `from` and `to` are never both zero.
     */
    function _extraData(
        address from,
        address to,
        uint24 previousExtraData
    ) internal view virtual returns (uint24) {}

    /**
     * @dev Returns the next extra data for the packed ownership data.
     * The returned result is shifted into position.
     */
    function _nextExtraData(
        address from,
        address to,
        uint256 prevOwnershipPacked
    ) private view returns (uint256) {
        uint24 extraData = uint24(prevOwnershipPacked >> _BITPOS_EXTRA_DATA);
        return uint256(_extraData(from, to, extraData)) << _BITPOS_EXTRA_DATA;
    }

    // =============================================================
    //                       OTHER OPERATIONS
    // =============================================================

    /**
     * @dev Returns the message sender (defaults to `msg.sender`).
     *
     * If you are writing GSN compatible contracts, you need to override this function.
     */
    function _msgSenderERC721A() internal view virtual returns (address) {
        return msg.sender;
    }

    /**
     * @dev Converts a uint256 to its ASCII string decimal representation.
     */
    function _toString(uint256 value) internal pure virtual returns (string memory str) {
        assembly {
            // The maximum value of a uint256 contains 78 digits (1 byte per digit),
            // but we allocate 0x80 bytes to keep the free memory pointer 32-byte word aliged.
            // We will need 1 32-byte word to store the length,
            // and 3 32-byte words to store a maximum of 78 digits. Total: 0x20 + 3 * 0x20 = 0x80.
            str := add(mload(0x40), 0x80)
            // Update the free memory pointer to allocate.
            mstore(0x40, str)

            // 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)
        }
    }
}

File 5 of 13 : Strings.sol
// 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);
    }
}

File 6 of 13 : Ownable.sol
// 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);
    }
}

File 7 of 13 : MerkleProof.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/MerkleProof.sol)

pragma solidity ^0.8.0;

/**
 * @dev These functions deal with verification of Merkle Tree proofs.
 *
 * The proofs can be generated using the JavaScript library
 * https://github.com/miguelmota/merkletreejs[merkletreejs].
 * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.
 *
 * See `test/utils/cryptography/MerkleProof.test.js` for some examples.
 *
 * WARNING: You should avoid using leaf values that are 64 bytes long prior to
 * hashing, or use a hash function other than keccak256 for hashing leaves.
 * This is because the concatenation of a sorted pair of internal nodes in
 * the merkle tree could be reinterpreted as a leaf value.
 */
library MerkleProof {
    /**
     * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
     * defined by `root`. For this, a `proof` must be provided, containing
     * sibling hashes on the branch from the leaf to the root of the tree. Each
     * pair of leaves and each pair of pre-images are assumed to be sorted.
     */
    function verify(
        bytes32[] memory proof,
        bytes32 root,
        bytes32 leaf
    ) internal pure returns (bool) {
        return processProof(proof, leaf) == root;
    }

    /**
     * @dev Calldata version of {verify}
     *
     * _Available since v4.7._
     */
    function verifyCalldata(
        bytes32[] calldata proof,
        bytes32 root,
        bytes32 leaf
    ) internal pure returns (bool) {
        return processProofCalldata(proof, leaf) == root;
    }

    /**
     * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
     * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
     * hash matches the root of the tree. When processing the proof, the pairs
     * of leafs & pre-images are assumed to be sorted.
     *
     * _Available since v4.4._
     */
    function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
        bytes32 computedHash = leaf;
        for (uint256 i = 0; i < proof.length; i++) {
            computedHash = _hashPair(computedHash, proof[i]);
        }
        return computedHash;
    }

    /**
     * @dev Calldata version of {processProof}
     *
     * _Available since v4.7._
     */
    function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {
        bytes32 computedHash = leaf;
        for (uint256 i = 0; i < proof.length; i++) {
            computedHash = _hashPair(computedHash, proof[i]);
        }
        return computedHash;
    }

    /**
     * @dev Returns true if the `leaves` can be proved to be a part of a Merkle tree defined by
     * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.
     *
     * _Available since v4.7._
     */
    function multiProofVerify(
        bytes32[] memory proof,
        bool[] memory proofFlags,
        bytes32 root,
        bytes32[] memory leaves
    ) internal pure returns (bool) {
        return processMultiProof(proof, proofFlags, leaves) == root;
    }

    /**
     * @dev Calldata version of {multiProofVerify}
     *
     * _Available since v4.7._
     */
    function multiProofVerifyCalldata(
        bytes32[] calldata proof,
        bool[] calldata proofFlags,
        bytes32 root,
        bytes32[] memory leaves
    ) internal pure returns (bool) {
        return processMultiProofCalldata(proof, proofFlags, leaves) == root;
    }

    /**
     * @dev Returns the root of a tree reconstructed from `leaves` and the sibling nodes in `proof`,
     * consuming from one or the other at each step according to the instructions given by
     * `proofFlags`.
     *
     * _Available since v4.7._
     */
    function processMultiProof(
        bytes32[] memory proof,
        bool[] memory proofFlags,
        bytes32[] memory leaves
    ) internal pure returns (bytes32 merkleRoot) {
        // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by
        // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
        // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
        // the merkle tree.
        uint256 leavesLen = leaves.length;
        uint256 totalHashes = proofFlags.length;

        // Check proof validity.
        require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof");

        // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
        // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
        bytes32[] memory hashes = new bytes32[](totalHashes);
        uint256 leafPos = 0;
        uint256 hashPos = 0;
        uint256 proofPos = 0;
        // At each step, we compute the next hash using two values:
        // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
        //   get the next hash.
        // - depending on the flag, either another value for the "main queue" (merging branches) or an element from the
        //   `proof` array.
        for (uint256 i = 0; i < totalHashes; i++) {
            bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
            bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];
            hashes[i] = _hashPair(a, b);
        }

        if (totalHashes > 0) {
            return hashes[totalHashes - 1];
        } else if (leavesLen > 0) {
            return leaves[0];
        } else {
            return proof[0];
        }
    }

    /**
     * @dev Calldata version of {processMultiProof}
     *
     * _Available since v4.7._
     */
    function processMultiProofCalldata(
        bytes32[] calldata proof,
        bool[] calldata proofFlags,
        bytes32[] memory leaves
    ) internal pure returns (bytes32 merkleRoot) {
        // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by
        // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
        // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
        // the merkle tree.
        uint256 leavesLen = leaves.length;
        uint256 totalHashes = proofFlags.length;

        // Check proof validity.
        require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof");

        // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
        // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
        bytes32[] memory hashes = new bytes32[](totalHashes);
        uint256 leafPos = 0;
        uint256 hashPos = 0;
        uint256 proofPos = 0;
        // At each step, we compute the next hash using two values:
        // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
        //   get the next hash.
        // - depending on the flag, either another value for the "main queue" (merging branches) or an element from the
        //   `proof` array.
        for (uint256 i = 0; i < totalHashes; i++) {
            bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
            bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];
            hashes[i] = _hashPair(a, b);
        }

        if (totalHashes > 0) {
            return hashes[totalHashes - 1];
        } else if (leavesLen > 0) {
            return leaves[0];
        } else {
            return proof[0];
        }
    }

    function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {
        return a < b ? _efficientHash(a, b) : _efficientHash(b, a);
    }

    function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, a)
            mstore(0x20, b)
            value := keccak256(0x00, 0x40)
        }
    }
}

File 8 of 13 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}

File 9 of 13 : DateTimeContract.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// ----------------------------------------------------------------------------
// DateTime Library v2.0 - Contract Instance
//
// A gas-efficient Solidity date and time library
//
// https://github.com/bokkypoobah/DateTime
//
// Tested date range 1970/01/01 to 2345/12/31
//
// Conventions:
// Unit      | Range         | Notes
// :-------- |:-------------:|:-----
// timestamp | >= 0          | Unix timestamp, number of seconds since 1970/01/01 00:00:00 UTC
// year      | 1970 ... 2345 |
// month     | 1 ... 12      |
// day       | 1 ... 31      |
// hour      | 0 ... 23      |
// minute    | 0 ... 59      |
// second    | 0 ... 59      |
// dayOfWeek | 1 ... 7       | 1 = Monday, ..., 7 = Sunday
//
//
// Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2018.
//
// GNU Lesser General Public License 3.0
// https://www.gnu.org/licenses/lgpl-3.0.en.html
// ----------------------------------------------------------------------------

import "./DateTime.sol";

contract DateTimeContract {
    uint256 public constant SECONDS_PER_DAY = 24 * 60 * 60;
    uint256 public constant SECONDS_PER_HOUR = 60 * 60;
    uint256 public constant SECONDS_PER_MINUTE = 60;
    int256 public constant OFFSET19700101 = 2440588;

    uint256 public constant DOW_MON = 1;
    uint256 public constant DOW_TUE = 2;
    uint256 public constant DOW_WED = 3;
    uint256 public constant DOW_THU = 4;
    uint256 public constant DOW_FRI = 5;
    uint256 public constant DOW_SAT = 6;
    uint256 public constant DOW_SUN = 7;

    function _now() public view returns (uint256 timestamp) {
        timestamp = block.timestamp;
    }

    function _nowDateTime()
        public
        view
        returns (uint256 year, uint256 month, uint256 day, uint256 hour, uint256 minute, uint256 second)
    {
        (year, month, day, hour, minute, second) = DateTime.timestampToDateTime(block.timestamp);
    }

    function _daysFromDate(uint256 year, uint256 month, uint256 day) public pure returns (uint256 _days) {
        return DateTime._daysFromDate(year, month, day);
    }

    function _daysToDate(uint256 _days) public pure returns (uint256 year, uint256 month, uint256 day) {
        return DateTime._daysToDate(_days);
    }

    function timestampFromDate(uint256 year, uint256 month, uint256 day) public pure returns (uint256 timestamp) {
        return DateTime.timestampFromDate(year, month, day);
    }

    function timestampFromDateTime(
        uint256 year,
        uint256 month,
        uint256 day,
        uint256 hour,
        uint256 minute,
        uint256 second
    )
        public
        pure
        returns (uint256 timestamp)
    {
        return DateTime.timestampFromDateTime(year, month, day, hour, minute, second);
    }

    function timestampToDate(uint256 timestamp) public pure returns (uint256 year, uint256 month, uint256 day) {
        (year, month, day) = DateTime.timestampToDate(timestamp);
    }

    function timestampToDateTime(uint256 timestamp)
        public
        pure
        returns (uint256 year, uint256 month, uint256 day, uint256 hour, uint256 minute, uint256 second)
    {
        (year, month, day, hour, minute, second) = DateTime.timestampToDateTime(timestamp);
    }

    function isValidDate(uint256 year, uint256 month, uint256 day) public pure returns (bool valid) {
        valid = DateTime.isValidDate(year, month, day);
    }

    function isValidDateTime(uint256 year, uint256 month, uint256 day, uint256 hour, uint256 minute, uint256 second)
        public
        pure
        returns (bool valid)
    {
        valid = DateTime.isValidDateTime(year, month, day, hour, minute, second);
    }

    function isLeapYear(uint256 timestamp) public pure returns (bool leapYear) {
        leapYear = DateTime.isLeapYear(timestamp);
    }

    function _isLeapYear(uint256 year) public pure returns (bool leapYear) {
        leapYear = DateTime._isLeapYear(year);
    }

    function isWeekDay(uint256 timestamp) public pure returns (bool weekDay) {
        weekDay = DateTime.isWeekDay(timestamp);
    }

    function isWeekEnd(uint256 timestamp) public pure returns (bool weekEnd) {
        weekEnd = DateTime.isWeekEnd(timestamp);
    }

    function getDaysInMonth(uint256 timestamp) public pure returns (uint256 daysInMonth) {
        daysInMonth = DateTime.getDaysInMonth(timestamp);
    }

    function _getDaysInMonth(uint256 year, uint256 month) public pure returns (uint256 daysInMonth) {
        daysInMonth = DateTime._getDaysInMonth(year, month);
    }

    function getDayOfWeek(uint256 timestamp) public pure returns (uint256 dayOfWeek) {
        dayOfWeek = DateTime.getDayOfWeek(timestamp);
    }

    function getYear(uint256 timestamp) public pure returns (uint256 year) {
        year = DateTime.getYear(timestamp);
    }

    function getMonth(uint256 timestamp) public pure returns (uint256 month) {
        month = DateTime.getMonth(timestamp);
    }

    function getDay(uint256 timestamp) public pure returns (uint256 day) {
        day = DateTime.getDay(timestamp);
    }

    function getHour(uint256 timestamp) public pure returns (uint256 hour) {
        hour = DateTime.getHour(timestamp);
    }

    function getMinute(uint256 timestamp) public pure returns (uint256 minute) {
        minute = DateTime.getMinute(timestamp);
    }

    function getSecond(uint256 timestamp) public pure returns (uint256 second) {
        second = DateTime.getSecond(timestamp);
    }

    function addYears(uint256 timestamp, uint256 _years) public pure returns (uint256 newTimestamp) {
        newTimestamp = DateTime.addYears(timestamp, _years);
    }

    function addMonths(uint256 timestamp, uint256 _months) public pure returns (uint256 newTimestamp) {
        newTimestamp = DateTime.addMonths(timestamp, _months);
    }

    function addDays(uint256 timestamp, uint256 _days) public pure returns (uint256 newTimestamp) {
        newTimestamp = DateTime.addDays(timestamp, _days);
    }

    function addHours(uint256 timestamp, uint256 _hours) public pure returns (uint256 newTimestamp) {
        newTimestamp = DateTime.addHours(timestamp, _hours);
    }

    function addMinutes(uint256 timestamp, uint256 _minutes) public pure returns (uint256 newTimestamp) {
        newTimestamp = DateTime.addMinutes(timestamp, _minutes);
    }

    function addSeconds(uint256 timestamp, uint256 _seconds) public pure returns (uint256 newTimestamp) {
        newTimestamp = DateTime.addSeconds(timestamp, _seconds);
    }

    function subYears(uint256 timestamp, uint256 _years) public pure returns (uint256 newTimestamp) {
        newTimestamp = DateTime.subYears(timestamp, _years);
    }

    function subMonths(uint256 timestamp, uint256 _months) public pure returns (uint256 newTimestamp) {
        newTimestamp = DateTime.subMonths(timestamp, _months);
    }

    function subDays(uint256 timestamp, uint256 _days) public pure returns (uint256 newTimestamp) {
        newTimestamp = DateTime.subDays(timestamp, _days);
    }

    function subHours(uint256 timestamp, uint256 _hours) public pure returns (uint256 newTimestamp) {
        newTimestamp = DateTime.subHours(timestamp, _hours);
    }

    function subMinutes(uint256 timestamp, uint256 _minutes) public pure returns (uint256 newTimestamp) {
        newTimestamp = DateTime.subMinutes(timestamp, _minutes);
    }

    function subSeconds(uint256 timestamp, uint256 _seconds) public pure returns (uint256 newTimestamp) {
        newTimestamp = DateTime.subSeconds(timestamp, _seconds);
    }

    function diffYears(uint256 fromTimestamp, uint256 toTimestamp) public pure returns (uint256 _years) {
        _years = DateTime.diffYears(fromTimestamp, toTimestamp);
    }

    function diffMonths(uint256 fromTimestamp, uint256 toTimestamp) public pure returns (uint256 _months) {
        _months = DateTime.diffMonths(fromTimestamp, toTimestamp);
    }

    function diffDays(uint256 fromTimestamp, uint256 toTimestamp) public pure returns (uint256 _days) {
        _days = DateTime.diffDays(fromTimestamp, toTimestamp);
    }

    function diffHours(uint256 fromTimestamp, uint256 toTimestamp) public pure returns (uint256 _hours) {
        _hours = DateTime.diffHours(fromTimestamp, toTimestamp);
    }

    function diffMinutes(uint256 fromTimestamp, uint256 toTimestamp) public pure returns (uint256 _minutes) {
        _minutes = DateTime.diffMinutes(fromTimestamp, toTimestamp);
    }

    function diffSeconds(uint256 fromTimestamp, uint256 toTimestamp) public pure returns (uint256 _seconds) {
        _seconds = DateTime.diffSeconds(fromTimestamp, toTimestamp);
    }
}

File 10 of 13 : DateTime.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// ----------------------------------------------------------------------------
// DateTime Library v2.0
//
// A gas-efficient Solidity date and time library
//
// https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary
//
// Tested date range 1970/01/01 to 2345/12/31
//
// Conventions:
// Unit      | Range         | Notes
// :-------- |:-------------:|:-----
// timestamp | >= 0          | Unix timestamp, number of seconds since 1970/01/01 00:00:00 UTC
// year      | 1970 ... 2345 |
// month     | 1 ... 12      |
// day       | 1 ... 31      |
// hour      | 0 ... 23      |
// minute    | 0 ... 59      |
// second    | 0 ... 59      |
// dayOfWeek | 1 ... 7       | 1 = Monday, ..., 7 = Sunday
//
//
// Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2018-2019. The MIT Licence.
// ----------------------------------------------------------------------------

library DateTime {
    uint256 constant SECONDS_PER_DAY = 24 * 60 * 60;
    uint256 constant SECONDS_PER_HOUR = 60 * 60;
    uint256 constant SECONDS_PER_MINUTE = 60;
    int256 constant OFFSET19700101 = 2440588;

    uint256 constant DOW_MON = 1;
    uint256 constant DOW_TUE = 2;
    uint256 constant DOW_WED = 3;
    uint256 constant DOW_THU = 4;
    uint256 constant DOW_FRI = 5;
    uint256 constant DOW_SAT = 6;
    uint256 constant DOW_SUN = 7;

    // ------------------------------------------------------------------------
    // Calculate the number of days from 1970/01/01 to year/month/day using
    // the date conversion algorithm from
    //   http://aa.usno.navy.mil/faq/docs/JD_Formula.php
    // and subtracting the offset 2440588 so that 1970/01/01 is day 0
    //
    // days = day
    //      - 32075
    //      + 1461 * (year + 4800 + (month - 14) / 12) / 4
    //      + 367 * (month - 2 - (month - 14) / 12 * 12) / 12
    //      - 3 * ((year + 4900 + (month - 14) / 12) / 100) / 4
    //      - offset
    // ------------------------------------------------------------------------
    function _daysFromDate(uint256 year, uint256 month, uint256 day) internal pure returns (uint256 _days) {
        require(year >= 1970);
        int256 _year = int256(year);
        int256 _month = int256(month);
        int256 _day = int256(day);

        int256 __days = _day - 32075 + (1461 * (_year + 4800 + (_month - 14) / 12)) / 4
            + (367 * (_month - 2 - ((_month - 14) / 12) * 12)) / 12
            - (3 * ((_year + 4900 + (_month - 14) / 12) / 100)) / 4 - OFFSET19700101;

        _days = uint256(__days);
    }

    // ------------------------------------------------------------------------
    // Calculate year/month/day from the number of days since 1970/01/01 using
    // the date conversion algorithm from
    //   http://aa.usno.navy.mil/faq/docs/JD_Formula.php
    // and adding the offset 2440588 so that 1970/01/01 is day 0
    //
    // int L = days + 68569 + offset
    // int N = 4 * L / 146097
    // L = L - (146097 * N + 3) / 4
    // year = 4000 * (L + 1) / 1461001
    // L = L - 1461 * year / 4 + 31
    // month = 80 * L / 2447
    // dd = L - 2447 * month / 80
    // L = month / 11
    // month = month + 2 - 12 * L
    // year = 100 * (N - 49) + year + L
    // ------------------------------------------------------------------------
    function _daysToDate(uint256 _days) internal pure returns (uint256 year, uint256 month, uint256 day) {
        unchecked {
            int256 __days = int256(_days);

            int256 L = __days + 68569 + OFFSET19700101;
            int256 N = (4 * L) / 146097;
            L = L - (146097 * N + 3) / 4;
            int256 _year = (4000 * (L + 1)) / 1461001;
            L = L - (1461 * _year) / 4 + 31;
            int256 _month = (80 * L) / 2447;
            int256 _day = L - (2447 * _month) / 80;
            L = _month / 11;
            _month = _month + 2 - 12 * L;
            _year = 100 * (N - 49) + _year + L;

            year = uint256(_year);
            month = uint256(_month);
            day = uint256(_day);
        }
    }

    function timestampFromDate(uint256 year, uint256 month, uint256 day) internal pure returns (uint256 timestamp) {
        timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY;
    }

    function timestampFromDateTime(
        uint256 year,
        uint256 month,
        uint256 day,
        uint256 hour,
        uint256 minute,
        uint256 second
    )
        internal
        pure
        returns (uint256 timestamp)
    {
        timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + hour * SECONDS_PER_HOUR
            + minute * SECONDS_PER_MINUTE + second;
    }

    function timestampToDate(uint256 timestamp) internal pure returns (uint256 year, uint256 month, uint256 day) {
        unchecked {
            (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY);
        }
    }

    function timestampToDateTime(uint256 timestamp)
        internal
        pure
        returns (uint256 year, uint256 month, uint256 day, uint256 hour, uint256 minute, uint256 second)
    {
        unchecked {
            (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY);
            uint256 secs = timestamp % SECONDS_PER_DAY;
            hour = secs / SECONDS_PER_HOUR;
            secs = secs % SECONDS_PER_HOUR;
            minute = secs / SECONDS_PER_MINUTE;
            second = secs % SECONDS_PER_MINUTE;
        }
    }

    function isValidDate(uint256 year, uint256 month, uint256 day) internal pure returns (bool valid) {
        if (year >= 1970 && month > 0 && month <= 12) {
            uint256 daysInMonth = _getDaysInMonth(year, month);
            if (day > 0 && day <= daysInMonth) {
                valid = true;
            }
        }
    }

    function isValidDateTime(uint256 year, uint256 month, uint256 day, uint256 hour, uint256 minute, uint256 second)
        internal
        pure
        returns (bool valid)
    {
        if (isValidDate(year, month, day)) {
            if (hour < 24 && minute < 60 && second < 60) {
                valid = true;
            }
        }
    }

    function isLeapYear(uint256 timestamp) internal pure returns (bool leapYear) {
        (uint256 year,,) = _daysToDate(timestamp / SECONDS_PER_DAY);
        leapYear = _isLeapYear(year);
    }

    function _isLeapYear(uint256 year) internal pure returns (bool leapYear) {
        leapYear = ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
    }

    function isWeekDay(uint256 timestamp) internal pure returns (bool weekDay) {
        weekDay = getDayOfWeek(timestamp) <= DOW_FRI;
    }

    function isWeekEnd(uint256 timestamp) internal pure returns (bool weekEnd) {
        weekEnd = getDayOfWeek(timestamp) >= DOW_SAT;
    }

    function getDaysInMonth(uint256 timestamp) internal pure returns (uint256 daysInMonth) {
        (uint256 year, uint256 month,) = _daysToDate(timestamp / SECONDS_PER_DAY);
        daysInMonth = _getDaysInMonth(year, month);
    }

    function _getDaysInMonth(uint256 year, uint256 month) internal pure returns (uint256 daysInMonth) {
        if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) {
            daysInMonth = 31;
        } else if (month != 2) {
            daysInMonth = 30;
        } else {
            daysInMonth = _isLeapYear(year) ? 29 : 28;
        }
    }

    // 1 = Monday, 7 = Sunday
    function getDayOfWeek(uint256 timestamp) internal pure returns (uint256 dayOfWeek) {
        uint256 _days = timestamp / SECONDS_PER_DAY;
        dayOfWeek = ((_days + 3) % 7) + 1;
    }

    function getYear(uint256 timestamp) internal pure returns (uint256 year) {
        (year,,) = _daysToDate(timestamp / SECONDS_PER_DAY);
    }

    function getMonth(uint256 timestamp) internal pure returns (uint256 month) {
        (, month,) = _daysToDate(timestamp / SECONDS_PER_DAY);
    }

    function getDay(uint256 timestamp) internal pure returns (uint256 day) {
        (,, day) = _daysToDate(timestamp / SECONDS_PER_DAY);
    }

    function getHour(uint256 timestamp) internal pure returns (uint256 hour) {
        uint256 secs = timestamp % SECONDS_PER_DAY;
        hour = secs / SECONDS_PER_HOUR;
    }

    function getMinute(uint256 timestamp) internal pure returns (uint256 minute) {
        uint256 secs = timestamp % SECONDS_PER_HOUR;
        minute = secs / SECONDS_PER_MINUTE;
    }

    function getSecond(uint256 timestamp) internal pure returns (uint256 second) {
        second = timestamp % SECONDS_PER_MINUTE;
    }

    function addYears(uint256 timestamp, uint256 _years) internal pure returns (uint256 newTimestamp) {
        (uint256 year, uint256 month, uint256 day) = _daysToDate(timestamp / SECONDS_PER_DAY);
        year += _years;
        uint256 daysInMonth = _getDaysInMonth(year, month);
        if (day > daysInMonth) {
            day = daysInMonth;
        }
        newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + (timestamp % SECONDS_PER_DAY);
        require(newTimestamp >= timestamp);
    }

    function addMonths(uint256 timestamp, uint256 _months) internal pure returns (uint256 newTimestamp) {
        (uint256 year, uint256 month, uint256 day) = _daysToDate(timestamp / SECONDS_PER_DAY);
        month += _months;
        year += (month - 1) / 12;
        month = ((month - 1) % 12) + 1;
        uint256 daysInMonth = _getDaysInMonth(year, month);
        if (day > daysInMonth) {
            day = daysInMonth;
        }
        newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + (timestamp % SECONDS_PER_DAY);
        require(newTimestamp >= timestamp);
    }

    function addDays(uint256 timestamp, uint256 _days) internal pure returns (uint256 newTimestamp) {
        newTimestamp = timestamp + _days * SECONDS_PER_DAY;
        require(newTimestamp >= timestamp);
    }

    function addHours(uint256 timestamp, uint256 _hours) internal pure returns (uint256 newTimestamp) {
        newTimestamp = timestamp + _hours * SECONDS_PER_HOUR;
        require(newTimestamp >= timestamp);
    }

    function addMinutes(uint256 timestamp, uint256 _minutes) internal pure returns (uint256 newTimestamp) {
        newTimestamp = timestamp + _minutes * SECONDS_PER_MINUTE;
        require(newTimestamp >= timestamp);
    }

    function addSeconds(uint256 timestamp, uint256 _seconds) internal pure returns (uint256 newTimestamp) {
        newTimestamp = timestamp + _seconds;
        require(newTimestamp >= timestamp);
    }

    function subYears(uint256 timestamp, uint256 _years) internal pure returns (uint256 newTimestamp) {
        (uint256 year, uint256 month, uint256 day) = _daysToDate(timestamp / SECONDS_PER_DAY);
        year -= _years;
        uint256 daysInMonth = _getDaysInMonth(year, month);
        if (day > daysInMonth) {
            day = daysInMonth;
        }
        newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + (timestamp % SECONDS_PER_DAY);
        require(newTimestamp <= timestamp);
    }

    function subMonths(uint256 timestamp, uint256 _months) internal pure returns (uint256 newTimestamp) {
        (uint256 year, uint256 month, uint256 day) = _daysToDate(timestamp / SECONDS_PER_DAY);
        uint256 yearMonth = year * 12 + (month - 1) - _months;
        year = yearMonth / 12;
        month = (yearMonth % 12) + 1;
        uint256 daysInMonth = _getDaysInMonth(year, month);
        if (day > daysInMonth) {
            day = daysInMonth;
        }
        newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + (timestamp % SECONDS_PER_DAY);
        require(newTimestamp <= timestamp);
    }

    function subDays(uint256 timestamp, uint256 _days) internal pure returns (uint256 newTimestamp) {
        newTimestamp = timestamp - _days * SECONDS_PER_DAY;
        require(newTimestamp <= timestamp);
    }

    function subHours(uint256 timestamp, uint256 _hours) internal pure returns (uint256 newTimestamp) {
        newTimestamp = timestamp - _hours * SECONDS_PER_HOUR;
        require(newTimestamp <= timestamp);
    }

    function subMinutes(uint256 timestamp, uint256 _minutes) internal pure returns (uint256 newTimestamp) {
        newTimestamp = timestamp - _minutes * SECONDS_PER_MINUTE;
        require(newTimestamp <= timestamp);
    }

    function subSeconds(uint256 timestamp, uint256 _seconds) internal pure returns (uint256 newTimestamp) {
        newTimestamp = timestamp - _seconds;
        require(newTimestamp <= timestamp);
    }

    function diffYears(uint256 fromTimestamp, uint256 toTimestamp) internal pure returns (uint256 _years) {
        require(fromTimestamp <= toTimestamp);
        (uint256 fromYear,,) = _daysToDate(fromTimestamp / SECONDS_PER_DAY);
        (uint256 toYear,,) = _daysToDate(toTimestamp / SECONDS_PER_DAY);
        _years = toYear - fromYear;
    }

    function diffMonths(uint256 fromTimestamp, uint256 toTimestamp) internal pure returns (uint256 _months) {
        require(fromTimestamp <= toTimestamp);
        (uint256 fromYear, uint256 fromMonth,) = _daysToDate(fromTimestamp / SECONDS_PER_DAY);
        (uint256 toYear, uint256 toMonth,) = _daysToDate(toTimestamp / SECONDS_PER_DAY);
        _months = toYear * 12 + toMonth - fromYear * 12 - fromMonth;
    }

    function diffDays(uint256 fromTimestamp, uint256 toTimestamp) internal pure returns (uint256 _days) {
        require(fromTimestamp <= toTimestamp);
        _days = (toTimestamp - fromTimestamp) / SECONDS_PER_DAY;
    }

    function diffHours(uint256 fromTimestamp, uint256 toTimestamp) internal pure returns (uint256 _hours) {
        require(fromTimestamp <= toTimestamp);
        _hours = (toTimestamp - fromTimestamp) / SECONDS_PER_HOUR;
    }

    function diffMinutes(uint256 fromTimestamp, uint256 toTimestamp) internal pure returns (uint256 _minutes) {
        require(fromTimestamp <= toTimestamp);
        _minutes = (toTimestamp - fromTimestamp) / SECONDS_PER_MINUTE;
    }

    function diffSeconds(uint256 fromTimestamp, uint256 toTimestamp) internal pure returns (uint256 _seconds) {
        require(fromTimestamp <= toTimestamp);
        _seconds = toTimestamp - fromTimestamp;
    }
}

File 11 of 13 : IERC721A.sol
// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.2.2
// Creator: Chiru Labs

pragma solidity ^0.8.4;

/**
 * @dev Interface of ERC721A.
 */
interface IERC721A {
    /**
     * The caller must own the token or be an approved operator.
     */
    error ApprovalCallerNotOwnerNorApproved();

    /**
     * The token does not exist.
     */
    error ApprovalQueryForNonexistentToken();

    /**
     * The caller cannot approve to their own address.
     */
    error ApproveToCaller();

    /**
     * Cannot query the balance for the zero address.
     */
    error BalanceQueryForZeroAddress();

    /**
     * Cannot mint to the zero address.
     */
    error MintToZeroAddress();

    /**
     * The quantity of tokens minted must be more than zero.
     */
    error MintZeroQuantity();

    /**
     * The token does not exist.
     */
    error OwnerQueryForNonexistentToken();

    /**
     * The caller must own the token or be an approved operator.
     */
    error TransferCallerNotOwnerNorApproved();

    /**
     * The token must be owned by `from`.
     */
    error TransferFromIncorrectOwner();

    /**
     * Cannot safely transfer to a contract that does not implement the
     * ERC721Receiver interface.
     */
    error TransferToNonERC721ReceiverImplementer();

    /**
     * Cannot transfer to the zero address.
     */
    error TransferToZeroAddress();

    /**
     * The token does not exist.
     */
    error URIQueryForNonexistentToken();

    /**
     * The `quantity` minted with ERC2309 exceeds the safety limit.
     */
    error MintERC2309QuantityExceedsLimit();

    /**
     * The `extraData` cannot be set on an unintialized ownership slot.
     */
    error OwnershipNotInitializedForExtraData();

    // =============================================================
    //                            STRUCTS
    // =============================================================

    struct TokenOwnership {
        // The address of the owner.
        address addr;
        // Stores the start time of ownership with minimal overhead for tokenomics.
        uint64 startTimestamp;
        // Whether the token has been burned.
        bool burned;
        // Arbitrary data similar to `startTimestamp` that can be set via {_extraData}.
        uint24 extraData;
    }

    // =============================================================
    //                         TOKEN COUNTERS
    // =============================================================

    /**
     * @dev Returns the total number of tokens in existence.
     * Burned tokens will reduce the count.
     * To get the total number of tokens minted, please see {_totalMinted}.
     */
    function totalSupply() external view returns (uint256);

    // =============================================================
    //                            IERC165
    // =============================================================

    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);

    // =============================================================
    //                            IERC721
    // =============================================================

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

    /**
     * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Transfers `tokenId` 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);

    // =============================================================
    //                        IERC721Metadata
    // =============================================================

    /**
     * @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);

    // =============================================================
    //                           IERC2309
    // =============================================================

    /**
     * @dev Emitted when tokens in `fromTokenId` to `toTokenId`
     * (inclusive) is transferred from `from` to `to`, as defined in the
     * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309) standard.
     *
     * See {_mintERC2309} for more details.
     */
    event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to);
}

File 12 of 13 : tamagogi_data.sol
pragma solidity ^0.8.7;
// SPDX-License-Identifier: MIT

contract TamagogiData {
    //@@@ props
    uint[10] internal propOdds = [0,0,0,0,1,1,1,1,2,2];
    string[3] internal propTraits = ["food", "toy", "shield"];
    string[3] internal propDesc = ["Food will be able to prevent your pet from starvation.","Toys can keep your pet from being bored.","Shield to protect your pet from being hit."];

    //@@@ pets
    uint[3] internal eggs = [1,2,3];

    uint[13] internal ear = [0,1,2,3,4,5,6,7,8,9,10,11,12];
    uint[5] internal reaction = [0,1,2,3,4];
    uint[11] internal head = [0,1,2,3,4,5,6,7,8,9,10];
    uint[11] internal body = [0,1,2,3,4,5,6,7,8,9,10];

    string[13] internal earTraits = ["Melody","Cinna","Racoon","Long ear","Dog","Teddy","Trapa","Shorthair","Rabbit","Mick","Mouse","Bear","Cat"];    
    string[5] internal reactionTraits = ["Normal","Angry","Sad","Smile","Upset"];
    string[11] internal headTraits =  ["Horn","Whiskers","Whiskers fat","Fluffy","Whiskers thin","Square","Hamster","Normal","Cricetinae","Naja","Plump"];
    string[11] internal bodyTraits =  ["Sit","Dress","Stand","Huddle up","Feeble","Star","Clothes","Strong","Squat","Hulk","Long legs"];

    bytes[1] internal masterBytes = [bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af4000000017352474200aece1ce900000066494441545847edd5310e00100c85613d8efb1fc67108092961914a0dbfc540f25e3f0309ce4b9cf30305104000010410f84720c7982525e9fb8b5f7297d104eac11a58cb589638658c107dc13abc0fb2cb98a67cc9af4be8014d996f9e8c02082080000208145bcb2821effa51fe0000000049454e44ae426082')];
    bytes[13] internal earBytes = [bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000080494441545847ed94410ac0200c04f5ff8f6ec921250475d7da22c87ad48d1927602d9b57dddcbf30005782ecd5e49c95c1fb51c02ecd196f14f75b3903e8ed3f6f1a01a0623f6773cd69af00f80b91ea21203382b70d284308c0b5cd6a8ef925032c401c4736f609c06fdf053b0201c8800cc8800cc8800cc8800cc8c0b9066edd51182171bab4cb0000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000008f494441545847ed93d10e80200845f5ff3fba461b8de80a526daeedf6a628f778b4de167f7d717efb05c0662c09b01d23817e4d78c8cc8084d9357e8c004a7b228052234732bd1701a8e2cc4ef5fdc2be5eaf34ad2acf40908d3347c3d0ddeadcccbd8f20a21e476d04f0263483d1fa054026fdef96a97d52bf657cfdd0ca5004a0011aa0011aa0011aa0011aa0811d3de21d21bb35e40a0000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000006c494441545847edd4d10a4011108461deffa14951d2b2e342a8ff5c9d8bc98e8fc470f98b97e7876f0aa42aa51696f3ca8265b196ebff67a7b795f70a5803572576f3ee1d980d6bc4a382b5a1a5daf3026587cab92bf7c1cc7802c79f090a2080000208208000020820804006486e132187d8c7c60000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000072494441545847ed94510a00210844ebfe876e290844dacd8996085e7fd1a8e353cae9f0c987eba7a881628cce62146dc8404d688bfabb85a8685bdcac9baa51922ada7b0d742aa3fdf544bfc6b544a02fd8dbe8fcfb1603b6e3c8ce48fa68c2dfbe0b0c40000210800004200001084000020fc5ac172190ff741b0000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000075494441545847ed92410ec0200804f5ff8f6ee381a4c12a0b1ebc8ce765990cf676f9f5cbfb5b04f038c0286f71796e57e84bac3c8248cdadca5625a7179bf6650046768029062ceb81cb00eaf2ef1ff88328016497ef206400af4e515f9a89ee79fae9c279003080010c60000318c0000630808117a9bd1321772d676e0000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000007e494441545847ed92510ac0300843dbfb1f7a459820d22e993f52c8be0a33f1edad73343fb379ff60009e1792998ddf43e550a995f84c3c237174ee0b2097a0a5bbf7109e017095b6001973889c39da438595e52788ad410460a13fff3e2f81d92b002a978fce3006e8b2caa00064400664400664400664400664a0ddc00276971321672fab0a0000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000074494441545847ed94310ec0200cc4e0ff8f2e4202d481e452a062317372674cd59c2e9f7cb93f298067027874c70b9b95771e6beff3ce4a9005e1959be03b0035b4ef47cadff3e365d57bd6c168b8f53dbb1d11801d08992f07dab5562dc87c39f0f77f02000c60000318c000063080010c60a000b8610b216fdcaceb0000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000070494441545847ed92410ac0200c04f5ff8f6e9b4341aa761772082de34590641d27f656bc7af1fded3300c7652a609ffb28d0a999843b0676c1713eae15e0ddbb9db4029001c61f7acd5000919f8190bd0a4006fcde80f1c05c891a412edde806000318c000063080010c600003e5064e048315215641d2fc0000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000068494441545847ed94610b00100c44f9ff3f9a28b5165792d6eaf9a6e1eede965a82570dd62fe90c3443cc9b57b523e81b0243c09eb77b55935d4e63c0271ca914015f7f6e41a8819df84ab406efd44a7577be7133035fbe0c0c40000210800004200001084000021df3d61521c08b49860000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000067494441545847ed93410a00200cc3f4ff8f56100411ba513d8810cfb5ed32ade5f1a98ff3cb1705da46292b6de95db3d945dddbc3337db80265a64c5dfdf08908b886aefebac03a40162e873d7d03eeef9539590137c8d6530002108000042000010840000210e80b6d0b213ce71b1e0000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000068494441545847ed94c10a00101404f9ff8f2607a5478c835cc64dedee5b4372fabcf2e7f9c902844019ae89e89b1c7b4e812d68d4c4fdea095d796e0bc4d3ad0ac4cc6de953813e90e8088d49438309fa188e3cb4c0b3efc20212908004242001094840021290400533b70d21044e4ab70000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000065494441545847edd4dd0a00100c8661bbff8ba61d90ffad24a9d7216bfb3c8984c74b1ecf0fdf04889dd42ab8b7aeb4f30868d3beee64afb98b1560362837a8cfbc75c393238025a06416afd6ec1ee5768627c0d5af82000820800002082080000208209000f7ce15214de4787a0000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000006d494441545847ed93410ac0200c04f5ff8f5602e6225476410896e979b39d0cb1b7e2af17ffbf3d0130962517569a534ab32838947ce4e419a530ca22276db4e572f6f3d41c807db3d3fd66ef7500f7d1fc03c0dddaca2b376015ba61003080010c60000318c0000630506e6002f73b0f211a4494500000000049454e44ae426082')];
    bytes[5] internal reactionBytes = [bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000005f494441545847edd5bb0a00200846617dff87ae961a44f042e0721a237fe51b5265f8e8707f61000410400081aac03a5f77549379f3364014665745263cf3a63d80b7bb4a0d6d4055c013b977adac56d1cf15ce0008208000020820302eb00182580621fa639d260000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000005e494441545847ed95390e00200cc3e8ff1fcd3180104294b64317334362792052928f24f717003080010c60c06aa0f6af5b7bf373672d8016769b8a5781a97c847b004e2873e91e100598e56e88284078cd01c000063080010c6020dd4003cbd40721aa0beb880000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000061494441545847ed95410a00200804ebff8f2e3a142115ae045ea6abad4e73b05a924f4d9e5f00c00006308001d540db56b7cdbe6ad78daf028c4663d02df7aa1d215400cf00cf9d05a302d8574cede13ee1e0af6f1c000c60000318c00006d20d745ccf0721d52fc6040000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000005b494441545847edd5310e0020080441f9ffa3550a3b20014968d69620e714226bf8c8f0fc450004104000818ac0bedfb7d717d5cc5f3f1be00db006453577e56403b4efaedf00fa6a3de57bca8d5d1404400001041040008171810356ee0721ed9f05790000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000063494441545847ed954b0a00200844f3fe87eeb3898848cdc0cd6b6d33d3131a29c94792fd0b012000010840c04ba0f6af5bbb6399990da0899daae266e0321fe2de001603cb4c88c04a6598bd3ce45b80709b7b571036dc05080001084000021080400354df0721739252ba0000000049454e44ae426082')];
    bytes[11] internal headBytes = [bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000074494441545847ed94410ec0200cc3e0ff8f66e3c01192954905c99c9bd432526b497e35797f01000318b8c6407befc557582be3945a45938326b30a4016189774d9b102f863f9e09b761d6d40d2efeaef7965a0cfec7c85cc3a005108b9dc3560988e8fb806e21b4412000c60000318c040ba81073af6102143c1dc740000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af4000000017352474200aece1ce900000072494441545847ed943112c0200804cf49feffe214190a6752c1450a2dd65a605d9021e9d2c63300c000063060187824dd8bbbaa8cad165199c0004b73380051a363208dcf0082bc537cca49f31c6d205eb0750666f10e4499a36ac1b78f7f07d10277018cdfb67605000c60000318c000065e01921281db558cba0000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000006a494441545847ed944b0a00200844ebfe87eeb310dae88404153c5741cc383cc55a2e57bddcbf10000210f882401bb7221b546a95b134d83864a14714e04473cbe77a7901a6c04a515210422f083c4b605d9ef9ceee81cddfd5678dd5e26dff130002108000042000810e4ece1021878663410000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000005b494441545847ed94db0900200cc474ffa17d2c604a058b10bfbdf408b4bd15bf5e3cbf5940031af8c2c058b7225b14b3044640e0901d195460f36f4a60960a2040031a7861203023ff85b6204f0e262da0010d6840031a283730013af6102192d097b20000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000060494441545847edd6cb0a0020084451fdff8feeb16813e4580411dcd669c31124b7c7c71fbf6f044000812f044adb15a741656da6b16c122c33594b804860f049c6c408963dd4087ae138eaee9c23558bc02eebf5ef030110400001041040a0028cd31421444923dc0000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000049494441545847edd6410a00200804c0fcffa3ab17a40421c17857973988319a2b9af70f010810f84260ee5b711b34edad0c4e871c8e59da2b0001021581a72f8300040810204080c0023af610215e442abd0000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000064494441545847ed94490e00200803f1ff8f763978841a354193e16a6ceb80144bae92ec6f04800004be2050fbaed80d2aef2a6129b0b0c8428da703dc78fd04e46a79046e9a872108100de168c32835a8ea23843aa7e2ca5c9e13000210800004200081063eee1021a0220e8e0000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000061494441545847ed94410e00100c04f5ff8f460f8eac20a926e3cc760cad95e065c1f50b0018c0400a03b5cf8a5350795605cb808d41b6ccf81ae0c5ed87a069d6ca403880d3bf80c8fb07e4fbdd76809f575db051e36e0b0018c000063080010c343af61021f9935c500000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000067494441545847ed954b0a00200805f3fe87eeb368994f2ab0605ae77318c3ac241f4bee5f00c00006be3050fbaed80595b5916019e22c33590b8032201506fe1237c303b8d17cf22db39e0618f4372c6c8f2030def32bea119e7710090060000318c00006d20d343af6102106b4da3d0000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000060494441545847ed96410a00200804f3ff8f2e844e511a68e461bab74ea348d23e1ff95cbf0180010c9436d0e78e88429a39a770bd142dbceeb86d2600650d68ff32e7e098e50d5a068499e101444db80fb80178fa6500000318c00006308081013eee10210f9b3be30000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000072494441545847ed94310e00210804f5ff8ff68ec2c4e2803d43a2c55859c0b219597b3b7cfae1f90d031080804260bc5155eabe129df666c2a980f08f841a91818ae1d39fabe519a81c1e9ac0c0b504ecdd2af7e0f712ae8b63f72cae5e1a6d70d8bf2b2cc45f2bc10004200001084000020fec3f1221ce89b1720000000049454e44ae426082')];
    bytes[11] internal bodyBytes = [bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c086488000000b9494441545847ed96c10e80200c4321faff5fec4139cce0dc68410c979178215bf7a81b21a794b6eb5bb672008403e14038100e8403e140384038705c31fbe08b05e6b20f1228640052390c0025e4380473110014207e4d53a30530a3b8f0b95a1ec08ce2b5c6278051189d67ea300e588965afac7a3cbd3d89e90228e2226815d2a22dbb2db0bb77d1140888770a298c00dc8b8c01d010f5e4590008fa31b97f01c0f193001640f70471ffbc9ad4cce901608b76c52d073801df502d81d35c52b50000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c086488000000a4494441545847ed964b0ac0200c05957aff1377515d0444f2796ac1169e20144c759c1831a794aeda8fb54c001aa0011aa0011aa0011a000cdc35a62cbe58c27f9107493f49fb9636426963db00e304b3000dd685f00c788b2319e90d991016c0eee25a9a5488cf0248ee10d5688c5a494815ecc084e5fb2b006d375296d6d86b06ac7ab600c20b480e0e9a0289ef2f22eff0853b5f05404f3c1c376b009e180d3c0ef000b15d1d81d94175870000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c086488000000a6494441545847ed96c10a80201883957aff27ee501e0493e9e6df218405dedcfcfe39c29c523a9ef5db970de0049c801370024ec009ec90c0f5409ec10703d5aaef016a0400258d0220190d12a25a06400d84ab997acc007ae10a8cac1d01208332ac5ac6a2eff7c30114802a8c24d06a96000a7d3f450400f9bc6ac34ad86e8e024c7bfa05a026540f68fb21c34601d001f4be51145b01d04281e2d2ffd44a02d42cb2c10037c7f12981ef4fbe3c0000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c086488000000a0494441545847ed96c10a8020104495faff2fee907b30ac5667b6840e8d10c4e2eaf3b98a39a5b494efb396052003322003322003322003a481adf45b83af162a877990500375e0602e02f006b098b5ab9151bc6b2f0ad00231ff063ab41001e84d58edb340a7dd8a00046bf0e83ecdc03f016011012daf8fa157606dac9ddf3b96f0f24245e81988dc03530dd4d5a2555540efb2baed1863e069f5537902d801343f25816dd4601b0000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c086488000000a2494441545847ed964b0ac030084413dafb9fb88bc642200dea980f94c204bad2eae4f92139a57494efb3932980044880044880044880040204aee2734ebe58e0bfe84102030484b9313c013b92577d66acdf098850d17cb612f04458b6ad02a4ae43b734fc9ffe18e981362912d0dba7086837954072acbda0d9a7c7108ed0ea0e402568e36b48b5fc2d99c8c4b83dd027a8782325f07c5e71d12a0e505e73a1801b9c8b2581c49959130000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000009e494441545847ed96410ac0200c0495f6ff2feea17a08b4c1646314bcacd05b930c936db19652aef61c3b9500344003344003344003341030f0b477eee48d05d6a20b496fd0cf0a805bef01ac0e17696e1f0b60d77008e10164b55b7119e621020083e404f45b3b05d07bca1a7684d0ec81be0201b1d68120a1bd1500dd7c346c1b80566835d63b87eb8b18d079404dd15a7e998d0224ffc4b88c00c70dbcedba1d81b2a5703a0000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000092494441545847ed96410ac0200c0495f6ff2feea1061a0852bb9b40f1b282d0431227630af6d6da31f6b6d5052003322003322003322003a4816bc49dc9570b95c33e48ac586541680680ea644107731140b5f39967698201f0e42c4ccc2b0358277eb015612162ece71c2003b34a78a70f241c3e2f5c0160fe86df00e295d8f7db7cd0875b81ac01a6fb548c006460bb811b903311813716c23a0000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000089494441545847ed96b10ac0200c4423edff7f7187ea60493378977490c2096e313edf29d8ccece873db68029001199001199001199001c2c0d56bcee28f05ae653e24b0c9020eae4500b0016166d9230bc000c59a7f030cc3e3047ea00b99aa4711c4882b112cafc95780795a6f85817ca0b2003192b9b1d78e227a19a900102f8f2f11800c6c37700360131781b4054f830000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000091494441545847ed96b10e80200c444be4ffbfd8411848c060efda05872371f2da3e5ed050ccec6acfb1550420033220033220033220038481bb656af2c6026bd90b096cb401a46a1800aad1872158fb7b00b803e26cb83d9081a30068f8fc3e925da47906224d23d934c07b8867c0cbd2003dc80e8dc084003c88dd507ae783027d0523d71b6716fc85b30099e1548d001e930027810fe7f6160000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000098494441545847ed964b0ac0200c0523f5fe27eea26621049b98f82952784237d53c27038a8988aef21d1b090030000330000330000330e018b8cb7c5e7cad7433220f921508b7d60370030276a60decd8bcf2995996819d9b77217e033063a4ad5133a2062c00fecf433baa9f03c80d34c02500eeaa76573bec055a736dc6ebd47af7802c90619a766f5ebd3246000277cef812001c37f00086f72381b52e906c0000000049454e44ae426082'),bytes(hex'89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000092494441545847ed96d10ac02008458dedffbf780fab072142f3ea06637083bd44dae9e8a2262247ff3e1b8d0034400334400334400334001ab8faba33f96a816290070994c8810b63770023788cecc957966d1e0f20244f96632c377322004f60e6d87f01a832355ded03adbfdb4bc85fe0d56f4e6e6d0095ae0a60255fe708f0aa01b429c3a65bef0fb4070af70e1642801b8ad723816807111a0000000049454e44ae426082')];
}

File 13 of 13 : Context.sol
// 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;
    }
}

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

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ApprovalCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"ApprovalQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"ApproveToCaller","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"MintERC2309QuantityExceedsLimit","type":"error"},{"inputs":[],"name":"MintToZeroAddress","type":"error"},{"inputs":[],"name":"MintZeroQuantity","type":"error"},{"inputs":[],"name":"OwnerQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"OwnershipNotInitializedForExtraData","type":"error"},{"inputs":[],"name":"TransferCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferToNonERC721ReceiverImplementer","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[],"name":"URIQueryForNonexistentToken","type":"error"},{"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":"uint256","name":"fromTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toTokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"ConsecutiveTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"EFeed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"EHit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"EPlay","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":"uint256","name":"","type":"uint256"}],"name":"TMGGs","outputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"lastFeed","type":"uint256"},{"internalType":"uint256","name":"lastPlay","type":"uint256"},{"internalType":"uint256","name":"lastHit","type":"uint256"},{"internalType":"uint256","name":"birthhash","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"addresses","type":"address[]"},{"internalType":"uint256[]","name":"quantity","type":"uint256[]"}],"name":"airdrop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"airdropProgress","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"airdropReceivers","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"_proof","type":"bytes32[]"}],"name":"allowlistHatchEgg","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":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"propMaxSupply","type":"uint256"},{"internalType":"uint256","name":"petMaxSupply","type":"uint256"},{"internalType":"bool","name":"revealProp","type":"bool"},{"internalType":"bool","name":"revealPet","type":"bool"},{"internalType":"enum Tamagogi.MintStage","name":"mintStage","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"feed","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":"uint256","name":"tokenId","type":"uint256"}],"name":"getBirthdate","outputs":[{"internalType":"uint256","name":"month","type":"uint256"},{"internalType":"uint256","name":"day","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getPetHungerAndBored","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getPetUnhappinessAndProp","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bool","name":"","type":"bool"},{"internalType":"bool","name":"","type":"bool"},{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"hatchEgg","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"hit","outputs":[],"stateMutability":"nonpayable","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":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"isBirthdate","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"nameTable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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":"address","name":"","type":"address"}],"name":"petMinted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"play","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"propMinted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"reroll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rerollTable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rootHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","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":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"seeds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[3]","name":"_rate","type":"uint256[3]"}],"name":"setBoredRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[3]","name":"_rate","type":"uint256[3]"}],"name":"setHitRasing","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[3]","name":"_rate","type":"uint256[3]"}],"name":"setHitRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[3]","name":"_rate","type":"uint256[3]"}],"name":"setHungerRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_hash","type":"bytes32"}],"name":"setMerkle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stage","type":"uint256"}],"name":"setMintStage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"string","name":"name","type":"string"}],"name":"setName","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_price","type":"uint256"}],"name":"setPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[5]","name":"_rate","type":"uint256[5]"}],"name":"setReactionRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"setRevealPet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"setRevealProp","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":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"tokensOfOwner","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"}]

6101c06040526000608081815260a082905260c082905260e09190915260016101008190526101208190526101408190526101605260026101808190526101a0526200004f90600a90816200107c565b506040805160a08101825260046060820190815263199bdbd960e21b6080830152815281518083018352600380825262746f7960e81b602083810191909152808401929092528351808501855260068152651cda1a595b1960d21b9281019290925292820152620000c49160149190620010c4565b506040805160c081019091526036606082018181528291620088716080840139815260200160405180606001604052806028815260200162008b756028913981526020016040518060600160405280602a81526020016200939d602a9139905262000134906017906003620010c4565b5060408051606081018252600181526002602082015260039181018290526200016191601a919062001117565b50604080516101a08101825260008152600160208201526002918101919091526003606082015260046080820152600560a0820152600660c0820152600760e082015260086101008201526009610120820152600a610140820152600b610160820152600c610180820152620001dc90601d90600d6200114c565b506040805160a081018252600081526001602082015260029181019190915260036060820152600460808201526200021990602a90600562001181565b50604080516101608101825260008152600160208201526002918101919091526003606082015260046080820152600560a0820152600660c0820152600760e082015260086101008201526009610120820152600a6101408201526200028490602f90600b620011b6565b50604080516101608101825260008152600160208201526002918101919091526003606082015260046080820152600560a0820152600660c0820152600760e082015260086101008201526009610120820152600a610140820152620002ef90603a90600b620011b6565b50604080516101e08101825260066101a08201818152654d656c6f647960d01b6101c084015282528251808401845260058082526443696e6e6160d81b6020838101919091528085019290925284518086018652838152652930b1b7b7b760d11b81840152848601528451808601865260088152672637b7339032b0b960c11b81840152606085015284518086018652600380825262446f6760e81b8285015260808601919091528551808701875282815264546564647960d81b8185015260a08601528551808701875282815264547261706160d81b8185015260c086015285518087018752600981526829b437b93a3430b4b960b91b8185015260e08601528551808701875293845265149858989a5d60d21b84840152610100850193909352845180860186526004808252634d69636b60e01b8285015261012086019190915285518087018752918252644d6f75736560d81b8284015261014085019190915284518086018652908152632132b0b960e11b8183015261016084015283518085019094529083526210d85d60ea1b908301526101808101919091526200049d90604590600d620011eb565b506040805160e081018252600660a0820190815265139bdc9b585b60d21b60c0830152815281518083018352600580825264416e67727960d81b6020838101919091528084019290925283518085018552600381526214d85960ea1b81840152838501528351808501855281815264536d696c6560d81b818401526060840152835180850190945280845264155c1cd95d60da1b9184019190915260808201929092526200054f916052919062001230565b50604080516101a08101825260046101608201818152632437b93760e11b6101808401528252825180840184526008815267576869736b65727360c01b6020828101919091528084019190915283518085018552600c81526b15da1a5cdad95c9cc819985d60a21b818301528385015283518085018552600680825265466c7566667960d01b82840152606085019190915284518086018652600d81526c2bb434b9b5b2b939903a3434b760991b818401526080850152845180860186528181526553717561726560d01b8184015260a08501528451808601865260078152662430b6b9ba32b960c91b8184015260c08501528451808601865290815265139bdc9b585b60d21b8183015260e084015283518085018552600a815269437269636574696e616560b01b8183015261010084015283518085018552918252634e616a6160e01b82820152610120830191909152825180840190935260058352640506c756d760dc1b90830152610140810191909152620006d390605790600b62001275565b506040518061016001604052806040518060400160405280600381526020016214da5d60ea1b815250815260200160405180604001604052806005815260200164447265737360d81b81525081526020016040518060400160405280600581526020016414dd185b9960da1b8152508152602001604051806040016040528060098152602001680487564646c652075760bc1b815250815260200160405180604001604052806006815260200165466565626c6560d01b81525081526020016040518060400160405280600481526020016329ba30b960e11b815250815260200160405180604001604052806007815260200166436c6f7468657360c81b8152508152602001604051806040016040528060068152602001655374726f6e6760d01b81525081526020016040518060400160405280600581526020016414dc5d585d60da1b81525081526020016040518060400160405280600481526020016348756c6b60e01b8152508152602001604051806040016040528060098152602001684c6f6e67206c65677360b81b815250815250606290600b6200087992919062001275565b5060405180602001604052806040518060e0016040528060ac8152602001620092f160ac91399052620008b190606d906001620012ba565b50604080516102a0810190915260c96101a082018181528291620086076101c0840139815260200160405180610100016040528060d8815260200162008e8c60d8913981526020016040518060e0016040528060b5815260200162009e6260b5913981526020016040518060e0016040528060bb815260200162008aba60bb913981526020016040518060e0016040528060be8152602001620099e260be9139815260200160405180610100016040528060c78152602001620086d060c7913981526020016040518060e0016040528060bd81526020016200969c60bd913981526020016040518060e0016040528060b98152602001620095e360b9913981526020016040518060e0016040528060b1815260200162009aa060b1913981526020016040518060e0016040528060b081526020016200915a60b0913981526020016040518060e0016040528060b1815260200162008a0960b1913981526020016040518060e0016040528060ae815260200162009cd960ae913981526020016040518060e0016040528060b6815260200162009fd460b69139905262000a5c90606e90600d6200130d565b5060408051610180810190915260a860a0820181815282916200900860c084013981526020016040518060e0016040528060a78152602001620088a760a7913981526020016040518060e0016040528060aa81526020016200a17560aa913981526020016040518060e0016040528060a4815260200162008cf960a4913981526020016040518060e0016040528060ac815260200162008c4d60ac9139905262000b0b90607b90600562001352565b5060408051610240810190915260bd6101608201818152829162009f1761018084013981526020016040518060e0016040528060b881526020016200a21f60b8913981526020016040518060e0016040528060b381526020016200984660b3913981526020016040518060e0016040528060a4815260200162008f6460a4913981526020016040518060e0016040528060a981526020016200953a60a9913981526020016040518060c0016040528060928152602001620093c76092913981526020016040518060e0016040528060ad815260200162009b5160ad913981526020016040518060e0016040528060aa8152602001620090b060aa913981526020016040518060e0016040528060b0815260200162008b9d60b0913981526020016040518060e0016040528060a981526020016200848c60a9913981526020016040518060e0016040528060bb81526020016200894e60bb9139905262000c7690608090600b62001397565b50604080516102a08101909152610102610160820181815282916200838a610180840139815260200160405180610120016040528060ed81526020016200975960ed9139815260200160405180610120016040528060ef815260200162008d9d60ef9139815260200160405180610120016040528060e98152602001620098f960e99139815260200160405180610120016040528060eb81526020016200a08a60eb9139815260200160405180610120016040528060e781526020016200920a60e79139815260200160405180610100016040528060db815260200162009bfe60db9139815260200160405180610100016040528060d281526020016200853560d29139815260200160405180610100016040528060da81526020016200879760da9139815260200160405180610120016040528060e181526020016200945960e19139815260200160405180610100016040528060db815260200162009d8760db9139905262000dec90608b90600b62001397565b5060405162000dfb90620013dc565b604051809103906000f08015801562000e18573d6000803e3d6000fd5b50609680546001600160a01b0319166001600160a01b0392909216919091179055600060978190556361cf998160b35560b4819055600160b55560b6556103b360b75534801562000e6857600080fd5b506040518060400160405280600d81526020016c54616d61676f6769205065747360981b8152506040518060400160405280600881526020016754414d41474f474960c01b81525062000eca62000ec46200102860201b60201c565b6200102c565b815162000edf906003906020850190620013ea565b50805162000ef5906004906020840190620013ea565b506001808155600955505060006098556107d0609955610721609a5560ac805462ff00001916905560408051606081018252600881526028602082015260789181019190915262000f4b90609b90600362001117565b506040805160608101825260068152601e6020820152605a9181019190915262000f7a90609e90600362001117565b50604080516060810182526004815260146020820152603c9181019190915262000fa99060a190600362001117565b50604080516060810182526009815260036020820181905260019282019290925262000fd99160a4919062001117565b506040805160a08101825260008152600a6020820152601491810191909152601e606082015260286080820152620010169060a790600562001181565b5060ac805461ffff191690556200153f565b3390565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b82600a8101928215620010b2579160200282015b82811115620010b2578251829060ff1690559160200191906001019062001090565b50620010c092915062001467565b5090565b826003810192821562001109579160200282015b82811115620011095782518051620010f8918491602090910190620013ea565b5091602001919060010190620010d8565b50620010c09291506200147e565b8260038101928215620010b25791602002820182811115620010b2578251829060ff1690559160200191906001019062001090565b82600d8101928215620010b25791602002820182811115620010b2578251829060ff1690559160200191906001019062001090565b8260058101928215620010b25791602002820182811115620010b2578251829060ff1690559160200191906001019062001090565b82600b8101928215620010b25791602002820182811115620010b2578251829060ff1690559160200191906001019062001090565b82600d810192821562001109579160200282015b828111156200110957825180516200121f918491602090910190620013ea565b5091602001919060010190620011ff565b826005810192821562001109579160200282015b8281111562001109578251805162001264918491602090910190620013ea565b509160200191906001019062001244565b82600b810192821562001109579160200282015b82811115620011095782518051620012a9918491602090910190620013ea565b509160200191906001019062001289565b8260018101928215620012ff579160200282015b82811115620012ff5782518051620012ee918491602090910190620013ea565b5091602001919060010190620012ce565b50620010c09291506200149f565b82600d8101928215620012ff579160200282015b82811115620012ff578251805162001341918491602090910190620013ea565b509160200191906001019062001321565b8260058101928215620012ff579160200282015b82811115620012ff578251805162001386918491602090910190620013ea565b509160200191906001019062001366565b82600b8101928215620012ff579160200282015b82811115620012ff5782518051620013cb918491602090910190620013ea565b5091602001919060010190620013ab565b61154e8062006e3c83390190565b828054620013f89062001502565b90600052602060002090601f0160209004810192826200141c5760008555620010b2565b82601f106200143757805160ff1916838001178555620010b2565b82800160010185558215620010b2579182015b82811115620010b25782518255916020019190600101906200144a565b5b80821115620010c0576000815560010162001468565b80821115620010c0576000620014958282620014c0565b506001016200147e565b80821115620010c0576000620014b68282620014c0565b506001016200149f565b508054620014ce9062001502565b6000825580601f10620014df575050565b601f016020900490600052602060002090810190620014ff919062001467565b50565b600181811c908216806200151757607f821691505b602082108114156200153957634e487b7160e01b600052602260045260246000fd5b50919050565b6158ed806200154f6000396000f3fe6080604052600436106102c95760003560e01c806370a0823111610175578063b88d4fde116100dc578063e985e9c511610095578063f0503e801161006f578063f0503e801461094f578063f2fde38b1461097c578063f59dfdfb1461099c578063fe55932a146109bc57600080fd5b8063e985e9c5146108c6578063ebd799cc1461090f578063ebf6e91d1461092f57600080fd5b8063b88d4fde14610800578063c23c863b14610820578063c87b56dd14610850578063ca9c4b3314610870578063d3a2da3814610878578063df33fa31146108b357600080fd5b806391b7f5ed1161012e57806391b7f5ed1461073b57806395d89b411461075b5780639b993a1a14610770578063a22cb465146107a0578063a22d5823146107c0578063b6d22551146107e057600080fd5b806370a082311461063f578063715018a61461065f5780637908213d1461067457806379502c55146106a55780638462151c146106f05780638da5cb5b1461071d57600080fd5b806332063f52116102345780635a353cd3116101ed57806366d38ba9116101c757806366d38ba9146105bf57806367243482146105df5780636840690b146105ff5780636898f82b1461061f57600080fd5b80635a353cd3146105555780635d186c9f1461058a5780636352211e1461059f57600080fd5b806332063f521461049a57806335b34ca2146104b05780633cd434aa146104e057806341b3ba3d146104f557806342842e0e14610515578063439bbfd21461053557600080fd5b80630ea61c47116102865780630ea61c47146103bf57806318160ddd146104075780631c19c2151461042e5780631d80009a1461044e57806323b872dd1461046457806325b1f5ef1461048457600080fd5b806301ffc9a7146102ce57806306fdde0314610303578063081812fc1461032557806308a337331461035d578063095ea7b31461037f57806309a3849a1461039f575b600080fd5b3480156102da57600080fd5b506102ee6102e93660046145ef565b6109dc565b60405190151581526020015b60405180910390f35b34801561030f57600080fd5b50610318610a2e565b6040516102fa9190615615565b34801561033157600080fd5b506103456103403660046145d6565b610ac0565b6040516001600160a01b0390911681526020016102fa565b34801561036957600080fd5b5061037d610378366004614592565b610b04565b005b34801561038b57600080fd5b5061037d61039a3660046144ba565b610b1d565b3480156103ab57600080fd5b5061037d6103ba3660046145b4565b610bbd565b3480156103cb57600080fd5b506103df6103da3660046145d6565b610bd2565b60408051948552921515602085015290151591830191909152151560608201526080016102fa565b34801561041357600080fd5b5060025460015403600019015b6040519081526020016102fa565b34801561043a57600080fd5b5061037d6104493660046145d6565b610fe2565b34801561045a57600080fd5b5061042060975481565b34801561047057600080fd5b5061037d61047f3660046143c6565b611127565b34801561049057600080fd5b5061042060b75481565b3480156104a657600080fd5b5061042060b65481565b3480156104bc57600080fd5b506102ee6104cb366004614378565b60b26020526000908152604090205460ff1681565b3480156104ec57600080fd5b5061037d6112b8565b34801561050157600080fd5b5061037d6105103660046145d6565b6112d1565b34801561052157600080fd5b5061037d6105303660046143c6565b6112de565b34801561054157600080fd5b5061037d610550366004614592565b6112fe565b34801561056157600080fd5b506105756105703660046145d6565b611313565b604080519283526020830191909152016102fa565b34801561059657600080fd5b5061037d611644565b3480156105ab57600080fd5b506103456105ba3660046145d6565b61165b565b3480156105cb57600080fd5b5061037d6105da3660046145d6565b611666565b3480156105eb57600080fd5b5061037d6105fa3660046144e4565b6116a8565b34801561060b57600080fd5b506102ee61061a3660046145d6565b611788565b34801561062b57600080fd5b5061037d61063a3660046145d6565b611b02565b34801561064b57600080fd5b5061042061065a366004614378565b611bbd565b34801561066b57600080fd5b5061037d611c0c565b34801561068057600080fd5b5061069461068f3660046145d6565b611c20565b6040516102fa959493929190615628565b3480156106b157600080fd5b50609854609954609a5460ac546106de9392919060ff808216916101008104821691620100009091041686565b6040516102fa969594939291906156ad565b3480156106fc57600080fd5b5061071061070b366004614378565b611cd6565b6040516102fa91906155dd565b34801561072957600080fd5b506000546001600160a01b0316610345565b34801561074757600080fd5b5061037d6107563660046145d6565b611de6565b34801561076757600080fd5b50610318611df3565b34801561077c57600080fd5b506102ee61078b3660046145d6565b60af6020526000908152604090205460ff1681565b3480156107ac57600080fd5b5061037d6107bb36600461447e565b611e02565b3480156107cc57600080fd5b5061037d6107db366004614592565b611e98565b3480156107ec57600080fd5b506105756107fb3660046145d6565b611ead565b34801561080c57600080fd5b5061037d61081b366004614402565b61212f565b34801561082c57600080fd5b506102ee61083b366004614378565b60b16020526000908152604090205460ff1681565b34801561085c57600080fd5b5061031861086b3660046145d6565b612179565b61037d612184565b34801561088457600080fd5b506102ee610893366004614629565b805160208183018101805160b08252928201919093012091525460ff1681565b61037d6108c1366004614550565b6122e4565b3480156108d257600080fd5b506102ee6108e1366004614393565b6001600160a01b03918216600090815260086020908152604080832093909416825291909152205460ff1690565b34801561091b57600080fd5b5061037d61092a366004614592565b6124fa565b34801561093b57600080fd5b5061037d61094a3660046145d6565b61250f565b34801561095b57600080fd5b5061042061096a3660046145d6565b60ad6020526000908152604090205481565b34801561098857600080fd5b5061037d610997366004614378565b6125c2565b3480156109a857600080fd5b5061037d6109b73660046145d6565b61263b565b3480156109c857600080fd5b5061037d6109d736600461468b565b6126ee565b60006301ffc9a760e01b6001600160e01b031983161480610a0d57506380ac58cd60e01b6001600160e01b03198316145b80610a285750635b5e139f60e01b6001600160e01b03198316145b92915050565b606060038054610a3d9061578f565b80601f0160208091040260200160405190810160405280929190818152602001828054610a699061578f565b8015610ab65780601f10610a8b57610100808354040283529160200191610ab6565b820191906000526020600020905b815481529060010190602001808311610a9957829003601f168201915b5050505050905090565b6000610acb826128f5565b610ae8576040516333d1c03960e21b815260040160405180910390fd5b506000908152600760205260409020546001600160a01b031690565b610b0c61292a565b610b1960a4826003614138565b5050565b6000610b288261165b565b9050336001600160a01b03821614610b6157610b4481336108e1565b610b61576040516367d9dca160e11b815260040160405180910390fd5b60008281526007602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b610bc561292a565b610b1960a7826005614176565b60ac54600090819081908190610100900460ff16610c0b5760405162461bcd60e51b8152600401610c0290615689565b60405180910390fd5b609954859081118015610c2d5750609954609a54610c299190615701565b8111155b610c495760405162461bcd60e51b8152600401610c029061565f565b600086815260ae6020526040808220815160a081019092528054429392919082908290610c759061578f565b80601f0160208091040260200160405190810160405280929190818152602001828054610ca19061578f565b8015610cee5780601f10610cc357610100808354040283529160200191610cee565b820191906000526020600020905b815481529060010190602001808311610cd157829003601f168201915b5050505050815260200160018201548152602001600282015481526020016003820154815260200160048201548152505090506000609660009054906101000a90046001600160a01b03166001600160a01b0316632af123b88360200151856040518363ffffffff1660e01b8152600401610d73929190918252602082015260400190565b60206040518083038186803b158015610d8b57600080fd5b505afa158015610d9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dc39190614672565b609654604080850151905163055e247760e31b81529293506000926001600160a01b0390921691632af123b891610e07918890600401918252602082015260400190565b60206040518083038186803b158015610e1f57600080fd5b505afa158015610e33573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e579190614672565b905060008360600151600014610e8857603c846060015186610e79919061574c565b610e839190615719565b610e8b565b60005b9050600060a18101548211610eb25760a460005b0154610eab908361572d565b9050610ee6565b60a254821015610ec55760a46001610e9f565b60a354821015610ed85760a46002610e9f565b610ee382600061572d565b90505b6000610ef461070b8e61165b565b90506000806000805b8451811015610fb0576000858281518110610f1a57610f1a615835565b602002602001015190506098600101548111610f9d57600081815260ad602052604081205490600a610f4c81846157df565b600a8110610f5c57610f5c615835565b0154905080610f725760009b5060019650610f9a565b8060011415610f885760009a5060019550610f9a565b8060021415610f9a5760009850600194505b50505b5080610fa8816157c4565b915050610efd565b50600085610fbe898b615701565b610fc89190615701565b9f50929d50909b5099505050505050505050509193509193565b8033610fed8261165b565b6001600160a01b03161461103f5760405162461bcd60e51b81526020600482015260196024820152782cb7ba9030b932903737ba103a37b5b2b713b99037bbb732b960391b6044820152606401610c02565b60ac54610100900460ff166110665760405162461bcd60e51b8152600401610c0290615689565b6099548290811180156110885750609954609a546110849190615701565b8111155b6110a45760405162461bcd60e51b8152600401610c029061565f565b600083815260af602052604090205460ff16156110f35760405162461bcd60e51b815260206004820152600d60248201526c4e6f7420617661696c61626c6560981b6044820152606401610c02565b6110fc83612984565b600093845260ad602090815260408086209290925560af9052909220805460ff191660011790555050565b6000611132826129dd565b9050836001600160a01b0316816001600160a01b0316146111655760405162a1148160e81b815260040160405180910390fd5b60008281526007602052604090208054338082146001600160a01b038816909114176111b25761119586336108e1565b6111b257604051632ce44b5f60e11b815260040160405180910390fd5b6001600160a01b0385166111d957604051633a954ecd60e21b815260040160405180910390fd5b80156111e457600082555b6001600160a01b038681166000908152600660205260408082208054600019019055918716808252919020805460010190554260a01b17600160e11b17600085815260056020526040902055600160e11b831661126f576001840160008181526005602052604090205461126d57600154811461126d5760008181526005602052604090208490555b505b83856001600160a01b0316876001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050505050565b6112c061292a565b60ac805461ff001916610100179055565b6112d961292a565b609755565b6112f98383836040518060200160405280600081525061212f565b505050565b61130661292a565b610b19609e826003614138565b60ac546000908190610100900460ff1661133f5760405162461bcd60e51b8152600401610c0290615689565b6099548390811180156113615750609954609a5461135d9190615701565b8111155b61137d5760405162461bcd60e51b8152600401610c029061565f565b600084815260ae6020526040808220815160a0810190925280544293929190829082906113a99061578f565b80601f01602080910402602001604051908101604052809291908181526020018280546113d59061578f565b80156114225780601f106113f757610100808354040283529160200191611422565b820191906000526020600020905b81548152906001019060200180831161140557829003601f168201915b5050505050815260200160018201548152602001600282015481526020016003820154815260200160048201548152505090506000609660009054906101000a90046001600160a01b03166001600160a01b0316632af123b88360200151856040518363ffffffff1660e01b81526004016114a7929190918252602082015260400190565b60206040518083038186803b1580156114bf57600080fd5b505afa1580156114d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f79190614672565b609654604080850151905163055e247760e31b81529293506000926001600160a01b0390921691632af123b89161153b918890600401918252602082015260400190565b60206040518083038186803b15801561155357600080fd5b505afa158015611567573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061158b9190614672565b9050600061159b61070b8a61165b565b905060005b81518110156116355760008282815181106115bd576115bd615835565b60200260200101519050609860010154811161162257600081815260ad602052604081205490600a6115ef81846157df565b600a81106115ff576115ff615835565b0154905080611611576000965061161f565b806001141561161f57600095505b50505b508061162d816157c4565b9150506115a0565b50919650945050505050915091565b61164c61292a565b60ac805460ff19166001179055565b6000610a28826129dd565b61166e61292a565b8060038111156116805761168061581f565b60ac805462ff00001916620100008360038111156116a0576116a061581f565b021790555050565b6116b061292a565b60b75460b6546116c1908590615701565b11156117025760405162461bcd60e51b815260206004820152601060248201526f115e18d95959081d1a19481b1a5b5a5d60821b6044820152606401610c02565b60005b838110156117675761175585858381811061172257611722615835565b90506020020160208101906117379190614378565b84848481811061174957611749615835565b90506020020135612a4d565b8061175f816157c4565b915050611705565b508383905060b6600082825461177d9190615701565b909155505050505050565b600081609860010154811180156117ae5750609954609a546117aa9190615701565b8111155b6117ca5760405162461bcd60e51b8152600401610c029061565f565b600083815260ae6020526040808220815160a081019092528054829082906117f19061578f565b80601f016020809104026020016040519081016040528092919081815260200182805461181d9061578f565b801561186a5780601f1061183f5761010080835404028352916020019161186a565b820191906000526020600020905b81548152906001019060200180831161184d57829003601f168201915b5050505050815260200160018201548152602001600282015481526020016003820154815260200160048201548152505090506000429050600060ad600087815260200190815260200160002054905060006301e13380826118cc91906157df565b60965460808601519192506001600160a01b0316906365c72840906118f2908490615701565b6040518263ffffffff1660e01b815260040161191091815260200190565b60206040518083038186803b15801561192857600080fd5b505afa15801561193c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119609190614672565b6096546040516301971ca160e61b8152600481018690526001600160a01b03909116906365c728409060240160206040518083038186803b1580156119a457600080fd5b505afa1580156119b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119dc9190614672565b148015611af5575060965460808501516001600160a01b039091169063a324ad2490611a09908490615701565b6040518263ffffffff1660e01b8152600401611a2791815260200190565b60206040518083038186803b158015611a3f57600080fd5b505afa158015611a53573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a779190614672565b6096546040516328c92b4960e21b8152600481018690526001600160a01b039091169063a324ad249060240160206040518083038186803b158015611abb57600080fd5b505afa158015611acf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611af39190614672565b145b9550505050505b50919050565b60ac54610100900460ff16611b295760405162461bcd60e51b8152600401610c0290615689565b609954819081118015611b4b5750609954609a54611b479190615701565b8111155b611b675760405162461bcd60e51b8152600401610c029061565f565b600082815260ae602090815260409182902042600290910155815184815233918101919091527fd0017656a8c92d10b2fa3a77fa3c1e8e4c28817e89311616b8eed8e68f68a95091015b60405180910390a15050565b60006001600160a01b038216611be6576040516323d3ad8160e21b815260040160405180910390fd5b506001600160a01b031660009081526006602052604090205467ffffffffffffffff1690565b611c1461292a565b611c1e6000612aac565b565b60ae60205260009081526040902080548190611c3b9061578f565b80601f0160208091040260200160405190810160405280929190818152602001828054611c679061578f565b8015611cb45780601f10611c8957610100808354040283529160200191611cb4565b820191906000526020600020905b815481529060010190602001808311611c9757829003601f168201915b5050505050908060010154908060020154908060030154908060040154905085565b60606000806000611ce685611bbd565b905060008167ffffffffffffffff811115611d0357611d0361584b565b604051908082528060200260200182016040528015611d2c578160200160208202803683370190505b509050611d5960408051608081018252600080825260208201819052918101829052606081019190915290565b60015b838614611dda57611d6c81612afc565b9150816040015115611d7d57611dd2565b81516001600160a01b031615611d9257815194505b876001600160a01b0316856001600160a01b03161415611dd25780838780600101985081518110611dc557611dc5615835565b6020026020010181815250505b600101611d5c565b50909695505050505050565b611dee61292a565b609855565b606060048054610a3d9061578f565b6001600160a01b038216331415611e2c5760405163b06307db60e01b815260040160405180910390fd5b3360008181526008602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b611ea061292a565b610b19609b826003614138565b6000808260986001015481118015611ed45750609954609a54611ed09190615701565b8111155b611ef05760405162461bcd60e51b8152600401610c029061565f565b600084815260ae6020526040808220815160a08101909252805482908290611f179061578f565b80601f0160208091040260200160405190810160405280929190818152602001828054611f439061578f565b8015611f905780601f10611f6557610100808354040283529160200191611f90565b820191906000526020600020905b815481529060010190602001808311611f7357829003601f168201915b505050505081526020016001820154815260200160028201548152602001600382015481526020016004820154815250509050600060ad600087815260200190815260200160002054905060006301e1338082611fed91906157df565b60965460808501519192506000916001600160a01b039091169063a324ad2490612018908590615701565b6040518263ffffffff1660e01b815260040161203691815260200190565b60206040518083038186803b15801561204e57600080fd5b505afa158015612062573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120869190614672565b60965460808601519192506000916001600160a01b03909116906365c72840906120b1908690615701565b6040518263ffffffff1660e01b81526004016120cf91815260200190565b60206040518083038186803b1580156120e757600080fd5b505afa1580156120fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061211f9190614672565b9197509095505050505050915091565b61213a848484611127565b6001600160a01b0383163b156121735761215684848484612b7b565b612173576040516368d2bf6b60e11b815260040160405180910390fd5b50505050565b6060610a2882612c73565b600360ac5462010000900460ff1660038111156121a3576121a361581f565b146121f05760405162461bcd60e51b815260206004820152601960248201527f4e6f7420696e20737461676520746f206d696e7420544d4747000000000000006044820152606401610c02565b609954609a546122009190615701565b60015460001901106122425760405162461bcd60e51b815260206004820152600b60248201526a139bc81c195d081b19599d60aa1b6044820152606401610c02565b33600090815260b2602052604090205460ff161561228d5760405162461bcd60e51b81526020600482015260086024820152674d617820746f203160c01b6044820152606401610c02565b609854349061229d90600161572d565b11156122dc5760405162461bcd60e51b815260206004820152600e60248201526d27379032b737bab3b41032ba341760911b6044820152606401610c02565b611c1e612d42565b600260ac5462010000900460ff1660038111156123035761230361581f565b146123505760405162461bcd60e51b815260206004820181905260248201527f4e6f7420696e20737461676520746f206d696e74206d65726b6c6520544d47476044820152606401610c02565b609954609a546123609190615701565b60015460001901106123a25760405162461bcd60e51b815260206004820152600b60248201526a139bc81c195d081b19599d60aa1b6044820152606401610c02565b33600090815260b2602052604090205460ff16156123ed5760405162461bcd60e51b81526020600482015260086024820152674d617820746f203160c01b6044820152606401610c02565b60985434906123fd90600161572d565b111561243c5760405162461bcd60e51b815260206004820152600e60248201526d27379032b737bab3b41032ba341760911b6044820152606401610c02565b6040516bffffffffffffffffffffffff193360601b1660208201526000906034016040516020818303038152906040528051906020012090506124b6838380806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250506097549150849050612ed4565b6124f25760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b210383937b7b360991b6044820152606401610c02565b6112f9612d42565b61250261292a565b610b1960a1826003614138565b60ac54610100900460ff166125365760405162461bcd60e51b8152600401610c0290615689565b6099548190811180156125585750609954609a546125549190615701565b8111155b6125745760405162461bcd60e51b8152600401610c029061565f565b600082815260ae602090815260409182902042600390910155815184815233918101919091527fbae6551c0ddf25aa6805100ecbdc4535f2933a14d7ebafe9fab66af752e232ec9101611bb1565b6125ca61292a565b6001600160a01b03811661262f5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610c02565b61263881612aac565b50565b60ac54610100900460ff166126625760405162461bcd60e51b8152600401610c0290615689565b6099548190811180156126845750609954609a546126809190615701565b8111155b6126a05760405162461bcd60e51b8152600401610c029061565f565b600082815260ae602090815260409182902042600190910155815184815233918101919091527fd73f65a9b0fee6c2e3e08fd03cb4800137b36882554a7211fe8ce842b3d4f4fe9101611bb1565b82336126f98261165b565b6001600160a01b03161461274b5760405162461bcd60e51b81526020600482015260196024820152782cb7ba9030b932903737ba103a37b5b2b713b99037bbb732b960391b6044820152606401610c02565b60ac54610100900460ff166127725760405162461bcd60e51b8152600401610c0290615689565b6099548490811180156127945750609954609a546127909190615701565b8111155b6127b05760405162461bcd60e51b8152600401610c029061565f565b60b084846040516127c292919061485d565b9081526040519081900360200190205460ff161561280f5760405162461bcd60e51b815260206004820152600a60248201526913985b5948195e1a5cdd60b21b6044820152606401610c02565b600061285085858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612eea92505050565b90506001811180156128625750601281105b61289f5760405162461bcd60e51b815260206004820152600e60248201526d4e6f742076616c6964206e616d6560901b6044820152606401610c02565b600086815260ae602052604090206128b89086866141a3565b50600160b086866040516128cd92919061485d565b908152604051908190036020019020805491151560ff19909216919091179055505050505050565b600081600111158015612909575060015482105b8015610a28575050600090815260056020526040902054600160e01b161590565b6000546001600160a01b03163314611c1e5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610c02565b60008061299260014361574c565b6040805191406020830152810184905233606090811b6bffffffffffffffffffffffff19169082015260740160408051601f1981840301815291905280516020909101209392505050565b60008180600111612a3457600154811015612a3457600081815260056020526040902054600160e01b8116612a32575b80612a2b575060001901600081815260056020526040902054612a0d565b9392505050565b505b604051636f96cda160e11b815260040160405180910390fd5b60005b81811015612aa1576000612a6560b554612984565b60b58054600090815260ad602052604081208390558154929350612a88836157c4565b9190505550508080612a99906157c4565b915050612a50565b50610b198282613027565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b604080516080810182526000808252602082018190529181018290526060810191909152600082815260056020526040902054610a2890604080516080810182526001600160a01b038316815260a083901c67ffffffffffffffff166020820152600160e01b831615159181019190915260e89190911c606082015290565b604051630a85bd0160e11b81526000906001600160a01b0385169063150b7a0290612bb09033908990889088906004016155aa565b602060405180830381600087803b158015612bca57600080fd5b505af1925050508015612bfa575060408051601f3d908101601f19168201909252612bf79181019061460c565b60015b612c55573d808015612c28576040519150601f19603f3d011682016040523d82523d6000602084013e612c2d565b606091505b508051612c4d576040516368d2bf6b60e11b815260040160405180910390fd5b805181602001fd5b6001600160e01b031916630a85bd0160e11b1490505b949350505050565b60608160018110158015612c8d5750600154600019018111155b612cc85760405162461bcd60e51b815260206004820152600c60248201526b139bdd081d985b1a59081a5960a21b6044820152606401610c02565b609954600090841115612cfb5760ac54610100900460ff16612cf257612ced84613041565b612d17565b612ced846130ee565b60ac5460ff16612d0e57612ced84613265565b612d1784613285565b905080604051602001612d2a9190615409565b60405160208183030381529060405292505050919050565b6000612d516001546000190190565b612d5c906001615701565b905060b45460051415612df957600060b45560965460b354604051631c85d48f60e21b81526004810191909152600160248201526001600160a01b0390911690637217523c9060440160206040518083038186803b158015612dbd57600080fd5b505afa158015612dd1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612df59190614672565b60b3555b6040805160c081018252600060a082018181528252426020808401829052838501919091526060830182905260b354608084015284825260ae81529290208151805192938493612e4c9284920190614216565b5060208201516001820155604082015160028201556060820151600382015560809091015160049091015560b48054906000612e87836157c4565b91905055506000612e9783612984565b600084815260ad602052604090208190559050612eb5336001613027565b505033600090815260b260205260409020805460ff1916600117905550565b600082612ee1858461342a565b14949350505050565b600080825b8051821015613020576007818381518110612f0c57612f0c615835565b01602001516001600160f81b031990811690911c16612f3757612f30600183615701565b915061300e565b8051600360f91b90600590839085908110612f5457612f54615835565b01602001516001600160f81b031990811690911c161415612f7a57612f30600283615701565b8051600760f91b90600490839085908110612f9757612f97615835565b01602001516001600160f81b031990811690911c161415612fbd57612f30600383615701565b8051600f60f91b90600390839085908110612fda57612fda615835565b01602001516001600160f81b031990811690911c16141561300057612f30600483615701565b61300b600183615701565b91505b82613018816157c4565b935050612eef565b5050919050565b610b19828260405180602001604052806000815250613477565b606060008061304f84611ead565b600086815260ad60205260408120549294509092506130e4613070876134e4565b613079866134e4565b613082866134e4565b61308b886134e4565b613094886134e4565b6130bb601a6130a460038b6157df565b600381106130b4576130b4615835565b01546134e4565b6040516020016130d096959493929190615104565b6040516020818303038152906040526135e2565b9695505050505050565b60606000806000806130ff86610bd2565b935093509350935060008061311388611313565b91509150600061312289611788565b905060008680156131305750855b80156131395750845b806131415750815b61314c57600061314f565b60015b9050600061315c89613748565b905060006040518060e001604052808d815260200160ad60008f81526020019081526020016000205481526020018781526020018681526020018b8152602001841515815260200160af60008f815260200190815260200160002060009054906101000a900460ff161515815250905060006131ec60ad60008f81526020019081526020016000205484866137a8565b905060006131f983613b8a565b61320284613d1c565b61320b85613d62565b61321486613e5c565b61322561322087613e95565b6135e2565b6040516020016132399594939291906148f3565b6040516020818303038152906040529050613253816135e2565b9e9d5050505050505050505050505050565b60606000612a2b613275846134e4565b6040516020016130d09190614fd2565b600081815260ad6020526040812054606091600a6132a381846157df565b600a81106132b3576132b3615835565b015490506000601782600381106132cc576132cc615835565b0180546132d89061578f565b80601f01602080910402602001604051908101604052809291908181526020018280546133049061578f565b80156133515780601f1061332657610100808354040283529160200191613351565b820191906000526020600020905b81548152906001019060200180831161333457829003601f168201915b5050505050905060006014836003811061336d5761336d615835565b0180546133799061578f565b80601f01602080910402602001604051908101604052809291908181526020018280546133a59061578f565b80156133f25780601f106133c7576101008083540402835291602001916133f2565b820191906000526020600020905b8154815290600101906020018083116133d557829003601f168201915b50505050509050600061341f613407886134e4565b838585866040516020016130d0959493929190614e29565b979650505050505050565b600081815b845181101561346f5761345b8286838151811061344e5761344e615835565b6020026020010151613ebe565b915080613467816157c4565b91505061342f565b509392505050565b6134818383613eea565b6001600160a01b0383163b156112f9576001548281035b6134ab6000868380600101945086612b7b565b6134c8576040516368d2bf6b60e11b815260040160405180910390fd5b8181106134985781600154146134dd57600080fd5b5050505050565b6060816135085750506040805180820190915260018152600360fc1b602082015290565b8160005b8115613532578061351c816157c4565b915061352b9050600a83615719565b915061350c565b60008167ffffffffffffffff81111561354d5761354d61584b565b6040519080825280601f01601f191660200182016040528015613577576020820181803683370190505b5090505b8415612c6b5761358c60018361574c565b9150613599600a866157df565b6135a4906030615701565b60f81b8183815181106135b9576135b9615835565b60200101906001600160f81b031916908160001a9053506135db600a86615719565b945061357b565b606081516000141561360257505060408051602081019091526000815290565b600060405180606001604052806040815260200161587860409139905060006003845160026136319190615701565b61363b9190615719565b61364690600461572d565b90506000613655826020615701565b67ffffffffffffffff81111561366d5761366d61584b565b6040519080825280601f01601f191660200182016040528015613697576020820181803683370190505b509050818152600183018586518101602084015b81831015613703576003830192508251603f8160121c168501518253600182019150603f81600c1c168501518253600182019150603f8160061c168501518253600182019150603f81168501518253506001016136ab565b60038951066001811461371d576002811461372e5761373a565b613d3d60f01b60011983015261373a565b603d60f81b6000198301525b509398975050505050505050565b60a754600090821161376157602a60035b015492915050565b60a85482101561377457602a6000613759565b60a95482101561378757602a6001613759565b60aa5482101561379a57602a6002613759565b602a6004613759565b919050565b60606000608b600b6137bb600488615719565b6137c591906157df565b600b81106137d5576137d5615835565b0180546137e19061578f565b80601f016020809104026020016040519081016040528092919081815260200182805461380d9061578f565b801561385a5780601f1061382f5761010080835404028352916020019161385a565b820191906000526020600020905b81548152906001019060200180831161383d57829003601f168201915b5050505050905060006080600b6003886138749190615719565b61387e91906157df565b600b811061388e5761388e615835565b01805461389a9061578f565b80601f01602080910402602001604051908101604052809291908181526020018280546138c69061578f565b80156139135780601f106138e857610100808354040283529160200191613913565b820191906000526020600020905b8154815290600101906020018083116138f657829003601f168201915b505050505090506000606e600d60028961392d9190615719565b61393791906157df565b600d811061394757613947615835565b0180546139539061578f565b80601f016020809104026020016040519081016040528092919081815260200182805461397f9061578f565b80156139cc5780601f106139a1576101008083540402835291602001916139cc565b820191906000526020600020905b8154815290600101906020018083116139af57829003601f168201915b505050505090506000607b87600581106139e8576139e8615835565b0180546139f49061578f565b80601f0160208091040260200160405190810160405280929190818152602001828054613a209061578f565b8015613a6d5780601f10613a4257610100808354040283529160200191613a6d565b820191906000526020600020905b815481529060010190602001808311613a5057829003601f168201915b505050505090506000613a7f85613fe1565b613a8885613fe1565b613a9184613fe1565b613a9a86613fe1565b604051602001613aad949392919061489c565b60405160208183030381529060405290508615613b7e5780613b5b606d6000018054613ad89061578f565b80601f0160208091040260200160405190810160405280929190818152602001828054613b049061578f565b8015613b515780601f10613b2657610100808354040283529160200191613b51565b820191906000526020600020905b815481529060010190602001808311613b3457829003601f168201915b5050505050613fe1565b604051602001613b6c92919061486d565b60405160208183030381529060405290505b98975050505050505050565b6060600080613b9c8460000151611ead565b91509150600060ae6000866000015181526020019081526020016000206040518060a0016040529081600082018054613bd49061578f565b80601f0160208091040260200160405190810160405280929190818152602001828054613c009061578f565b8015613c4d5780601f10613c2257610100808354040283529160200191613c4d565b820191906000526020600020905b815481529060010190602001808311613c3057829003601f168201915b50505050508152602001600182015481526020016002820154815260200160038201548152602001600482015481525050905060006001613c918360000151612eea565b11613cab5760405180602001604052806000815250613ccd565b8151604051613cbd9190602001614aac565b6040516020818303038152906040525b905080613cdd87600001516134e4565b613ce6866134e4565b613cef866134e4565b604051602001613d0294939291906152bd565b604051602081830303815290604052945050505050919050565b60606000613d2d83604001516134e4565b613d3a84606001516134e4565b604051602001613d4b929190614ba7565b60408051601f198184030181529190529392505050565b606060008260a00151613d8f57604051806040016040528060028152602001616e6f60f01b815250613dac565b6040518060400160405280600381526020016279657360e81b8152505b905060008360c00151613dd957604051806040016040528060028152602001616e6f60f01b815250613df6565b6040518060400160405280600381526020016279657360e81b8152505b905060008282613e0987608001516134e4565b613e1288613ffc565b613e1b89614030565b613e248a614088565b613e2d8b6140e0565b604051602001613e439796959493929190614cd7565b60408051601f1981840301815291905295945050505050565b6060600080613e6e8460000151611ead565b91509150613e7b826134e4565b613e84826134e4565b604051602001612d2a929190615379565b606081604051602001613ea8919061544e565b6040516020818303038152906040529050919050565b6000818310613eda576000828152602084905260409020612a2b565b5060009182526020526040902090565b60015481613f0b5760405163b562e8dd60e01b815260040160405180910390fd5b6001600160a01b03831660008181526006602090815260408083208054680100000000000000018802019055848352600590915281206001851460e11b4260a01b178317905582840190839083907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a4600183015b818114613fba57808360007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a4600101613f82565b5081613fd857604051622e076360e81b815260040160405180910390fd5b60015550505050565b6060613fec826135e2565b604051602001613ea89190614ad3565b60606000605261400f8460800151613748565b6005811061401f5761401f615835565b01604051602001613d4b919061527c565b606060006045601d600d6002866020015161404b9190615719565b61405591906157df565b600d811061406557614065615835565b0154600d811061407757614077615835565b01604051602001613d4b9190614c88565b606060006057602f600b600386602001516140a39190615719565b6140ad91906157df565b600b81106140bd576140bd615835565b0154600b81106140cf576140cf615835565b01604051602001613d4b919061556d565b606060006062603a600b600486602001516140fb9190615719565b61410591906157df565b600b811061411557614115615835565b0154600b811061412757614127615835565b01604051602001613d4b91906153cc565b8260038101928215614166579160200282015b8281111561416657823582559160200191906001019061414b565b5061417292915061428a565b5090565b8260058101928215614166579160200282018281111561416657823582559160200191906001019061414b565b8280546141af9061578f565b90600052602060002090601f0160209004810192826141d15760008555614166565b82601f106141ea5782800160ff19823516178555614166565b82800160010185558215614166579182018281111561416657823582559160200191906001019061414b565b8280546142229061578f565b90600052602060002090601f0160209004810192826142445760008555614166565b82601f1061425d57805160ff1916838001178555614166565b82800160010185558215614166579182015b8281111561416657825182559160200191906001019061426f565b5b80821115614172576000815560010161428b565b600067ffffffffffffffff808411156142ba576142ba61584b565b604051601f8501601f19908116603f011681019082821181831017156142e2576142e261584b565b816040528093508581528686860111156142fb57600080fd5b858560208301376000602087830101525050509392505050565b80356001600160a01b03811681146137a357600080fd5b60008083601f84011261433e57600080fd5b50813567ffffffffffffffff81111561435657600080fd5b6020830191508360208260051b850101111561437157600080fd5b9250929050565b60006020828403121561438a57600080fd5b612a2b82614315565b600080604083850312156143a657600080fd5b6143af83614315565b91506143bd60208401614315565b90509250929050565b6000806000606084860312156143db57600080fd5b6143e484614315565b92506143f260208501614315565b9150604084013590509250925092565b6000806000806080858703121561441857600080fd5b61442185614315565b935061442f60208601614315565b925060408501359150606085013567ffffffffffffffff81111561445257600080fd5b8501601f8101871361446357600080fd5b6144728782356020840161429f565b91505092959194509250565b6000806040838503121561449157600080fd5b61449a83614315565b9150602083013580151581146144af57600080fd5b809150509250929050565b600080604083850312156144cd57600080fd5b6144d683614315565b946020939093013593505050565b600080600080604085870312156144fa57600080fd5b843567ffffffffffffffff8082111561451257600080fd5b61451e8883890161432c565b9096509450602087013591508082111561453757600080fd5b506145448782880161432c565b95989497509550505050565b6000806020838503121561456357600080fd5b823567ffffffffffffffff81111561457a57600080fd5b6145868582860161432c565b90969095509350505050565b6000606082840312156145a457600080fd5b82606083011115611afc57600080fd5b600060a082840312156145c657600080fd5b8260a083011115611afc57600080fd5b6000602082840312156145e857600080fd5b5035919050565b60006020828403121561460157600080fd5b8135612a2b81615861565b60006020828403121561461e57600080fd5b8151612a2b81615861565b60006020828403121561463b57600080fd5b813567ffffffffffffffff81111561465257600080fd5b8201601f8101841361466357600080fd5b612c6b8482356020840161429f565b60006020828403121561468457600080fd5b5051919050565b6000806000604084860312156146a057600080fd5b83359250602084013567ffffffffffffffff808211156146bf57600080fd5b818601915086601f8301126146d357600080fd5b8135818111156146e257600080fd5b8760208285010111156146f457600080fd5b6020830194508093505050509250925092565b6000815180845261471f816020860160208601615763565b601f01601f19169290920160200192915050565b60008151614745818560208601615763565b9290920192915050565b8054600090600181811c908083168061476957607f831692505b602080841082141561478b57634e487b7160e01b600052602260045260246000fd5b81801561479f57600181146147b0576147dd565b60ff198616895284890196506147dd565b60008881526020902060005b868110156147d55781548b8201529085019083016147bc565b505084890196505b50505050505092915050565b7f7b202274726169745f74797065223a202274797065222c202276616c7565223a81526808089c195d1cc89f4b60ba1b602082015260290190565b7f7b202274726169745f74797065223a2022626972746864617465222c20227661815266363ab2911d101160c91b602082015260270190565b8183823760009101908152919050565b6000835161487f818460208801615763565b835190830190614893818360208801615763565b01949350505050565b600085516148ae818460208a01615763565b8551908301906148c2818360208a01615763565b85519101906148d5818360208901615763565b84519101906148e8818360208801615763565b019695505050505050565b60008651614905818460208b01615763565b80830190507f226465736372697074696f6e223a202254616d61676f6769206973206120546181527f6d61676f74636869204461707020616e642066756c6c792067656e657261746560208201527f64206f6e2d636861696e2e2054686520636f6e747261637420696e746572616360408201527f74696f6e20616e642074696d652077696c6c206166666563742074686520737460608201527f6174757320616e64207265616374696f6e206f6620746865207065742e20496660808201527f20796f7520636f6c6c656374206f74686572206974656d732c2074686520706560a0820152721d081dda5b1b081cda1bddc81b1bdd9948488b606a1b60c08201526e2261747472696275746573223a205b60881b60d38201528651614a328160e2840160208b01615763565b614a9f614a91614a8b614a53614a4d60e2868801018c614733565b8a614733565b7f5d2c22696d616765223a2022646174613a696d6167652f7376672b786d6c3b62815265185cd94d8d0b60d21b602082015260260190565b87614733565b61227d60f01b815260020190565b9998505050505050505050565b60008251614abe818460208701615763565b6201017960ed1b920191825250600301919050565b7f3c696d61676520783d22302220793d2230222077696474683d2233322220686581527f696768743d2233322220696d6167652d72656e646572696e673d22706978656c60208201527f6174656422207072657365727665417370656374526174696f3d22784d69645960408201527f4d69642220786c696e6b3a687265663d22646174613a696d6167652f706e673b60608201526618985cd94d8d0b60ca1b608082015260008251614b8d816087850160208701615763565b6211179f60e91b6087939091019283015250608a01919050565b7f7b202274726169745f74797065223a202268756e676572222c2022646973706c81527f61795f74797065223a20226e756d626572222c202276616c7565223a20000000602082015260008351614c0581603d850160208801615763565b8083019050611f4b60f21b80603d8301527f7b202274726169745f74797065223a2022626f726564222c2022646973706c61603f8301527f795f74797065223a20226e756d626572222c202276616c7565223a2000000000605f8301528451614c7581607b850160208901615763565b607b920191820152607d01949350505050565b7f7b202274726169745f74797065223a2022656172222c202276616c7565223a208152601160f91b60208201526000614cc4602183018461474f565b62089f4b60ea1b81526003019392505050565b6000614ce2826147e9565b7f7b202274726169745f74797065223a20226d6173746572222c202276616c7565815263111d101160e11b60208201528951614d25816024840160208e01615763565b62089f4b60ea1b6024929091019182018190527f7b202274726169745f74797065223a20227265726f6c6c6564222c202276616c6027830152653ab2911d101160d11b60478301528951614d8081604d850160208e01615763565b604d9201918201527f7b202274726169745f74797065223a2022756e68617070696e657373222c202260508201527f646973706c61795f74797065223a20226e756d626572222c202276616c75652260708201526101d160f51b6090820152614e1b614e15614a8b614e0f614e09614dfb609287018e614733565b611f4b60f21b815260020190565b8b614733565b89614733565b85614733565b9a9950505050505050505050565b6a7b226e616d65223a20222360a81b81528551600090614e5081600b850160208b01615763565b6a040a8c2dac2cedeced240560ab1b600b918401918201528651614e7b816016840160208b01615763565b7314911610113232b9b1b934b83a34b7b7111d101160611b601692909101918201528551614eb081602a840160208a01615763565b61088b60f21b9101602a8101919091526e2261747472696275746573223a205b60881b602c8201527f7b202274726169745f74797065223a202274797065222c202276616c7565223a603b8201526908089c1c9bdc1cc89f4b60b21b605b8201527f7b202274726169745f74797065223a20227573616765222c202276616c7565226065820152621d101160e91b6085820152613b7e614fc0614fba614f6b614f5b60888601614a4d565b63089f574b60e21b815260040190565b7f22696d616765223a2022697066733a2f2f516d56784344666d7767593270734181527f683777746938614c43796b6b6a3939736e79674751383970327a6b664174662f602082015260400190565b86614733565b652e676966227d60d01b815260060190565b6a7b226e616d65223a20222360a81b81528151600090614ff981600b850160208701615763565b7f2054616d61676f67692028556e72657665616c2050726f707329222c20226465600b9390910192830152507f736372697074696f6e223a2022556e72657665616c2050726f7073222c000000602b8201526e2261747472696275746573223a205b60881b60488201527f7b202274726169745f74797065223a202274797065222c202276616c7565223a605782015268202270726f7073227d60b81b607782015261174b60f21b60808201527f22696d616765223a2022697066733a2f2f516d5462423644443277387433367a60828201527f4c50764245646f576f363252464d794a69394558636a39395a6978507278432260a2820152607d60f81b60c282015260c301919050565b6a7b226e616d65223a20222360a81b8152865160009061512b81600b850160208c01615763565b6e040a8c2dac2cedeced2408acece405608b1b600b91840191820152875161515a81601a840160208c01615763565b602f60f81b601a9290910191820152865161517c81601b840160208b01615763565b602960f81b9101601b8101919091527f222c20226465736372697074696f6e223a2022556e62726f6b656e2054616d61601c8201526d19dbd9da481959d9dccb8b8b888b60921b603c8201526e2261747472696275746573223a205b60881b604a820152614a9f614fc0614fba61522d61521f614a91614e0961521261520c61520760598b016147e9565b614824565b8e614733565b602f60f81b815260010190565b61174b60f21b815260020190565b7f22696d616765223a2022697066733a2f2f516d57317463635971426d534c514681527f54664e38725777384a4858787837685a53344d6969775757444e35747647382f602082015260400190565b7f7b202274726169745f74797065223a20227265616374696f6e222c202276616c8152653ab2911d101160d11b60208201526000614cc4602683018461474f565b693d913730b6b2911d101160b11b815284516000906152e381600a850160208a01615763565b602360f81b600a91840191820152855161530481600b840160208a01615763565b6a040a8c2dac2cedeced240560ab1b600b92909101918201528451615330816016840160208901615763565b602f60f81b601692909101918201528351615352816017840160208801615763565b602960f81b6017929091019182015261088b60f21b6018820152601a019695505050505050565b600061538482614824565b8451615394818360208901615763565b602f60f81b910190815283516153b1816001840160208801615763565b61227d60f01b60019290910191820152600301949350505050565b7f7b202274726169745f74797065223a2022626f6479222c202276616c7565223a815261101160f11b60208201526000614cc4602283018461474f565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c00000081526000825161544181601d850160208701615763565b91909101601d0192915050565b7f3c7376672077696474683d2239363022206865696768743d223936302220766581527f7273696f6e3d22312e31222076696577426f783d22302030203332203332222060208201527f786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323030302f737660408201527f672220786d6c6e733a786c696e6b3d22687474703a2f2f7777772e77332e6f7260608201526d3397989c9c9c97bc3634b735911f60911b60808201527f3c726563742077696474683d223130302522206865696768743d223130302522608e82015271103334b6361e9111b0b0b21c9c9c9110179f60711b60ae820152600082516155508160c0850160208701615763565b651e17b9bb339f60d11b60c093909101928301525060c601919050565b7f7b202274726169745f74797065223a202268656164222c202276616c7565223a815261101160f11b60208201526000614cc4602283018461474f565b6001600160a01b03858116825284166020820152604081018390526080606082018190526000906130e490830184614707565b6020808252825182820181905260009190848201906040850190845b81811015611dda578351835292840192918401916001016155f9565b602081526000612a2b6020830184614707565b60a08152600061563b60a0830188614707565b90508560208301528460408301528360608301528260808301529695505050505050565b60208082526010908201526f139bdd081d985b1a59081c195d081a5960821b604082015260600190565b6020808252600a9082015269139bdd081c995d99585b60b21b604082015260600190565b86815260208101869052604081018590528315156060820152821515608082015260c08101600483106156f057634e487b7160e01b600052602160045260246000fd5b8260a0830152979650505050505050565b60008219821115615714576157146157f3565b500190565b60008261572857615728615809565b500490565b6000816000190483118215151615615747576157476157f3565b500290565b60008282101561575e5761575e6157f3565b500390565b60005b8381101561577e578181015183820152602001615766565b838111156121735750506000910152565b600181811c908216806157a357607f821691505b60208210811415611afc57634e487b7160e01b600052602260045260246000fd5b60006000198214156157d8576157d86157f3565b5060010190565b6000826157ee576157ee615809565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160e01b03198116811461263857600080fdfe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2fa264697066735822122069c56940fd46b970901e4cefbf1663ce7fd9f697bb1b49a889da5193c1fc526564736f6c63430008070033608060405234801561001057600080fd5b5061152e806100206000396000f3fe608060405234801561001057600080fd5b506004361061030b5760003560e01c80638aa001fc1161019d578063c7b6fd6a116100e9578063de5101af116100a2578063f615ed541161007c578063f615ed541461068a578063f9fd52501461069d578063fa93f883146106a5578063ff2258cb146106b857600080fd5b8063de5101af1461065c578063e95564301461066f578063ea1c16901461067757600080fd5b8063c7b6fd6a1461060b578063c7edf88c1461061e578063c9d3462214610626578063cfbb9f3714610639578063d2b5074314610641578063d6582d0d1461064957600080fd5b80639e524caa11610156578063ad203bd411610130578063ad203bd4146105cc578063b05eb08d146105df578063b3bb8cd4146105f2578063b8d16dbc146105f857600080fd5b80639e524caa1461059c578063a324ad24146105af578063a3f144ae146105c257600080fd5b80638aa001fc146104f85780638bbf51b71461050b5780638d4a2d391461051357806390059aed146105265780639220d4261461055457806392d663131461058957600080fd5b80634355644d1161025c5780635e05bd6d116102155780637217523c116101ef5780637217523c146104b557806374f0314f146104c85780637be34109146104d257806389a3a00d146104e557600080fd5b80635e05bd6d1461047c57806362fb96971461048f57806365c72840146104a257600080fd5b80634355644d146104145780634371c46514610427578063442b8c791461043a578063444fda821461044d5780634b321502146104605780634df861261461047357600080fd5b80631f4f77b2116102c95780632af123b8116102a35780632af123b8146103c85780633293d007146103db5780633e239e1a146103ee5780633f9e0eb71461040157600080fd5b80631f4f77b21461039a57806322f8a2b8146103ad57806329441674146103c057600080fd5b80625015531461031057806302e98e0d1461033657806310848ddf14610349578063126702a01461035c57806314b2d6dc146103645780631e0582e914610387575b600080fd5b61032361031e366004611292565b6106cb565b6040519081526020015b60405180910390f35b610323610344366004611292565b6106de565b610323610357366004611279565b6106ea565b610323600281565b6103776103723660046112b4565b6106fb565b604051901515815260200161032d565b6103236103953660046112b4565b610710565b6103236103a83660046112b4565b61071d565b6103236103bb366004611279565b61072a565b610323600781565b6103236103d6366004611292565b610735565b6103776103e93660046112e0565b610741565b6103236103fc366004611279565b61075c565b61032361040f366004611292565b610767565b610323610422366004611292565b610773565b610377610435366004611279565b61077f565b610323610448366004611292565b61078a565b61032361045b366004611292565b610796565b61032361046e366004611292565b6107a2565b610323610e1081565b61032361048a3660046112e0565b6107ae565b61032361049d366004611292565b6107c8565b6103236104b0366004611279565b6107d4565b6103236104c3366004611292565b6107df565b6103236201518081565b6103236104e0366004611292565b6107eb565b6103236104f3366004611292565b6107f7565b610323610506366004611279565b610803565b610323600381565b610323610521366004611292565b61080e565b610539610534366004611279565b61081a565b6040805193845260208401929092529082015260600161032d565b61055c610835565b604080519687526020870195909552938501929092526060840152608083015260a082015260c00161032d565b610323610597366004611279565b61085a565b6103236105aa366004611292565b610865565b6103236105bd366004611279565b610871565b61032362253d8c81565b6103236105da366004611292565b61087c565b6103776105ed366004611279565b610888565b42610323565b610377610606366004611279565b610893565b610323610619366004611292565b61089e565b610323600681565b610323610634366004611292565b6108aa565b610323600481565b610323600581565b610377610657366004611279565b6108b6565b61053961066a366004611279565b6108c1565b610323603c81565b61055c610685366004611279565b6108dc565b610323610698366004611292565b610902565b610323600181565b6103236106b3366004611279565b61090e565b6103236106c6366004611292565b610919565b60006106d78383610925565b9392505050565b60006106d7838361094c565b60006106f582610971565b92915050565b6000610708848484610999565b949350505050565b60006107088484846109ef565b6000610708848484610b2c565b60006106f582610b47565b60006106d78383610b7b565b6000610751878787878787610b97565b979650505050505050565b60006106f582610bd7565b60006106d78383610bf5565b60006106d78383610c7b565b60006106f582610d4d565b60006106d78383610d62565b60006106d78383610d96565b60006106d78383610e17565b6000610751878787878787610e3e565b9695505050505050565b60006106d78383610e8f565b60006106f582610ea8565b60006106d78383610eba565b60006106d78383610ec9565b60006106d78383610f40565b60006106f582610f4d565b60006106d78383610f5a565b600080600061082884610f66565b9250925092509193909250565b60008060008060008061084742611002565b949b939a50919850965094509092509050565b60006106f582611043565b60006106d7838361105e565b60006106f58261106b565b60006106d7838361107d565b60006106f582611151565b60006106f58261118d565b60006106d783836111ad565b60006106d783836111bc565b60006106f5826111d9565b60008060006108cf846111ee565b9196909550909350915050565b6000806000806000806108ee87611002565b949c939b5091995097509550909350915050565b60006106d783836111ff565b60006106f58261120b565b60006106d78383611227565b6000610933610e1083611443565b61093d90846114a1565b9050828111156106f557600080fd5b60008183111561095b57600080fd5b603c61096784846114a1565b6106d791906113aa565b6000808061098a61098562015180866113aa565b610f66565b50915091506107088282610bf5565b60006107b284101580156109ad5750600083115b80156109ba5750600c8311155b156106d75760006109cb8585610bf5565b90506000831180156109dd5750808311155b156109e757600191505b509392505050565b60006107b2841015610a0057600080fd5b838383600062253d8c60046064600c610a1a600e88611462565b610a24919061137c565b610a3088611324611323565b610a3a9190611323565b610a44919061137c565b610a4f9060036113be565b610a59919061137c565b600c80610a67600e88611462565b610a71919061137c565b610a7c90600c6113be565b610a87600288611462565b610a919190611462565b610a9d9061016f6113be565b610aa7919061137c565b6004600c610ab6600e89611462565b610ac0919061137c565b610acc896112c0611323565b610ad69190611323565b610ae2906105b56113be565b610aec919061137c565b610af8617d4b87611462565b610b029190611323565b610b0c9190611323565b610b169190611462565b610b209190611462565b98975050505050505050565b600062015180610b3d8585856109ef565b6107089190611443565b600080610b5762015180846113aa565b90506007610b66826003611364565b610b7091906114b8565b6106d7906001611364565b600081831115610b8a57600080fd5b610e1061096784846114a1565b6000610ba4878787610999565b156107be57601884108015610bb95750603c83105b8015610bc55750603c82105b156107be575060019695505050505050565b600080610be762015180846114b8565b90506106d7610e10826113aa565b60008160011480610c065750816003145b80610c115750816005145b80610c1c5750816007145b80610c275750816008145b80610c32575081600a145b80610c3d575081600c145b15610c4a5750601f6106f5565b81600214610c5a5750601e6106f5565b610c6383611151565b610c6e57601c610c71565b601d5b60ff169392505050565b6000808080610c9061098562015180886113aa565b91945092509050610ca18583611364565b9150600c610cb06001846114a1565b610cba91906113aa565b610cc49084611364565b9250600c610cd36001846114a1565b610cdd91906114b8565b610ce8906001611364565b91506000610cf68484610bf5565b905080821115610d04578091505b610d1162015180886114b8565b62015180610d208686866109ef565b610d2a9190611443565b610d349190611364565b945086851015610d4357600080fd5b5050505092915050565b60006006610d5a83610b47565b101592915050565b6000808080610d7761098562015180886113aa565b91945092509050610d888584611364565b92506000610cf68484610bf5565b6000808080610dab61098562015180886113aa565b91945092509050610dbc85846114a1565b92506000610dca8484610bf5565b905080821115610dd8578091505b610de562015180886114b8565b62015180610df48686866109ef565b610dfe9190611443565b610e089190611364565b945086851115610d4357600080fd5b6000610e25610e1083611443565b610e2f9084611364565b9050828110156106f557600080fd5b600081610e4c603c85611443565b610e58610e1087611443565b62015180610e678b8b8b6109ef565b610e719190611443565b610e7b9190611364565b610e859190611364565b6107519190611364565b600081831115610e9e57600080fd5b6106d783836114a1565b600061070861098562015180846113aa565b6000610e256201518083611443565b600081831115610ed857600080fd5b600080610eeb61098562015180876113aa565b509092509050600080610f0461098562015180886113aa565b50909250905082610f1685600c611443565b82610f2285600c611443565b610f2c9190611364565b610f3691906114a1565b61075191906114a1565b6000610e25603c83611443565b60006106f5603c836114b8565b6000610e2f8284611364565b60008080836226496581018262023ab1600483020590506004600362023ab18302010590910390600062164b09610fa0600185010205905060046105b58202058303601f019250600061098f8460500281610fc357610fc36114e2565b0590506000605061098f83020585039050600b820560301994909401606402929092018301996002600c90940290910392909201975095509350505050565b6000808080808061101862015180885b04610f66565b91999098919750610e10620151809092068281049750603c9290068281049650919091069350915050565b600061105561098562015180846113aa565b50909392505050565b6000610933603c83611443565b60006109e761098562015180846113aa565b600080808061109261098562015180886113aa565b919450925090506000856110a76001856114a1565b6110b286600c611443565b6110bc9190611364565b6110c691906114a1565b90506110d3600c826113aa565b93506110e0600c826114b8565b6110eb906001611364565b925060006110f98585610bf5565b905080831115611107578092505b61111462015180896114b8565b620151806111238787876109ef565b61112d9190611443565b6111379190611364565b95508786111561114657600080fd5b505050505092915050565b600061115e6004836114b8565b15801561117457506111716064836114b8565b15155b806106f55750611186610190836114b8565b1592915050565b6000806111a061098562015180856113aa565b505090506106d781611151565b60006109336201518083611443565b6000818311156111cb57600080fd5b6201518061096784846114a1565b600060056111e683610b47565b111592915050565b600080806108cf6201518085611012565b600061093d82846114a1565b60008061121a610e10846114b8565b90506106d7603c826113aa565b60008183111561123657600080fd5b600061124861098562015180866113aa565b505090506000611260620151808561098591906113aa565b50509050818161127091906114a1565b95945050505050565b60006020828403121561128b57600080fd5b5035919050565b600080604083850312156112a557600080fd5b50508035926020909101359150565b6000806000606084860312156112c957600080fd5b505081359360208301359350604090920135919050565b60008060008060008060c087890312156112f957600080fd5b505084359660208601359650604086013595606081013595506080810135945060a0013592509050565b600080821280156001600160ff1b0384900385131615611345576113456114cc565b600160ff1b839003841281161561135e5761135e6114cc565b50500190565b60008219821115611377576113776114cc565b500190565b60008261138b5761138b6114e2565b600160ff1b8214600019841416156113a5576113a56114cc565b500590565b6000826113b9576113b96114e2565b500490565b60006001600160ff1b03818413828413808216868404861116156113e4576113e46114cc565b600160ff1b6000871282811687830589121615611403576114036114cc565b6000871292508782058712848416161561141f5761141f6114cc565b87850587128184161615611435576114356114cc565b505050929093029392505050565b600081600019048311821515161561145d5761145d6114cc565b500290565b60008083128015600160ff1b850184121615611480576114806114cc565b6001600160ff1b038401831381161561149b5761149b6114cc565b50500390565b6000828210156114b3576114b36114cc565b500390565b6000826114c7576114c76114e2565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fdfea26469706673582212202464ec77d55c0b8b938a36e973509d6bb0bb2d18b4f4c56e73bccd066d6eca6264736f6c6343000807003389504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c086488000000b9494441545847ed96c10e80200c4321faff5fec4139cce0dc68410c979178215bf7a81b21a794b6eb5bb672008403e14038100e8403e140384038705c31fbe08b05e6b20f1228640052390c0025e4380473110014207e4d53a30530a3b8f0b95a1ec08ce2b5c6278051189d67ea300e588965afac7a3cbd3d89e90228e2226815d2a22dbb2db0bb77d1140888770a298c00dc8b8c01d010f5e4590008fa31b97f01c0f193001640f70471ffbc9ad4cce901608b76c52d073801df502d81d35c52b50000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000060494441545847ed96410a00200804f3ff8f2e844e511a68e461bab74ea348d23e1ff95cbf0180010c9436d0e78e88429a39a770bd142dbceeb86d2600650d68ff32e7e098e50d5a068499e101444db80fb80178fa6500000318c00006308081013eee10210f9b3be30000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000089494441545847ed96b10ac0200c4423edff7f7187ea60493378977490c2096e313edf29d8ccece873db68029001199001199001199001c2c0d56bcee28f05ae653e24b0c9020eae4500b0016166d9230bc000c59a7f030cc3e3047ea00b99aa4711c4882b112cafc95780795a6f85817ca0b2003192b9b1d78e227a19a900102f8f2f11800c6c37700360131781b4054f830000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000080494441545847ed94410ac0200c04f5ff8f6ec921250475d7da22c87ad48d1927602d9b57dddcbf30005782ecd5e49c95c1fb51c02ecd196f14f75b3903e8ed3f6f1a01a0623f6773cd69af00f80b91ea21203382b70d284308c0b5cd6a8ef925032c401c4736f609c06fdf053b0201c8800cc8800cc8800cc8800cc8c0b9066edd51182171bab4cb0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000007e494441545847ed92510ac0300843dbfb1f7a459820d22e993f52c8be0a33f1edad73343fb379ff60009e1792998ddf43e550a995f84c3c237174ee0b2097a0a5bbf7109e017095b6001973889c39da438595e52788ad410460a13fff3e2f81d92b002a978fce3006e8b2caa00064400664400664400664400664a0ddc00276971321672fab0a0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000091494441545847ed96b10e80200c444be4ffbfd8411848c060efda05872371f2da3e5ed050ccec6acfb1550420033220033220033220038481bb656af2c6026bd90b096cb401a46a1800aad1872158fb7b00b803e26cb83d9081a30068f8fc3e925da47906224d23d934c07b8867c0cbd2003dc80e8dc084003c88dd507ae783027d0523d71b6716fc85b30099e1548d001e930027810fe7f6160000000049454e44ae426082466f6f642077696c6c2062652061626c6520746f2070726576656e7420796f7572207065742066726f6d2073746172766174696f6e2e89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000005e494441545847ed95390e00200cc3e8ff1fcd3180104294b64317334362792052928f24f717003080010c60c06aa0f6af5b7bf373672d8016769b8a5781a97c847b004e2873e91e100598e56e88284078cd01c000063080010c6020dd4003cbd40721aa0beb880000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000072494441545847ed94310e00210804f5ff8ff68ec2c4e2803d43a2c55859c0b219597b3b7cfae1f90d031080804260bc5155eabe129df666c2a980f08f841a91818ae1d39fabe519a81c1e9ac0c0b504ecdd2af7e0f712ae8b63f72cae5e1a6d70d8bf2b2cc45f2bc10004200001084000020fec3f1221ce89b1720000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000068494441545847ed94c10a00101404f9ff8f2607a5478c835cc64dedee5b4372fabcf2e7f9c902844019ae89e89b1c7b4e812d68d4c4fdea095d796e0bc4d3ad0ac4cc6de953813e90e8088d49438309fa188e3cb4c0b3efc20212908004242001094840021290400533b70d21044e4ab70000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000072494441545847ed94510a00210844ebfe876e290844dacd8996085e7fd1a8e353cae9f0c987eba7a881628cce62146dc8404d688bfabb85a8685bdcac9baa51922ada7b0d742aa3fdf544bfc6b544a02fd8dbe8fcfb1603b6e3c8ce48fa68c2dfbe0b0c40000210800004200001084000020fc5ac172190ff741b0000000049454e44ae426082546f79732063616e206b65657020796f7572207065742066726f6d206265696e6720626f7265642e89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000067494441545847ed954b0a00200805f3fe87eeb368994f2ab0605ae77318c3ac241f4bee5f00c00006be3050fbaed80595b5916019e22c33590b8032201506fe1237c303b8d17cf22db39e0618f4372c6c8f2030def32bea119e7710090060000318c00006d20d343af6102106b4da3d0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000063494441545847ed954b0a00200844f3fe87eeb3898848cdc0cd6b6d33d3131a29c94792fd0b012000010840c04ba0f6af5bbb6399990da0899daae266e0321fe2de001603cb4c88c04a6598bd3ce45b80709b7b571036dc05080001084000021080400354df0721739252ba0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000005b494441545847edd5310e0020080441f9ffa3550a3b20014968d69620e714226bf8c8f0fc450004104000818ac0bedfb7d717d5cc5f3f1be00db006453577e56403b4efaedf00fa6a3de57bca8d5d1404400001041040008171810356ee0721ed9f05790000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c086488000000a6494441545847ed96c10a80201883957aff27ee501e0493e9e6df218405dedcfcfe39c29c523a9ef5db970de0049c801370024ec009ec90c0f5409ec10703d5aaef016a0400258d0220190d12a25a06400d84ab997acc007ae10a8cac1d01208332ac5ac6a2eff7c30114802a8c24d06a96000a7d3f450400f9bc6ac34ad86e8e024c7bfa05a026540f68fb21c34601d001f4be51145b01d04281e2d2ffd44a02d42cb2c10037c7f12981ef4fbe3c0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000008f494441545847ed93d10e80200845f5ff3fba461b8de80a526daeedf6a628f778b4de167f7d717efb05c0662c09b01d23817e4d78c8cc8084d9357e8c004a7b228052234732bd1701a8e2cc4ef5fdc2be5eaf34ad2acf40908d3347c3d0ddeadcccbd8f20a21e476d04f0263483d1fa054026fdef96a97d52bf657cfdd0ca5004a0011aa0011aa0011aa0011aa0811d3de21d21bb35e40a0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000005b494441545847ed94db0900200cc474ffa17d2c604a058b10bfbdf408b4bd15bf5e3cbf5940031af8c2c058b7225b14b3044640e0901d195460f36f4a60960a2040031a7861203023ff85b6204f0e262da0010d6840031a283730013af6102192d097b20000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000005f494441545847edd5bb0a00200846617dff87ae961a44f042e0721a237fe51b5265f8e8707f61000410400081aac03a5f77549379f3364014665745263cf3a63d80b7bb4a0d6d4055c013b977adac56d1cf15ce0008208000020820302eb00182580621fa639d260000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000061494441545847ed94410e00100c04f5ff8f460f8eac20a926e3cc760cad95e065c1f50b0018c0400a03b5cf8a5350795605cb808d41b6ccf81ae0c5ed87a069d6ca403880d3bf80c8fb07e4fbdd76809f575db051e36e0b0018c000063080010c343af61021f9935c500000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000067494441545847ed93410a00200cc3f4ff8f56100411ba513d8810cfb5ed32ade5f1a98ff3cb1705da46292b6de95db3d945dddbc3337db80265a64c5dfdf08908b886aefebac03a40162e873d7d03eeef9539590137c8d6530002108000042000010840000210e80b6d0b213ce71b1e0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000009e494441545847ed96410ac0200c0495f6ff2feea17a08b4c1646314bcacd05b930c936db19652aef61c3b9500344003344003344003341030f0b477eee48d05d6a20b496fd0cf0a805bef01ac0e17696e1f0b60d77008e10164b55b7119e621020083e404f45b3b05d07bca1a7684d0ec81be0201b1d68120a1bd1500dd7c346c1b80566835d63b87eb8b18d079404dd15a7e998d0224ffc4b88c00c70dbcedba1d81b2a5703a0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af4000000017352474200aece1ce900000066494441545847edd5310e00100c85613d8efb1fc67108092961914a0dbfc540f25e3f0309ce4b9cf30305104000010410f84720c7982525e9fb8b5f7297d104eac11a58cb589638658c107dc13abc0fb2cb98a67cc9af4be8014d996f9e8c02082080000208145bcb2821effa51fe0000000049454e44ae426082536869656c6420746f2070726f7465637420796f7572207065742066726f6d206265696e67206869742e89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000049494441545847edd6410a00200804c0fcffa3ab17a40421c17857973988319a2b9af70f010810f84260ee5b711b34edad0c4e871c8e59da2b0001021581a72f8300040810204080c0023af610215e442abd0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000098494441545847ed964b0ac0200c0523f5fe27eea26621049b98f82952784237d53c27038a8988aef21d1b090030000330000330000330e018b8cb7c5e7cad7433220f921508b7d60370030276a60decd8bcf2995996819d9b77217e033063a4ad5133a2062c00fecf433baa9f03c80d34c02500eeaa76573bec055a736dc6ebd47af7802c90619a766f5ebd3246000277cef812001c37f00086f72381b52e906c0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000060494441545847edd6cb0a0020084451fdff8feeb16813e4580411dcd669c31124b7c7c71fbf6f044000812f044adb15a741656da6b16c122c33594b804860f049c6c408963dd4087ae138eaee9c23558bc02eebf5ef030110400001041040a0028cd31421444923dc0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000070494441545847ed92410ac0200c04f5ff8f6e9b4341aa761772082de34590641d27f656bc7af1fded3300c7652a609ffb28d0a999843b0676c1713eae15e0ddbb9db4029001c61f7acd5000919f8190bd0a4006fcde80f1c05c891a412edde806000318c000063080010c600003e5064e048315215641d2fc0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000074494441545847ed94310ec0200cc4e0ff8f2e4202d481e452a062317372674cd59c2e9f7cb93f298067027874c70b9b95771e6beff3ce4a9005e1959be03b0035b4ef47cadff3e365d57bd6c168b8f53dbb1d11801d08992f07dab5562dc87c39f0f77f02000c60000318c000063080010c60a000b8610b216fdcaceb0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c086488000000a4494441545847ed964b0ac0200c05957aff1377515d0444f2796ac1169e20144c759c1831a794aeda8fb54c001aa0011aa0011aa0011a000cdc35a62cbe58c27f9107493f49fb9636426963db00e304b3000dd685f00c788b2319e90d991016c0eee25a9a5488cf0248ee10d5688c5a494815ecc084e5fb2b006d375296d6d86b06ac7ab600c20b480e0e9a0289ef2f22eff0853b5f05404f3c1c376b009e180d3c0ef000b15d1d81d94175870000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000006a494441545847ed944b0a00200844ebfe87eeb310dae88404153c5741cc383cc55a2e57bddcbf10000210f882401bb7221b546a95b134d83864a14714e04473cbe77a7901a6c04a515210422f083c4b605d9ef9ceee81cddfd5678dd5e26dff130002108000042000810e4ece1021878663410000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c086488000000a0494441545847ed96c10a8020104495faff2fee907b30ac5667b6840e8d10c4e2eaf3b98a39a5b494efb396052003322003322003322003a481adf45b83af162a877990500375e0602e02f006b098b5ab9151bc6b2f0ad00231ff063ab41001e84d58edb340a7dd8a00046bf0e83ecdc03f016011012daf8fa157606dac9ddf3b96f0f24245e81988dc03530dd4d5a2555540efb2baed1863e069f5537902d801343f25816dd4601b0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000075494441545847ed92410ec0200804f5ff8f6ee381a4c12a0b1ebc8ce765990cf676f9f5cbfb5b04f038c0286f71796e57e84bac3c8248cdadca5625a7179bf6650046768029062ceb81cb00eaf2ef1ff88328016497ef206400af4e515f9a89ee79fae9c279003080010c60000318c0000630808117a9bd1321772d676e0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000068494441545847ed94610b00100c44f9ff3f9a28b5165792d6eaf9a6e1eede965a82570dd62fe90c3443cc9b57b523e81b0243c09eb77b55935d4e63c0271ca914015f7f6e41a8819df84ab406efd44a7577be7133035fbe0c0c40000210800004200001084000021df3d61521c08b49860000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000064494441545847ed94490e00200803f1ff8f763978841a354193e16a6ceb80144bae92ec6f04800004be2050fbaed80d2aef2a6129b0b0c8428da703dc78fd04e46a79046e9a872108100de168c32835a8ea23843aa7e2ca5c9e13000210800004200081063eee1021a0220e8e0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000092494441545847ed96410ac0200c0495f6ff2feea1061a0852bb9b40f1b282d0431227630af6d6da31f6b6d5052003322003322003322003a4816bc49dc9570b95c33e48ac586541680680ea644107731140b5f39967698201f0e42c4ccc2b0358277eb015612162ece71c2003b34a78a70f241c3e2f5c0160fe86df00e295d8f7db7cd0875b81ac01a6fb548c006460bb811b903311813716c23a0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000065494441545847edd4dd0a00100c8661bbff8ba61d90ffad24a9d7216bfb3c8984c74b1ecf0fdf04889dd42ab8b7aeb4f30868d3beee64afb98b1560362837a8cfbc75c393238025a06416afd6ec1ee5768627c0d5af82000820800002082080000208209000f7ce15214de4787a0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000092494441545847ed96d10ac02008458dedffbf780fab072142f3ea06637083bd44dae9e8a2262247ff3e1b8d0034400334400334400334001ab8faba33f96a816290070994c8810b63770023788cecc957966d1e0f20244f96632c377322004f60e6d87f01a832355ded03adbfdb4bc85fe0d56f4e6e6d0095ae0a60255fe708f0aa01b429c3a65bef0fb4070af70e1642801b8ad723816807111a0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000006c494441545847edd4d10a4011108461deffa14951d2b2e342a8ff5c9d8bc98e8fc470f98b97e7876f0aa42aa51696f3ca8265b196ebff67a7b795f70a5803572576f3ee1d980d6bc4a382b5a1a5daf3026587cab92bf7c1cc7802c79f090a2080000208208000020820804006486e132187d8c7c60000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000074494441545847ed94410ec0200cc3e0ff8f66e3c01192954905c99c9bd432526b497e35797f01000318b8c6407befc557582be3945a45938326b30a4016189774d9b102f863f9e09b761d6d40d2efeaef7965a0cfec7c85cc3a005108b9dc3560988e8fb806e21b4412000c60000318c040ba81073af6102143c1dc740000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000006d494441545847ed93410ac0200c04f5ff8f5602e6225476410896e979b39d0cb1b7e2af17ffbf3d0130962517569a534ab32838947ce4e419a530ca22276db4e572f6f3d41c807db3d3fd66ef7500f7d1fc03c0dddaca2b376015ba61003080010c60000318c0000630506e6002f73b0f211a4494500000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c086488000000a2494441545847ed964b0ac030084413dafb9fb88bc642200dea980f94c204bad2eae4f92139a57494efb3932980044880044880044880040204aee2734ebe58e0bfe84102030484b9313c013b92577d66acdf098850d17cb612f04458b6ad02a4ae43b734fc9ffe18e981362912d0dba7086837954072acbda0d9a7c7108ed0ea0e402568e36b48b5fc2d99c8c4b83dd027a8782325f07c5e71d12a0e505e73a1801b9c8b2581c49959130000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000061494441545847ed95410a00200804ebff8f2e3a142115ae045ea6abad4e73b05a924f4d9e5f00c00006308001d540db56b7cdbe6ad78daf028c4663d02df7aa1d215400cf00cf9d05a302d8574cede13ee1e0af6f1c000c60000318c00006d20d745ccf0721d52fc6040000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af4000000017352474200aece1ce900000072494441545847ed943112c0200804cf49feffe214190a6752c1450a2dd65a605d9021e9d2c63300c000063060187824dd8bbbaa8cad165199c0004b73380051a363208dcf0082bc537cca49f31c6d205eb0750666f10e4499a36ac1b78f7f07d10277018cdfb67605000c60000318c000065e01921281db558cba0000000049454e44ae426082

Deployed Bytecode

0x6080604052600436106102c95760003560e01c806370a0823111610175578063b88d4fde116100dc578063e985e9c511610095578063f0503e801161006f578063f0503e801461094f578063f2fde38b1461097c578063f59dfdfb1461099c578063fe55932a146109bc57600080fd5b8063e985e9c5146108c6578063ebd799cc1461090f578063ebf6e91d1461092f57600080fd5b8063b88d4fde14610800578063c23c863b14610820578063c87b56dd14610850578063ca9c4b3314610870578063d3a2da3814610878578063df33fa31146108b357600080fd5b806391b7f5ed1161012e57806391b7f5ed1461073b57806395d89b411461075b5780639b993a1a14610770578063a22cb465146107a0578063a22d5823146107c0578063b6d22551146107e057600080fd5b806370a082311461063f578063715018a61461065f5780637908213d1461067457806379502c55146106a55780638462151c146106f05780638da5cb5b1461071d57600080fd5b806332063f52116102345780635a353cd3116101ed57806366d38ba9116101c757806366d38ba9146105bf57806367243482146105df5780636840690b146105ff5780636898f82b1461061f57600080fd5b80635a353cd3146105555780635d186c9f1461058a5780636352211e1461059f57600080fd5b806332063f521461049a57806335b34ca2146104b05780633cd434aa146104e057806341b3ba3d146104f557806342842e0e14610515578063439bbfd21461053557600080fd5b80630ea61c47116102865780630ea61c47146103bf57806318160ddd146104075780631c19c2151461042e5780631d80009a1461044e57806323b872dd1461046457806325b1f5ef1461048457600080fd5b806301ffc9a7146102ce57806306fdde0314610303578063081812fc1461032557806308a337331461035d578063095ea7b31461037f57806309a3849a1461039f575b600080fd5b3480156102da57600080fd5b506102ee6102e93660046145ef565b6109dc565b60405190151581526020015b60405180910390f35b34801561030f57600080fd5b50610318610a2e565b6040516102fa9190615615565b34801561033157600080fd5b506103456103403660046145d6565b610ac0565b6040516001600160a01b0390911681526020016102fa565b34801561036957600080fd5b5061037d610378366004614592565b610b04565b005b34801561038b57600080fd5b5061037d61039a3660046144ba565b610b1d565b3480156103ab57600080fd5b5061037d6103ba3660046145b4565b610bbd565b3480156103cb57600080fd5b506103df6103da3660046145d6565b610bd2565b60408051948552921515602085015290151591830191909152151560608201526080016102fa565b34801561041357600080fd5b5060025460015403600019015b6040519081526020016102fa565b34801561043a57600080fd5b5061037d6104493660046145d6565b610fe2565b34801561045a57600080fd5b5061042060975481565b34801561047057600080fd5b5061037d61047f3660046143c6565b611127565b34801561049057600080fd5b5061042060b75481565b3480156104a657600080fd5b5061042060b65481565b3480156104bc57600080fd5b506102ee6104cb366004614378565b60b26020526000908152604090205460ff1681565b3480156104ec57600080fd5b5061037d6112b8565b34801561050157600080fd5b5061037d6105103660046145d6565b6112d1565b34801561052157600080fd5b5061037d6105303660046143c6565b6112de565b34801561054157600080fd5b5061037d610550366004614592565b6112fe565b34801561056157600080fd5b506105756105703660046145d6565b611313565b604080519283526020830191909152016102fa565b34801561059657600080fd5b5061037d611644565b3480156105ab57600080fd5b506103456105ba3660046145d6565b61165b565b3480156105cb57600080fd5b5061037d6105da3660046145d6565b611666565b3480156105eb57600080fd5b5061037d6105fa3660046144e4565b6116a8565b34801561060b57600080fd5b506102ee61061a3660046145d6565b611788565b34801561062b57600080fd5b5061037d61063a3660046145d6565b611b02565b34801561064b57600080fd5b5061042061065a366004614378565b611bbd565b34801561066b57600080fd5b5061037d611c0c565b34801561068057600080fd5b5061069461068f3660046145d6565b611c20565b6040516102fa959493929190615628565b3480156106b157600080fd5b50609854609954609a5460ac546106de9392919060ff808216916101008104821691620100009091041686565b6040516102fa969594939291906156ad565b3480156106fc57600080fd5b5061071061070b366004614378565b611cd6565b6040516102fa91906155dd565b34801561072957600080fd5b506000546001600160a01b0316610345565b34801561074757600080fd5b5061037d6107563660046145d6565b611de6565b34801561076757600080fd5b50610318611df3565b34801561077c57600080fd5b506102ee61078b3660046145d6565b60af6020526000908152604090205460ff1681565b3480156107ac57600080fd5b5061037d6107bb36600461447e565b611e02565b3480156107cc57600080fd5b5061037d6107db366004614592565b611e98565b3480156107ec57600080fd5b506105756107fb3660046145d6565b611ead565b34801561080c57600080fd5b5061037d61081b366004614402565b61212f565b34801561082c57600080fd5b506102ee61083b366004614378565b60b16020526000908152604090205460ff1681565b34801561085c57600080fd5b5061031861086b3660046145d6565b612179565b61037d612184565b34801561088457600080fd5b506102ee610893366004614629565b805160208183018101805160b08252928201919093012091525460ff1681565b61037d6108c1366004614550565b6122e4565b3480156108d257600080fd5b506102ee6108e1366004614393565b6001600160a01b03918216600090815260086020908152604080832093909416825291909152205460ff1690565b34801561091b57600080fd5b5061037d61092a366004614592565b6124fa565b34801561093b57600080fd5b5061037d61094a3660046145d6565b61250f565b34801561095b57600080fd5b5061042061096a3660046145d6565b60ad6020526000908152604090205481565b34801561098857600080fd5b5061037d610997366004614378565b6125c2565b3480156109a857600080fd5b5061037d6109b73660046145d6565b61263b565b3480156109c857600080fd5b5061037d6109d736600461468b565b6126ee565b60006301ffc9a760e01b6001600160e01b031983161480610a0d57506380ac58cd60e01b6001600160e01b03198316145b80610a285750635b5e139f60e01b6001600160e01b03198316145b92915050565b606060038054610a3d9061578f565b80601f0160208091040260200160405190810160405280929190818152602001828054610a699061578f565b8015610ab65780601f10610a8b57610100808354040283529160200191610ab6565b820191906000526020600020905b815481529060010190602001808311610a9957829003601f168201915b5050505050905090565b6000610acb826128f5565b610ae8576040516333d1c03960e21b815260040160405180910390fd5b506000908152600760205260409020546001600160a01b031690565b610b0c61292a565b610b1960a4826003614138565b5050565b6000610b288261165b565b9050336001600160a01b03821614610b6157610b4481336108e1565b610b61576040516367d9dca160e11b815260040160405180910390fd5b60008281526007602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b610bc561292a565b610b1960a7826005614176565b60ac54600090819081908190610100900460ff16610c0b5760405162461bcd60e51b8152600401610c0290615689565b60405180910390fd5b609954859081118015610c2d5750609954609a54610c299190615701565b8111155b610c495760405162461bcd60e51b8152600401610c029061565f565b600086815260ae6020526040808220815160a081019092528054429392919082908290610c759061578f565b80601f0160208091040260200160405190810160405280929190818152602001828054610ca19061578f565b8015610cee5780601f10610cc357610100808354040283529160200191610cee565b820191906000526020600020905b815481529060010190602001808311610cd157829003601f168201915b5050505050815260200160018201548152602001600282015481526020016003820154815260200160048201548152505090506000609660009054906101000a90046001600160a01b03166001600160a01b0316632af123b88360200151856040518363ffffffff1660e01b8152600401610d73929190918252602082015260400190565b60206040518083038186803b158015610d8b57600080fd5b505afa158015610d9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dc39190614672565b609654604080850151905163055e247760e31b81529293506000926001600160a01b0390921691632af123b891610e07918890600401918252602082015260400190565b60206040518083038186803b158015610e1f57600080fd5b505afa158015610e33573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e579190614672565b905060008360600151600014610e8857603c846060015186610e79919061574c565b610e839190615719565b610e8b565b60005b9050600060a18101548211610eb25760a460005b0154610eab908361572d565b9050610ee6565b60a254821015610ec55760a46001610e9f565b60a354821015610ed85760a46002610e9f565b610ee382600061572d565b90505b6000610ef461070b8e61165b565b90506000806000805b8451811015610fb0576000858281518110610f1a57610f1a615835565b602002602001015190506098600101548111610f9d57600081815260ad602052604081205490600a610f4c81846157df565b600a8110610f5c57610f5c615835565b0154905080610f725760009b5060019650610f9a565b8060011415610f885760009a5060019550610f9a565b8060021415610f9a5760009850600194505b50505b5080610fa8816157c4565b915050610efd565b50600085610fbe898b615701565b610fc89190615701565b9f50929d50909b5099505050505050505050509193509193565b8033610fed8261165b565b6001600160a01b03161461103f5760405162461bcd60e51b81526020600482015260196024820152782cb7ba9030b932903737ba103a37b5b2b713b99037bbb732b960391b6044820152606401610c02565b60ac54610100900460ff166110665760405162461bcd60e51b8152600401610c0290615689565b6099548290811180156110885750609954609a546110849190615701565b8111155b6110a45760405162461bcd60e51b8152600401610c029061565f565b600083815260af602052604090205460ff16156110f35760405162461bcd60e51b815260206004820152600d60248201526c4e6f7420617661696c61626c6560981b6044820152606401610c02565b6110fc83612984565b600093845260ad602090815260408086209290925560af9052909220805460ff191660011790555050565b6000611132826129dd565b9050836001600160a01b0316816001600160a01b0316146111655760405162a1148160e81b815260040160405180910390fd5b60008281526007602052604090208054338082146001600160a01b038816909114176111b25761119586336108e1565b6111b257604051632ce44b5f60e11b815260040160405180910390fd5b6001600160a01b0385166111d957604051633a954ecd60e21b815260040160405180910390fd5b80156111e457600082555b6001600160a01b038681166000908152600660205260408082208054600019019055918716808252919020805460010190554260a01b17600160e11b17600085815260056020526040902055600160e11b831661126f576001840160008181526005602052604090205461126d57600154811461126d5760008181526005602052604090208490555b505b83856001600160a01b0316876001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050505050565b6112c061292a565b60ac805461ff001916610100179055565b6112d961292a565b609755565b6112f98383836040518060200160405280600081525061212f565b505050565b61130661292a565b610b19609e826003614138565b60ac546000908190610100900460ff1661133f5760405162461bcd60e51b8152600401610c0290615689565b6099548390811180156113615750609954609a5461135d9190615701565b8111155b61137d5760405162461bcd60e51b8152600401610c029061565f565b600084815260ae6020526040808220815160a0810190925280544293929190829082906113a99061578f565b80601f01602080910402602001604051908101604052809291908181526020018280546113d59061578f565b80156114225780601f106113f757610100808354040283529160200191611422565b820191906000526020600020905b81548152906001019060200180831161140557829003601f168201915b5050505050815260200160018201548152602001600282015481526020016003820154815260200160048201548152505090506000609660009054906101000a90046001600160a01b03166001600160a01b0316632af123b88360200151856040518363ffffffff1660e01b81526004016114a7929190918252602082015260400190565b60206040518083038186803b1580156114bf57600080fd5b505afa1580156114d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f79190614672565b609654604080850151905163055e247760e31b81529293506000926001600160a01b0390921691632af123b89161153b918890600401918252602082015260400190565b60206040518083038186803b15801561155357600080fd5b505afa158015611567573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061158b9190614672565b9050600061159b61070b8a61165b565b905060005b81518110156116355760008282815181106115bd576115bd615835565b60200260200101519050609860010154811161162257600081815260ad602052604081205490600a6115ef81846157df565b600a81106115ff576115ff615835565b0154905080611611576000965061161f565b806001141561161f57600095505b50505b508061162d816157c4565b9150506115a0565b50919650945050505050915091565b61164c61292a565b60ac805460ff19166001179055565b6000610a28826129dd565b61166e61292a565b8060038111156116805761168061581f565b60ac805462ff00001916620100008360038111156116a0576116a061581f565b021790555050565b6116b061292a565b60b75460b6546116c1908590615701565b11156117025760405162461bcd60e51b815260206004820152601060248201526f115e18d95959081d1a19481b1a5b5a5d60821b6044820152606401610c02565b60005b838110156117675761175585858381811061172257611722615835565b90506020020160208101906117379190614378565b84848481811061174957611749615835565b90506020020135612a4d565b8061175f816157c4565b915050611705565b508383905060b6600082825461177d9190615701565b909155505050505050565b600081609860010154811180156117ae5750609954609a546117aa9190615701565b8111155b6117ca5760405162461bcd60e51b8152600401610c029061565f565b600083815260ae6020526040808220815160a081019092528054829082906117f19061578f565b80601f016020809104026020016040519081016040528092919081815260200182805461181d9061578f565b801561186a5780601f1061183f5761010080835404028352916020019161186a565b820191906000526020600020905b81548152906001019060200180831161184d57829003601f168201915b5050505050815260200160018201548152602001600282015481526020016003820154815260200160048201548152505090506000429050600060ad600087815260200190815260200160002054905060006301e13380826118cc91906157df565b60965460808601519192506001600160a01b0316906365c72840906118f2908490615701565b6040518263ffffffff1660e01b815260040161191091815260200190565b60206040518083038186803b15801561192857600080fd5b505afa15801561193c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119609190614672565b6096546040516301971ca160e61b8152600481018690526001600160a01b03909116906365c728409060240160206040518083038186803b1580156119a457600080fd5b505afa1580156119b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119dc9190614672565b148015611af5575060965460808501516001600160a01b039091169063a324ad2490611a09908490615701565b6040518263ffffffff1660e01b8152600401611a2791815260200190565b60206040518083038186803b158015611a3f57600080fd5b505afa158015611a53573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a779190614672565b6096546040516328c92b4960e21b8152600481018690526001600160a01b039091169063a324ad249060240160206040518083038186803b158015611abb57600080fd5b505afa158015611acf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611af39190614672565b145b9550505050505b50919050565b60ac54610100900460ff16611b295760405162461bcd60e51b8152600401610c0290615689565b609954819081118015611b4b5750609954609a54611b479190615701565b8111155b611b675760405162461bcd60e51b8152600401610c029061565f565b600082815260ae602090815260409182902042600290910155815184815233918101919091527fd0017656a8c92d10b2fa3a77fa3c1e8e4c28817e89311616b8eed8e68f68a95091015b60405180910390a15050565b60006001600160a01b038216611be6576040516323d3ad8160e21b815260040160405180910390fd5b506001600160a01b031660009081526006602052604090205467ffffffffffffffff1690565b611c1461292a565b611c1e6000612aac565b565b60ae60205260009081526040902080548190611c3b9061578f565b80601f0160208091040260200160405190810160405280929190818152602001828054611c679061578f565b8015611cb45780601f10611c8957610100808354040283529160200191611cb4565b820191906000526020600020905b815481529060010190602001808311611c9757829003601f168201915b5050505050908060010154908060020154908060030154908060040154905085565b60606000806000611ce685611bbd565b905060008167ffffffffffffffff811115611d0357611d0361584b565b604051908082528060200260200182016040528015611d2c578160200160208202803683370190505b509050611d5960408051608081018252600080825260208201819052918101829052606081019190915290565b60015b838614611dda57611d6c81612afc565b9150816040015115611d7d57611dd2565b81516001600160a01b031615611d9257815194505b876001600160a01b0316856001600160a01b03161415611dd25780838780600101985081518110611dc557611dc5615835565b6020026020010181815250505b600101611d5c565b50909695505050505050565b611dee61292a565b609855565b606060048054610a3d9061578f565b6001600160a01b038216331415611e2c5760405163b06307db60e01b815260040160405180910390fd5b3360008181526008602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b611ea061292a565b610b19609b826003614138565b6000808260986001015481118015611ed45750609954609a54611ed09190615701565b8111155b611ef05760405162461bcd60e51b8152600401610c029061565f565b600084815260ae6020526040808220815160a08101909252805482908290611f179061578f565b80601f0160208091040260200160405190810160405280929190818152602001828054611f439061578f565b8015611f905780601f10611f6557610100808354040283529160200191611f90565b820191906000526020600020905b815481529060010190602001808311611f7357829003601f168201915b505050505081526020016001820154815260200160028201548152602001600382015481526020016004820154815250509050600060ad600087815260200190815260200160002054905060006301e1338082611fed91906157df565b60965460808501519192506000916001600160a01b039091169063a324ad2490612018908590615701565b6040518263ffffffff1660e01b815260040161203691815260200190565b60206040518083038186803b15801561204e57600080fd5b505afa158015612062573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120869190614672565b60965460808601519192506000916001600160a01b03909116906365c72840906120b1908690615701565b6040518263ffffffff1660e01b81526004016120cf91815260200190565b60206040518083038186803b1580156120e757600080fd5b505afa1580156120fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061211f9190614672565b9197509095505050505050915091565b61213a848484611127565b6001600160a01b0383163b156121735761215684848484612b7b565b612173576040516368d2bf6b60e11b815260040160405180910390fd5b50505050565b6060610a2882612c73565b600360ac5462010000900460ff1660038111156121a3576121a361581f565b146121f05760405162461bcd60e51b815260206004820152601960248201527f4e6f7420696e20737461676520746f206d696e7420544d4747000000000000006044820152606401610c02565b609954609a546122009190615701565b60015460001901106122425760405162461bcd60e51b815260206004820152600b60248201526a139bc81c195d081b19599d60aa1b6044820152606401610c02565b33600090815260b2602052604090205460ff161561228d5760405162461bcd60e51b81526020600482015260086024820152674d617820746f203160c01b6044820152606401610c02565b609854349061229d90600161572d565b11156122dc5760405162461bcd60e51b815260206004820152600e60248201526d27379032b737bab3b41032ba341760911b6044820152606401610c02565b611c1e612d42565b600260ac5462010000900460ff1660038111156123035761230361581f565b146123505760405162461bcd60e51b815260206004820181905260248201527f4e6f7420696e20737461676520746f206d696e74206d65726b6c6520544d47476044820152606401610c02565b609954609a546123609190615701565b60015460001901106123a25760405162461bcd60e51b815260206004820152600b60248201526a139bc81c195d081b19599d60aa1b6044820152606401610c02565b33600090815260b2602052604090205460ff16156123ed5760405162461bcd60e51b81526020600482015260086024820152674d617820746f203160c01b6044820152606401610c02565b60985434906123fd90600161572d565b111561243c5760405162461bcd60e51b815260206004820152600e60248201526d27379032b737bab3b41032ba341760911b6044820152606401610c02565b6040516bffffffffffffffffffffffff193360601b1660208201526000906034016040516020818303038152906040528051906020012090506124b6838380806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250506097549150849050612ed4565b6124f25760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b210383937b7b360991b6044820152606401610c02565b6112f9612d42565b61250261292a565b610b1960a1826003614138565b60ac54610100900460ff166125365760405162461bcd60e51b8152600401610c0290615689565b6099548190811180156125585750609954609a546125549190615701565b8111155b6125745760405162461bcd60e51b8152600401610c029061565f565b600082815260ae602090815260409182902042600390910155815184815233918101919091527fbae6551c0ddf25aa6805100ecbdc4535f2933a14d7ebafe9fab66af752e232ec9101611bb1565b6125ca61292a565b6001600160a01b03811661262f5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610c02565b61263881612aac565b50565b60ac54610100900460ff166126625760405162461bcd60e51b8152600401610c0290615689565b6099548190811180156126845750609954609a546126809190615701565b8111155b6126a05760405162461bcd60e51b8152600401610c029061565f565b600082815260ae602090815260409182902042600190910155815184815233918101919091527fd73f65a9b0fee6c2e3e08fd03cb4800137b36882554a7211fe8ce842b3d4f4fe9101611bb1565b82336126f98261165b565b6001600160a01b03161461274b5760405162461bcd60e51b81526020600482015260196024820152782cb7ba9030b932903737ba103a37b5b2b713b99037bbb732b960391b6044820152606401610c02565b60ac54610100900460ff166127725760405162461bcd60e51b8152600401610c0290615689565b6099548490811180156127945750609954609a546127909190615701565b8111155b6127b05760405162461bcd60e51b8152600401610c029061565f565b60b084846040516127c292919061485d565b9081526040519081900360200190205460ff161561280f5760405162461bcd60e51b815260206004820152600a60248201526913985b5948195e1a5cdd60b21b6044820152606401610c02565b600061285085858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612eea92505050565b90506001811180156128625750601281105b61289f5760405162461bcd60e51b815260206004820152600e60248201526d4e6f742076616c6964206e616d6560901b6044820152606401610c02565b600086815260ae602052604090206128b89086866141a3565b50600160b086866040516128cd92919061485d565b908152604051908190036020019020805491151560ff19909216919091179055505050505050565b600081600111158015612909575060015482105b8015610a28575050600090815260056020526040902054600160e01b161590565b6000546001600160a01b03163314611c1e5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610c02565b60008061299260014361574c565b6040805191406020830152810184905233606090811b6bffffffffffffffffffffffff19169082015260740160408051601f1981840301815291905280516020909101209392505050565b60008180600111612a3457600154811015612a3457600081815260056020526040902054600160e01b8116612a32575b80612a2b575060001901600081815260056020526040902054612a0d565b9392505050565b505b604051636f96cda160e11b815260040160405180910390fd5b60005b81811015612aa1576000612a6560b554612984565b60b58054600090815260ad602052604081208390558154929350612a88836157c4565b9190505550508080612a99906157c4565b915050612a50565b50610b198282613027565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b604080516080810182526000808252602082018190529181018290526060810191909152600082815260056020526040902054610a2890604080516080810182526001600160a01b038316815260a083901c67ffffffffffffffff166020820152600160e01b831615159181019190915260e89190911c606082015290565b604051630a85bd0160e11b81526000906001600160a01b0385169063150b7a0290612bb09033908990889088906004016155aa565b602060405180830381600087803b158015612bca57600080fd5b505af1925050508015612bfa575060408051601f3d908101601f19168201909252612bf79181019061460c565b60015b612c55573d808015612c28576040519150601f19603f3d011682016040523d82523d6000602084013e612c2d565b606091505b508051612c4d576040516368d2bf6b60e11b815260040160405180910390fd5b805181602001fd5b6001600160e01b031916630a85bd0160e11b1490505b949350505050565b60608160018110158015612c8d5750600154600019018111155b612cc85760405162461bcd60e51b815260206004820152600c60248201526b139bdd081d985b1a59081a5960a21b6044820152606401610c02565b609954600090841115612cfb5760ac54610100900460ff16612cf257612ced84613041565b612d17565b612ced846130ee565b60ac5460ff16612d0e57612ced84613265565b612d1784613285565b905080604051602001612d2a9190615409565b60405160208183030381529060405292505050919050565b6000612d516001546000190190565b612d5c906001615701565b905060b45460051415612df957600060b45560965460b354604051631c85d48f60e21b81526004810191909152600160248201526001600160a01b0390911690637217523c9060440160206040518083038186803b158015612dbd57600080fd5b505afa158015612dd1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612df59190614672565b60b3555b6040805160c081018252600060a082018181528252426020808401829052838501919091526060830182905260b354608084015284825260ae81529290208151805192938493612e4c9284920190614216565b5060208201516001820155604082015160028201556060820151600382015560809091015160049091015560b48054906000612e87836157c4565b91905055506000612e9783612984565b600084815260ad602052604090208190559050612eb5336001613027565b505033600090815260b260205260409020805460ff1916600117905550565b600082612ee1858461342a565b14949350505050565b600080825b8051821015613020576007818381518110612f0c57612f0c615835565b01602001516001600160f81b031990811690911c16612f3757612f30600183615701565b915061300e565b8051600360f91b90600590839085908110612f5457612f54615835565b01602001516001600160f81b031990811690911c161415612f7a57612f30600283615701565b8051600760f91b90600490839085908110612f9757612f97615835565b01602001516001600160f81b031990811690911c161415612fbd57612f30600383615701565b8051600f60f91b90600390839085908110612fda57612fda615835565b01602001516001600160f81b031990811690911c16141561300057612f30600483615701565b61300b600183615701565b91505b82613018816157c4565b935050612eef565b5050919050565b610b19828260405180602001604052806000815250613477565b606060008061304f84611ead565b600086815260ad60205260408120549294509092506130e4613070876134e4565b613079866134e4565b613082866134e4565b61308b886134e4565b613094886134e4565b6130bb601a6130a460038b6157df565b600381106130b4576130b4615835565b01546134e4565b6040516020016130d096959493929190615104565b6040516020818303038152906040526135e2565b9695505050505050565b60606000806000806130ff86610bd2565b935093509350935060008061311388611313565b91509150600061312289611788565b905060008680156131305750855b80156131395750845b806131415750815b61314c57600061314f565b60015b9050600061315c89613748565b905060006040518060e001604052808d815260200160ad60008f81526020019081526020016000205481526020018781526020018681526020018b8152602001841515815260200160af60008f815260200190815260200160002060009054906101000a900460ff161515815250905060006131ec60ad60008f81526020019081526020016000205484866137a8565b905060006131f983613b8a565b61320284613d1c565b61320b85613d62565b61321486613e5c565b61322561322087613e95565b6135e2565b6040516020016132399594939291906148f3565b6040516020818303038152906040529050613253816135e2565b9e9d5050505050505050505050505050565b60606000612a2b613275846134e4565b6040516020016130d09190614fd2565b600081815260ad6020526040812054606091600a6132a381846157df565b600a81106132b3576132b3615835565b015490506000601782600381106132cc576132cc615835565b0180546132d89061578f565b80601f01602080910402602001604051908101604052809291908181526020018280546133049061578f565b80156133515780601f1061332657610100808354040283529160200191613351565b820191906000526020600020905b81548152906001019060200180831161333457829003601f168201915b5050505050905060006014836003811061336d5761336d615835565b0180546133799061578f565b80601f01602080910402602001604051908101604052809291908181526020018280546133a59061578f565b80156133f25780601f106133c7576101008083540402835291602001916133f2565b820191906000526020600020905b8154815290600101906020018083116133d557829003601f168201915b50505050509050600061341f613407886134e4565b838585866040516020016130d0959493929190614e29565b979650505050505050565b600081815b845181101561346f5761345b8286838151811061344e5761344e615835565b6020026020010151613ebe565b915080613467816157c4565b91505061342f565b509392505050565b6134818383613eea565b6001600160a01b0383163b156112f9576001548281035b6134ab6000868380600101945086612b7b565b6134c8576040516368d2bf6b60e11b815260040160405180910390fd5b8181106134985781600154146134dd57600080fd5b5050505050565b6060816135085750506040805180820190915260018152600360fc1b602082015290565b8160005b8115613532578061351c816157c4565b915061352b9050600a83615719565b915061350c565b60008167ffffffffffffffff81111561354d5761354d61584b565b6040519080825280601f01601f191660200182016040528015613577576020820181803683370190505b5090505b8415612c6b5761358c60018361574c565b9150613599600a866157df565b6135a4906030615701565b60f81b8183815181106135b9576135b9615835565b60200101906001600160f81b031916908160001a9053506135db600a86615719565b945061357b565b606081516000141561360257505060408051602081019091526000815290565b600060405180606001604052806040815260200161587860409139905060006003845160026136319190615701565b61363b9190615719565b61364690600461572d565b90506000613655826020615701565b67ffffffffffffffff81111561366d5761366d61584b565b6040519080825280601f01601f191660200182016040528015613697576020820181803683370190505b509050818152600183018586518101602084015b81831015613703576003830192508251603f8160121c168501518253600182019150603f81600c1c168501518253600182019150603f8160061c168501518253600182019150603f81168501518253506001016136ab565b60038951066001811461371d576002811461372e5761373a565b613d3d60f01b60011983015261373a565b603d60f81b6000198301525b509398975050505050505050565b60a754600090821161376157602a60035b015492915050565b60a85482101561377457602a6000613759565b60a95482101561378757602a6001613759565b60aa5482101561379a57602a6002613759565b602a6004613759565b919050565b60606000608b600b6137bb600488615719565b6137c591906157df565b600b81106137d5576137d5615835565b0180546137e19061578f565b80601f016020809104026020016040519081016040528092919081815260200182805461380d9061578f565b801561385a5780601f1061382f5761010080835404028352916020019161385a565b820191906000526020600020905b81548152906001019060200180831161383d57829003601f168201915b5050505050905060006080600b6003886138749190615719565b61387e91906157df565b600b811061388e5761388e615835565b01805461389a9061578f565b80601f01602080910402602001604051908101604052809291908181526020018280546138c69061578f565b80156139135780601f106138e857610100808354040283529160200191613913565b820191906000526020600020905b8154815290600101906020018083116138f657829003601f168201915b505050505090506000606e600d60028961392d9190615719565b61393791906157df565b600d811061394757613947615835565b0180546139539061578f565b80601f016020809104026020016040519081016040528092919081815260200182805461397f9061578f565b80156139cc5780601f106139a1576101008083540402835291602001916139cc565b820191906000526020600020905b8154815290600101906020018083116139af57829003601f168201915b505050505090506000607b87600581106139e8576139e8615835565b0180546139f49061578f565b80601f0160208091040260200160405190810160405280929190818152602001828054613a209061578f565b8015613a6d5780601f10613a4257610100808354040283529160200191613a6d565b820191906000526020600020905b815481529060010190602001808311613a5057829003601f168201915b505050505090506000613a7f85613fe1565b613a8885613fe1565b613a9184613fe1565b613a9a86613fe1565b604051602001613aad949392919061489c565b60405160208183030381529060405290508615613b7e5780613b5b606d6000018054613ad89061578f565b80601f0160208091040260200160405190810160405280929190818152602001828054613b049061578f565b8015613b515780601f10613b2657610100808354040283529160200191613b51565b820191906000526020600020905b815481529060010190602001808311613b3457829003601f168201915b5050505050613fe1565b604051602001613b6c92919061486d565b60405160208183030381529060405290505b98975050505050505050565b6060600080613b9c8460000151611ead565b91509150600060ae6000866000015181526020019081526020016000206040518060a0016040529081600082018054613bd49061578f565b80601f0160208091040260200160405190810160405280929190818152602001828054613c009061578f565b8015613c4d5780601f10613c2257610100808354040283529160200191613c4d565b820191906000526020600020905b815481529060010190602001808311613c3057829003601f168201915b50505050508152602001600182015481526020016002820154815260200160038201548152602001600482015481525050905060006001613c918360000151612eea565b11613cab5760405180602001604052806000815250613ccd565b8151604051613cbd9190602001614aac565b6040516020818303038152906040525b905080613cdd87600001516134e4565b613ce6866134e4565b613cef866134e4565b604051602001613d0294939291906152bd565b604051602081830303815290604052945050505050919050565b60606000613d2d83604001516134e4565b613d3a84606001516134e4565b604051602001613d4b929190614ba7565b60408051601f198184030181529190529392505050565b606060008260a00151613d8f57604051806040016040528060028152602001616e6f60f01b815250613dac565b6040518060400160405280600381526020016279657360e81b8152505b905060008360c00151613dd957604051806040016040528060028152602001616e6f60f01b815250613df6565b6040518060400160405280600381526020016279657360e81b8152505b905060008282613e0987608001516134e4565b613e1288613ffc565b613e1b89614030565b613e248a614088565b613e2d8b6140e0565b604051602001613e439796959493929190614cd7565b60408051601f1981840301815291905295945050505050565b6060600080613e6e8460000151611ead565b91509150613e7b826134e4565b613e84826134e4565b604051602001612d2a929190615379565b606081604051602001613ea8919061544e565b6040516020818303038152906040529050919050565b6000818310613eda576000828152602084905260409020612a2b565b5060009182526020526040902090565b60015481613f0b5760405163b562e8dd60e01b815260040160405180910390fd5b6001600160a01b03831660008181526006602090815260408083208054680100000000000000018802019055848352600590915281206001851460e11b4260a01b178317905582840190839083907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a4600183015b818114613fba57808360007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a4600101613f82565b5081613fd857604051622e076360e81b815260040160405180910390fd5b60015550505050565b6060613fec826135e2565b604051602001613ea89190614ad3565b60606000605261400f8460800151613748565b6005811061401f5761401f615835565b01604051602001613d4b919061527c565b606060006045601d600d6002866020015161404b9190615719565b61405591906157df565b600d811061406557614065615835565b0154600d811061407757614077615835565b01604051602001613d4b9190614c88565b606060006057602f600b600386602001516140a39190615719565b6140ad91906157df565b600b81106140bd576140bd615835565b0154600b81106140cf576140cf615835565b01604051602001613d4b919061556d565b606060006062603a600b600486602001516140fb9190615719565b61410591906157df565b600b811061411557614115615835565b0154600b811061412757614127615835565b01604051602001613d4b91906153cc565b8260038101928215614166579160200282015b8281111561416657823582559160200191906001019061414b565b5061417292915061428a565b5090565b8260058101928215614166579160200282018281111561416657823582559160200191906001019061414b565b8280546141af9061578f565b90600052602060002090601f0160209004810192826141d15760008555614166565b82601f106141ea5782800160ff19823516178555614166565b82800160010185558215614166579182018281111561416657823582559160200191906001019061414b565b8280546142229061578f565b90600052602060002090601f0160209004810192826142445760008555614166565b82601f1061425d57805160ff1916838001178555614166565b82800160010185558215614166579182015b8281111561416657825182559160200191906001019061426f565b5b80821115614172576000815560010161428b565b600067ffffffffffffffff808411156142ba576142ba61584b565b604051601f8501601f19908116603f011681019082821181831017156142e2576142e261584b565b816040528093508581528686860111156142fb57600080fd5b858560208301376000602087830101525050509392505050565b80356001600160a01b03811681146137a357600080fd5b60008083601f84011261433e57600080fd5b50813567ffffffffffffffff81111561435657600080fd5b6020830191508360208260051b850101111561437157600080fd5b9250929050565b60006020828403121561438a57600080fd5b612a2b82614315565b600080604083850312156143a657600080fd5b6143af83614315565b91506143bd60208401614315565b90509250929050565b6000806000606084860312156143db57600080fd5b6143e484614315565b92506143f260208501614315565b9150604084013590509250925092565b6000806000806080858703121561441857600080fd5b61442185614315565b935061442f60208601614315565b925060408501359150606085013567ffffffffffffffff81111561445257600080fd5b8501601f8101871361446357600080fd5b6144728782356020840161429f565b91505092959194509250565b6000806040838503121561449157600080fd5b61449a83614315565b9150602083013580151581146144af57600080fd5b809150509250929050565b600080604083850312156144cd57600080fd5b6144d683614315565b946020939093013593505050565b600080600080604085870312156144fa57600080fd5b843567ffffffffffffffff8082111561451257600080fd5b61451e8883890161432c565b9096509450602087013591508082111561453757600080fd5b506145448782880161432c565b95989497509550505050565b6000806020838503121561456357600080fd5b823567ffffffffffffffff81111561457a57600080fd5b6145868582860161432c565b90969095509350505050565b6000606082840312156145a457600080fd5b82606083011115611afc57600080fd5b600060a082840312156145c657600080fd5b8260a083011115611afc57600080fd5b6000602082840312156145e857600080fd5b5035919050565b60006020828403121561460157600080fd5b8135612a2b81615861565b60006020828403121561461e57600080fd5b8151612a2b81615861565b60006020828403121561463b57600080fd5b813567ffffffffffffffff81111561465257600080fd5b8201601f8101841361466357600080fd5b612c6b8482356020840161429f565b60006020828403121561468457600080fd5b5051919050565b6000806000604084860312156146a057600080fd5b83359250602084013567ffffffffffffffff808211156146bf57600080fd5b818601915086601f8301126146d357600080fd5b8135818111156146e257600080fd5b8760208285010111156146f457600080fd5b6020830194508093505050509250925092565b6000815180845261471f816020860160208601615763565b601f01601f19169290920160200192915050565b60008151614745818560208601615763565b9290920192915050565b8054600090600181811c908083168061476957607f831692505b602080841082141561478b57634e487b7160e01b600052602260045260246000fd5b81801561479f57600181146147b0576147dd565b60ff198616895284890196506147dd565b60008881526020902060005b868110156147d55781548b8201529085019083016147bc565b505084890196505b50505050505092915050565b7f7b202274726169745f74797065223a202274797065222c202276616c7565223a81526808089c195d1cc89f4b60ba1b602082015260290190565b7f7b202274726169745f74797065223a2022626972746864617465222c20227661815266363ab2911d101160c91b602082015260270190565b8183823760009101908152919050565b6000835161487f818460208801615763565b835190830190614893818360208801615763565b01949350505050565b600085516148ae818460208a01615763565b8551908301906148c2818360208a01615763565b85519101906148d5818360208901615763565b84519101906148e8818360208801615763565b019695505050505050565b60008651614905818460208b01615763565b80830190507f226465736372697074696f6e223a202254616d61676f6769206973206120546181527f6d61676f74636869204461707020616e642066756c6c792067656e657261746560208201527f64206f6e2d636861696e2e2054686520636f6e747261637420696e746572616360408201527f74696f6e20616e642074696d652077696c6c206166666563742074686520737460608201527f6174757320616e64207265616374696f6e206f6620746865207065742e20496660808201527f20796f7520636f6c6c656374206f74686572206974656d732c2074686520706560a0820152721d081dda5b1b081cda1bddc81b1bdd9948488b606a1b60c08201526e2261747472696275746573223a205b60881b60d38201528651614a328160e2840160208b01615763565b614a9f614a91614a8b614a53614a4d60e2868801018c614733565b8a614733565b7f5d2c22696d616765223a2022646174613a696d6167652f7376672b786d6c3b62815265185cd94d8d0b60d21b602082015260260190565b87614733565b61227d60f01b815260020190565b9998505050505050505050565b60008251614abe818460208701615763565b6201017960ed1b920191825250600301919050565b7f3c696d61676520783d22302220793d2230222077696474683d2233322220686581527f696768743d2233322220696d6167652d72656e646572696e673d22706978656c60208201527f6174656422207072657365727665417370656374526174696f3d22784d69645960408201527f4d69642220786c696e6b3a687265663d22646174613a696d6167652f706e673b60608201526618985cd94d8d0b60ca1b608082015260008251614b8d816087850160208701615763565b6211179f60e91b6087939091019283015250608a01919050565b7f7b202274726169745f74797065223a202268756e676572222c2022646973706c81527f61795f74797065223a20226e756d626572222c202276616c7565223a20000000602082015260008351614c0581603d850160208801615763565b8083019050611f4b60f21b80603d8301527f7b202274726169745f74797065223a2022626f726564222c2022646973706c61603f8301527f795f74797065223a20226e756d626572222c202276616c7565223a2000000000605f8301528451614c7581607b850160208901615763565b607b920191820152607d01949350505050565b7f7b202274726169745f74797065223a2022656172222c202276616c7565223a208152601160f91b60208201526000614cc4602183018461474f565b62089f4b60ea1b81526003019392505050565b6000614ce2826147e9565b7f7b202274726169745f74797065223a20226d6173746572222c202276616c7565815263111d101160e11b60208201528951614d25816024840160208e01615763565b62089f4b60ea1b6024929091019182018190527f7b202274726169745f74797065223a20227265726f6c6c6564222c202276616c6027830152653ab2911d101160d11b60478301528951614d8081604d850160208e01615763565b604d9201918201527f7b202274726169745f74797065223a2022756e68617070696e657373222c202260508201527f646973706c61795f74797065223a20226e756d626572222c202276616c75652260708201526101d160f51b6090820152614e1b614e15614a8b614e0f614e09614dfb609287018e614733565b611f4b60f21b815260020190565b8b614733565b89614733565b85614733565b9a9950505050505050505050565b6a7b226e616d65223a20222360a81b81528551600090614e5081600b850160208b01615763565b6a040a8c2dac2cedeced240560ab1b600b918401918201528651614e7b816016840160208b01615763565b7314911610113232b9b1b934b83a34b7b7111d101160611b601692909101918201528551614eb081602a840160208a01615763565b61088b60f21b9101602a8101919091526e2261747472696275746573223a205b60881b602c8201527f7b202274726169745f74797065223a202274797065222c202276616c7565223a603b8201526908089c1c9bdc1cc89f4b60b21b605b8201527f7b202274726169745f74797065223a20227573616765222c202276616c7565226065820152621d101160e91b6085820152613b7e614fc0614fba614f6b614f5b60888601614a4d565b63089f574b60e21b815260040190565b7f22696d616765223a2022697066733a2f2f516d56784344666d7767593270734181527f683777746938614c43796b6b6a3939736e79674751383970327a6b664174662f602082015260400190565b86614733565b652e676966227d60d01b815260060190565b6a7b226e616d65223a20222360a81b81528151600090614ff981600b850160208701615763565b7f2054616d61676f67692028556e72657665616c2050726f707329222c20226465600b9390910192830152507f736372697074696f6e223a2022556e72657665616c2050726f7073222c000000602b8201526e2261747472696275746573223a205b60881b60488201527f7b202274726169745f74797065223a202274797065222c202276616c7565223a605782015268202270726f7073227d60b81b607782015261174b60f21b60808201527f22696d616765223a2022697066733a2f2f516d5462423644443277387433367a60828201527f4c50764245646f576f363252464d794a69394558636a39395a6978507278432260a2820152607d60f81b60c282015260c301919050565b6a7b226e616d65223a20222360a81b8152865160009061512b81600b850160208c01615763565b6e040a8c2dac2cedeced2408acece405608b1b600b91840191820152875161515a81601a840160208c01615763565b602f60f81b601a9290910191820152865161517c81601b840160208b01615763565b602960f81b9101601b8101919091527f222c20226465736372697074696f6e223a2022556e62726f6b656e2054616d61601c8201526d19dbd9da481959d9dccb8b8b888b60921b603c8201526e2261747472696275746573223a205b60881b604a820152614a9f614fc0614fba61522d61521f614a91614e0961521261520c61520760598b016147e9565b614824565b8e614733565b602f60f81b815260010190565b61174b60f21b815260020190565b7f22696d616765223a2022697066733a2f2f516d57317463635971426d534c514681527f54664e38725777384a4858787837685a53344d6969775757444e35747647382f602082015260400190565b7f7b202274726169745f74797065223a20227265616374696f6e222c202276616c8152653ab2911d101160d11b60208201526000614cc4602683018461474f565b693d913730b6b2911d101160b11b815284516000906152e381600a850160208a01615763565b602360f81b600a91840191820152855161530481600b840160208a01615763565b6a040a8c2dac2cedeced240560ab1b600b92909101918201528451615330816016840160208901615763565b602f60f81b601692909101918201528351615352816017840160208801615763565b602960f81b6017929091019182015261088b60f21b6018820152601a019695505050505050565b600061538482614824565b8451615394818360208901615763565b602f60f81b910190815283516153b1816001840160208801615763565b61227d60f01b60019290910191820152600301949350505050565b7f7b202274726169745f74797065223a2022626f6479222c202276616c7565223a815261101160f11b60208201526000614cc4602283018461474f565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c00000081526000825161544181601d850160208701615763565b91909101601d0192915050565b7f3c7376672077696474683d2239363022206865696768743d223936302220766581527f7273696f6e3d22312e31222076696577426f783d22302030203332203332222060208201527f786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323030302f737660408201527f672220786d6c6e733a786c696e6b3d22687474703a2f2f7777772e77332e6f7260608201526d3397989c9c9c97bc3634b735911f60911b60808201527f3c726563742077696474683d223130302522206865696768743d223130302522608e82015271103334b6361e9111b0b0b21c9c9c9110179f60711b60ae820152600082516155508160c0850160208701615763565b651e17b9bb339f60d11b60c093909101928301525060c601919050565b7f7b202274726169745f74797065223a202268656164222c202276616c7565223a815261101160f11b60208201526000614cc4602283018461474f565b6001600160a01b03858116825284166020820152604081018390526080606082018190526000906130e490830184614707565b6020808252825182820181905260009190848201906040850190845b81811015611dda578351835292840192918401916001016155f9565b602081526000612a2b6020830184614707565b60a08152600061563b60a0830188614707565b90508560208301528460408301528360608301528260808301529695505050505050565b60208082526010908201526f139bdd081d985b1a59081c195d081a5960821b604082015260600190565b6020808252600a9082015269139bdd081c995d99585b60b21b604082015260600190565b86815260208101869052604081018590528315156060820152821515608082015260c08101600483106156f057634e487b7160e01b600052602160045260246000fd5b8260a0830152979650505050505050565b60008219821115615714576157146157f3565b500190565b60008261572857615728615809565b500490565b6000816000190483118215151615615747576157476157f3565b500290565b60008282101561575e5761575e6157f3565b500390565b60005b8381101561577e578181015183820152602001615766565b838111156121735750506000910152565b600181811c908216806157a357607f821691505b60208210811415611afc57634e487b7160e01b600052602260045260246000fd5b60006000198214156157d8576157d86157f3565b5060010190565b6000826157ee576157ee615809565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160e01b03198116811461263857600080fdfe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2fa264697066735822122069c56940fd46b970901e4cefbf1663ce7fd9f697bb1b49a889da5193c1fc526564736f6c63430008070033

Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.