ETH Price: $3,603.60 (+8.45%)

Token

Tamagogi (TMGG)
 

Overview

Max Total Supply

2,000 TMGG

Holders

969

Total Transfers

-

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information
# 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;
    }

    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", "TMGG") {
        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) private 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;

    //@@@ 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, "Not valid pet id");
        _;
    }

    //@@@ mint
    function getProp() external payable {
        require(config.mintStage == MintStage.PROPS, "Not in stage to buy prop");
        require(_totalMinted() < config.propMaxSupply, "No props left");
        require(!propMinted[msg.sender], "Max to 1");

        uint propId = _startTokenId() + _totalMinted();
        uint seed = _getRandom(propId);
        seeds[propId] = seed;

        _safeMint(msg.sender, 1);
        propMinted[msg.sender] = true;
    }

    function hatchEgg() external payable {
        require(config.mintStage == MintStage.PETS, "Not in stage to mint TMGG");
        require(_totalMinted() < config.petMaxSupply, "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, "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 attr = string(abi.encodePacked(
            '{ "trait_type": "type", "value": "pets"},',
            '{ "trait_type": "master", "value": "',masterLabel,'"},',
            '{ "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);
        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":"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":"getProp","outputs":[],"stateMutability":"payable","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":"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"}]

6101c06040526000608081815260a082905260c082905260e09190915260016101008190526101208190526101408190526101605260026101808190526101a0526200004f90600a908162001063565b506040805160a08101825260046060820190815263199bdbd960e21b6080830152815281518083018352600380825262746f7960e81b602083810191909152808401929092528351808501855260068152651cda1a595b1960d21b9281019290925292820152620000c49160149190620010ab565b506040805160c081019091526036606082018181528291620085d960808401398152602001604051806060016040528060288152602001620088dd6028913981526020016040518060600160405280602a815260200162009105602a9139905262000134906017906003620010ab565b5060408051606081018252600181526002602082015260039181018290526200016191601a9190620010fe565b50604080516101a08101825260008152600160208201526002918101919091526003606082015260046080820152600560a0820152600660c0820152600760e082015260086101008201526009610120820152600a610140820152600b610160820152600c610180820152620001dc90601d90600d62001133565b506040805160a081018252600081526001602082015260029181019190915260036060820152600460808201526200021990602a90600562001168565b50604080516101608101825260008152600160208201526002918101919091526003606082015260046080820152600560a0820152600660c0820152600760e082015260086101008201526009610120820152600a6101408201526200028490602f90600b6200119d565b50604080516101608101825260008152600160208201526002918101919091526003606082015260046080820152600560a0820152600660c0820152600760e082015260086101008201526009610120820152600a610140820152620002ef90603a90600b6200119d565b50604080516101e08101825260066101a08201818152654d656c6f647960d01b6101c084015282528251808401845260058082526443696e6e6160d81b6020838101919091528085019290925284518086018652838152652930b1b7b7b760d11b81840152848601528451808601865260088152672637b7339032b0b960c11b81840152606085015284518086018652600380825262446f6760e81b8285015260808601919091528551808701875282815264546564647960d81b8185015260a08601528551808701875282815264547261706160d81b8185015260c086015285518087018752600981526829b437b93a3430b4b960b91b8185015260e08601528551808701875293845265149858989a5d60d21b84840152610100850193909352845180860186526004808252634d69636b60e01b8285015261012086019190915285518087018752918252644d6f75736560d81b8284015261014085019190915284518086018652908152632132b0b960e11b8183015261016084015283518085019094529083526210d85d60ea1b908301526101808101919091526200049d90604590600d620011d2565b506040805160e081018252600660a0820190815265139bdc9b585b60d21b60c0830152815281518083018352600580825264416e67727960d81b6020838101919091528084019290925283518085018552600381526214d85960ea1b81840152838501528351808501855281815264536d696c6560d81b818401526060840152835180850190945280845264155c1cd95d60da1b9184019190915260808201929092526200054f916052919062001217565b50604080516101a08101825260046101608201818152632437b93760e11b6101808401528252825180840184526008815267576869736b65727360c01b6020828101919091528084019190915283518085018552600c81526b15da1a5cdad95c9cc819985d60a21b818301528385015283518085018552600680825265466c7566667960d01b82840152606085019190915284518086018652600d81526c2bb434b9b5b2b939903a3434b760991b818401526080850152845180860186528181526553717561726560d01b8184015260a08501528451808601865260078152662430b6b9ba32b960c91b8184015260c08501528451808601865290815265139bdc9b585b60d21b8183015260e084015283518085018552600a815269437269636574696e616560b01b8183015261010084015283518085018552918252634e616a6160e01b82820152610120830191909152825180840190935260058352640506c756d760dc1b90830152610140810191909152620006d390605790600b6200125c565b506040518061016001604052806040518060400160405280600381526020016214da5d60ea1b815250815260200160405180604001604052806005815260200164447265737360d81b81525081526020016040518060400160405280600581526020016414dd185b9960da1b8152508152602001604051806040016040528060098152602001680487564646c652075760bc1b815250815260200160405180604001604052806006815260200165466565626c6560d01b81525081526020016040518060400160405280600481526020016329ba30b960e11b815250815260200160405180604001604052806007815260200166436c6f7468657360c81b8152508152602001604051806040016040528060068152602001655374726f6e6760d01b81525081526020016040518060400160405280600581526020016414dc5d585d60da1b81525081526020016040518060400160405280600481526020016348756c6b60e01b8152508152602001604051806040016040528060098152602001684c6f6e67206c65677360b81b815250815250606290600b620008799291906200125c565b5060405180602001604052806040518060e0016040528060ac81526020016200905960ac91399052620008b190606d906001620012a1565b50604080516102a0810190915260c96101a0820181815282916200836f6101c0840139815260200160405180610100016040528060d8815260200162008bf460d8913981526020016040518060e0016040528060b5815260200162009bca60b5913981526020016040518060e0016040528060bb81526020016200882260bb913981526020016040518060e0016040528060be81526020016200974a60be9139815260200160405180610100016040528060c781526020016200843860c7913981526020016040518060e0016040528060bd81526020016200940460bd913981526020016040518060e0016040528060b981526020016200934b60b9913981526020016040518060e0016040528060b181526020016200980860b1913981526020016040518060e0016040528060b0815260200162008ec260b0913981526020016040518060e0016040528060b181526020016200877160b1913981526020016040518060e0016040528060ae815260200162009a4160ae913981526020016040518060e0016040528060b6815260200162009d3c60b69139905262000a5c90606e90600d620012f4565b5060408051610180810190915260a860a08201818152829162008d7060c084013981526020016040518060e0016040528060a781526020016200860f60a7913981526020016040518060e0016040528060aa815260200162009edd60aa913981526020016040518060e0016040528060a4815260200162008a6160a4913981526020016040518060e0016040528060ac8152602001620089b560ac9139905262000b0b90607b90600562001339565b5060408051610240810190915260bd6101608201818152829162009c7f61018084013981526020016040518060e0016040528060b8815260200162009f8760b8913981526020016040518060e0016040528060b38152602001620095ae60b3913981526020016040518060e0016040528060a4815260200162008ccc60a4913981526020016040518060e0016040528060a98152602001620092a260a9913981526020016040518060c00160405280609281526020016200912f6092913981526020016040518060e0016040528060ad8152602001620098b960ad913981526020016040518060e0016040528060aa815260200162008e1860aa913981526020016040518060e0016040528060b081526020016200890560b0913981526020016040518060e0016040528060a98152602001620081f460a9913981526020016040518060e0016040528060bb8152602001620086b660bb9139905262000c7690608090600b6200137e565b50604080516102a0810190915261010261016082018181528291620080f2610180840139815260200160405180610120016040528060ed8152602001620094c160ed9139815260200160405180610120016040528060ef815260200162008b0560ef9139815260200160405180610120016040528060e981526020016200966160e99139815260200160405180610120016040528060eb815260200162009df260eb9139815260200160405180610120016040528060e7815260200162008f7260e79139815260200160405180610100016040528060db81526020016200996660db9139815260200160405180610100016040528060d281526020016200829d60d29139815260200160405180610100016040528060da8152602001620084ff60da9139815260200160405180610120016040528060e18152602001620091c160e19139815260200160405180610100016040528060db815260200162009aef60db9139905262000dec90608b90600b6200137e565b5060405162000dfb90620013c3565b604051809103906000f08015801562000e18573d6000803e3d6000fd5b50609680546001600160a01b0319166001600160a01b0392909216919091179055600060978190556361cf998160b35560b45534801562000e5857600080fd5b506040518060400160405280600881526020016754616d61676f676960c01b81525060405180604001604052806004815260200163544d474760e01b81525062000eb162000eab6200100f60201b60201c565b62001013565b815162000ec6906003906020850190620013d1565b50805162000edc906004906020840190620013d1565b506001808155600955505060006098556107d0609955610721609a5560ac805462ff00001916905560408051606081018252600881526028602082015260789181019190915262000f3290609b906003620010fe565b506040805160608101825260068152601e6020820152605a9181019190915262000f6190609e906003620010fe565b50604080516060810182526004815260146020820152603c9181019190915262000f909060a1906003620010fe565b50604080516060810182526009815260036020820181905260019282019290925262000fc09160a49190620010fe565b506040805160a08101825260008152600a6020820152601491810191909152601e60608201526028608082015262000ffd9060a790600562001168565b5060ac805461ffff1916905562001526565b3390565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b82600a810192821562001099579160200282015b8281111562001099578251829060ff1690559160200191906001019062001077565b50620010a79291506200144e565b5090565b8260038101928215620010f0579160200282015b82811115620010f05782518051620010df918491602090910190620013d1565b5091602001919060010190620010bf565b50620010a792915062001465565b826003810192821562001099579160200282018281111562001099578251829060ff1690559160200191906001019062001077565b82600d810192821562001099579160200282018281111562001099578251829060ff1690559160200191906001019062001077565b826005810192821562001099579160200282018281111562001099578251829060ff1690559160200191906001019062001077565b82600b810192821562001099579160200282018281111562001099578251829060ff1690559160200191906001019062001077565b82600d8101928215620010f0579160200282015b82811115620010f0578251805162001206918491602090910190620013d1565b5091602001919060010190620011e6565b8260058101928215620010f0579160200282015b82811115620010f057825180516200124b918491602090910190620013d1565b50916020019190600101906200122b565b82600b8101928215620010f0579160200282015b82811115620010f0578251805162001290918491602090910190620013d1565b509160200191906001019062001270565b8260018101928215620012e6579160200282015b82811115620012e65782518051620012d5918491602090910190620013d1565b5091602001919060010190620012b5565b50620010a792915062001486565b82600d8101928215620012e6579160200282015b82811115620012e6578251805162001328918491602090910190620013d1565b509160200191906001019062001308565b8260058101928215620012e6579160200282015b82811115620012e657825180516200136d918491602090910190620013d1565b50916020019190600101906200134d565b82600b8101928215620012e6579160200282015b82811115620012e65782518051620013b2918491602090910190620013d1565b509160200191906001019062001392565b61154e8062006ba483390190565b828054620013df90620014e9565b90600052602060002090601f01602090048101928262001403576000855562001099565b82601f106200141e57805160ff191683800117855562001099565b8280016001018555821562001099579182015b828111156200109957825182559160200191906001019062001431565b5b80821115620010a757600081556001016200144f565b80821115620010a75760006200147c8282620014a7565b5060010162001465565b80821115620010a75760006200149d8282620014a7565b5060010162001486565b508054620014b590620014e9565b6000825580601f10620014c6575050565b601f016020900490600052602060002090810190620014e691906200144e565b50565b600181811c90821680620014fe57607f821691505b602082108114156200152057634e487b7160e01b600052602260045260246000fd5b50919050565b61566e80620015366000396000f3fe6080604052600436106102885760003560e01c806370a082311161015a578063b88d4fde116100c1578063e985e9c51161007a578063e985e9c514610841578063ebd799cc1461088a578063ebf6e91d146108aa578063f2fde38b146108ca578063f59dfdfb146108ea578063fe55932a1461090a57600080fd5b8063b88d4fde1461077b578063c23c863b1461079b578063c87b56dd146107cb578063ca9c4b33146107eb578063d3a2da38146107f3578063df33fa311461082e57600080fd5b806391b7f5ed1161011357806391b7f5ed146106b657806395d89b41146106d65780639b993a1a146106eb578063a22cb4651461071b578063a22d58231461073b578063b6d225511461075b57600080fd5b806370a08231146105ba578063715018a6146105da5780637908213d146105ef57806379502c55146106205780638462151c1461066b5780638da5cb5b1461069857600080fd5b806335b34ca2116101fe5780635d186c9f116101b75780635d186c9f1461051d57806361fd3f62146105325780636352211e1461053a57806366d38ba91461055a5780636840690b1461057a5780636898f82b1461059a57600080fd5b806335b34ca2146104435780633cd434aa1461047357806341b3ba3d1461048857806342842e0e146104a8578063439bbfd2146104c85780635a353cd3146104e857600080fd5b806309a3849a1161025057806309a3849a1461035e5780630ea61c471461037e57806318160ddd146103c65780631c19c215146103ed5780631d80009a1461040d57806323b872dd1461042357600080fd5b806301ffc9a71461028d57806306fdde03146102c2578063081812fc146102e457806308a337331461031c578063095ea7b31461033e575b600080fd5b34801561029957600080fd5b506102ad6102a8366004614385565b61092a565b60405190151581526020015b60405180910390f35b3480156102ce57600080fd5b506102d761097c565b6040516102b99190615374565b3480156102f057600080fd5b506103046102ff36600461436c565b610a0e565b6040516001600160a01b0390911681526020016102b9565b34801561032857600080fd5b5061033c610337366004614328565b610a52565b005b34801561034a57600080fd5b5061033c610359366004614289565b610a6b565b34801561036a57600080fd5b5061033c61037936600461434a565b610b0b565b34801561038a57600080fd5b5061039e61039936600461436c565b610b20565b60408051948552921515602085015290151591830191909152151560608201526080016102b9565b3480156103d257600080fd5b5060025460015403600019015b6040519081526020016102b9565b3480156103f957600080fd5b5061033c61040836600461436c565b610f23565b34801561041957600080fd5b506103df60975481565b34801561042f57600080fd5b5061033c61043e366004614195565b61105b565b34801561044f57600080fd5b506102ad61045e366004614147565b60b26020526000908152604090205460ff1681565b34801561047f57600080fd5b5061033c6111ec565b34801561049457600080fd5b5061033c6104a336600461436c565b611205565b3480156104b457600080fd5b5061033c6104c3366004614195565b611212565b3480156104d457600080fd5b5061033c6104e3366004614328565b611232565b3480156104f457600080fd5b5061050861050336600461436c565b611247565b604080519283526020830191909152016102b9565b34801561052957600080fd5b5061033c61156b565b61033c611582565b34801561054657600080fd5b5061030461055536600461436c565b6116c8565b34801561056657600080fd5b5061033c61057536600461436c565b6116d3565b34801561058657600080fd5b506102ad61059536600461436c565b611715565b3480156105a657600080fd5b5061033c6105b536600461436c565b611a82565b3480156105c657600080fd5b506103df6105d5366004614147565b611b30565b3480156105e657600080fd5b5061033c611b7f565b3480156105fb57600080fd5b5061060f61060a36600461436c565b611b93565b6040516102b9959493929190615387565b34801561062c57600080fd5b50609854609954609a5460ac546106599392919060ff808216916101008104821691620100009091041686565b6040516102b99695949392919061542e565b34801561067757600080fd5b5061068b610686366004614147565b611c49565b6040516102b9919061533c565b3480156106a457600080fd5b506000546001600160a01b0316610304565b3480156106c257600080fd5b5061033c6106d136600461436c565b611d59565b3480156106e257600080fd5b506102d7611d66565b3480156106f757600080fd5b506102ad61070636600461436c565b60af6020526000908152604090205460ff1681565b34801561072757600080fd5b5061033c61073636600461424d565b611d75565b34801561074757600080fd5b5061033c610756366004614328565b611e0b565b34801561076757600080fd5b5061050861077636600461436c565b611e20565b34801561078757600080fd5b5061033c6107963660046141d1565b612095565b3480156107a757600080fd5b506102ad6107b6366004614147565b60b16020526000908152604090205460ff1681565b3480156107d757600080fd5b506102d76107e636600461436c565b6120df565b61033c6120ea565b3480156107ff57600080fd5b506102ad61080e3660046143bf565b805160208183018101805160b08252928201919093012091525460ff1681565b61033c61083c3660046142b3565b612222565b34801561084d57600080fd5b506102ad61085c366004614162565b6001600160a01b03918216600090815260086020908152604080832093909416825291909152205460ff1690565b34801561089657600080fd5b5061033c6108a5366004614328565b612410565b3480156108b657600080fd5b5061033c6108c536600461436c565b612425565b3480156108d657600080fd5b5061033c6108e5366004614147565b6124cb565b3480156108f657600080fd5b5061033c61090536600461436c565b612544565b34801561091657600080fd5b5061033c610925366004614421565b6125ea565b60006301ffc9a760e01b6001600160e01b03198316148061095b57506380ac58cd60e01b6001600160e01b03198316145b806109765750635b5e139f60e01b6001600160e01b03198316145b92915050565b60606003805461098b90615510565b80601f01602080910402602001604051908101604052809291908181526020018280546109b790615510565b8015610a045780601f106109d957610100808354040283529160200191610a04565b820191906000526020600020905b8154815290600101906020018083116109e757829003601f168201915b5050505050905090565b6000610a19826127e4565b610a36576040516333d1c03960e21b815260040160405180910390fd5b506000908152600760205260409020546001600160a01b031690565b610a5a612819565b610a6760a4826003613f53565b5050565b6000610a76826116c8565b9050336001600160a01b03821614610aaf57610a92813361085c565b610aaf576040516367d9dca160e11b815260040160405180910390fd5b60008281526007602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b610b13612819565b610a6760a7826005613f91565b60ac54600090819081908190610100900460ff16610b595760405162461bcd60e51b8152600401610b50906153e8565b60405180910390fd5b609954859081118015610b6e5750609a548111155b610b8a5760405162461bcd60e51b8152600401610b50906153be565b600086815260ae6020526040808220815160a081019092528054429392919082908290610bb690615510565b80601f0160208091040260200160405190810160405280929190818152602001828054610be290615510565b8015610c2f5780601f10610c0457610100808354040283529160200191610c2f565b820191906000526020600020905b815481529060010190602001808311610c1257829003601f168201915b5050505050815260200160018201548152602001600282015481526020016003820154815260200160048201548152505090506000609660009054906101000a90046001600160a01b03166001600160a01b0316632af123b88360200151856040518363ffffffff1660e01b8152600401610cb4929190918252602082015260400190565b60206040518083038186803b158015610ccc57600080fd5b505afa158015610ce0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d049190614408565b609654604080850151905163055e247760e31b81529293506000926001600160a01b0390921691632af123b891610d48918890600401918252602082015260400190565b60206040518083038186803b158015610d6057600080fd5b505afa158015610d74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d989190614408565b905060008360600151600014610dc957603c846060015186610dba91906154cd565b610dc4919061549a565b610dcc565b60005b9050600060a18101548211610df35760a460005b0154610dec90836154ae565b9050610e27565b60a254821015610e065760a46001610de0565b60a354821015610e195760a46002610de0565b610e248260006154ae565b90505b6000610e356106868e6116c8565b90506000806000805b8451811015610ef1576000858281518110610e5b57610e5b6155b6565b602002602001015190506098600101548111610ede57600081815260ad602052604081205490600a610e8d8184615560565b600a8110610e9d57610e9d6155b6565b0154905080610eb35760009b5060019650610edb565b8060011415610ec95760009a5060019550610edb565b8060021415610edb5760009850600194505b50505b5080610ee981615545565b915050610e3e565b50600085610eff898b615482565b610f099190615482565b9f50929d50909b5099505050505050505050509193509193565b8033610f2e826116c8565b6001600160a01b031614610f805760405162461bcd60e51b81526020600482015260196024820152782cb7ba9030b932903737ba103a37b5b2b713b99037bbb732b960391b6044820152606401610b50565b60ac54610100900460ff16610fa75760405162461bcd60e51b8152600401610b50906153e8565b609954829081118015610fbc5750609a548111155b610fd85760405162461bcd60e51b8152600401610b50906153be565b600083815260af602052604090205460ff16156110275760405162461bcd60e51b815260206004820152600d60248201526c4e6f7420617661696c61626c6560981b6044820152606401610b50565b61103083612873565b600093845260ad602090815260408086209290925560af9052909220805460ff191660011790555050565b6000611066826128cc565b9050836001600160a01b0316816001600160a01b0316146110995760405162a1148160e81b815260040160405180910390fd5b60008281526007602052604090208054338082146001600160a01b038816909114176110e6576110c9863361085c565b6110e657604051632ce44b5f60e11b815260040160405180910390fd5b6001600160a01b03851661110d57604051633a954ecd60e21b815260040160405180910390fd5b801561111857600082555b6001600160a01b038681166000908152600660205260408082208054600019019055918716808252919020805460010190554260a01b17600160e11b17600085815260056020526040902055600160e11b83166111a357600184016000818152600560205260409020546111a15760015481146111a15760008181526005602052604090208490555b505b83856001600160a01b0316876001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050505050565b6111f4612819565b60ac805461ff001916610100179055565b61120d612819565b609755565b61122d83838360405180602001604052806000815250612095565b505050565b61123a612819565b610a67609e826003613f53565b60ac546000908190610100900460ff166112735760405162461bcd60e51b8152600401610b50906153e8565b6099548390811180156112885750609a548111155b6112a45760405162461bcd60e51b8152600401610b50906153be565b600084815260ae6020526040808220815160a0810190925280544293929190829082906112d090615510565b80601f01602080910402602001604051908101604052809291908181526020018280546112fc90615510565b80156113495780601f1061131e57610100808354040283529160200191611349565b820191906000526020600020905b81548152906001019060200180831161132c57829003601f168201915b5050505050815260200160018201548152602001600282015481526020016003820154815260200160048201548152505090506000609660009054906101000a90046001600160a01b03166001600160a01b0316632af123b88360200151856040518363ffffffff1660e01b81526004016113ce929190918252602082015260400190565b60206040518083038186803b1580156113e657600080fd5b505afa1580156113fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061141e9190614408565b609654604080850151905163055e247760e31b81529293506000926001600160a01b0390921691632af123b891611462918890600401918252602082015260400190565b60206040518083038186803b15801561147a57600080fd5b505afa15801561148e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114b29190614408565b905060006114c26106868a6116c8565b905060005b815181101561155c5760008282815181106114e4576114e46155b6565b60200260200101519050609860010154811161154957600081815260ad602052604081205490600a6115168184615560565b600a8110611526576115266155b6565b01549050806115385760009650611546565b806001141561154657600095505b50505b508061155481615545565b9150506114c7565b50919650945050505050915091565b611573612819565b60ac805460ff19166001179055565b600160ac5462010000900460ff1660038111156115a1576115a16155a0565b146115ee5760405162461bcd60e51b815260206004820152601860248201527f4e6f7420696e20737461676520746f206275792070726f7000000000000000006044820152606401610b50565b60995460015460001901106116355760405162461bcd60e51b815260206004820152600d60248201526c139bc81c1c9bdc1cc81b19599d609a1b6044820152606401610b50565b33600090815260b1602052604090205460ff16156116655760405162461bcd60e51b8152600401610b509061540c565b60006116746001546000190190565b61167f906001615482565b9050600061168c82612873565b600083815260ad6020526040902081905590506116aa33600161293c565b505033600090815260b160205260409020805460ff19166001179055565b6000610976826128cc565b6116db612819565b8060038111156116ed576116ed6155a0565b60ac805462ff000019166201000083600381111561170d5761170d6155a0565b021790555050565b6000816098600101548111801561172e5750609a548111155b61174a5760405162461bcd60e51b8152600401610b50906153be565b600083815260ae6020526040808220815160a0810190925280548290829061177190615510565b80601f016020809104026020016040519081016040528092919081815260200182805461179d90615510565b80156117ea5780601f106117bf576101008083540402835291602001916117ea565b820191906000526020600020905b8154815290600101906020018083116117cd57829003601f168201915b5050505050815260200160018201548152602001600282015481526020016003820154815260200160048201548152505090506000429050600060ad600087815260200190815260200160002054905060006301e133808261184c9190615560565b60965460808601519192506001600160a01b0316906365c7284090611872908490615482565b6040518263ffffffff1660e01b815260040161189091815260200190565b60206040518083038186803b1580156118a857600080fd5b505afa1580156118bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118e09190614408565b6096546040516301971ca160e61b8152600481018690526001600160a01b03909116906365c728409060240160206040518083038186803b15801561192457600080fd5b505afa158015611938573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061195c9190614408565b148015611a75575060965460808501516001600160a01b039091169063a324ad2490611989908490615482565b6040518263ffffffff1660e01b81526004016119a791815260200190565b60206040518083038186803b1580156119bf57600080fd5b505afa1580156119d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119f79190614408565b6096546040516328c92b4960e21b8152600481018690526001600160a01b039091169063a324ad249060240160206040518083038186803b158015611a3b57600080fd5b505afa158015611a4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a739190614408565b145b9550505050505b50919050565b60ac54610100900460ff16611aa95760405162461bcd60e51b8152600401610b50906153e8565b609954819081118015611abe5750609a548111155b611ada5760405162461bcd60e51b8152600401610b50906153be565b600082815260ae602090815260409182902042600290910155815184815233918101919091527fd0017656a8c92d10b2fa3a77fa3c1e8e4c28817e89311616b8eed8e68f68a95091015b60405180910390a15050565b60006001600160a01b038216611b59576040516323d3ad8160e21b815260040160405180910390fd5b506001600160a01b031660009081526006602052604090205467ffffffffffffffff1690565b611b87612819565b611b916000612956565b565b60ae60205260009081526040902080548190611bae90615510565b80601f0160208091040260200160405190810160405280929190818152602001828054611bda90615510565b8015611c275780601f10611bfc57610100808354040283529160200191611c27565b820191906000526020600020905b815481529060010190602001808311611c0a57829003601f168201915b5050505050908060010154908060020154908060030154908060040154905085565b60606000806000611c5985611b30565b905060008167ffffffffffffffff811115611c7657611c766155cc565b604051908082528060200260200182016040528015611c9f578160200160208202803683370190505b509050611ccc60408051608081018252600080825260208201819052918101829052606081019190915290565b60015b838614611d4d57611cdf816129a6565b9150816040015115611cf057611d45565b81516001600160a01b031615611d0557815194505b876001600160a01b0316856001600160a01b03161415611d455780838780600101985081518110611d3857611d386155b6565b6020026020010181815250505b600101611ccf565b50909695505050505050565b611d61612819565b609855565b60606004805461098b90615510565b6001600160a01b038216331415611d9f5760405163b06307db60e01b815260040160405180910390fd5b3360008181526008602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b611e13612819565b610a67609b826003613f53565b6000808260986001015481118015611e3a5750609a548111155b611e565760405162461bcd60e51b8152600401610b50906153be565b600084815260ae6020526040808220815160a08101909252805482908290611e7d90615510565b80601f0160208091040260200160405190810160405280929190818152602001828054611ea990615510565b8015611ef65780601f10611ecb57610100808354040283529160200191611ef6565b820191906000526020600020905b815481529060010190602001808311611ed957829003601f168201915b505050505081526020016001820154815260200160028201548152602001600382015481526020016004820154815250509050600060ad600087815260200190815260200160002054905060006301e1338082611f539190615560565b60965460808501519192506000916001600160a01b039091169063a324ad2490611f7e908590615482565b6040518263ffffffff1660e01b8152600401611f9c91815260200190565b60206040518083038186803b158015611fb457600080fd5b505afa158015611fc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fec9190614408565b60965460808601519192506000916001600160a01b03909116906365c7284090612017908690615482565b6040518263ffffffff1660e01b815260040161203591815260200190565b60206040518083038186803b15801561204d57600080fd5b505afa158015612061573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120859190614408565b9197509095505050505050915091565b6120a084848461105b565b6001600160a01b0383163b156120d9576120bc84848484612a25565b6120d9576040516368d2bf6b60e11b815260040160405180910390fd5b50505050565b606061097682612b1d565b600360ac5462010000900460ff166003811115612109576121096155a0565b146121565760405162461bcd60e51b815260206004820152601960248201527f4e6f7420696e20737461676520746f206d696e7420544d4747000000000000006044820152606401610b50565b609a54600154600019011061219b5760405162461bcd60e51b815260206004820152600b60248201526a139bc81c195d081b19599d60aa1b6044820152606401610b50565b33600090815260b2602052604090205460ff16156121cb5760405162461bcd60e51b8152600401610b509061540c565b60985434906121db9060016154ae565b111561221a5760405162461bcd60e51b815260206004820152600e60248201526d27379032b737bab3b41032ba341760911b6044820152606401610b50565b611b91612bec565b600260ac5462010000900460ff166003811115612241576122416155a0565b1461228e5760405162461bcd60e51b815260206004820181905260248201527f4e6f7420696e20737461676520746f206d696e74206d65726b6c6520544d47476044820152606401610b50565b609a5460015460001901106122d35760405162461bcd60e51b815260206004820152600b60248201526a139bc81c195d081b19599d60aa1b6044820152606401610b50565b33600090815260b2602052604090205460ff16156123035760405162461bcd60e51b8152600401610b509061540c565b60985434906123139060016154ae565b11156123525760405162461bcd60e51b815260206004820152600e60248201526d27379032b737bab3b41032ba341760911b6044820152606401610b50565b6040516bffffffffffffffffffffffff193360601b1660208201526000906034016040516020818303038152906040528051906020012090506123cc838380806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250506097549150849050612d7e565b6124085760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b210383937b7b360991b6044820152606401610b50565b61122d612bec565b612418612819565b610a6760a1826003613f53565b60ac54610100900460ff1661244c5760405162461bcd60e51b8152600401610b50906153e8565b6099548190811180156124615750609a548111155b61247d5760405162461bcd60e51b8152600401610b50906153be565b600082815260ae602090815260409182902042600390910155815184815233918101919091527fbae6551c0ddf25aa6805100ecbdc4535f2933a14d7ebafe9fab66af752e232ec9101611b24565b6124d3612819565b6001600160a01b0381166125385760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610b50565b61254181612956565b50565b60ac54610100900460ff1661256b5760405162461bcd60e51b8152600401610b50906153e8565b6099548190811180156125805750609a548111155b61259c5760405162461bcd60e51b8152600401610b50906153be565b600082815260ae602090815260409182902042600190910155815184815233918101919091527fd73f65a9b0fee6c2e3e08fd03cb4800137b36882554a7211fe8ce842b3d4f4fe9101611b24565b82336125f5826116c8565b6001600160a01b0316146126475760405162461bcd60e51b81526020600482015260196024820152782cb7ba9030b932903737ba103a37b5b2b713b99037bbb732b960391b6044820152606401610b50565b60ac54610100900460ff1661266e5760405162461bcd60e51b8152600401610b50906153e8565b6099548490811180156126835750609a548111155b61269f5760405162461bcd60e51b8152600401610b50906153be565b60b084846040516126b19291906145f3565b9081526040519081900360200190205460ff16156126fe5760405162461bcd60e51b815260206004820152600a60248201526913985b5948195e1a5cdd60b21b6044820152606401610b50565b600061273f85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612d9492505050565b90506001811180156127515750601281105b61278e5760405162461bcd60e51b815260206004820152600e60248201526d4e6f742076616c6964206e616d6560901b6044820152606401610b50565b600086815260ae602052604090206127a7908686613fbe565b50600160b086866040516127bc9291906145f3565b908152604051908190036020019020805491151560ff19909216919091179055505050505050565b6000816001111580156127f8575060015482105b8015610976575050600090815260056020526040902054600160e01b161590565b6000546001600160a01b03163314611b915760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b50565b6000806128816001436154cd565b6040805191406020830152810184905233606090811b6bffffffffffffffffffffffff19169082015260740160408051601f1981840301815291905280516020909101209392505050565b600081806001116129235760015481101561292357600081815260056020526040902054600160e01b8116612921575b8061291a5750600019016000818152600560205260409020546128fc565b9392505050565b505b604051636f96cda160e11b815260040160405180910390fd5b610a67828260405180602001604052806000815250612ed1565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60408051608081018252600080825260208201819052918101829052606081019190915260008281526005602052604090205461097690604080516080810182526001600160a01b038316815260a083901c67ffffffffffffffff166020820152600160e01b831615159181019190915260e89190911c606082015290565b604051630a85bd0160e11b81526000906001600160a01b0385169063150b7a0290612a5a903390899088908890600401615309565b602060405180830381600087803b158015612a7457600080fd5b505af1925050508015612aa4575060408051601f3d908101601f19168201909252612aa1918101906143a2565b60015b612aff573d808015612ad2576040519150601f19603f3d011682016040523d82523d6000602084013e612ad7565b606091505b508051612af7576040516368d2bf6b60e11b815260040160405180910390fd5b805181602001fd5b6001600160e01b031916630a85bd0160e11b1490505b949350505050565b60608160018110158015612b375750600154600019018111155b612b725760405162461bcd60e51b815260206004820152600c60248201526b139bdd081d985b1a59081a5960a21b6044820152606401610b50565b609954600090841115612ba55760ac54610100900460ff16612b9c57612b9784612f3e565b612bc1565b612b9784612feb565b60ac5460ff16612bb857612b978461313a565b612bc18461315a565b905080604051602001612bd49190615168565b60405160208183030381529060405292505050919050565b6000612bfb6001546000190190565b612c06906001615482565b905060b45460051415612ca357600060b45560965460b354604051631c85d48f60e21b81526004810191909152600160248201526001600160a01b0390911690637217523c9060440160206040518083038186803b158015612c6757600080fd5b505afa158015612c7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c9f9190614408565b60b3555b6040805160c081018252600060a082018181528252426020808401829052838501919091526060830182905260b354608084015284825260ae81529290208151805192938493612cf69284920190614031565b5060208201516001820155604082015160028201556060820151600382015560809091015160049091015560b48054906000612d3183615545565b91905055506000612d4183612873565b600084815260ad602052604090208190559050612d5f33600161293c565b505033600090815260b260205260409020805460ff1916600117905550565b600082612d8b85846132ff565b14949350505050565b600080825b8051821015612eca576007818381518110612db657612db66155b6565b01602001516001600160f81b031990811690911c16612de157612dda600183615482565b9150612eb8565b8051600360f91b90600590839085908110612dfe57612dfe6155b6565b01602001516001600160f81b031990811690911c161415612e2457612dda600283615482565b8051600760f91b90600490839085908110612e4157612e416155b6565b01602001516001600160f81b031990811690911c161415612e6757612dda600383615482565b8051600f60f91b90600390839085908110612e8457612e846155b6565b01602001516001600160f81b031990811690911c161415612eaa57612dda600483615482565b612eb5600183615482565b91505b82612ec281615545565b935050612d99565b5050919050565b612edb838361334c565b6001600160a01b0383163b1561122d576001548281035b612f056000868380600101945086612a25565b612f22576040516368d2bf6b60e11b815260040160405180910390fd5b818110612ef2578160015414612f3757600080fd5b5050505050565b6060600080612f4c84611e20565b600086815260ad6020526040812054929450909250612fe1612f6d87613443565b612f7686613443565b612f7f86613443565b612f8888613443565b612f9188613443565b612fb8601a612fa160038b615560565b60038110612fb157612fb16155b6565b0154613443565b604051602001612fcd96959493929190614e5d565b604051602081830303815290604052613541565b9695505050505050565b6060600080600080612ffc86610b20565b935093509350935060008061301088611247565b91509150600061301f89611715565b9050600086801561302d5750855b80156130365750845b8061303e5750815b61304957600061304c565b60015b90506000613059896136a7565b905060006040518060c001604052808d815260200160ad60008f81526020019081526020016000205481526020018781526020018681526020018b8152602001841515815250905060006130c160ad60008f8152602001908152602001600020548486613707565b905060006130ce83613ae9565b6130d784613c7b565b6130e085613cc1565b6130e986613d6e565b6130fa6130f587613da7565b613541565b60405160200161310e959493929190614689565b604051602081830303815290604052905061312881613541565b9e9d5050505050505050505050505050565b6060600061291a61314a84613443565b604051602001612fcd9190614d2b565b600081815260ad6020526040812054606091600a6131788184615560565b600a8110613188576131886155b6565b015490506000601782600381106131a1576131a16155b6565b0180546131ad90615510565b80601f01602080910402602001604051908101604052809291908181526020018280546131d990615510565b80156132265780601f106131fb57610100808354040283529160200191613226565b820191906000526020600020905b81548152906001019060200180831161320957829003601f168201915b50505050509050600060148360038110613242576132426155b6565b01805461324e90615510565b80601f016020809104026020016040519081016040528092919081815260200182805461327a90615510565b80156132c75780601f1061329c576101008083540402835291602001916132c7565b820191906000526020600020905b8154815290600101906020018083116132aa57829003601f168201915b5050505050905060006132f46132dc88613443565b83858586604051602001612fcd959493929190614b88565b979650505050505050565b600081815b84518110156133445761333082868381518110613323576133236155b6565b6020026020010151613dd0565b91508061333c81615545565b915050613304565b509392505050565b6001548161336d5760405163b562e8dd60e01b815260040160405180910390fd5b6001600160a01b03831660008181526006602090815260408083208054680100000000000000018802019055848352600590915281206001851460e11b4260a01b178317905582840190839083907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a4600183015b81811461341c57808360007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a46001016133e4565b508161343a57604051622e076360e81b815260040160405180910390fd5b60015550505050565b6060816134675750506040805180820190915260018152600360fc1b602082015290565b8160005b8115613491578061347b81615545565b915061348a9050600a8361549a565b915061346b565b60008167ffffffffffffffff8111156134ac576134ac6155cc565b6040519080825280601f01601f1916602001820160405280156134d6576020820181803683370190505b5090505b8415612b15576134eb6001836154cd565b91506134f8600a86615560565b613503906030615482565b60f81b818381518110613518576135186155b6565b60200101906001600160f81b031916908160001a90535061353a600a8661549a565b94506134da565b606081516000141561356157505060408051602081019091526000815290565b60006040518060600160405280604081526020016155f960409139905060006003845160026135909190615482565b61359a919061549a565b6135a59060046154ae565b905060006135b4826020615482565b67ffffffffffffffff8111156135cc576135cc6155cc565b6040519080825280601f01601f1916602001820160405280156135f6576020820181803683370190505b509050818152600183018586518101602084015b81831015613662576003830192508251603f8160121c168501518253600182019150603f81600c1c168501518253600182019150603f8160061c168501518253600182019150603f811685015182535060010161360a565b60038951066001811461367c576002811461368d57613699565b613d3d60f01b600119830152613699565b603d60f81b6000198301525b509398975050505050505050565b60a75460009082116136c057602a60035b015492915050565b60a8548210156136d357602a60006136b8565b60a9548210156136e657602a60016136b8565b60aa548210156136f957602a60026136b8565b602a60046136b8565b919050565b60606000608b600b61371a60048861549a565b6137249190615560565b600b8110613734576137346155b6565b01805461374090615510565b80601f016020809104026020016040519081016040528092919081815260200182805461376c90615510565b80156137b95780601f1061378e576101008083540402835291602001916137b9565b820191906000526020600020905b81548152906001019060200180831161379c57829003601f168201915b5050505050905060006080600b6003886137d3919061549a565b6137dd9190615560565b600b81106137ed576137ed6155b6565b0180546137f990615510565b80601f016020809104026020016040519081016040528092919081815260200182805461382590615510565b80156138725780601f1061384757610100808354040283529160200191613872565b820191906000526020600020905b81548152906001019060200180831161385557829003601f168201915b505050505090506000606e600d60028961388c919061549a565b6138969190615560565b600d81106138a6576138a66155b6565b0180546138b290615510565b80601f01602080910402602001604051908101604052809291908181526020018280546138de90615510565b801561392b5780601f106139005761010080835404028352916020019161392b565b820191906000526020600020905b81548152906001019060200180831161390e57829003601f168201915b505050505090506000607b8760058110613947576139476155b6565b01805461395390615510565b80601f016020809104026020016040519081016040528092919081815260200182805461397f90615510565b80156139cc5780601f106139a1576101008083540402835291602001916139cc565b820191906000526020600020905b8154815290600101906020018083116139af57829003601f168201915b5050505050905060006139de85613dfc565b6139e785613dfc565b6139f084613dfc565b6139f986613dfc565b604051602001613a0c9493929190614632565b60405160208183030381529060405290508615613add5780613aba606d6000018054613a3790615510565b80601f0160208091040260200160405190810160405280929190818152602001828054613a6390615510565b8015613ab05780601f10613a8557610100808354040283529160200191613ab0565b820191906000526020600020905b815481529060010190602001808311613a9357829003601f168201915b5050505050613dfc565b604051602001613acb929190614603565b60405160208183030381529060405290505b98975050505050505050565b6060600080613afb8460000151611e20565b91509150600060ae6000866000015181526020019081526020016000206040518060a0016040529081600082018054613b3390615510565b80601f0160208091040260200160405190810160405280929190818152602001828054613b5f90615510565b8015613bac5780601f10613b8157610100808354040283529160200191613bac565b820191906000526020600020905b815481529060010190602001808311613b8f57829003601f168201915b50505050508152602001600182015481526020016002820154815260200160038201548152602001600482015481525050905060006001613bf08360000151612d94565b11613c0a5760405180602001604052806000815250613c2c565b8151604051613c1c9190602001614842565b6040516020818303038152906040525b905080613c3c8760000151613443565b613c4586613443565b613c4e86613443565b604051602001613c61949392919061501c565b604051602081830303815290604052945050505050919050565b60606000613c8c8360400151613443565b613c998460600151613443565b604051602001613caa92919061493d565b60408051601f198184030181529190529392505050565b606060008260a00151613cee57604051806040016040528060028152602001616e6f60f01b815250613d0b565b6040518060400160405280600381526020016279657360e81b8152505b9050600081613d1d8560800151613443565b613d2686613e17565b613d2f87613e4b565b613d3888613ea3565b613d4189613efb565b604051602001613d5696959493929190614a6d565b60408051601f19818403018152919052949350505050565b6060600080613d808460000151611e20565b91509150613d8d82613443565b613d9682613443565b604051602001612bd49291906150d8565b606081604051602001613dba91906151ad565b6040516020818303038152906040529050919050565b6000818310613dec57600082815260208490526040902061291a565b5060009182526020526040902090565b6060613e0782613541565b604051602001613dba9190614869565b606060006052613e2a84608001516136a7565b60058110613e3a57613e3a6155b6565b01604051602001613caa9190614fdb565b606060006045601d600d60028660200151613e66919061549a565b613e709190615560565b600d8110613e8057613e806155b6565b0154600d8110613e9257613e926155b6565b01604051602001613caa9190614a1e565b606060006057602f600b60038660200151613ebe919061549a565b613ec89190615560565b600b8110613ed857613ed86155b6565b0154600b8110613eea57613eea6155b6565b01604051602001613caa91906152cc565b606060006062603a600b60048660200151613f16919061549a565b613f209190615560565b600b8110613f3057613f306155b6565b0154600b8110613f4257613f426155b6565b01604051602001613caa919061512b565b8260038101928215613f81579160200282015b82811115613f81578235825591602001919060010190613f66565b50613f8d9291506140a5565b5090565b8260058101928215613f815791602002820182811115613f81578235825591602001919060010190613f66565b828054613fca90615510565b90600052602060002090601f016020900481019282613fec5760008555613f81565b82601f106140055782800160ff19823516178555613f81565b82800160010185558215613f815791820182811115613f81578235825591602001919060010190613f66565b82805461403d90615510565b90600052602060002090601f01602090048101928261405f5760008555613f81565b82601f1061407857805160ff1916838001178555613f81565b82800160010185558215613f81579182015b82811115613f8157825182559160200191906001019061408a565b5b80821115613f8d57600081556001016140a6565b600067ffffffffffffffff808411156140d5576140d56155cc565b604051601f8501601f19908116603f011681019082821181831017156140fd576140fd6155cc565b8160405280935085815286868601111561411657600080fd5b858560208301376000602087830101525050509392505050565b80356001600160a01b038116811461370257600080fd5b60006020828403121561415957600080fd5b61291a82614130565b6000806040838503121561417557600080fd5b61417e83614130565b915061418c60208401614130565b90509250929050565b6000806000606084860312156141aa57600080fd5b6141b384614130565b92506141c160208501614130565b9150604084013590509250925092565b600080600080608085870312156141e757600080fd5b6141f085614130565b93506141fe60208601614130565b925060408501359150606085013567ffffffffffffffff81111561422157600080fd5b8501601f8101871361423257600080fd5b614241878235602084016140ba565b91505092959194509250565b6000806040838503121561426057600080fd5b61426983614130565b91506020830135801515811461427e57600080fd5b809150509250929050565b6000806040838503121561429c57600080fd5b6142a583614130565b946020939093013593505050565b600080602083850312156142c657600080fd5b823567ffffffffffffffff808211156142de57600080fd5b818501915085601f8301126142f257600080fd5b81358181111561430157600080fd5b8660208260051b850101111561431657600080fd5b60209290920196919550909350505050565b60006060828403121561433a57600080fd5b82606083011115611a7c57600080fd5b600060a0828403121561435c57600080fd5b8260a083011115611a7c57600080fd5b60006020828403121561437e57600080fd5b5035919050565b60006020828403121561439757600080fd5b813561291a816155e2565b6000602082840312156143b457600080fd5b815161291a816155e2565b6000602082840312156143d157600080fd5b813567ffffffffffffffff8111156143e857600080fd5b8201601f810184136143f957600080fd5b612b15848235602084016140ba565b60006020828403121561441a57600080fd5b5051919050565b60008060006040848603121561443657600080fd5b83359250602084013567ffffffffffffffff8082111561445557600080fd5b818601915086601f83011261446957600080fd5b81358181111561447857600080fd5b87602082850101111561448a57600080fd5b6020830194508093505050509250925092565b600081518084526144b58160208601602086016154e4565b601f01601f19169290920160200192915050565b600081516144db8185602086016154e4565b9290920192915050565b8054600090600181811c90808316806144ff57607f831692505b602080841082141561452157634e487b7160e01b600052602260045260246000fd5b818015614535576001811461454657614573565b60ff19861689528489019650614573565b60008881526020902060005b8681101561456b5781548b820152908501908301614552565b505084890196505b50505050505092915050565b7f7b202274726169745f74797065223a202274797065222c202276616c7565223a81526808089c195d1cc89f4b60ba1b602082015260290190565b7f7b202274726169745f74797065223a2022626972746864617465222c20227661815266363ab2911d101160c91b602082015260270190565b8183823760009101908152919050565b600083516146158184602088016154e4565b8351908301906146298183602088016154e4565b01949350505050565b60008551614644818460208a016154e4565b855190830190614658818360208a016154e4565b855191019061466b8183602089016154e4565b845191019061467e8183602088016154e4565b019695505050505050565b6000865161469b818460208b016154e4565b80830190507f226465736372697074696f6e223a202254616d61676f6769206973206120546181527f6d61676f74636869204461707020616e642066756c6c792067656e657261746560208201527f64206f6e2d636861696e2e2054686520636f6e747261637420696e746572616360408201527f74696f6e20616e642074696d652077696c6c206166666563742074686520737460608201527f6174757320616e64207265616374696f6e206f6620746865207065742e20496660808201527f20796f7520636f6c6c656374206f74686572206974656d732c2074686520706560a0820152721d081dda5b1b081cda1bddc81b1bdd9948488b606a1b60c08201526e2261747472696275746573223a205b60881b60d382015286516147c88160e2840160208b016154e4565b6148356148276148216147e96147e360e2868801018c6144c9565b8a6144c9565b7f5d2c22696d616765223a2022646174613a696d6167652f7376672b786d6c3b62815265185cd94d8d0b60d21b602082015260260190565b876144c9565b61227d60f01b815260020190565b9998505050505050505050565b600082516148548184602087016154e4565b6201017960ed1b920191825250600301919050565b7f3c696d61676520783d22302220793d2230222077696474683d2233322220686581527f696768743d2233322220696d6167652d72656e646572696e673d22706978656c60208201527f6174656422207072657365727665417370656374526174696f3d22784d69645960408201527f4d69642220786c696e6b3a687265663d22646174613a696d6167652f706e673b60608201526618985cd94d8d0b60ca1b6080820152600082516149238160878501602087016154e4565b6211179f60e91b6087939091019283015250608a01919050565b7f7b202274726169745f74797065223a202268756e676572222c2022646973706c81527f61795f74797065223a20226e756d626572222c202276616c7565223a2000000060208201526000835161499b81603d8501602088016154e4565b8083019050611f4b60f21b80603d8301527f7b202274726169745f74797065223a2022626f726564222c2022646973706c61603f8301527f795f74797065223a20226e756d626572222c202276616c7565223a2000000000605f8301528451614a0b81607b8501602089016154e4565b607b920191820152607d01949350505050565b7f7b202274726169745f74797065223a2022656172222c202276616c7565223a208152601160f91b60208201526000614a5a60218301846144e5565b62089f4b60ea1b81526003019392505050565b6000614a788261457f565b7f7b202274726169745f74797065223a20226d6173746572222c202276616c7565815263111d101160e11b60208201528851614abb816024840160208d016154e4565b62089f4b60ea1b602492909101918201527f7b202274726169745f74797065223a2022756e68617070696e657373222c202260278201527f646973706c61795f74797065223a20226e756d626572222c202276616c75652260478201526101d160f51b60678201528751614b36816069840160208c016154e4565b611f4b60f21b606992909101918201528651614b5981606b840160208b016154e4565b614b7a614b74614b6e606b848601018a6144c9565b886144c9565b866144c9565b9a9950505050505050505050565b6a7b226e616d65223a20222360a81b81528551600090614baf81600b850160208b016154e4565b6a040a8c2dac2cedeced240560ab1b600b918401918201528651614bda816016840160208b016154e4565b7314911610113232b9b1b934b83a34b7b7111d101160611b601692909101918201528551614c0f81602a840160208a016154e4565b61088b60f21b9101602a8101919091526e2261747472696275746573223a205b60881b602c8201527f7b202274726169745f74797065223a202274797065222c202276616c7565223a603b8201526908089c1c9bdc1cc89f4b60b21b605b8201527f7b202274726169745f74797065223a20227573616765222c202276616c7565226065820152621d101160e91b6085820152613add614d19614b74614cca614cba608886016147e3565b63089f574b60e21b815260040190565b7f22696d616765223a2022697066733a2f2f516d56784344666d7767593270734181527f683777746938614c43796b6b6a3939736e79674751383970327a6b664174662f602082015260400190565b652e676966227d60d01b815260060190565b6a7b226e616d65223a20222360a81b81528151600090614d5281600b8501602087016154e4565b7f2054616d61676f67692028556e72657665616c2050726f707329222c20226465600b9390910192830152507f736372697074696f6e223a2022556e72657665616c2050726f7073222c000000602b8201526e2261747472696275746573223a205b60881b60488201527f7b202274726169745f74797065223a202274797065222c202276616c7565223a605782015268202270726f7073227d60b81b607782015261174b60f21b60808201527f22696d616765223a2022697066733a2f2f516d5462423644443277387433367a60828201527f4c50764245646f576f363252464d794a69394558636a39395a6978507278432260a2820152607d60f81b60c282015260c301919050565b6a7b226e616d65223a20222360a81b81528651600090614e8481600b850160208c016154e4565b6e040a8c2dac2cedeced2408acece405608b1b600b918401918201528751614eb381601a840160208c016154e4565b602f60f81b601a92909101918201528651614ed581601b840160208b016154e4565b602960f81b9101601b8101919091527f222c20226465736372697074696f6e223a2022556e62726f6b656e2054616d61601c8201526d19dbd9da481959d9dccb8b8b888b60921b603c8201526e2261747472696275746573223a205b60881b604a820152614835614d19614b74614f8c614f7e614827614f78614f6b614f65614f6060598b0161457f565b6145ba565b8e6144c9565b602f60f81b815260010190565b8b6144c9565b61174b60f21b815260020190565b7f22696d616765223a2022697066733a2f2f516d57317463635971426d534c514681527f54664e38725777384a4858787837685a53344d6969775757444e35747647382f602082015260400190565b7f7b202274726169745f74797065223a20227265616374696f6e222c202276616c8152653ab2911d101160d11b60208201526000614a5a60268301846144e5565b693d913730b6b2911d101160b11b8152845160009061504281600a850160208a016154e4565b602360f81b600a91840191820152855161506381600b840160208a016154e4565b6a040a8c2dac2cedeced240560ab1b600b9290910191820152845161508f8160168401602089016154e4565b602f60f81b6016929091019182015283516150b18160178401602088016154e4565b602960f81b6017929091019182015261088b60f21b6018820152601a019695505050505050565b60006150e3826145ba565b84516150f38183602089016154e4565b602f60f81b910190815283516151108160018401602088016154e4565b61227d60f01b60019290910191820152600301949350505050565b7f7b202274726169745f74797065223a2022626f6479222c202276616c7565223a815261101160f11b60208201526000614a5a60228301846144e5565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c0000008152600082516151a081601d8501602087016154e4565b91909101601d0192915050565b7f3c7376672077696474683d2239363022206865696768743d223936302220766581527f7273696f6e3d22312e31222076696577426f783d22302030203332203332222060208201527f786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323030302f737660408201527f672220786d6c6e733a786c696e6b3d22687474703a2f2f7777772e77332e6f7260608201526d3397989c9c9c97bc3634b735911f60911b60808201527f3c726563742077696474683d223130302522206865696768743d223130302522608e82015271103334b6361e9111b0b0b21c9c9c9110179f60711b60ae820152600082516152af8160c08501602087016154e4565b651e17b9bb339f60d11b60c093909101928301525060c601919050565b7f7b202274726169745f74797065223a202268656164222c202276616c7565223a815261101160f11b60208201526000614a5a60228301846144e5565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090612fe19083018461449d565b6020808252825182820181905260009190848201906040850190845b81811015611d4d57835183529284019291840191600101615358565b60208152600061291a602083018461449d565b60a08152600061539a60a083018861449d565b90508560208301528460408301528360608301528260808301529695505050505050565b60208082526010908201526f139bdd081d985b1a59081c195d081a5960821b604082015260600190565b6020808252600a9082015269139bdd081c995d99585b60b21b604082015260600190565b6020808252600890820152674d617820746f203160c01b604082015260600190565b86815260208101869052604081018590528315156060820152821515608082015260c081016004831061547157634e487b7160e01b600052602160045260246000fd5b8260a0830152979650505050505050565b6000821982111561549557615495615574565b500190565b6000826154a9576154a961558a565b500490565b60008160001904831182151516156154c8576154c8615574565b500290565b6000828210156154df576154df615574565b500390565b60005b838110156154ff5781810151838201526020016154e7565b838111156120d95750506000910152565b600181811c9082168061552457607f821691505b60208210811415611a7c57634e487b7160e01b600052602260045260246000fd5b600060001982141561555957615559615574565b5060010190565b60008261556f5761556f61558a565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160e01b03198116811461254157600080fdfe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2fa2646970667358221220f1bbe7fca7f3263c3e811e6ceea38359c62c7b09c7e4845d05a74dcb604827eb64736f6c63430008070033608060405234801561001057600080fd5b5061152e806100206000396000f3fe608060405234801561001057600080fd5b506004361061030b5760003560e01c80638aa001fc1161019d578063c7b6fd6a116100e9578063de5101af116100a2578063f615ed541161007c578063f615ed541461068a578063f9fd52501461069d578063fa93f883146106a5578063ff2258cb146106b857600080fd5b8063de5101af1461065c578063e95564301461066f578063ea1c16901461067757600080fd5b8063c7b6fd6a1461060b578063c7edf88c1461061e578063c9d3462214610626578063cfbb9f3714610639578063d2b5074314610641578063d6582d0d1461064957600080fd5b80639e524caa11610156578063ad203bd411610130578063ad203bd4146105cc578063b05eb08d146105df578063b3bb8cd4146105f2578063b8d16dbc146105f857600080fd5b80639e524caa1461059c578063a324ad24146105af578063a3f144ae146105c257600080fd5b80638aa001fc146104f85780638bbf51b71461050b5780638d4a2d391461051357806390059aed146105265780639220d4261461055457806392d663131461058957600080fd5b80634355644d1161025c5780635e05bd6d116102155780637217523c116101ef5780637217523c146104b557806374f0314f146104c85780637be34109146104d257806389a3a00d146104e557600080fd5b80635e05bd6d1461047c57806362fb96971461048f57806365c72840146104a257600080fd5b80634355644d146104145780634371c46514610427578063442b8c791461043a578063444fda821461044d5780634b321502146104605780634df861261461047357600080fd5b80631f4f77b2116102c95780632af123b8116102a35780632af123b8146103c85780633293d007146103db5780633e239e1a146103ee5780633f9e0eb71461040157600080fd5b80631f4f77b21461039a57806322f8a2b8146103ad57806329441674146103c057600080fd5b80625015531461031057806302e98e0d1461033657806310848ddf14610349578063126702a01461035c57806314b2d6dc146103645780631e0582e914610387575b600080fd5b61032361031e366004611292565b6106cb565b6040519081526020015b60405180910390f35b610323610344366004611292565b6106de565b610323610357366004611279565b6106ea565b610323600281565b6103776103723660046112b4565b6106fb565b604051901515815260200161032d565b6103236103953660046112b4565b610710565b6103236103a83660046112b4565b61071d565b6103236103bb366004611279565b61072a565b610323600781565b6103236103d6366004611292565b610735565b6103776103e93660046112e0565b610741565b6103236103fc366004611279565b61075c565b61032361040f366004611292565b610767565b610323610422366004611292565b610773565b610377610435366004611279565b61077f565b610323610448366004611292565b61078a565b61032361045b366004611292565b610796565b61032361046e366004611292565b6107a2565b610323610e1081565b61032361048a3660046112e0565b6107ae565b61032361049d366004611292565b6107c8565b6103236104b0366004611279565b6107d4565b6103236104c3366004611292565b6107df565b6103236201518081565b6103236104e0366004611292565b6107eb565b6103236104f3366004611292565b6107f7565b610323610506366004611279565b610803565b610323600381565b610323610521366004611292565b61080e565b610539610534366004611279565b61081a565b6040805193845260208401929092529082015260600161032d565b61055c610835565b604080519687526020870195909552938501929092526060840152608083015260a082015260c00161032d565b610323610597366004611279565b61085a565b6103236105aa366004611292565b610865565b6103236105bd366004611279565b610871565b61032362253d8c81565b6103236105da366004611292565b61087c565b6103776105ed366004611279565b610888565b42610323565b610377610606366004611279565b610893565b610323610619366004611292565b61089e565b610323600681565b610323610634366004611292565b6108aa565b610323600481565b610323600581565b610377610657366004611279565b6108b6565b61053961066a366004611279565b6108c1565b610323603c81565b61055c610685366004611279565b6108dc565b610323610698366004611292565b610902565b610323600181565b6103236106b3366004611279565b61090e565b6103236106c6366004611292565b610919565b60006106d78383610925565b9392505050565b60006106d7838361094c565b60006106f582610971565b92915050565b6000610708848484610999565b949350505050565b60006107088484846109ef565b6000610708848484610b2c565b60006106f582610b47565b60006106d78383610b7b565b6000610751878787878787610b97565b979650505050505050565b60006106f582610bd7565b60006106d78383610bf5565b60006106d78383610c7b565b60006106f582610d4d565b60006106d78383610d62565b60006106d78383610d96565b60006106d78383610e17565b6000610751878787878787610e3e565b9695505050505050565b60006106d78383610e8f565b60006106f582610ea8565b60006106d78383610eba565b60006106d78383610ec9565b60006106d78383610f40565b60006106f582610f4d565b60006106d78383610f5a565b600080600061082884610f66565b9250925092509193909250565b60008060008060008061084742611002565b949b939a50919850965094509092509050565b60006106f582611043565b60006106d7838361105e565b60006106f58261106b565b60006106d7838361107d565b60006106f582611151565b60006106f58261118d565b60006106d783836111ad565b60006106d783836111bc565b60006106f5826111d9565b60008060006108cf846111ee565b9196909550909350915050565b6000806000806000806108ee87611002565b949c939b5091995097509550909350915050565b60006106d783836111ff565b60006106f58261120b565b60006106d78383611227565b6000610933610e1083611443565b61093d90846114a1565b9050828111156106f557600080fd5b60008183111561095b57600080fd5b603c61096784846114a1565b6106d791906113aa565b6000808061098a61098562015180866113aa565b610f66565b50915091506107088282610bf5565b60006107b284101580156109ad5750600083115b80156109ba5750600c8311155b156106d75760006109cb8585610bf5565b90506000831180156109dd5750808311155b156109e757600191505b509392505050565b60006107b2841015610a0057600080fd5b838383600062253d8c60046064600c610a1a600e88611462565b610a24919061137c565b610a3088611324611323565b610a3a9190611323565b610a44919061137c565b610a4f9060036113be565b610a59919061137c565b600c80610a67600e88611462565b610a71919061137c565b610a7c90600c6113be565b610a87600288611462565b610a919190611462565b610a9d9061016f6113be565b610aa7919061137c565b6004600c610ab6600e89611462565b610ac0919061137c565b610acc896112c0611323565b610ad69190611323565b610ae2906105b56113be565b610aec919061137c565b610af8617d4b87611462565b610b029190611323565b610b0c9190611323565b610b169190611462565b610b209190611462565b98975050505050505050565b600062015180610b3d8585856109ef565b6107089190611443565b600080610b5762015180846113aa565b90506007610b66826003611364565b610b7091906114b8565b6106d7906001611364565b600081831115610b8a57600080fd5b610e1061096784846114a1565b6000610ba4878787610999565b156107be57601884108015610bb95750603c83105b8015610bc55750603c82105b156107be575060019695505050505050565b600080610be762015180846114b8565b90506106d7610e10826113aa565b60008160011480610c065750816003145b80610c115750816005145b80610c1c5750816007145b80610c275750816008145b80610c32575081600a145b80610c3d575081600c145b15610c4a5750601f6106f5565b81600214610c5a5750601e6106f5565b610c6383611151565b610c6e57601c610c71565b601d5b60ff169392505050565b6000808080610c9061098562015180886113aa565b91945092509050610ca18583611364565b9150600c610cb06001846114a1565b610cba91906113aa565b610cc49084611364565b9250600c610cd36001846114a1565b610cdd91906114b8565b610ce8906001611364565b91506000610cf68484610bf5565b905080821115610d04578091505b610d1162015180886114b8565b62015180610d208686866109ef565b610d2a9190611443565b610d349190611364565b945086851015610d4357600080fd5b5050505092915050565b60006006610d5a83610b47565b101592915050565b6000808080610d7761098562015180886113aa565b91945092509050610d888584611364565b92506000610cf68484610bf5565b6000808080610dab61098562015180886113aa565b91945092509050610dbc85846114a1565b92506000610dca8484610bf5565b905080821115610dd8578091505b610de562015180886114b8565b62015180610df48686866109ef565b610dfe9190611443565b610e089190611364565b945086851115610d4357600080fd5b6000610e25610e1083611443565b610e2f9084611364565b9050828110156106f557600080fd5b600081610e4c603c85611443565b610e58610e1087611443565b62015180610e678b8b8b6109ef565b610e719190611443565b610e7b9190611364565b610e859190611364565b6107519190611364565b600081831115610e9e57600080fd5b6106d783836114a1565b600061070861098562015180846113aa565b6000610e256201518083611443565b600081831115610ed857600080fd5b600080610eeb61098562015180876113aa565b509092509050600080610f0461098562015180886113aa565b50909250905082610f1685600c611443565b82610f2285600c611443565b610f2c9190611364565b610f3691906114a1565b61075191906114a1565b6000610e25603c83611443565b60006106f5603c836114b8565b6000610e2f8284611364565b60008080836226496581018262023ab1600483020590506004600362023ab18302010590910390600062164b09610fa0600185010205905060046105b58202058303601f019250600061098f8460500281610fc357610fc36114e2565b0590506000605061098f83020585039050600b820560301994909401606402929092018301996002600c90940290910392909201975095509350505050565b6000808080808061101862015180885b04610f66565b91999098919750610e10620151809092068281049750603c9290068281049650919091069350915050565b600061105561098562015180846113aa565b50909392505050565b6000610933603c83611443565b60006109e761098562015180846113aa565b600080808061109261098562015180886113aa565b919450925090506000856110a76001856114a1565b6110b286600c611443565b6110bc9190611364565b6110c691906114a1565b90506110d3600c826113aa565b93506110e0600c826114b8565b6110eb906001611364565b925060006110f98585610bf5565b905080831115611107578092505b61111462015180896114b8565b620151806111238787876109ef565b61112d9190611443565b6111379190611364565b95508786111561114657600080fd5b505050505092915050565b600061115e6004836114b8565b15801561117457506111716064836114b8565b15155b806106f55750611186610190836114b8565b1592915050565b6000806111a061098562015180856113aa565b505090506106d781611151565b60006109336201518083611443565b6000818311156111cb57600080fd5b6201518061096784846114a1565b600060056111e683610b47565b111592915050565b600080806108cf6201518085611012565b600061093d82846114a1565b60008061121a610e10846114b8565b90506106d7603c826113aa565b60008183111561123657600080fd5b600061124861098562015180866113aa565b505090506000611260620151808561098591906113aa565b50509050818161127091906114a1565b95945050505050565b60006020828403121561128b57600080fd5b5035919050565b600080604083850312156112a557600080fd5b50508035926020909101359150565b6000806000606084860312156112c957600080fd5b505081359360208301359350604090920135919050565b60008060008060008060c087890312156112f957600080fd5b505084359660208601359650604086013595606081013595506080810135945060a0013592509050565b600080821280156001600160ff1b0384900385131615611345576113456114cc565b600160ff1b839003841281161561135e5761135e6114cc565b50500190565b60008219821115611377576113776114cc565b500190565b60008261138b5761138b6114e2565b600160ff1b8214600019841416156113a5576113a56114cc565b500590565b6000826113b9576113b96114e2565b500490565b60006001600160ff1b03818413828413808216868404861116156113e4576113e46114cc565b600160ff1b6000871282811687830589121615611403576114036114cc565b6000871292508782058712848416161561141f5761141f6114cc565b87850587128184161615611435576114356114cc565b505050929093029392505050565b600081600019048311821515161561145d5761145d6114cc565b500290565b60008083128015600160ff1b850184121615611480576114806114cc565b6001600160ff1b038401831381161561149b5761149b6114cc565b50500390565b6000828210156114b3576114b36114cc565b500390565b6000826114c7576114c76114e2565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fdfea26469706673582212202464ec77d55c0b8b938a36e973509d6bb0bb2d18b4f4c56e73bccd066d6eca6264736f6c6343000807003389504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c086488000000b9494441545847ed96c10e80200c4321faff5fec4139cce0dc68410c979178215bf7a81b21a794b6eb5bb672008403e14038100e8403e140384038705c31fbe08b05e6b20f1228640052390c0025e4380473110014207e4d53a30530a3b8f0b95a1ec08ce2b5c6278051189d67ea300e588965afac7a3cbd3d89e90228e2226815d2a22dbb2db0bb77d1140888770a298c00dc8b8c01d010f5e4590008fa31b97f01c0f193001640f70471ffbc9ad4cce901608b76c52d073801df502d81d35c52b50000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000060494441545847ed96410a00200804f3ff8f2e844e511a68e461bab74ea348d23e1ff95cbf0180010c9436d0e78e88429a39a770bd142dbceeb86d2600650d68ff32e7e098e50d5a068499e101444db80fb80178fa6500000318c00006308081013eee10210f9b3be30000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000089494441545847ed96b10ac0200c4423edff7f7187ea60493378977490c2096e313edf29d8ccece873db68029001199001199001199001c2c0d56bcee28f05ae653e24b0c9020eae4500b0016166d9230bc000c59a7f030cc3e3047ea00b99aa4711c4882b112cafc95780795a6f85817ca0b2003192b9b1d78e227a19a900102f8f2f11800c6c37700360131781b4054f830000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000080494441545847ed94410ac0200c04f5ff8f6ec921250475d7da22c87ad48d1927602d9b57dddcbf30005782ecd5e49c95c1fb51c02ecd196f14f75b3903e8ed3f6f1a01a0623f6773cd69af00f80b91ea21203382b70d284308c0b5cd6a8ef925032c401c4736f609c06fdf053b0201c8800cc8800cc8800cc8800cc8c0b9066edd51182171bab4cb0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000007e494441545847ed92510ac0300843dbfb1f7a459820d22e993f52c8be0a33f1edad73343fb379ff60009e1792998ddf43e550a995f84c3c237174ee0b2097a0a5bbf7109e017095b6001973889c39da438595e52788ad410460a13fff3e2f81d92b002a978fce3006e8b2caa00064400664400664400664400664a0ddc00276971321672fab0a0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000091494441545847ed96b10e80200c444be4ffbfd8411848c060efda05872371f2da3e5ed050ccec6acfb1550420033220033220033220038481bb656af2c6026bd90b096cb401a46a1800aad1872158fb7b00b803e26cb83d9081a30068f8fc3e925da47906224d23d934c07b8867c0cbd2003dc80e8dc084003c88dd507ae783027d0523d71b6716fc85b30099e1548d001e930027810fe7f6160000000049454e44ae426082466f6f642077696c6c2062652061626c6520746f2070726576656e7420796f7572207065742066726f6d2073746172766174696f6e2e89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000005e494441545847ed95390e00200cc3e8ff1fcd3180104294b64317334362792052928f24f717003080010c60c06aa0f6af5b7bf373672d8016769b8a5781a97c847b004e2873e91e100598e56e88284078cd01c000063080010c6020dd4003cbd40721aa0beb880000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000072494441545847ed94310e00210804f5ff8ff68ec2c4e2803d43a2c55859c0b219597b3b7cfae1f90d031080804260bc5155eabe129df666c2a980f08f841a91818ae1d39fabe519a81c1e9ac0c0b504ecdd2af7e0f712ae8b63f72cae5e1a6d70d8bf2b2cc45f2bc10004200001084000020fec3f1221ce89b1720000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000068494441545847ed94c10a00101404f9ff8f2607a5478c835cc64dedee5b4372fabcf2e7f9c902844019ae89e89b1c7b4e812d68d4c4fdea095d796e0bc4d3ad0ac4cc6de953813e90e8088d49438309fa188e3cb4c0b3efc20212908004242001094840021290400533b70d21044e4ab70000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000072494441545847ed94510a00210844ebfe876e290844dacd8996085e7fd1a8e353cae9f0c987eba7a881628cce62146dc8404d688bfabb85a8685bdcac9baa51922ada7b0d742aa3fdf544bfc6b544a02fd8dbe8fcfb1603b6e3c8ce48fa68c2dfbe0b0c40000210800004200001084000020fc5ac172190ff741b0000000049454e44ae426082546f79732063616e206b65657020796f7572207065742066726f6d206265696e6720626f7265642e89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000067494441545847ed954b0a00200805f3fe87eeb368994f2ab0605ae77318c3ac241f4bee5f00c00006be3050fbaed80595b5916019e22c33590b8032201506fe1237c303b8d17cf22db39e0618f4372c6c8f2030def32bea119e7710090060000318c00006d20d343af6102106b4da3d0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000063494441545847ed954b0a00200844f3fe87eeb3898848cdc0cd6b6d33d3131a29c94792fd0b012000010840c04ba0f6af5bbb6399990da0899daae266e0321fe2de001603cb4c88c04a6598bd3ce45b80709b7b571036dc05080001084000021080400354df0721739252ba0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000005b494441545847edd5310e0020080441f9ffa3550a3b20014968d69620e714226bf8c8f0fc450004104000818ac0bedfb7d717d5cc5f3f1be00db006453577e56403b4efaedf00fa6a3de57bca8d5d1404400001041040008171810356ee0721ed9f05790000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c086488000000a6494441545847ed96c10a80201883957aff27ee501e0493e9e6df218405dedcfcfe39c29c523a9ef5db970de0049c801370024ec009ec90c0f5409ec10703d5aaef016a0400258d0220190d12a25a06400d84ab997acc007ae10a8cac1d01208332ac5ac6a2eff7c30114802a8c24d06a96000a7d3f450400f9bc6ac34ad86e8e024c7bfa05a026540f68fb21c34601d001f4be51145b01d04281e2d2ffd44a02d42cb2c10037c7f12981ef4fbe3c0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000008f494441545847ed93d10e80200845f5ff3fba461b8de80a526daeedf6a628f778b4de167f7d717efb05c0662c09b01d23817e4d78c8cc8084d9357e8c004a7b228052234732bd1701a8e2cc4ef5fdc2be5eaf34ad2acf40908d3347c3d0ddeadcccbd8f20a21e476d04f0263483d1fa054026fdef96a97d52bf657cfdd0ca5004a0011aa0011aa0011aa0011aa0811d3de21d21bb35e40a0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000005b494441545847ed94db0900200cc474ffa17d2c604a058b10bfbdf408b4bd15bf5e3cbf5940031af8c2c058b7225b14b3044640e0901d195460f36f4a60960a2040031a7861203023ff85b6204f0e262da0010d6840031a283730013af6102192d097b20000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000005f494441545847edd5bb0a00200846617dff87ae961a44f042e0721a237fe51b5265f8e8707f61000410400081aac03a5f77549379f3364014665745263cf3a63d80b7bb4a0d6d4055c013b977adac56d1cf15ce0008208000020820302eb00182580621fa639d260000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000061494441545847ed94410e00100c04f5ff8f460f8eac20a926e3cc760cad95e065c1f50b0018c0400a03b5cf8a5350795605cb808d41b6ccf81ae0c5ed87a069d6ca403880d3bf80c8fb07e4fbdd76809f575db051e36e0b0018c000063080010c343af61021f9935c500000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000067494441545847ed93410a00200cc3f4ff8f56100411ba513d8810cfb5ed32ade5f1a98ff3cb1705da46292b6de95db3d945dddbc3337db80265a64c5dfdf08908b886aefebac03a40162e873d7d03eeef9539590137c8d6530002108000042000010840000210e80b6d0b213ce71b1e0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000009e494441545847ed96410ac0200c0495f6ff2feea17a08b4c1646314bcacd05b930c936db19652aef61c3b9500344003344003344003341030f0b477eee48d05d6a20b496fd0cf0a805bef01ac0e17696e1f0b60d77008e10164b55b7119e621020083e404f45b3b05d07bca1a7684d0ec81be0201b1d68120a1bd1500dd7c346c1b80566835d63b87eb8b18d079404dd15a7e998d0224ffc4b88c00c70dbcedba1d81b2a5703a0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af4000000017352474200aece1ce900000066494441545847edd5310e00100c85613d8efb1fc67108092961914a0dbfc540f25e3f0309ce4b9cf30305104000010410f84720c7982525e9fb8b5f7297d104eac11a58cb589638658c107dc13abc0fb2cb98a67cc9af4be8014d996f9e8c02082080000208145bcb2821effa51fe0000000049454e44ae426082536869656c6420746f2070726f7465637420796f7572207065742066726f6d206265696e67206869742e89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000049494441545847edd6410a00200804c0fcffa3ab17a40421c17857973988319a2b9af70f010810f84260ee5b711b34edad0c4e871c8e59da2b0001021581a72f8300040810204080c0023af610215e442abd0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000098494441545847ed964b0ac0200c0523f5fe27eea26621049b98f82952784237d53c27038a8988aef21d1b090030000330000330000330e018b8cb7c5e7cad7433220f921508b7d60370030276a60decd8bcf2995996819d9b77217e033063a4ad5133a2062c00fecf433baa9f03c80d34c02500eeaa76573bec055a736dc6ebd47af7802c90619a766f5ebd3246000277cef812001c37f00086f72381b52e906c0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000060494441545847edd6cb0a0020084451fdff8feeb16813e4580411dcd669c31124b7c7c71fbf6f044000812f044adb15a741656da6b16c122c33594b804860f049c6c408963dd4087ae138eaee9c23558bc02eebf5ef030110400001041040a0028cd31421444923dc0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000070494441545847ed92410ac0200c04f5ff8f6e9b4341aa761772082de34590641d27f656bc7af1fded3300c7652a609ffb28d0a999843b0676c1713eae15e0ddbb9db4029001c61f7acd5000919f8190bd0a4006fcde80f1c05c891a412edde806000318c000063080010c600003e5064e048315215641d2fc0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000074494441545847ed94310ec0200cc4e0ff8f2e4202d481e452a062317372674cd59c2e9f7cb93f298067027874c70b9b95771e6beff3ce4a9005e1959be03b0035b4ef47cadff3e365d57bd6c168b8f53dbb1d11801d08992f07dab5562dc87c39f0f77f02000c60000318c000063080010c60a000b8610b216fdcaceb0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c086488000000a4494441545847ed964b0ac0200c05957aff1377515d0444f2796ac1169e20144c759c1831a794aeda8fb54c001aa0011aa0011aa0011a000cdc35a62cbe58c27f9107493f49fb9636426963db00e304b3000dd685f00c788b2319e90d991016c0eee25a9a5488cf0248ee10d5688c5a494815ecc084e5fb2b006d375296d6d86b06ac7ab600c20b480e0e9a0289ef2f22eff0853b5f05404f3c1c376b009e180d3c0ef000b15d1d81d94175870000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000006a494441545847ed944b0a00200844ebfe87eeb310dae88404153c5741cc383cc55a2e57bddcbf10000210f882401bb7221b546a95b134d83864a14714e04473cbe77a7901a6c04a515210422f083c4b605d9ef9ceee81cddfd5678dd5e26dff130002108000042000810e4ece1021878663410000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c086488000000a0494441545847ed96c10a8020104495faff2fee907b30ac5667b6840e8d10c4e2eaf3b98a39a5b494efb396052003322003322003322003a481adf45b83af162a877990500375e0602e02f006b098b5ab9151bc6b2f0ad00231ff063ab41001e84d58edb340a7dd8a00046bf0e83ecdc03f016011012daf8fa157606dac9ddf3b96f0f24245e81988dc03530dd4d5a2555540efb2baed1863e069f5537902d801343f25816dd4601b0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000075494441545847ed92410ec0200804f5ff8f6ee381a4c12a0b1ebc8ce765990cf676f9f5cbfb5b04f038c0286f71796e57e84bac3c8248cdadca5625a7179bf6650046768029062ceb81cb00eaf2ef1ff88328016497ef206400af4e515f9a89ee79fae9c279003080010c60000318c0000630808117a9bd1321772d676e0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000068494441545847ed94610b00100c44f9ff3f9a28b5165792d6eaf9a6e1eede965a82570dd62fe90c3443cc9b57b523e81b0243c09eb77b55935d4e63c0271ca914015f7f6e41a8819df84ab406efd44a7577be7133035fbe0c0c40000210800004200001084000021df3d61521c08b49860000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000064494441545847ed94490e00200803f1ff8f763978841a354193e16a6ceb80144bae92ec6f04800004be2050fbaed80d2aef2a6129b0b0c8428da703dc78fd04e46a79046e9a872108100de168c32835a8ea23843aa7e2ca5c9e13000210800004200081063eee1021a0220e8e0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000092494441545847ed96410ac0200c0495f6ff2feea1061a0852bb9b40f1b282d0431227630af6d6da31f6b6d5052003322003322003322003a4816bc49dc9570b95c33e48ac586541680680ea644107731140b5f39967698201f0e42c4ccc2b0358277eb015612162ece71c2003b34a78a70f241c3e2f5c0160fe86df00e295d8f7db7cd0875b81ac01a6fb548c006460bb811b903311813716c23a0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000065494441545847edd4dd0a00100c8661bbff8ba61d90ffad24a9d7216bfb3c8984c74b1ecf0fdf04889dd42ab8b7aeb4f30868d3beee64afb98b1560362837a8cfbc75c393238025a06416afd6ec1ee5768627c0d5af82000820800002082080000208209000f7ce15214de4787a0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000092494441545847ed96d10ac02008458dedffbf780fab072142f3ea06637083bd44dae9e8a2262247ff3e1b8d0034400334400334400334001ab8faba33f96a816290070994c8810b63770023788cecc957966d1e0f20244f96632c377322004f60e6d87f01a832355ded03adbfdb4bc85fe0d56f4e6e6d0095ae0a60255fe708f0aa01b429c3a65bef0fb4070af70e1642801b8ad723816807111a0000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000006c494441545847edd4d10a4011108461deffa14951d2b2e342a8ff5c9d8bc98e8fc470f98b97e7876f0aa42aa51696f3ca8265b196ebff67a7b795f70a5803572576f3ee1d980d6bc4a382b5a1a5daf3026587cab92bf7c1cc7802c79f090a2080000208208000020820804006486e132187d8c7c60000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000074494441545847ed94410ec0200cc3e0ff8f66e3c01192954905c99c9bd432526b497e35797f01000318b8c6407befc557582be3945a45938326b30a4016189774d9b102f863f9e09b761d6d40d2efeaef7965a0cfec7c85cc3a005108b9dc3560988e8fb806e21b4412000c60000318c040ba81073af6102143c1dc740000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c0864880000006d494441545847ed93410ac0200c04f5ff8f5602e6225476410896e979b39d0cb1b7e2af17ffbf3d0130962517569a534ab32838947ce4e419a530ca22276db4e572f6f3d41c807db3d3fd66ef7500f7d1fc03c0dddaca2b376015ba61003080010c60000318c0000630506e6002f73b0f211a4494500000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c086488000000a2494441545847ed964b0ac030084413dafb9fb88bc642200dea980f94c204bad2eae4f92139a57494efb3932980044880044880044880040204aee2734ebe58e0bfe84102030484b9313c013b92577d66acdf098850d17cb612f04458b6ad02a4ae43b734fc9ffe18e981362912d0dba7086837954072acbda0d9a7c7108ed0ea0e402568e36b48b5fc2d99c8c4b83dd027a8782325f07c5e71d12a0e505e73a1801b9c8b2581c49959130000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af40000000473424954080808087c08648800000061494441545847ed95410a00200804ebff8f2e3a142115ae045ea6abad4e73b05a924f4d9e5f00c00006308001d540db56b7cdbe6ad78daf028c4663d02df7aa1d215400cf00cf9d05a302d8574cede13ee1e0af6f1c000c60000318c00006d20d745ccf0721d52fc6040000000049454e44ae42608289504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af4000000017352474200aece1ce900000072494441545847ed943112c0200804cf49feffe214190a6752c1450a2dd65a605d9021e9d2c63300c000063060187824dd8bbbaa8cad165199c0004b73380051a363208dcf0082bc537cca49f31c6d205eb0750666f10e4499a36ac1b78f7f07d10277018cdfb67605000c60000318c000065e01921281db558cba0000000049454e44ae426082

Deployed Bytecode

0x6080604052600436106102885760003560e01c806370a082311161015a578063b88d4fde116100c1578063e985e9c51161007a578063e985e9c514610841578063ebd799cc1461088a578063ebf6e91d146108aa578063f2fde38b146108ca578063f59dfdfb146108ea578063fe55932a1461090a57600080fd5b8063b88d4fde1461077b578063c23c863b1461079b578063c87b56dd146107cb578063ca9c4b33146107eb578063d3a2da38146107f3578063df33fa311461082e57600080fd5b806391b7f5ed1161011357806391b7f5ed146106b657806395d89b41146106d65780639b993a1a146106eb578063a22cb4651461071b578063a22d58231461073b578063b6d225511461075b57600080fd5b806370a08231146105ba578063715018a6146105da5780637908213d146105ef57806379502c55146106205780638462151c1461066b5780638da5cb5b1461069857600080fd5b806335b34ca2116101fe5780635d186c9f116101b75780635d186c9f1461051d57806361fd3f62146105325780636352211e1461053a57806366d38ba91461055a5780636840690b1461057a5780636898f82b1461059a57600080fd5b806335b34ca2146104435780633cd434aa1461047357806341b3ba3d1461048857806342842e0e146104a8578063439bbfd2146104c85780635a353cd3146104e857600080fd5b806309a3849a1161025057806309a3849a1461035e5780630ea61c471461037e57806318160ddd146103c65780631c19c215146103ed5780631d80009a1461040d57806323b872dd1461042357600080fd5b806301ffc9a71461028d57806306fdde03146102c2578063081812fc146102e457806308a337331461031c578063095ea7b31461033e575b600080fd5b34801561029957600080fd5b506102ad6102a8366004614385565b61092a565b60405190151581526020015b60405180910390f35b3480156102ce57600080fd5b506102d761097c565b6040516102b99190615374565b3480156102f057600080fd5b506103046102ff36600461436c565b610a0e565b6040516001600160a01b0390911681526020016102b9565b34801561032857600080fd5b5061033c610337366004614328565b610a52565b005b34801561034a57600080fd5b5061033c610359366004614289565b610a6b565b34801561036a57600080fd5b5061033c61037936600461434a565b610b0b565b34801561038a57600080fd5b5061039e61039936600461436c565b610b20565b60408051948552921515602085015290151591830191909152151560608201526080016102b9565b3480156103d257600080fd5b5060025460015403600019015b6040519081526020016102b9565b3480156103f957600080fd5b5061033c61040836600461436c565b610f23565b34801561041957600080fd5b506103df60975481565b34801561042f57600080fd5b5061033c61043e366004614195565b61105b565b34801561044f57600080fd5b506102ad61045e366004614147565b60b26020526000908152604090205460ff1681565b34801561047f57600080fd5b5061033c6111ec565b34801561049457600080fd5b5061033c6104a336600461436c565b611205565b3480156104b457600080fd5b5061033c6104c3366004614195565b611212565b3480156104d457600080fd5b5061033c6104e3366004614328565b611232565b3480156104f457600080fd5b5061050861050336600461436c565b611247565b604080519283526020830191909152016102b9565b34801561052957600080fd5b5061033c61156b565b61033c611582565b34801561054657600080fd5b5061030461055536600461436c565b6116c8565b34801561056657600080fd5b5061033c61057536600461436c565b6116d3565b34801561058657600080fd5b506102ad61059536600461436c565b611715565b3480156105a657600080fd5b5061033c6105b536600461436c565b611a82565b3480156105c657600080fd5b506103df6105d5366004614147565b611b30565b3480156105e657600080fd5b5061033c611b7f565b3480156105fb57600080fd5b5061060f61060a36600461436c565b611b93565b6040516102b9959493929190615387565b34801561062c57600080fd5b50609854609954609a5460ac546106599392919060ff808216916101008104821691620100009091041686565b6040516102b99695949392919061542e565b34801561067757600080fd5b5061068b610686366004614147565b611c49565b6040516102b9919061533c565b3480156106a457600080fd5b506000546001600160a01b0316610304565b3480156106c257600080fd5b5061033c6106d136600461436c565b611d59565b3480156106e257600080fd5b506102d7611d66565b3480156106f757600080fd5b506102ad61070636600461436c565b60af6020526000908152604090205460ff1681565b34801561072757600080fd5b5061033c61073636600461424d565b611d75565b34801561074757600080fd5b5061033c610756366004614328565b611e0b565b34801561076757600080fd5b5061050861077636600461436c565b611e20565b34801561078757600080fd5b5061033c6107963660046141d1565b612095565b3480156107a757600080fd5b506102ad6107b6366004614147565b60b16020526000908152604090205460ff1681565b3480156107d757600080fd5b506102d76107e636600461436c565b6120df565b61033c6120ea565b3480156107ff57600080fd5b506102ad61080e3660046143bf565b805160208183018101805160b08252928201919093012091525460ff1681565b61033c61083c3660046142b3565b612222565b34801561084d57600080fd5b506102ad61085c366004614162565b6001600160a01b03918216600090815260086020908152604080832093909416825291909152205460ff1690565b34801561089657600080fd5b5061033c6108a5366004614328565b612410565b3480156108b657600080fd5b5061033c6108c536600461436c565b612425565b3480156108d657600080fd5b5061033c6108e5366004614147565b6124cb565b3480156108f657600080fd5b5061033c61090536600461436c565b612544565b34801561091657600080fd5b5061033c610925366004614421565b6125ea565b60006301ffc9a760e01b6001600160e01b03198316148061095b57506380ac58cd60e01b6001600160e01b03198316145b806109765750635b5e139f60e01b6001600160e01b03198316145b92915050565b60606003805461098b90615510565b80601f01602080910402602001604051908101604052809291908181526020018280546109b790615510565b8015610a045780601f106109d957610100808354040283529160200191610a04565b820191906000526020600020905b8154815290600101906020018083116109e757829003601f168201915b5050505050905090565b6000610a19826127e4565b610a36576040516333d1c03960e21b815260040160405180910390fd5b506000908152600760205260409020546001600160a01b031690565b610a5a612819565b610a6760a4826003613f53565b5050565b6000610a76826116c8565b9050336001600160a01b03821614610aaf57610a92813361085c565b610aaf576040516367d9dca160e11b815260040160405180910390fd5b60008281526007602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b610b13612819565b610a6760a7826005613f91565b60ac54600090819081908190610100900460ff16610b595760405162461bcd60e51b8152600401610b50906153e8565b60405180910390fd5b609954859081118015610b6e5750609a548111155b610b8a5760405162461bcd60e51b8152600401610b50906153be565b600086815260ae6020526040808220815160a081019092528054429392919082908290610bb690615510565b80601f0160208091040260200160405190810160405280929190818152602001828054610be290615510565b8015610c2f5780601f10610c0457610100808354040283529160200191610c2f565b820191906000526020600020905b815481529060010190602001808311610c1257829003601f168201915b5050505050815260200160018201548152602001600282015481526020016003820154815260200160048201548152505090506000609660009054906101000a90046001600160a01b03166001600160a01b0316632af123b88360200151856040518363ffffffff1660e01b8152600401610cb4929190918252602082015260400190565b60206040518083038186803b158015610ccc57600080fd5b505afa158015610ce0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d049190614408565b609654604080850151905163055e247760e31b81529293506000926001600160a01b0390921691632af123b891610d48918890600401918252602082015260400190565b60206040518083038186803b158015610d6057600080fd5b505afa158015610d74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d989190614408565b905060008360600151600014610dc957603c846060015186610dba91906154cd565b610dc4919061549a565b610dcc565b60005b9050600060a18101548211610df35760a460005b0154610dec90836154ae565b9050610e27565b60a254821015610e065760a46001610de0565b60a354821015610e195760a46002610de0565b610e248260006154ae565b90505b6000610e356106868e6116c8565b90506000806000805b8451811015610ef1576000858281518110610e5b57610e5b6155b6565b602002602001015190506098600101548111610ede57600081815260ad602052604081205490600a610e8d8184615560565b600a8110610e9d57610e9d6155b6565b0154905080610eb35760009b5060019650610edb565b8060011415610ec95760009a5060019550610edb565b8060021415610edb5760009850600194505b50505b5080610ee981615545565b915050610e3e565b50600085610eff898b615482565b610f099190615482565b9f50929d50909b5099505050505050505050509193509193565b8033610f2e826116c8565b6001600160a01b031614610f805760405162461bcd60e51b81526020600482015260196024820152782cb7ba9030b932903737ba103a37b5b2b713b99037bbb732b960391b6044820152606401610b50565b60ac54610100900460ff16610fa75760405162461bcd60e51b8152600401610b50906153e8565b609954829081118015610fbc5750609a548111155b610fd85760405162461bcd60e51b8152600401610b50906153be565b600083815260af602052604090205460ff16156110275760405162461bcd60e51b815260206004820152600d60248201526c4e6f7420617661696c61626c6560981b6044820152606401610b50565b61103083612873565b600093845260ad602090815260408086209290925560af9052909220805460ff191660011790555050565b6000611066826128cc565b9050836001600160a01b0316816001600160a01b0316146110995760405162a1148160e81b815260040160405180910390fd5b60008281526007602052604090208054338082146001600160a01b038816909114176110e6576110c9863361085c565b6110e657604051632ce44b5f60e11b815260040160405180910390fd5b6001600160a01b03851661110d57604051633a954ecd60e21b815260040160405180910390fd5b801561111857600082555b6001600160a01b038681166000908152600660205260408082208054600019019055918716808252919020805460010190554260a01b17600160e11b17600085815260056020526040902055600160e11b83166111a357600184016000818152600560205260409020546111a15760015481146111a15760008181526005602052604090208490555b505b83856001600160a01b0316876001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050505050565b6111f4612819565b60ac805461ff001916610100179055565b61120d612819565b609755565b61122d83838360405180602001604052806000815250612095565b505050565b61123a612819565b610a67609e826003613f53565b60ac546000908190610100900460ff166112735760405162461bcd60e51b8152600401610b50906153e8565b6099548390811180156112885750609a548111155b6112a45760405162461bcd60e51b8152600401610b50906153be565b600084815260ae6020526040808220815160a0810190925280544293929190829082906112d090615510565b80601f01602080910402602001604051908101604052809291908181526020018280546112fc90615510565b80156113495780601f1061131e57610100808354040283529160200191611349565b820191906000526020600020905b81548152906001019060200180831161132c57829003601f168201915b5050505050815260200160018201548152602001600282015481526020016003820154815260200160048201548152505090506000609660009054906101000a90046001600160a01b03166001600160a01b0316632af123b88360200151856040518363ffffffff1660e01b81526004016113ce929190918252602082015260400190565b60206040518083038186803b1580156113e657600080fd5b505afa1580156113fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061141e9190614408565b609654604080850151905163055e247760e31b81529293506000926001600160a01b0390921691632af123b891611462918890600401918252602082015260400190565b60206040518083038186803b15801561147a57600080fd5b505afa15801561148e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114b29190614408565b905060006114c26106868a6116c8565b905060005b815181101561155c5760008282815181106114e4576114e46155b6565b60200260200101519050609860010154811161154957600081815260ad602052604081205490600a6115168184615560565b600a8110611526576115266155b6565b01549050806115385760009650611546565b806001141561154657600095505b50505b508061155481615545565b9150506114c7565b50919650945050505050915091565b611573612819565b60ac805460ff19166001179055565b600160ac5462010000900460ff1660038111156115a1576115a16155a0565b146115ee5760405162461bcd60e51b815260206004820152601860248201527f4e6f7420696e20737461676520746f206275792070726f7000000000000000006044820152606401610b50565b60995460015460001901106116355760405162461bcd60e51b815260206004820152600d60248201526c139bc81c1c9bdc1cc81b19599d609a1b6044820152606401610b50565b33600090815260b1602052604090205460ff16156116655760405162461bcd60e51b8152600401610b509061540c565b60006116746001546000190190565b61167f906001615482565b9050600061168c82612873565b600083815260ad6020526040902081905590506116aa33600161293c565b505033600090815260b160205260409020805460ff19166001179055565b6000610976826128cc565b6116db612819565b8060038111156116ed576116ed6155a0565b60ac805462ff000019166201000083600381111561170d5761170d6155a0565b021790555050565b6000816098600101548111801561172e5750609a548111155b61174a5760405162461bcd60e51b8152600401610b50906153be565b600083815260ae6020526040808220815160a0810190925280548290829061177190615510565b80601f016020809104026020016040519081016040528092919081815260200182805461179d90615510565b80156117ea5780601f106117bf576101008083540402835291602001916117ea565b820191906000526020600020905b8154815290600101906020018083116117cd57829003601f168201915b5050505050815260200160018201548152602001600282015481526020016003820154815260200160048201548152505090506000429050600060ad600087815260200190815260200160002054905060006301e133808261184c9190615560565b60965460808601519192506001600160a01b0316906365c7284090611872908490615482565b6040518263ffffffff1660e01b815260040161189091815260200190565b60206040518083038186803b1580156118a857600080fd5b505afa1580156118bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118e09190614408565b6096546040516301971ca160e61b8152600481018690526001600160a01b03909116906365c728409060240160206040518083038186803b15801561192457600080fd5b505afa158015611938573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061195c9190614408565b148015611a75575060965460808501516001600160a01b039091169063a324ad2490611989908490615482565b6040518263ffffffff1660e01b81526004016119a791815260200190565b60206040518083038186803b1580156119bf57600080fd5b505afa1580156119d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119f79190614408565b6096546040516328c92b4960e21b8152600481018690526001600160a01b039091169063a324ad249060240160206040518083038186803b158015611a3b57600080fd5b505afa158015611a4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a739190614408565b145b9550505050505b50919050565b60ac54610100900460ff16611aa95760405162461bcd60e51b8152600401610b50906153e8565b609954819081118015611abe5750609a548111155b611ada5760405162461bcd60e51b8152600401610b50906153be565b600082815260ae602090815260409182902042600290910155815184815233918101919091527fd0017656a8c92d10b2fa3a77fa3c1e8e4c28817e89311616b8eed8e68f68a95091015b60405180910390a15050565b60006001600160a01b038216611b59576040516323d3ad8160e21b815260040160405180910390fd5b506001600160a01b031660009081526006602052604090205467ffffffffffffffff1690565b611b87612819565b611b916000612956565b565b60ae60205260009081526040902080548190611bae90615510565b80601f0160208091040260200160405190810160405280929190818152602001828054611bda90615510565b8015611c275780601f10611bfc57610100808354040283529160200191611c27565b820191906000526020600020905b815481529060010190602001808311611c0a57829003601f168201915b5050505050908060010154908060020154908060030154908060040154905085565b60606000806000611c5985611b30565b905060008167ffffffffffffffff811115611c7657611c766155cc565b604051908082528060200260200182016040528015611c9f578160200160208202803683370190505b509050611ccc60408051608081018252600080825260208201819052918101829052606081019190915290565b60015b838614611d4d57611cdf816129a6565b9150816040015115611cf057611d45565b81516001600160a01b031615611d0557815194505b876001600160a01b0316856001600160a01b03161415611d455780838780600101985081518110611d3857611d386155b6565b6020026020010181815250505b600101611ccf565b50909695505050505050565b611d61612819565b609855565b60606004805461098b90615510565b6001600160a01b038216331415611d9f5760405163b06307db60e01b815260040160405180910390fd5b3360008181526008602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b611e13612819565b610a67609b826003613f53565b6000808260986001015481118015611e3a5750609a548111155b611e565760405162461bcd60e51b8152600401610b50906153be565b600084815260ae6020526040808220815160a08101909252805482908290611e7d90615510565b80601f0160208091040260200160405190810160405280929190818152602001828054611ea990615510565b8015611ef65780601f10611ecb57610100808354040283529160200191611ef6565b820191906000526020600020905b815481529060010190602001808311611ed957829003601f168201915b505050505081526020016001820154815260200160028201548152602001600382015481526020016004820154815250509050600060ad600087815260200190815260200160002054905060006301e1338082611f539190615560565b60965460808501519192506000916001600160a01b039091169063a324ad2490611f7e908590615482565b6040518263ffffffff1660e01b8152600401611f9c91815260200190565b60206040518083038186803b158015611fb457600080fd5b505afa158015611fc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fec9190614408565b60965460808601519192506000916001600160a01b03909116906365c7284090612017908690615482565b6040518263ffffffff1660e01b815260040161203591815260200190565b60206040518083038186803b15801561204d57600080fd5b505afa158015612061573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120859190614408565b9197509095505050505050915091565b6120a084848461105b565b6001600160a01b0383163b156120d9576120bc84848484612a25565b6120d9576040516368d2bf6b60e11b815260040160405180910390fd5b50505050565b606061097682612b1d565b600360ac5462010000900460ff166003811115612109576121096155a0565b146121565760405162461bcd60e51b815260206004820152601960248201527f4e6f7420696e20737461676520746f206d696e7420544d4747000000000000006044820152606401610b50565b609a54600154600019011061219b5760405162461bcd60e51b815260206004820152600b60248201526a139bc81c195d081b19599d60aa1b6044820152606401610b50565b33600090815260b2602052604090205460ff16156121cb5760405162461bcd60e51b8152600401610b509061540c565b60985434906121db9060016154ae565b111561221a5760405162461bcd60e51b815260206004820152600e60248201526d27379032b737bab3b41032ba341760911b6044820152606401610b50565b611b91612bec565b600260ac5462010000900460ff166003811115612241576122416155a0565b1461228e5760405162461bcd60e51b815260206004820181905260248201527f4e6f7420696e20737461676520746f206d696e74206d65726b6c6520544d47476044820152606401610b50565b609a5460015460001901106122d35760405162461bcd60e51b815260206004820152600b60248201526a139bc81c195d081b19599d60aa1b6044820152606401610b50565b33600090815260b2602052604090205460ff16156123035760405162461bcd60e51b8152600401610b509061540c565b60985434906123139060016154ae565b11156123525760405162461bcd60e51b815260206004820152600e60248201526d27379032b737bab3b41032ba341760911b6044820152606401610b50565b6040516bffffffffffffffffffffffff193360601b1660208201526000906034016040516020818303038152906040528051906020012090506123cc838380806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250506097549150849050612d7e565b6124085760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b210383937b7b360991b6044820152606401610b50565b61122d612bec565b612418612819565b610a6760a1826003613f53565b60ac54610100900460ff1661244c5760405162461bcd60e51b8152600401610b50906153e8565b6099548190811180156124615750609a548111155b61247d5760405162461bcd60e51b8152600401610b50906153be565b600082815260ae602090815260409182902042600390910155815184815233918101919091527fbae6551c0ddf25aa6805100ecbdc4535f2933a14d7ebafe9fab66af752e232ec9101611b24565b6124d3612819565b6001600160a01b0381166125385760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610b50565b61254181612956565b50565b60ac54610100900460ff1661256b5760405162461bcd60e51b8152600401610b50906153e8565b6099548190811180156125805750609a548111155b61259c5760405162461bcd60e51b8152600401610b50906153be565b600082815260ae602090815260409182902042600190910155815184815233918101919091527fd73f65a9b0fee6c2e3e08fd03cb4800137b36882554a7211fe8ce842b3d4f4fe9101611b24565b82336125f5826116c8565b6001600160a01b0316146126475760405162461bcd60e51b81526020600482015260196024820152782cb7ba9030b932903737ba103a37b5b2b713b99037bbb732b960391b6044820152606401610b50565b60ac54610100900460ff1661266e5760405162461bcd60e51b8152600401610b50906153e8565b6099548490811180156126835750609a548111155b61269f5760405162461bcd60e51b8152600401610b50906153be565b60b084846040516126b19291906145f3565b9081526040519081900360200190205460ff16156126fe5760405162461bcd60e51b815260206004820152600a60248201526913985b5948195e1a5cdd60b21b6044820152606401610b50565b600061273f85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612d9492505050565b90506001811180156127515750601281105b61278e5760405162461bcd60e51b815260206004820152600e60248201526d4e6f742076616c6964206e616d6560901b6044820152606401610b50565b600086815260ae602052604090206127a7908686613fbe565b50600160b086866040516127bc9291906145f3565b908152604051908190036020019020805491151560ff19909216919091179055505050505050565b6000816001111580156127f8575060015482105b8015610976575050600090815260056020526040902054600160e01b161590565b6000546001600160a01b03163314611b915760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b50565b6000806128816001436154cd565b6040805191406020830152810184905233606090811b6bffffffffffffffffffffffff19169082015260740160408051601f1981840301815291905280516020909101209392505050565b600081806001116129235760015481101561292357600081815260056020526040902054600160e01b8116612921575b8061291a5750600019016000818152600560205260409020546128fc565b9392505050565b505b604051636f96cda160e11b815260040160405180910390fd5b610a67828260405180602001604052806000815250612ed1565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60408051608081018252600080825260208201819052918101829052606081019190915260008281526005602052604090205461097690604080516080810182526001600160a01b038316815260a083901c67ffffffffffffffff166020820152600160e01b831615159181019190915260e89190911c606082015290565b604051630a85bd0160e11b81526000906001600160a01b0385169063150b7a0290612a5a903390899088908890600401615309565b602060405180830381600087803b158015612a7457600080fd5b505af1925050508015612aa4575060408051601f3d908101601f19168201909252612aa1918101906143a2565b60015b612aff573d808015612ad2576040519150601f19603f3d011682016040523d82523d6000602084013e612ad7565b606091505b508051612af7576040516368d2bf6b60e11b815260040160405180910390fd5b805181602001fd5b6001600160e01b031916630a85bd0160e11b1490505b949350505050565b60608160018110158015612b375750600154600019018111155b612b725760405162461bcd60e51b815260206004820152600c60248201526b139bdd081d985b1a59081a5960a21b6044820152606401610b50565b609954600090841115612ba55760ac54610100900460ff16612b9c57612b9784612f3e565b612bc1565b612b9784612feb565b60ac5460ff16612bb857612b978461313a565b612bc18461315a565b905080604051602001612bd49190615168565b60405160208183030381529060405292505050919050565b6000612bfb6001546000190190565b612c06906001615482565b905060b45460051415612ca357600060b45560965460b354604051631c85d48f60e21b81526004810191909152600160248201526001600160a01b0390911690637217523c9060440160206040518083038186803b158015612c6757600080fd5b505afa158015612c7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c9f9190614408565b60b3555b6040805160c081018252600060a082018181528252426020808401829052838501919091526060830182905260b354608084015284825260ae81529290208151805192938493612cf69284920190614031565b5060208201516001820155604082015160028201556060820151600382015560809091015160049091015560b48054906000612d3183615545565b91905055506000612d4183612873565b600084815260ad602052604090208190559050612d5f33600161293c565b505033600090815260b260205260409020805460ff1916600117905550565b600082612d8b85846132ff565b14949350505050565b600080825b8051821015612eca576007818381518110612db657612db66155b6565b01602001516001600160f81b031990811690911c16612de157612dda600183615482565b9150612eb8565b8051600360f91b90600590839085908110612dfe57612dfe6155b6565b01602001516001600160f81b031990811690911c161415612e2457612dda600283615482565b8051600760f91b90600490839085908110612e4157612e416155b6565b01602001516001600160f81b031990811690911c161415612e6757612dda600383615482565b8051600f60f91b90600390839085908110612e8457612e846155b6565b01602001516001600160f81b031990811690911c161415612eaa57612dda600483615482565b612eb5600183615482565b91505b82612ec281615545565b935050612d99565b5050919050565b612edb838361334c565b6001600160a01b0383163b1561122d576001548281035b612f056000868380600101945086612a25565b612f22576040516368d2bf6b60e11b815260040160405180910390fd5b818110612ef2578160015414612f3757600080fd5b5050505050565b6060600080612f4c84611e20565b600086815260ad6020526040812054929450909250612fe1612f6d87613443565b612f7686613443565b612f7f86613443565b612f8888613443565b612f9188613443565b612fb8601a612fa160038b615560565b60038110612fb157612fb16155b6565b0154613443565b604051602001612fcd96959493929190614e5d565b604051602081830303815290604052613541565b9695505050505050565b6060600080600080612ffc86610b20565b935093509350935060008061301088611247565b91509150600061301f89611715565b9050600086801561302d5750855b80156130365750845b8061303e5750815b61304957600061304c565b60015b90506000613059896136a7565b905060006040518060c001604052808d815260200160ad60008f81526020019081526020016000205481526020018781526020018681526020018b8152602001841515815250905060006130c160ad60008f8152602001908152602001600020548486613707565b905060006130ce83613ae9565b6130d784613c7b565b6130e085613cc1565b6130e986613d6e565b6130fa6130f587613da7565b613541565b60405160200161310e959493929190614689565b604051602081830303815290604052905061312881613541565b9e9d5050505050505050505050505050565b6060600061291a61314a84613443565b604051602001612fcd9190614d2b565b600081815260ad6020526040812054606091600a6131788184615560565b600a8110613188576131886155b6565b015490506000601782600381106131a1576131a16155b6565b0180546131ad90615510565b80601f01602080910402602001604051908101604052809291908181526020018280546131d990615510565b80156132265780601f106131fb57610100808354040283529160200191613226565b820191906000526020600020905b81548152906001019060200180831161320957829003601f168201915b50505050509050600060148360038110613242576132426155b6565b01805461324e90615510565b80601f016020809104026020016040519081016040528092919081815260200182805461327a90615510565b80156132c75780601f1061329c576101008083540402835291602001916132c7565b820191906000526020600020905b8154815290600101906020018083116132aa57829003601f168201915b5050505050905060006132f46132dc88613443565b83858586604051602001612fcd959493929190614b88565b979650505050505050565b600081815b84518110156133445761333082868381518110613323576133236155b6565b6020026020010151613dd0565b91508061333c81615545565b915050613304565b509392505050565b6001548161336d5760405163b562e8dd60e01b815260040160405180910390fd5b6001600160a01b03831660008181526006602090815260408083208054680100000000000000018802019055848352600590915281206001851460e11b4260a01b178317905582840190839083907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a4600183015b81811461341c57808360007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a46001016133e4565b508161343a57604051622e076360e81b815260040160405180910390fd5b60015550505050565b6060816134675750506040805180820190915260018152600360fc1b602082015290565b8160005b8115613491578061347b81615545565b915061348a9050600a8361549a565b915061346b565b60008167ffffffffffffffff8111156134ac576134ac6155cc565b6040519080825280601f01601f1916602001820160405280156134d6576020820181803683370190505b5090505b8415612b15576134eb6001836154cd565b91506134f8600a86615560565b613503906030615482565b60f81b818381518110613518576135186155b6565b60200101906001600160f81b031916908160001a90535061353a600a8661549a565b94506134da565b606081516000141561356157505060408051602081019091526000815290565b60006040518060600160405280604081526020016155f960409139905060006003845160026135909190615482565b61359a919061549a565b6135a59060046154ae565b905060006135b4826020615482565b67ffffffffffffffff8111156135cc576135cc6155cc565b6040519080825280601f01601f1916602001820160405280156135f6576020820181803683370190505b509050818152600183018586518101602084015b81831015613662576003830192508251603f8160121c168501518253600182019150603f81600c1c168501518253600182019150603f8160061c168501518253600182019150603f811685015182535060010161360a565b60038951066001811461367c576002811461368d57613699565b613d3d60f01b600119830152613699565b603d60f81b6000198301525b509398975050505050505050565b60a75460009082116136c057602a60035b015492915050565b60a8548210156136d357602a60006136b8565b60a9548210156136e657602a60016136b8565b60aa548210156136f957602a60026136b8565b602a60046136b8565b919050565b60606000608b600b61371a60048861549a565b6137249190615560565b600b8110613734576137346155b6565b01805461374090615510565b80601f016020809104026020016040519081016040528092919081815260200182805461376c90615510565b80156137b95780601f1061378e576101008083540402835291602001916137b9565b820191906000526020600020905b81548152906001019060200180831161379c57829003601f168201915b5050505050905060006080600b6003886137d3919061549a565b6137dd9190615560565b600b81106137ed576137ed6155b6565b0180546137f990615510565b80601f016020809104026020016040519081016040528092919081815260200182805461382590615510565b80156138725780601f1061384757610100808354040283529160200191613872565b820191906000526020600020905b81548152906001019060200180831161385557829003601f168201915b505050505090506000606e600d60028961388c919061549a565b6138969190615560565b600d81106138a6576138a66155b6565b0180546138b290615510565b80601f01602080910402602001604051908101604052809291908181526020018280546138de90615510565b801561392b5780601f106139005761010080835404028352916020019161392b565b820191906000526020600020905b81548152906001019060200180831161390e57829003601f168201915b505050505090506000607b8760058110613947576139476155b6565b01805461395390615510565b80601f016020809104026020016040519081016040528092919081815260200182805461397f90615510565b80156139cc5780601f106139a1576101008083540402835291602001916139cc565b820191906000526020600020905b8154815290600101906020018083116139af57829003601f168201915b5050505050905060006139de85613dfc565b6139e785613dfc565b6139f084613dfc565b6139f986613dfc565b604051602001613a0c9493929190614632565b60405160208183030381529060405290508615613add5780613aba606d6000018054613a3790615510565b80601f0160208091040260200160405190810160405280929190818152602001828054613a6390615510565b8015613ab05780601f10613a8557610100808354040283529160200191613ab0565b820191906000526020600020905b815481529060010190602001808311613a9357829003601f168201915b5050505050613dfc565b604051602001613acb929190614603565b60405160208183030381529060405290505b98975050505050505050565b6060600080613afb8460000151611e20565b91509150600060ae6000866000015181526020019081526020016000206040518060a0016040529081600082018054613b3390615510565b80601f0160208091040260200160405190810160405280929190818152602001828054613b5f90615510565b8015613bac5780601f10613b8157610100808354040283529160200191613bac565b820191906000526020600020905b815481529060010190602001808311613b8f57829003601f168201915b50505050508152602001600182015481526020016002820154815260200160038201548152602001600482015481525050905060006001613bf08360000151612d94565b11613c0a5760405180602001604052806000815250613c2c565b8151604051613c1c9190602001614842565b6040516020818303038152906040525b905080613c3c8760000151613443565b613c4586613443565b613c4e86613443565b604051602001613c61949392919061501c565b604051602081830303815290604052945050505050919050565b60606000613c8c8360400151613443565b613c998460600151613443565b604051602001613caa92919061493d565b60408051601f198184030181529190529392505050565b606060008260a00151613cee57604051806040016040528060028152602001616e6f60f01b815250613d0b565b6040518060400160405280600381526020016279657360e81b8152505b9050600081613d1d8560800151613443565b613d2686613e17565b613d2f87613e4b565b613d3888613ea3565b613d4189613efb565b604051602001613d5696959493929190614a6d565b60408051601f19818403018152919052949350505050565b6060600080613d808460000151611e20565b91509150613d8d82613443565b613d9682613443565b604051602001612bd49291906150d8565b606081604051602001613dba91906151ad565b6040516020818303038152906040529050919050565b6000818310613dec57600082815260208490526040902061291a565b5060009182526020526040902090565b6060613e0782613541565b604051602001613dba9190614869565b606060006052613e2a84608001516136a7565b60058110613e3a57613e3a6155b6565b01604051602001613caa9190614fdb565b606060006045601d600d60028660200151613e66919061549a565b613e709190615560565b600d8110613e8057613e806155b6565b0154600d8110613e9257613e926155b6565b01604051602001613caa9190614a1e565b606060006057602f600b60038660200151613ebe919061549a565b613ec89190615560565b600b8110613ed857613ed86155b6565b0154600b8110613eea57613eea6155b6565b01604051602001613caa91906152cc565b606060006062603a600b60048660200151613f16919061549a565b613f209190615560565b600b8110613f3057613f306155b6565b0154600b8110613f4257613f426155b6565b01604051602001613caa919061512b565b8260038101928215613f81579160200282015b82811115613f81578235825591602001919060010190613f66565b50613f8d9291506140a5565b5090565b8260058101928215613f815791602002820182811115613f81578235825591602001919060010190613f66565b828054613fca90615510565b90600052602060002090601f016020900481019282613fec5760008555613f81565b82601f106140055782800160ff19823516178555613f81565b82800160010185558215613f815791820182811115613f81578235825591602001919060010190613f66565b82805461403d90615510565b90600052602060002090601f01602090048101928261405f5760008555613f81565b82601f1061407857805160ff1916838001178555613f81565b82800160010185558215613f81579182015b82811115613f8157825182559160200191906001019061408a565b5b80821115613f8d57600081556001016140a6565b600067ffffffffffffffff808411156140d5576140d56155cc565b604051601f8501601f19908116603f011681019082821181831017156140fd576140fd6155cc565b8160405280935085815286868601111561411657600080fd5b858560208301376000602087830101525050509392505050565b80356001600160a01b038116811461370257600080fd5b60006020828403121561415957600080fd5b61291a82614130565b6000806040838503121561417557600080fd5b61417e83614130565b915061418c60208401614130565b90509250929050565b6000806000606084860312156141aa57600080fd5b6141b384614130565b92506141c160208501614130565b9150604084013590509250925092565b600080600080608085870312156141e757600080fd5b6141f085614130565b93506141fe60208601614130565b925060408501359150606085013567ffffffffffffffff81111561422157600080fd5b8501601f8101871361423257600080fd5b614241878235602084016140ba565b91505092959194509250565b6000806040838503121561426057600080fd5b61426983614130565b91506020830135801515811461427e57600080fd5b809150509250929050565b6000806040838503121561429c57600080fd5b6142a583614130565b946020939093013593505050565b600080602083850312156142c657600080fd5b823567ffffffffffffffff808211156142de57600080fd5b818501915085601f8301126142f257600080fd5b81358181111561430157600080fd5b8660208260051b850101111561431657600080fd5b60209290920196919550909350505050565b60006060828403121561433a57600080fd5b82606083011115611a7c57600080fd5b600060a0828403121561435c57600080fd5b8260a083011115611a7c57600080fd5b60006020828403121561437e57600080fd5b5035919050565b60006020828403121561439757600080fd5b813561291a816155e2565b6000602082840312156143b457600080fd5b815161291a816155e2565b6000602082840312156143d157600080fd5b813567ffffffffffffffff8111156143e857600080fd5b8201601f810184136143f957600080fd5b612b15848235602084016140ba565b60006020828403121561441a57600080fd5b5051919050565b60008060006040848603121561443657600080fd5b83359250602084013567ffffffffffffffff8082111561445557600080fd5b818601915086601f83011261446957600080fd5b81358181111561447857600080fd5b87602082850101111561448a57600080fd5b6020830194508093505050509250925092565b600081518084526144b58160208601602086016154e4565b601f01601f19169290920160200192915050565b600081516144db8185602086016154e4565b9290920192915050565b8054600090600181811c90808316806144ff57607f831692505b602080841082141561452157634e487b7160e01b600052602260045260246000fd5b818015614535576001811461454657614573565b60ff19861689528489019650614573565b60008881526020902060005b8681101561456b5781548b820152908501908301614552565b505084890196505b50505050505092915050565b7f7b202274726169745f74797065223a202274797065222c202276616c7565223a81526808089c195d1cc89f4b60ba1b602082015260290190565b7f7b202274726169745f74797065223a2022626972746864617465222c20227661815266363ab2911d101160c91b602082015260270190565b8183823760009101908152919050565b600083516146158184602088016154e4565b8351908301906146298183602088016154e4565b01949350505050565b60008551614644818460208a016154e4565b855190830190614658818360208a016154e4565b855191019061466b8183602089016154e4565b845191019061467e8183602088016154e4565b019695505050505050565b6000865161469b818460208b016154e4565b80830190507f226465736372697074696f6e223a202254616d61676f6769206973206120546181527f6d61676f74636869204461707020616e642066756c6c792067656e657261746560208201527f64206f6e2d636861696e2e2054686520636f6e747261637420696e746572616360408201527f74696f6e20616e642074696d652077696c6c206166666563742074686520737460608201527f6174757320616e64207265616374696f6e206f6620746865207065742e20496660808201527f20796f7520636f6c6c656374206f74686572206974656d732c2074686520706560a0820152721d081dda5b1b081cda1bddc81b1bdd9948488b606a1b60c08201526e2261747472696275746573223a205b60881b60d382015286516147c88160e2840160208b016154e4565b6148356148276148216147e96147e360e2868801018c6144c9565b8a6144c9565b7f5d2c22696d616765223a2022646174613a696d6167652f7376672b786d6c3b62815265185cd94d8d0b60d21b602082015260260190565b876144c9565b61227d60f01b815260020190565b9998505050505050505050565b600082516148548184602087016154e4565b6201017960ed1b920191825250600301919050565b7f3c696d61676520783d22302220793d2230222077696474683d2233322220686581527f696768743d2233322220696d6167652d72656e646572696e673d22706978656c60208201527f6174656422207072657365727665417370656374526174696f3d22784d69645960408201527f4d69642220786c696e6b3a687265663d22646174613a696d6167652f706e673b60608201526618985cd94d8d0b60ca1b6080820152600082516149238160878501602087016154e4565b6211179f60e91b6087939091019283015250608a01919050565b7f7b202274726169745f74797065223a202268756e676572222c2022646973706c81527f61795f74797065223a20226e756d626572222c202276616c7565223a2000000060208201526000835161499b81603d8501602088016154e4565b8083019050611f4b60f21b80603d8301527f7b202274726169745f74797065223a2022626f726564222c2022646973706c61603f8301527f795f74797065223a20226e756d626572222c202276616c7565223a2000000000605f8301528451614a0b81607b8501602089016154e4565b607b920191820152607d01949350505050565b7f7b202274726169745f74797065223a2022656172222c202276616c7565223a208152601160f91b60208201526000614a5a60218301846144e5565b62089f4b60ea1b81526003019392505050565b6000614a788261457f565b7f7b202274726169745f74797065223a20226d6173746572222c202276616c7565815263111d101160e11b60208201528851614abb816024840160208d016154e4565b62089f4b60ea1b602492909101918201527f7b202274726169745f74797065223a2022756e68617070696e657373222c202260278201527f646973706c61795f74797065223a20226e756d626572222c202276616c75652260478201526101d160f51b60678201528751614b36816069840160208c016154e4565b611f4b60f21b606992909101918201528651614b5981606b840160208b016154e4565b614b7a614b74614b6e606b848601018a6144c9565b886144c9565b866144c9565b9a9950505050505050505050565b6a7b226e616d65223a20222360a81b81528551600090614baf81600b850160208b016154e4565b6a040a8c2dac2cedeced240560ab1b600b918401918201528651614bda816016840160208b016154e4565b7314911610113232b9b1b934b83a34b7b7111d101160611b601692909101918201528551614c0f81602a840160208a016154e4565b61088b60f21b9101602a8101919091526e2261747472696275746573223a205b60881b602c8201527f7b202274726169745f74797065223a202274797065222c202276616c7565223a603b8201526908089c1c9bdc1cc89f4b60b21b605b8201527f7b202274726169745f74797065223a20227573616765222c202276616c7565226065820152621d101160e91b6085820152613add614d19614b74614cca614cba608886016147e3565b63089f574b60e21b815260040190565b7f22696d616765223a2022697066733a2f2f516d56784344666d7767593270734181527f683777746938614c43796b6b6a3939736e79674751383970327a6b664174662f602082015260400190565b652e676966227d60d01b815260060190565b6a7b226e616d65223a20222360a81b81528151600090614d5281600b8501602087016154e4565b7f2054616d61676f67692028556e72657665616c2050726f707329222c20226465600b9390910192830152507f736372697074696f6e223a2022556e72657665616c2050726f7073222c000000602b8201526e2261747472696275746573223a205b60881b60488201527f7b202274726169745f74797065223a202274797065222c202276616c7565223a605782015268202270726f7073227d60b81b607782015261174b60f21b60808201527f22696d616765223a2022697066733a2f2f516d5462423644443277387433367a60828201527f4c50764245646f576f363252464d794a69394558636a39395a6978507278432260a2820152607d60f81b60c282015260c301919050565b6a7b226e616d65223a20222360a81b81528651600090614e8481600b850160208c016154e4565b6e040a8c2dac2cedeced2408acece405608b1b600b918401918201528751614eb381601a840160208c016154e4565b602f60f81b601a92909101918201528651614ed581601b840160208b016154e4565b602960f81b9101601b8101919091527f222c20226465736372697074696f6e223a2022556e62726f6b656e2054616d61601c8201526d19dbd9da481959d9dccb8b8b888b60921b603c8201526e2261747472696275746573223a205b60881b604a820152614835614d19614b74614f8c614f7e614827614f78614f6b614f65614f6060598b0161457f565b6145ba565b8e6144c9565b602f60f81b815260010190565b8b6144c9565b61174b60f21b815260020190565b7f22696d616765223a2022697066733a2f2f516d57317463635971426d534c514681527f54664e38725777384a4858787837685a53344d6969775757444e35747647382f602082015260400190565b7f7b202274726169745f74797065223a20227265616374696f6e222c202276616c8152653ab2911d101160d11b60208201526000614a5a60268301846144e5565b693d913730b6b2911d101160b11b8152845160009061504281600a850160208a016154e4565b602360f81b600a91840191820152855161506381600b840160208a016154e4565b6a040a8c2dac2cedeced240560ab1b600b9290910191820152845161508f8160168401602089016154e4565b602f60f81b6016929091019182015283516150b18160178401602088016154e4565b602960f81b6017929091019182015261088b60f21b6018820152601a019695505050505050565b60006150e3826145ba565b84516150f38183602089016154e4565b602f60f81b910190815283516151108160018401602088016154e4565b61227d60f01b60019290910191820152600301949350505050565b7f7b202274726169745f74797065223a2022626f6479222c202276616c7565223a815261101160f11b60208201526000614a5a60228301846144e5565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c0000008152600082516151a081601d8501602087016154e4565b91909101601d0192915050565b7f3c7376672077696474683d2239363022206865696768743d223936302220766581527f7273696f6e3d22312e31222076696577426f783d22302030203332203332222060208201527f786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323030302f737660408201527f672220786d6c6e733a786c696e6b3d22687474703a2f2f7777772e77332e6f7260608201526d3397989c9c9c97bc3634b735911f60911b60808201527f3c726563742077696474683d223130302522206865696768743d223130302522608e82015271103334b6361e9111b0b0b21c9c9c9110179f60711b60ae820152600082516152af8160c08501602087016154e4565b651e17b9bb339f60d11b60c093909101928301525060c601919050565b7f7b202274726169745f74797065223a202268656164222c202276616c7565223a815261101160f11b60208201526000614a5a60228301846144e5565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090612fe19083018461449d565b6020808252825182820181905260009190848201906040850190845b81811015611d4d57835183529284019291840191600101615358565b60208152600061291a602083018461449d565b60a08152600061539a60a083018861449d565b90508560208301528460408301528360608301528260808301529695505050505050565b60208082526010908201526f139bdd081d985b1a59081c195d081a5960821b604082015260600190565b6020808252600a9082015269139bdd081c995d99585b60b21b604082015260600190565b6020808252600890820152674d617820746f203160c01b604082015260600190565b86815260208101869052604081018590528315156060820152821515608082015260c081016004831061547157634e487b7160e01b600052602160045260246000fd5b8260a0830152979650505050505050565b6000821982111561549557615495615574565b500190565b6000826154a9576154a961558a565b500490565b60008160001904831182151516156154c8576154c8615574565b500290565b6000828210156154df576154df615574565b500390565b60005b838110156154ff5781810151838201526020016154e7565b838111156120d95750506000910152565b600181811c9082168061552457607f821691505b60208210811415611a7c57634e487b7160e01b600052602260045260246000fd5b600060001982141561555957615559615574565b5060010190565b60008261556f5761556f61558a565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160e01b03198116811461254157600080fdfe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2fa2646970667358221220f1bbe7fca7f3263c3e811e6ceea38359c62c7b09c7e4845d05a74dcb604827eb64736f6c63430008070033

Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ 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.