HYPE Price: $38.54 (-3.16%)

Token

Gems (GEM)

Overview

Max Total Supply

1,111 GEM

Holders

490

Market

Onchain Market Cap

-

Circulating Supply Market Cap

-
Balance
1 GEM
0x358a2c0ccc467eaae57d07ade9fa3d4fb8257e58
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information

Contract Source Code Verified (Exact Match)

Contract Name:
Gems

Compiler Version
v0.8.12+commit.f00d7308

Optimization Enabled:
Yes with 200 runs

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

pragma solidity ^0.8.12;

/*

      /\      
     /  \     
    / /\ \    
   / /  \ \   
  /_/____\_\  
  \        /  
   \______/

Gems by @dailofrog
Art by @goopgoop_art

*/

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import 'base64-sol/base64.sol';

contract Gems is ERC721Enumerable, Ownable, ReentrancyGuard {

    uint256 public MAX_TOKEN_SUPPLY = 1111;
    uint256 public RESERVE_SUPPLY = 10;
    uint256 public price = 0.75 ether;
    
    enum MintStatus { 
        DISABLED, 
        WHITELIST,
        PUBLIC
    }

    MintStatus public mintStatus = MintStatus.DISABLED;
    uint256 public mintTokenId = 0;
    uint256 public maxPerWallet = 2;

    mapping(address => uint256) public numMinted;
    mapping(address => bool) public whitelist;

    bytes[] public gemTemplate = 
    [
        // refined
        bytes(hex'8f0003011c000101030201011a0001010102010401020104010201011800010101020104020201050104010301011600010105020205010401030101140001010102010402020104010203050104010301011200010104030502040301011100010101030505010205060103020110000101010301050304020201060405010302011000010101030105020403020106030501040103020110000101010301050104020201040102010602050204010302011000010101030105020202040102010602050204010302011000010101030105030402020106030501040103020110000101010301050104020201040102010604050103020110000101010301050102030401020106030501040103020110000101010301050404010201060305010401030201100001010103010504040102010604050103020110000101050303020503020111000101010302050206010204060102030112000101010303050102020601040102030114000101010302050102010601040102030116000101010301050102010401020301180001010103020203011a0005011c000301'),
        bytes(hex'ff00110001011e000101010201011c0001010202010301011a0001010102010401020105010301011800010101020204010202050103010116000101010203040102030501030101140001010102030401050102010501040205010301011200010101020304020501020105020402050103010110000101090205050103010110000101010306050506010403011000010101030205020601050106020501060104030112000101010302050106010501060105010601040301140001010103030502060104030116000101010302050106010403011800010101030105010403011a000101010403011c0003011e000101'),
        bytes(hex'ce0005011a000101050201011800010101020504010201011600010101020104030202050104010201011400010101020104030201040305010401020101120001010c0201030101110001010102020501020506010202050103020110000101010202050102050501020205010302011000010101020204010205050102020501030201100001010102020501020504010202050103020110000101010302040102050501020205010302011000010101030205010305040103020501030201100001010103020501030504010302050103020110000101010302050103050401030204010302011000010101030205010305050103020501030201110001010b0303011200010101030506020401020301140001010103030602040102030116000101030302020301180007011a000501'),
        bytes(hex'ff000a000f01100001010f0201010f00010102020b040102010602010e000101010201050102090401020105010602010e0001010102020509020205010602010e000101010202040102070501030205010602010e000101010202050102070401030205010602010e00010103040102070501030205010602010e000101010202050102070401030104020502010e0001010102020501020704010301040105010602010e000101010402050102070401030204010502010e00010101040205090301050104010502010e000101010401050103070602050102020502010e00010101040103090602050102010502010e00010101030506010501060605010202010f00110110000f01'),
        bytes(hex'ff000f0004011a00020104020201170001010202010303040203010115000101010201030604020301011300010101020103010402020504020301011200010101020104010302020404010501040103020110000101010209040105020401030101100001010102090402050104010302010f0001010102080403050104010302010f00010101020204010504040205010601050104010302011000010101030204040503060104010203011000010101030105010402050406010501040102020112000101010301050204030502040102030113000101020304040202030115000201010303020401170008011a000401'),
        bytes(hex'ed000601190001010103040401030101170001010104010204040102010501011500010102040102040401020205010113000101030401030404010303050101110001010404010204040103040501010f0001010205090203030104010601010e000101010404050302020401020406010402010d000101010404050302020401020406010402010d000101010404050102040401020406010402010d00010101040405010204040102050602010d000101010603040103060201030304010602010e000101010603050103040601030305010403010f0001010106020501020406010302050104030111000101010601050104040601020105010403011300010101060104040602040301150001010106050403011700080119000601'),
        bytes(hex'ff00100002011d000101020201011b0001010402010119000101050201040101170001010102020402020205010401011500010101020204040202050104010113000101010202040402010501020205010401011100010107020204010504030101100001010305030204040103030502010f00010103040202040401050103030402010f000101030501020105030402050102030502010f000101030501030102040301020103030502010f00010102050203060602020205020110000101010501030806010201050301110001010a05030113000c0115000a01'),
        bytes(hex'ff002c000a01150001010a0201011300010102020904010301011100010101020104010209040103010201010f000101010201040c020104010201010d000101010201040302090401030204010201010c00010101020104030203050104010503040105010301060104010202010b000101010201040102010401020305010401050304010501030206010302010b00010101020104020501020305010401050304010501030206010302010b00010101020104020501020305010401050304010501030206010302010c000101010201040105060205030106010303010d0001010102010401020906020303010f000101020202050104010501040405010303011100010105020503030113000c0115000a01'),
        bytes(hex'ff000c000a01150001010a020101130001010102010508040105010301011100010101020105040201050204020201040105010301010f0001010102010504020905010301010e00010103020304040203040202010302010d0001010102010603040206010401020606010202010d000101010201060202020601050204010603040205010202010e00010101030106020201060105010201040505010203010f0001010103010502020105010204060104010203011100010101030104010202050306010401020301130001010103010401020105020601040102030115000101010301040105010601040102030117000101010301040202030119000101020203011b0004011d000201'),

        // raw
        bytes(hex'f00001011e000101010201011c000101020202011a00010101020104010204011700010101020204010201010202010301011500010101020304020201060104010302011300010101020204010201040105010201060104010302011200010101020204020202050106020501030201120001010102010501040102030501020104010501030201120001010102050502020104010601020201130001010106020402060204010502060103010112000101010201040102020401050306020501030201110001010103020401020104010502060305010302011200010101030304010501060102020504011300010101030204010601020101010501020401140001010103020601020101010501020201170001010103010601020101020202011800010102030501190006011b000201'),
        bytes(hex'ee0001011e000101010201011c00010101020104010301011a0001010102010401050104010301011800010101020104010201050106010401030101160001010102010402020105010602050103010114000101010202040102010401050206010501030201130001010102040401020206010501030501100001010102030501030102010302050502020110000101010201040102010401020306020502040102020110000101010201050202010501060103010501060205010203011100010101030105010201050106010502060105010203011200010101030105010401050106010501060104010203011400010101030104010501060105010401020301150001010103010401050106010401020301170001010103010501040102030119000101020203011b0004011d000201'),
        bytes(hex'ed0001011e000101010201011c00010101020104010301011a0001010102020401050103010118000101010202040102010501030601130001010102010402020105010303010202020111000101010201040302010501030101020201040102020111000101010204040105010601020304010302011100010101020304020501060104020201050103030110000101010303040206010405050103020201010f000101010303060202010404060305010202010f0001010103010501040102010401060102010401060103030203010f000201010202040105010602020104010305010f0001010202010401050206060403011000010101030104010501060104020201040103010101040105010202011000030101020104010502040105010301010104020202011100010101020204010302050103070111000101020402010203030101000401110009011800030102000301'),
        bytes(hex'f10003011b000201020202011800020102020204010301011600020102020404010302011400010102020104020202040205020113000101010202040302010403050103010113000101010202040202030502060103020113000101010202040205020602050103020113000101010203050206030501030201130001010102070601030301130001010102010502060202010401060103020115000101010301060202010401050103030115000101010301060204020501020201160001010103010601040205020601020101160001010103010501060105030601040102010116000101010301050206010303040102010115000101010302050103010105020101150001010303080115000a0117000301'),
        bytes(hex'ff000c0005011a0001010402010301011800010101020405010601030101010002011300010101020605010601030101020201011100010101020205020202040205010601020206010301010f00010101020205030202040205010603050106010301010e000101010201050104020201040305010601050202010401050106010301010d00010101020105030402050103010601050202020402050106010301010c0001010102020501040105010601030106010504040105010301050106010302010b0001010103010604050206010502040205010301050206010302010b00010101030206020503060305010602050306010302010b000101010305060105020601050206010502060205010202010c0001010103010502060105010303060205020601030205010202010d0001010103010503060105050601030204010203010e000101010301060305020302060105020401020301100001010403020102030302030112000d011400040102000501'),
        bytes(hex'ec000101060003011500010101020101030002010202020113000101010201050102030102020204010301011200010101020105010401050102010101030204010201040103020110000101010204040105010201010104020201040105010301010f000101010202040102020402050102010102040205010302010d00010101020104030201040105020601050102030501060105010301010c000101010202040202010401050206010501060105010201010306010302010b00010101020404010506060104010201010306010301010c000101010302040105020602050506010201010206010302010c00010101030105030601050306020202040102010501060105010301010d0001010103020504060202020403050206010302010d0001010103010503060202020401050106020502060105010201010e000101010302060404010506060104010202010e00010101030106030401050306020501060104010203010f0001010103050602050106010501040102030111000101010307050204010202011300010107030202030114000b0116000901'),
        bytes(hex'e50007010100050113000101050201030101040201030101120001010102050401030202020401060103010111000101010201040202020501060103010203050106010301011000010101020104020202040105010601040105010402050106010301010f0001010102030401020104020501060105020402050106010301010e000101010203040105020402050106030501040206010301010d000201010201060305020401050206010502040306010301010c000101030202060205010202050102040601050206010301010b0001010102030402060205010202050102020601050104010601020106010301010a0001010102010401020104010501020106030501040106010203060202010601020201090001010102020403050102010603040406020201060104010202010a0001010103030501040506010502060102010601050104020202010b000101010303040202020601050104010202060203030202010c00010101030306010401020206020201060104010306010d0001010103010601040203010203050104020206010e0001010203020201010602020113000d011400040101000701'),
        bytes(hex'8b0003011c000101020202010500040111000101020201040102010104000101030202010f00010102020304010201010200010101020204010302010e000101020204040103030102020204010302010d0001010202040401020106010301010103010202040102010302010d000101010204040102010602050103030401020106010302010d0001010102010501040202010603050106010402020306010301010c00010101020206040502040105020603050206010302010a000101010202040106010401050102020501020104010501060105010602050204010301010a000101020203040202030501020405010602040102010302010a00010101030102010402020106060501060204010602020105010301010b0001010103020501060205030401050106030402060305010201010b0001010103030503040102010603040102030601050104010202010b00010101030106010503040102020602020106020502060104010202010c000101010302060104010201060105010602050104010501060205010303010d00010101030106010502040105020601050104010201050206010302010e00010101030206010401020205020601050204010501060104010201010f0001010103010602040305020603050104020202010f0001010103010502040205020602050104020203011000010102030104020501060303020203011200010101030205020401030601140001010102010502040102050116000101040202011a0006011b000501'),
        bytes(hex'ac000701180001010502010302011400030101020106030401020103020113000101030201030304020201030201120001010202020401060204010202050103020111000101020203040106010401020305030304010d00010101020204010201050106050503060202020301010c00010101020104010203050206030201050606010301010b0001010302020503060304010501060102020401050106010302010a00010101020305010601050106010202040102010501020204010201050106010302010a00010101020203040601020104010201050106020402020106010501030201090001010102010601020204020201060302010602040102020501060105010302010900010102020304010201050206020501060204010502060205010201030101090001010102030401020105020603040a060103010108000101030202050206030401020306020202040106010501060102020107000101010203060105020602040102020501060102030401020106020501020201070001010603010602020205020603040202030601020201080005010202020301060205010602040102030602050102020109000701010301060205020604050103030202010e0002010103050502020203060110000101030302020a0111000a0117000501'),
        bytes(hex'8d0002011d000101020201011b000101010202050103010119000101010203040105010303011600010101020204010201060103010102030101140001010103020601020106010301010103010401060103010112000101010303060104020602030102010501060102010110000101010201030104010602040105030601050206010202010e000101020202040105010601050106020201050206010203010d000101020202040102010502060102030401050206020301010d000101020201040202010502060304010201050106010201040106010301010d0001010103030501060304020202050106020401050106010201010d0001010203010201060104010501060305030602050106010202010d0001010103020404060102010401050406020202010c0001010103030401050306010202040102020602040106010201010c00010101030104020201050106010402050104020201060204010201050106010201010c00010101030205020602050106020502060104020201050106010202010c00010101030206010301060204050602050206010202010d0001010303020401020105030601030306010203010e0002010103010401020205010602030101030203011000010101030106020502060102070111000101010305060102020101000301130001010103030601020301180001010103020203011a0005011c000301'),
        bytes(hex'e50007011900010104020203010118000101010204040105010301011700010101020404010501060103050112000101010203040102010502060101040201011100010101020304010202050106010101020304010301011000010101020104020205050106020401020105010301011000010101030206050501060104020201050106010301011000010101030306030502060305020601030101100001010103050601050406010502060103010110000101010201050906010502060103010110000101010201050306010402050306010501060105010301011000010101020105020601040105010206060105010301011000010101020206010502020606010501020201100001010103040601050106010501030305010202011100010101030506010501010103030202011200010101030306020501020601130001010303030206011400080119000701'),
        bytes(hex'f2000701130006010602020111000101050201010504010205010d0001010102050401010105010401020104010501030101030202010b00010101020104020203050104010202040205010102040105010302010a000101010202040202020501040102010401050206010501040102010401050103020109000101010202040102020502060104030502060105010201040205010302010800010101020104010203050206030501040206010501040205010601030301070001010102020403050306010501040306020503060103030107000101010201060305010403060205040601040306010303010800010101020106010502040306010401050306010503060105010203010900010101020105050602050406010301050204010203010a0001010103020601040105070601030101030203010b0001010102010602050706010307010c00010102030201030601040105010601020301010003010d000401020603040105010203011300020101030106040501020301150001010303030203011600090118000701'),
        bytes(hex'c8000701190001010602010118000101010204040105010301011700010101020104020202050106010301011600010101020104020203050106010301011500010101020104010501040102030501060103010114000101010201040205010401020104020501060103010114000201020602050104020502060103010112000101010201040202020601050102010503060103010111000101010201040202010502060305030601030101100001010102030401020105030601050306010302010f00010101020205020401020105030601050206010202010f000101010203050204010205060105010202011000010101030206020501040105020601010105010401020201110001010103020602050104010502060101020202011200010101030306020502060501130001010103050601050102040114000101010303060105010401020201170001010303030202011800080119000701'),
        bytes(hex'b400060112000601010001010402010302010c00060101030402010101030106010401020104010302010c000101050201030304010601010106010501020204010302010c00010101020304010601030204010201040106010101040305010202010c0001010102010402020104010602050104010201050106010502040106010202010c000101010201050202010401050106030501040406010203010c00010101020106020501020104020603050104020605010d00020101060405030602040306010301010e000101030201060105010601050104040601050306010301010d0001010102030404060105040601050206010302010c00010101020104020201040a060105010302010c0001010102010501040202010504060203020601050104010302010c00010101030106030501040105010601030301050202010d00010101030106030501020206010309010e0001010103010603050104020601030101010006010f00010101030206010501040306010301011600010101030306010501060105010202011600010101030406010501020201170001010103020601050104010202011800010105020201190007011a000601'),
        bytes(hex'f0000601190001010602010117000101010205040202010115000101010202040202020402050103010113000101010202040302020402050103020111000101010203040405010201050206010301011000010101020104010501020104040501020306010302010e000101010201040106010501040405010203060105010302010d00010101020104020601040405010404060105010302010c000101010201040206050501040206010502060105010302010b0001010102080501040206010503060105010302010b00010101020104020501020104020501020206020502060105010203010b0001010102020401020104020501020306010502060105010203010c00010101030304020501020306010502060105010203010d0001010103020403020206010503060105010203010f0001010103090601050102030110000101010303060605010203011200010103030602030114000b0116000901')
    ];

    bytes[] public shineTemplate = [
        bytes(hex'260001023f0001021f0001021b00010201000202010302021d0001021f000102'),
        bytes(hex'c70001021e000102010301021e000102ff00b20001021e000102010301021e000102'),
        bytes(hex'250001023f0001021e0003021b0003020103030201000102190003021e0001021f0001023f000102ff00b60001023f0001021e000102010301021e000102'),
        bytes(hex'480001021c000102010001020103010201000102100001020b00010212000102010301021e000102ff00ff002a0001023f0001021b0001020200010201030102010001021c0001021f0001023f000102'),
        bytes(hex'da0001023f0001021c00010201000102010302021d0001023f000102c80001023f0001021f0001021e00010201030102010001021c000102230001021e000102010301021e0001023f000102'),
        bytes(hex'47000102060001021e000102010301021700010206000102180001021b0001020100020201030102010001021c0001023f000102'),
        bytes(hex'460001023f0001021e000102010301023e000102ff00ff0054000102210001021e000102010341000102'),
        bytes(hex'270001021f0001021a0001020200020201030202020001021a0001021f000102ff00ff00600001021b00010202000102010301021e0001023f000102090001021e000102010301021e000102'),
        bytes(hex'450001021600010209000202140001020900010201030d00010203000102010001020103010201000102000208000102130001021f0001023f000102'),
        bytes(hex'290001021f0001021d000102030001021d0001029b0001031f0001031b00010301000203010202031d0001033f000103ff00360001033f0001031e000103010201031e0001033f000103'),
        bytes(hex'460001021f0001033c0001020103030001030102010001021a0001031f0001023f000102ff00960001025f0001021f0001021f0001031c00020203000103010200023c0001021f000102'),
        bytes(hex'850001021e000102010301021e000102ff00ff00b90001021e000102010301021e000102'),
        bytes(hex'7a0001021b000102020003021e0001023f000102690001025f0001021c0001020100010201030102010001021c0001023f000102'),
        bytes(hex'22000102080001021b000102010001030300010302021200010208000103160001020800010214000202010302021d0001021f0001023f0001023a0001023f0001021d000102010001020100010200023d000102'),
        bytes(hex'2c000102030001031300010206000102010301021600010207000102130001030100020202030102010001031b0001020700010317000102400001031d0001021e000102010301021e000102'),
        bytes(hex'3c0001025f0001021f0001021f0001031c00010201000102010301021e0001021f0001023f000102c10001021e0001020103010200021e0001027d0001023f0001021c000102010003021e0001021f000102')
    ];
        
    constructor() ERC721("Gems", "GEM") {
        reserveGems(RESERVE_SUPPLY);
    }

    function _mintGems(address to, uint256 quantity) private {
        require(mintTokenId + quantity <= MAX_TOKEN_SUPPLY, "Overcap");

        for(uint256 i = 0; i < quantity; i++) {
            _mint(to, ++mintTokenId);
        }
    }

    function reserveGems(uint256 numToMint) public onlyOwner {
        _mintGems(msg.sender, numToMint);
    }

    function mintGems(uint256 numToMint) external payable nonReentrant {
        require(numToMint > 0, "Non-zero mint");
        require(numMinted[msg.sender] + numToMint <= maxPerWallet, "Wallet limit exceeded");
        require(mintStatus == MintStatus.PUBLIC, "Mint disabled");
        require(msg.value >= numToMint * price, "Bad price" );
        
        numMinted[msg.sender] += numToMint;
        _mintGems(msg.sender, numToMint);
    }

    function mintGemsWhitelist(uint256 numToMint) external payable nonReentrant {
        require(mintStatus == MintStatus.WHITELIST, "Whitelist disabled");
        require(whitelist[msg.sender], "Not WL");
        require(numMinted[msg.sender] + numToMint <= maxPerWallet, "Wallet limit exceeded");
        require(msg.value >= numToMint * price, "Bad price");

        numMinted[msg.sender] += numToMint;
        _mintGems(msg.sender, numToMint);
    }

    function setStatus(uint256 _status) external onlyOwner {
        mintStatus = MintStatus(_status);
    }

    function setPrice(uint256 _price) external onlyOwner {
        price = _price;
    }

    function setMaxPerWallet(uint256 _value) external onlyOwner {
        maxPerWallet = _value;
    }

    function withdraw(address to) external onlyOwner {
        uint256 contractBalance = address(this).balance;
        (bool success,) = payable(to).call{ value: contractBalance }("");
        require(success, "WITHDRAWAL_FAILED");
    }

    function tokenJson(uint256 tokenId) public view returns (string memory) {
        //require(_exists(tokenId), "Nonexistent token");

        uint256 seed = uint256(keccak256(abi.encodePacked(tokenId, address(this))));
        uint backgroundIndex = randIndex(seed, 12345, backgroundColors.length);
        uint gemTemplateIndex = randIndex(seed, 4324343, gemTemplate.length);
        uint colorPaletteIndex= randIndex(seed, 78954, colorPalette.length);
        uint shineExists = randIndex(seed, 898543539, 4);

        string memory svg = render(tokenId);
        string memory json = 
            string(
                abi.encodePacked(
                    '{"name": "Gem #', Strings.toString(tokenId),'",',
                    '"description": "100% fully onchain gems of opulence on Hyperliquid EVM. No utility, no roadmap, just oooh shiny gems. Created by dailofrog and goopgoop_art.",',
                    '"attributes":[',
                        '{"trait_type":"Background", "value":"',Strings.toString(backgroundIndex+1),'"},'
                        '{"trait_type":"Gem", "value":"',Strings.toString(gemTemplateIndex+1),'"},'
                        '{"trait_type":"Palette", "value":"',Strings.toString(colorPaletteIndex+1),'"},'
                        '{"trait_type":"Refinement", "value":"', gemTemplateIndex<=8 ? "Cut":"Raw",'"},'
                        '{"trait_type":"Shiny", "value":"', shineExists==0 ? "True":"False",'"},'
                        '{"trait_type":"Onchain", "value":"',"True",'"}'
                    '],',
                    '"image": "data:image/svg+xml;base64,', Base64.encode(bytes(svg)), '"}' 
                )
            );

        return json;
    }

    function batchWhitelist(address[] calldata addresses, bool enable) external onlyOwner {
        for (uint i = 0; i < addresses.length; i++) {
            whitelist[addresses[i]] = enable;
        }
    }

    function isWhitelist(address _address) external view returns (bool) {
        return whitelist[_address];
    }

    function getNumMinted(address _address) external view returns (uint256) {
        return numMinted[_address];
    }

    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        return string(abi.encodePacked('data:application/json;base64,', Base64.encode(bytes(tokenJson(tokenId)))));
    }

    function randIndex(uint256 seed, uint256 randVal, uint256 len) private pure returns (uint256) {
        uint256 random = uint256(keccak256(abi.encodePacked(seed, randVal)));
        return random % len;
        //return (seed/randVal) % len;
    }

    string[] public backgroundColors = [
        "#b2b2b2", // light
        "#858585",
        "#585858",
        "#2a2a2a" // dark
    ];

    string[][] public colorPalette = [
        // [ null, BLACK, WHITE, GRAY, ...Colors ]
        [ "#000000", "#000000", "#fdffd0", "#f0f0f0", "#ff99a5", "#ff3419", "#d61900"],
        [ "#000000", "#000000", "#fdffd0", "#f0f0f0", "#ff3419", "#d61900", "#b30015"],
        [ "#000000", "#000000", "#fdffd0", "#f0f0f0", "#d61900", "#b30015", "#60000e"],
        [ "#000000", "#000000", "#fdffd0", "#f0f0f0", "#93d9d3", "#56b8b3", "#002365"],
        [ "#000000", "#000000", "#fdffd0", "#f0f0f0", "#858585", "#003632", "#2a2a2a"], // obsidian
        [ "#000000", "#000000", "#fdffd0", "#f0f0f0", "#00acf5", "#0068de", "#023bac"],
        [ "#000000", "#000000", "#fdffd0", "#f0f0f0", "#00e9f5", "#00acf5", "#0068de"],
        [ "#000000", "#000000", "#fdffd0", "#f0f0f0", "#7b47ff", "#532ee6", "#0928b3"],
        [ "#000000", "#000000", "#fdffd0", "#f0f0f0", "#d580ff", "#7b47ff", "#532ee6"],
        [ "#000000", "#000000", "#fdffd0", "#f0f0f0", "#2ab539", "#00807b", "#003632"],
        [ "#000000", "#000000", "#fdffd0", "#f0f0f0", "#66d330", "#2ab539", "#00807b"],
        [ "#000000", "#000000", "#fdffd0", "#f0f0f0", "#abff2d", "#66d330", "#2ab539"],
        [ "#000000", "#000000", "#fdffd0", "#f0f0f0", "#faec32", "#ffa500", "#db6a00"],
        [ "#000000", "#000000", "#fdffd0", "#f0f0f0", "#e65c6a", "#b31954", "#73002b"],
        [ "#000000", "#000000", "#fdffd0", "#f0f0f0", "#ff828f", "#e65c6a", "#b31954"],
        [ "#000000", "#000000", "#fdffd0", "#f0f0f0", "#ff6600", "#e63600", "#b30c00"],
        [ "#000000", "#000000", "#fdffd0", "#f0f0f0", "#ffa733", "#ff6600", "#e63600"]
    ];

    //string[] public debugPalette = ["#ffffff","#000000", "#ff0000", "#00ff00", "#0000ff"];

    function _renderRects(bytes memory data, string[] memory palette) private pure returns (string memory) {
        string memory rects;
        uint256 drawIndex = 0;

        for (uint256 i = 0; i < data.length; i = i+2) {
          uint8 runLength = uint8(data[i]); // we assume runLength of any non-transparent segment cannot exceed image width
          uint8 colorIndex = uint8(data[i+1]);

          if (colorIndex != 0) { // transparent
            uint8 x = uint8(drawIndex % 32);
            uint8 y = uint8(drawIndex / 32);
            string memory color = palette[colorIndex];

            rects = string(abi.encodePacked(rects, '<rect width="', Strings.toString(runLength), '" height="1" x="', Strings.toString(x), '" y="', Strings.toString(y), '" fill="', color, '"/>'));
          }
          drawIndex += runLength;
        }

        return rects; 
    }

    function render(uint256 tokenId) public view returns (string memory) {
        uint256 seed = uint256(keccak256(abi.encodePacked(tokenId, address(this))));

        uint backgroundIndex = randIndex(seed, 12345, backgroundColors.length);
        uint gemTemplateIndex = randIndex(seed, 4324343, gemTemplate.length);
        uint colorPaletteIndex= randIndex(seed, 78954, colorPalette.length);
        uint shineIndex = randIndex(seed, 435780, shineTemplate.length);
        uint shineExists = randIndex(seed, 898543539, 4);

        // colors
        string memory backgroundColor = backgroundColors[backgroundIndex];

        return string.concat(
            '<svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 32 32" shape-rendering="crispEdges" preserveAspectRatio="xMidYMid meet"> <rect width="32" height="32" fill="',
            backgroundColor,
            '" />',
            _renderRects(gemTemplate[gemTemplateIndex], colorPalette[colorPaletteIndex]),
            shineExists == 0 ? _renderRects(shineTemplate[shineIndex], colorPalette[colorPaletteIndex]) : "",
            '</svg>'
        );
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard signed math utilities missing in the Solidity language.
 */
library SignedMath {
    /**
     * @dev Returns the largest of two signed numbers.
     */
    function max(int256 a, int256 b) internal pure returns (int256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two signed numbers.
     */
    function min(int256 a, int256 b) internal pure returns (int256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two signed numbers without overflow.
     * The result is rounded towards zero.
     */
    function average(int256 a, int256 b) internal pure returns (int256) {
        // Formula from the book "Hacker's Delight"
        int256 x = (a & b) + ((a ^ b) >> 1);
        return x + (int256(uint256(x) >> 255) & (a ^ b));
    }

    /**
     * @dev Returns the absolute unsigned value of a signed value.
     */
    function abs(int256 n) internal pure returns (uint256) {
        unchecked {
            // must be unchecked in order to support `n = type(int256).min`
            return uint256(n >= 0 ? n : -n);
        }
    }
}

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

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
     * understand this adds an external call which potentially creates a reentrancy vulnerability.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 tokenId) external;

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

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

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

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

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

pragma solidity ^0.8.0;

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/extensions/ERC721Enumerable.sol)

pragma solidity ^0.8.0;

import "../ERC721.sol";
import "./IERC721Enumerable.sol";

/**
 * @dev This implements an optional extension of {ERC721} defined in the EIP that adds
 * enumerability of all the token ids in the contract as well as all token ids owned by each
 * account.
 */
abstract contract ERC721Enumerable is ERC721, IERC721Enumerable {
    // Mapping from owner to list of owned token IDs
    mapping(address => mapping(uint256 => uint256)) private _ownedTokens;

    // Mapping from token ID to index of the owner tokens list
    mapping(uint256 => uint256) private _ownedTokensIndex;

    // Array with all token ids, used for enumeration
    uint256[] private _allTokens;

    // Mapping from token id to position in the allTokens array
    mapping(uint256 => uint256) private _allTokensIndex;

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721) returns (bool) {
        return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
     */
    function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) {
        require(index < ERC721.balanceOf(owner), "ERC721Enumerable: owner index out of bounds");
        return _ownedTokens[owner][index];
    }

    /**
     * @dev See {IERC721Enumerable-totalSupply}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        return _allTokens.length;
    }

    /**
     * @dev See {IERC721Enumerable-tokenByIndex}.
     */
    function tokenByIndex(uint256 index) public view virtual override returns (uint256) {
        require(index < ERC721Enumerable.totalSupply(), "ERC721Enumerable: global index out of bounds");
        return _allTokens[index];
    }

    /**
     * @dev See {ERC721-_beforeTokenTransfer}.
     */
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 firstTokenId,
        uint256 batchSize
    ) internal virtual override {
        super._beforeTokenTransfer(from, to, firstTokenId, batchSize);

        if (batchSize > 1) {
            // Will only trigger during construction. Batch transferring (minting) is not available afterwards.
            revert("ERC721Enumerable: consecutive transfers not supported");
        }

        uint256 tokenId = firstTokenId;

        if (from == address(0)) {
            _addTokenToAllTokensEnumeration(tokenId);
        } else if (from != to) {
            _removeTokenFromOwnerEnumeration(from, tokenId);
        }
        if (to == address(0)) {
            _removeTokenFromAllTokensEnumeration(tokenId);
        } else if (to != from) {
            _addTokenToOwnerEnumeration(to, tokenId);
        }
    }

    /**
     * @dev Private function to add a token to this extension's ownership-tracking data structures.
     * @param to address representing the new owner of the given token ID
     * @param tokenId uint256 ID of the token to be added to the tokens list of the given address
     */
    function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
        uint256 length = ERC721.balanceOf(to);
        _ownedTokens[to][length] = tokenId;
        _ownedTokensIndex[tokenId] = length;
    }

    /**
     * @dev Private function to add a token to this extension's token tracking data structures.
     * @param tokenId uint256 ID of the token to be added to the tokens list
     */
    function _addTokenToAllTokensEnumeration(uint256 tokenId) private {
        _allTokensIndex[tokenId] = _allTokens.length;
        _allTokens.push(tokenId);
    }

    /**
     * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that
     * while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for
     * gas optimizations e.g. when performing a transfer operation (avoiding double writes).
     * This has O(1) time complexity, but alters the order of the _ownedTokens array.
     * @param from address representing the previous owner of the given token ID
     * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address
     */
    function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {
        // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and
        // then delete the last slot (swap and pop).

        uint256 lastTokenIndex = ERC721.balanceOf(from) - 1;
        uint256 tokenIndex = _ownedTokensIndex[tokenId];

        // When the token to delete is the last token, the swap operation is unnecessary
        if (tokenIndex != lastTokenIndex) {
            uint256 lastTokenId = _ownedTokens[from][lastTokenIndex];

            _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
            _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
        }

        // This also deletes the contents at the last position of the array
        delete _ownedTokensIndex[tokenId];
        delete _ownedTokens[from][lastTokenIndex];
    }

    /**
     * @dev Private function to remove a token from this extension's token tracking data structures.
     * This has O(1) time complexity, but alters the order of the _allTokens array.
     * @param tokenId uint256 ID of the token to be removed from the tokens list
     */
    function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
        // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and
        // then delete the last slot (swap and pop).

        uint256 lastTokenIndex = _allTokens.length - 1;
        uint256 tokenIndex = _allTokensIndex[tokenId];

        // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so
        // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding
        // an 'if' statement (like in _removeTokenFromOwnerEnumeration)
        uint256 lastTokenId = _allTokens[lastTokenIndex];

        _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
        _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index

        // This also deletes the contents at the last position of the array
        delete _allTokensIndex[tokenId];
        _allTokens.pop();
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/IERC721Enumerable.sol)

pragma solidity ^0.8.0;

import "../IERC721.sol";

/**
 * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Enumerable is IERC721 {
    /**
     * @dev Returns the total amount of tokens stored by the contract.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns a token ID owned by `owner` at a given `index` of its token list.
     * Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
     */
    function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);

    /**
     * @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
     * Use along with {totalSupply} to enumerate all tokens.
     */
    function tokenByIndex(uint256 index) external view returns (uint256);
}

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

pragma solidity ^0.8.0;

import "../IERC721.sol";

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

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

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

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

pragma solidity ^0.8.1;

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

        return account.code.length > 0;
    }

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

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

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

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

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

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

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (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;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

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

pragma solidity ^0.8.0;

import "./math/Math.sol";
import "./math/SignedMath.sol";

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _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) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `int256` to its ASCII `string` decimal representation.
     */
    function toString(int256 value) internal pure returns (string memory) {
        return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

    /**
     * @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] = _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);
    }

    /**
     * @dev Returns true if the two strings are equal.
     */
    function equal(string memory a, string memory b) internal pure returns (bool) {
        return keccak256(bytes(a)) == keccak256(bytes(b));
    }
}

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

pragma solidity ^0.8.0;

import "./IERC165.sol";

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

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

pragma solidity ^0.8.0;

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    enum Rounding {
        Down, // Toward negative infinity
        Up, // Toward infinity
        Zero // Toward zero
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
     * with further edits by Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod0 := mul(x, y)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1, "Math: mulDiv overflow");

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
            // See https://cs.stackexchange.com/q/138556/92363.

            // Does not overflow because the denominator cannot be zero at this stage in the function.
            uint256 twos = denominator & (~denominator + 1);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
            // in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256, rounded down, of a positive value.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.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. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

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

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (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() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be _NOT_ENTERED
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

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

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

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == _ENTERED;
    }
}

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

pragma solidity ^0.8.0;

import "./IERC721.sol";
import "./IERC721Receiver.sol";
import "./extensions/IERC721Metadata.sol";
import "../../utils/Address.sol";
import "../../utils/Context.sol";
import "../../utils/Strings.sol";
import "../../utils/introspection/ERC165.sol";

/**
 * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
 * the Metadata extension, but not including the Enumerable extension, which is available separately as
 * {ERC721Enumerable}.
 */
contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
    using Address for address;
    using Strings for uint256;

    // Token name
    string private _name;

    // Token symbol
    string private _symbol;

    // Mapping from token ID to owner address
    mapping(uint256 => address) private _owners;

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

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

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

    /**
     * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
        return
            interfaceId == type(IERC721).interfaceId ||
            interfaceId == type(IERC721Metadata).interfaceId ||
            super.supportsInterface(interfaceId);
    }

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

    /**
     * @dev See {IERC721-ownerOf}.
     */
    function ownerOf(uint256 tokenId) public view virtual override returns (address) {
        address owner = _ownerOf(tokenId);
        require(owner != address(0), "ERC721: invalid token ID");
        return owner;
    }

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

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

    /**
     * @dev See {IERC721Metadata-tokenURI}.
     */
    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        _requireMinted(tokenId);

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

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

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

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

        _approve(to, tokenId);
    }

    /**
     * @dev See {IERC721-getApproved}.
     */
    function getApproved(uint256 tokenId) public view virtual override returns (address) {
        _requireMinted(tokenId);

        return _tokenApprovals[tokenId];
    }

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

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

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

        _transfer(from, to, tokenId);
    }

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

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

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

    /**
     * @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist
     */
    function _ownerOf(uint256 tokenId) internal view virtual returns (address) {
        return _owners[tokenId];
    }

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

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

    /**
     * @dev Safely mints `tokenId` and transfers it to `to`.
     *
     * Requirements:
     *
     * - `tokenId` must not exist.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function _safeMint(address to, uint256 tokenId) internal virtual {
        _safeMint(to, tokenId, "");
    }

    /**
     * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
     * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
     */
    function _safeMint(address to, uint256 tokenId, bytes memory data) internal virtual {
        _mint(to, tokenId);
        require(
            _checkOnERC721Received(address(0), to, tokenId, data),
            "ERC721: transfer to non ERC721Receiver implementer"
        );
    }

    /**
     * @dev Mints `tokenId` and transfers it to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
     *
     * Requirements:
     *
     * - `tokenId` must not exist.
     * - `to` cannot be the zero address.
     *
     * Emits a {Transfer} event.
     */
    function _mint(address to, uint256 tokenId) internal virtual {
        require(to != address(0), "ERC721: mint to the zero address");
        require(!_exists(tokenId), "ERC721: token already minted");

        _beforeTokenTransfer(address(0), to, tokenId, 1);

        // Check that tokenId was not minted by `_beforeTokenTransfer` hook
        require(!_exists(tokenId), "ERC721: token already minted");

        unchecked {
            // Will not overflow unless all 2**256 token ids are minted to the same owner.
            // Given that tokens are minted one by one, it is impossible in practice that
            // this ever happens. Might change if we allow batch minting.
            // The ERC fails to describe this case.
            _balances[to] += 1;
        }

        _owners[tokenId] = to;

        emit Transfer(address(0), to, tokenId);

        _afterTokenTransfer(address(0), to, tokenId, 1);
    }

    /**
     * @dev Destroys `tokenId`.
     * The approval is cleared when the token is burned.
     * This is an internal function that does not check if the sender is authorized to operate on the token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     *
     * Emits a {Transfer} event.
     */
    function _burn(uint256 tokenId) internal virtual {
        address owner = ERC721.ownerOf(tokenId);

        _beforeTokenTransfer(owner, address(0), tokenId, 1);

        // Update ownership in case tokenId was transferred by `_beforeTokenTransfer` hook
        owner = ERC721.ownerOf(tokenId);

        // Clear approvals
        delete _tokenApprovals[tokenId];

        unchecked {
            // Cannot overflow, as that would require more tokens to be burned/transferred
            // out than the owner initially received through minting and transferring in.
            _balances[owner] -= 1;
        }
        delete _owners[tokenId];

        emit Transfer(owner, address(0), tokenId);

        _afterTokenTransfer(owner, address(0), tokenId, 1);
    }

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

        _beforeTokenTransfer(from, to, tokenId, 1);

        // Check that tokenId was not transferred by `_beforeTokenTransfer` hook
        require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner");

        // Clear approvals from the previous owner
        delete _tokenApprovals[tokenId];

        unchecked {
            // `_balances[from]` cannot overflow for the same reason as described in `_burn`:
            // `from`'s balance is the number of token held, which is at least one before the current
            // transfer.
            // `_balances[to]` could overflow in the conditions described in `_mint`. That would require
            // all 2**256 token ids to be minted, which in practice is impossible.
            _balances[from] -= 1;
            _balances[to] += 1;
        }
        _owners[tokenId] = to;

        emit Transfer(from, to, tokenId);

        _afterTokenTransfer(from, to, tokenId, 1);
    }

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

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

    /**
     * @dev Reverts if the `tokenId` has not been minted yet.
     */
    function _requireMinted(uint256 tokenId) internal view virtual {
        require(_exists(tokenId), "ERC721: invalid token ID");
    }

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

    /**
     * @dev Hook that is called before any token transfer. This includes minting and burning. If {ERC721Consecutive} is
     * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1.
     *
     * Calling conditions:
     *
     * - When `from` and `to` are both non-zero, ``from``'s tokens will be transferred to `to`.
     * - When `from` is zero, the tokens will be minted for `to`.
     * - When `to` is zero, ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     * - `batchSize` is non-zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize) internal virtual {}

    /**
     * @dev Hook that is called after any token transfer. This includes minting and burning. If {ERC721Consecutive} is
     * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1.
     *
     * Calling conditions:
     *
     * - When `from` and `to` are both non-zero, ``from``'s tokens were transferred to `to`.
     * - When `from` is zero, the tokens were minted for `to`.
     * - When `to` is zero, ``from``'s tokens were burned.
     * - `from` and `to` are never both zero.
     * - `batchSize` is non-zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _afterTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize) internal virtual {}

    /**
     * @dev Unsafe write access to the balances, used by extensions that "mint" tokens using an {ownerOf} override.
     *
     * WARNING: Anyone calling this MUST ensure that the balances remain consistent with the ownership. The invariant
     * being that for any address `a` the value returned by `balanceOf(a)` must be equal to the number of tokens such
     * that `ownerOf(tokenId)` is `a`.
     */
    // solhint-disable-next-line func-name-mixedcase
    function __unsafe_increaseBalance(address account, uint256 amount) internal {
        _balances[account] += amount;
    }
}

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

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

Contract Security Audit

Contract ABI

API
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"MAX_TOKEN_SUPPLY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RESERVE_SUPPLY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"backgroundColors","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"addresses","type":"address[]"},{"internalType":"bool","name":"enable","type":"bool"}],"name":"batchWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"colorPalette","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"gemTemplate","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"getNumMinted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"isWhitelist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxPerWallet","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"numToMint","type":"uint256"}],"name":"mintGems","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"numToMint","type":"uint256"}],"name":"mintGemsWhitelist","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"mintStatus","outputs":[{"internalType":"enum Gems.MintStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintTokenId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"numMinted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":[],"name":"price","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"render","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"numToMint","type":"uint256"}],"name":"reserveGems","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"setMaxPerWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_price","type":"uint256"}],"name":"setPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_status","type":"uint256"}],"name":"setStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"shineTemplate","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","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":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenJson","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"whitelist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]

610457600c55600a600d55670a688906bd8b0000600e55600f805460ff191690556000601055600260115561054060405261019e610380818152608091829190620064376103a039815260200160405180610120016040528060f2815260200162005e7b60f291398152602001604051806101600160405280610132815260200162007f2f6101329139815260200160405180610140016040528061010a81526020016200632d61010a9139815260200160405180610120016040528060f2815260200162006f1160f29139815260200160405180610140016040528061011e815260200162005bc961011e9139815260200160405180610100016040528060dc81526020016200766160dc9139815260200160405180610140016040528061011481526020016200754d6101149139815260200160405180610140016040528061010c815260200162005d6f61010c913981526020016040518061016001604052806101328152602001620067a361013291398152602001604051806101600160405280610132815260200162007231610132913981526020016040518061018001604052806101568152602001620065d561015691398152602001604051806101400160405280610114815260200162007aff61011491398152602001604051806101a001604052806101748152602001620073d961017491398152602001604051806101c0016040528061019c81526020016200603161019c91398152602001604051806101e001604052806101ae8152602001620070836101ae913981526020016040518061026001604052806102348152602001620068d5610234913981526020016040518061022001604052806101e4815260200162006b096101e4913981526020016040518061024001604052806102088152602001620078f761020891398152602001604051806101800160405280610150815260200162007ddf61015091398152602001604051806101c0016040528061018e815260200162006ced61018e9139815260200160405180610180016040528061015c815260200162007c1361015c91398152602001604051806101e001604052806101ba81526020016200773d6101ba913981526020016040518061018001604052806101608152602001620061cd610160913990526200036190601490601862001e4b565b506040518061020001604052806040518060400160405280602081526020017f260001023f0001021f0001021b00010201000202010302021d0001021f00010281525081526020016040518060600160405280602281526020016200600f6022913981526020016040518060600160405280603e815260200162005d31603e9139815260200160405180608001604052806050815260200162005f6d6050913981526020016040518060800160405280604c815260200162007037604c91398152602001604051806060016040528060348152602001620070036034913981526020016040518060600160405280602a8152602001620073af602a913981526020016040518060800160405280604c815260200162007363604c913981526020016040518060600160405280603c815260200162007d6f603c913981526020016040518060800160405280604a815260200162006ec7604a913981526020016040518060800160405280604a815260200162005ce7604a913981526020016040518060600160405280602481526020016200672b60249139815260200160405180606001604052806034815260200162007dab6034913981526020016040518060800160405280605481526020016200674f6054913981526020016040518060800160405280604c815260200162006e7b604c9139815260200160405180608001604052806052815260200162005fbd6052913990526200058790601590601062001eaf565b506040805160c0810182526007608082018181526611b1193119311960c91b60a0840152825282518084018452818152662338353835383560c81b6020828101919091528084019190915283518085018552828152660466a706a706a760cb1b81830152838501528351808501909452908352662332613261326160c81b9083015260608101919091526200062190601690600462001f01565b506040518061022001604052806040518060e00160405280604051806040016040528060078152602001660233030303030360cc1b8152508152602001604051806040016040528060078152602001660233030303030360cc1b8152508152602001604051806040016040528060078152602001660236664666664360cc1b8152508152602001604051806040016040528060078152602001660236630663066360cc1b8152508152602001604051806040016040528060078152602001662366663939613560c81b8152508152602001604051806040016040528060078152602001662366663334313960c81b8152508152602001604051806040016040528060078152602001660236436313930360cc1b81525081525081526020016040518060e00160405280604051806040016040528060078152602001660233030303030360cc1b8152508152602001604051806040016040528060078152602001660233030303030360cc1b8152508152602001604051806040016040528060078152602001660236664666664360cc1b8152508152602001604051806040016040528060078152602001660236630663066360cc1b8152508152602001604051806040016040528060078152602001662366663334313960c81b8152508152602001604051806040016040528060078152602001660236436313930360cc1b8152508152602001604051806040016040528060078152602001662362333030313560c81b81525081525081526020016040518060e00160405280604051806040016040528060078152602001660233030303030360cc1b8152508152602001604051806040016040528060078152602001660233030303030360cc1b8152508152602001604051806040016040528060078152602001660236664666664360cc1b8152508152602001604051806040016040528060078152602001660236630663066360cc1b8152508152602001604051806040016040528060078152602001660236436313930360cc1b8152508152602001604051806040016040528060078152602001662362333030313560c81b8152508152602001604051806040016040528060078152602001662336303030306560c81b81525081525081526020016040518060e00160405280604051806040016040528060078152602001660233030303030360cc1b8152508152602001604051806040016040528060078152602001660233030303030360cc1b8152508152602001604051806040016040528060078152602001660236664666664360cc1b8152508152602001604051806040016040528060078152602001660236630663066360cc1b8152508152602001604051806040016040528060078152602001662339336439643360c81b8152508152602001604051806040016040528060078152602001662335366238623360c81b8152508152602001604051806040016040528060078152602001662330303233363560c81b81525081525081526020016040518060e00160405280604051806040016040528060078152602001660233030303030360cc1b8152508152602001604051806040016040528060078152602001660233030303030360cc1b8152508152602001604051806040016040528060078152602001660236664666664360cc1b8152508152602001604051806040016040528060078152602001660236630663066360cc1b8152508152602001604051806040016040528060078152602001662338353835383560c81b815250815260200160405180604001604052806007815260200166119818199b199960c91b8152508152602001604051806040016040528060078152602001662332613261326160c81b81525081525081526020016040518060e00160405280604051806040016040528060078152602001660233030303030360cc1b8152508152602001604051806040016040528060078152602001660233030303030360cc1b8152508152602001604051806040016040528060078152602001660236664666664360cc1b8152508152602001604051806040016040528060078152602001660236630663066360cc1b8152508152602001604051806040016040528060078152602001662330306163663560c81b8152508152602001604051806040016040528060078152602001662330303638646560c81b8152508152602001604051806040016040528060078152602001662330323362616360c81b81525081525081526020016040518060e00160405280604051806040016040528060078152602001660233030303030360cc1b8152508152602001604051806040016040528060078152602001660233030303030360cc1b8152508152602001604051806040016040528060078152602001660236664666664360cc1b8152508152602001604051806040016040528060078152602001660236630663066360cc1b8152508152602001604051806040016040528060078152602001662330306539663560c81b8152508152602001604051806040016040528060078152602001662330306163663560c81b8152508152602001604051806040016040528060078152602001662330303638646560c81b81525081525081526020016040518060e00160405280604051806040016040528060078152602001660233030303030360cc1b8152508152602001604051806040016040528060078152602001660233030303030360cc1b8152508152602001604051806040016040528060078152602001660236664666664360cc1b8152508152602001604051806040016040528060078152602001660236630663066360cc1b815250815260200160405180604001604052806007815260200166119bb11a1bb33360c91b815250815260200160405180604001604052806007815260200166119a999932b29b60c91b8152508152602001604051806040016040528060078152602001662330393238623360c81b81525081525081526020016040518060e00160405280604051806040016040528060078152602001660233030303030360cc1b8152508152602001604051806040016040528060078152602001660233030303030360cc1b8152508152602001604051806040016040528060078152602001660236664666664360cc1b8152508152602001604051806040016040528060078152602001660236630663066360cc1b81525081526020016040518060400160405280600781526020016611b21a9c18333360c91b815250815260200160405180604001604052806007815260200166119bb11a1bb33360c91b815250815260200160405180604001604052806007815260200166119a999932b29b60c91b81525081525081526020016040518060e00160405280604051806040016040528060078152602001660233030303030360cc1b8152508152602001604051806040016040528060078152602001660233030303030360cc1b8152508152602001604051806040016040528060078152602001660236664666664360cc1b8152508152602001604051806040016040528060078152602001660236630663066360cc1b8152508152602001604051806040016040528060078152602001662332616235333960c81b8152508152602001604051806040016040528060078152602001661198181c181bb160c91b815250815260200160405180604001604052806007815260200166119818199b199960c91b81525081525081526020016040518060e00160405280604051806040016040528060078152602001660233030303030360cc1b8152508152602001604051806040016040528060078152602001660233030303030360cc1b8152508152602001604051806040016040528060078152602001660236664666664360cc1b8152508152602001604051806040016040528060078152602001660236630663066360cc1b8152508152602001604051806040016040528060078152602001660233636643333360cc1b8152508152602001604051806040016040528060078152602001662332616235333960c81b8152508152602001604051806040016040528060078152602001661198181c181bb160c91b81525081525081526020016040518060e00160405280604051806040016040528060078152602001660233030303030360cc1b8152508152602001604051806040016040528060078152602001660233030303030360cc1b8152508152602001604051806040016040528060078152602001660236664666664360cc1b8152508152602001604051806040016040528060078152602001660236630663066360cc1b81525081526020016040518060400160405280600781526020016608d85899998c9960ca1b8152508152602001604051806040016040528060078152602001660233636643333360cc1b8152508152602001604051806040016040528060078152602001662332616235333960c81b81525081525081526020016040518060e00160405280604051806040016040528060078152602001660233030303030360cc1b8152508152602001604051806040016040528060078152602001660233030303030360cc1b8152508152602001604051806040016040528060078152602001660236664666664360cc1b8152508152602001604051806040016040528060078152602001660236630663066360cc1b81525081526020016040518060400160405280600781526020016611b330b2b1999960c91b8152508152602001604051806040016040528060078152602001660236666613530360cc1b8152508152602001604051806040016040528060078152602001660236462366130360cc1b81525081525081526020016040518060e00160405280604051806040016040528060078152602001660233030303030360cc1b8152508152602001604051806040016040528060078152602001660233030303030360cc1b8152508152602001604051806040016040528060078152602001660236664666664360cc1b8152508152602001604051806040016040528060078152602001660236630663066360cc1b8152508152602001604051806040016040528060078152602001662365363563366160c81b81525081526020016040518060400160405280600781526020016608d88ccc4e4d4d60ca1b815250815260200160405180604001604052806007815260200166119b999818193160c91b81525081525081526020016040518060e00160405280604051806040016040528060078152602001660233030303030360cc1b8152508152602001604051806040016040528060078152602001660233030303030360cc1b8152508152602001604051806040016040528060078152602001660236664666664360cc1b8152508152602001604051806040016040528060078152602001660236630663066360cc1b81525081526020016040518060400160405280600781526020016611b3331c191c3360c91b8152508152602001604051806040016040528060078152602001662365363563366160c81b81525081526020016040518060400160405280600781526020016608d88ccc4e4d4d60ca1b81525081525081526020016040518060e00160405280604051806040016040528060078152602001660233030303030360cc1b8152508152602001604051806040016040528060078152602001660233030303030360cc1b8152508152602001604051806040016040528060078152602001660236664666664360cc1b8152508152602001604051806040016040528060078152602001660236630663066360cc1b8152508152602001604051806040016040528060078152602001660236666363630360cc1b8152508152602001604051806040016040528060078152602001660236536333630360cc1b8152508152602001604051806040016040528060078152602001660236233306330360cc1b81525081525081526020016040518060e00160405280604051806040016040528060078152602001660233030303030360cc1b8152508152602001604051806040016040528060078152602001660233030303030360cc1b8152508152602001604051806040016040528060078152602001660236664666664360cc1b8152508152602001604051806040016040528060078152602001660236630663066360cc1b8152508152602001604051806040016040528060078152602001662366666137333360c81b8152508152602001604051806040016040528060078152602001660236666363630360cc1b8152508152602001604051806040016040528060078152602001660236536333630360cc1b81525081525081525060179060116200185f92919062001f61565b503480156200186d57600080fd5b50604080518082018252600481526347656d7360e01b60208083019182528351808501909452600384526247454d60e81b908401528151919291620018b59160009162001fbb565b508051620018cb90600190602084019062001fbb565b505050620018e8620018e26200190160201b60201c565b62001905565b6001600b55600d54620018fb9062001957565b6200241f565b3390565b600a80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6200196162001970565b6200196d3382620019a8565b50565b600a546001600160a01b03163314620019a65760405162461bcd60e51b81526004016200199d90620021a6565b60405180910390fd5b565b600c5481601054620019bb9190620021d4565b1115620019dc5760405162461bcd60e51b81526004016200199d906200220e565b60005b8181101562001a1e5762001a0983601060008154620019fe9062002220565b918290555062001a23565b8062001a158162002220565b915050620019df565b505050565b6001600160a01b03821662001a4c5760405162461bcd60e51b81526004016200199d9062002271565b6000818152600260205260409020546001600160a01b03161562001a845760405162461bcd60e51b81526004016200199d90620022b8565b62001a9460008383600162001b37565b6000818152600260205260409020546001600160a01b03161562001acc5760405162461bcd60e51b81526004016200199d90620022b8565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b62001b508484848462001c4660201b62000fcf1760201c565b600181111562001b745760405162461bcd60e51b81526004016200199d9062002327565b816001600160a01b03851662001bd35762001bcd81600880546000838152600960205260408120829055600182018355919091527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30155565b62001bf9565b836001600160a01b0316856001600160a01b03161462001bf95762001bf9858262001c4c565b6001600160a01b03841662001c195762001c138162001cf9565b62001c3f565b846001600160a01b0316846001600160a01b03161462001c3f5762001c3f848262001db3565b5050505050565b50505050565b6000600162001c668462001e0460201b62000ec31760201c565b62001c72919062002339565b60008381526007602052604090205490915080821462001cc6576001600160a01b03841660009081526006602090815260408083208584528252808320548484528184208190558352600790915290208190555b5060009182526007602090815260408084208490556001600160a01b039094168352600681528383209183525290812055565b60085460009062001d0d9060019062002339565b6000838152600960205260408120546008805493945090928490811062001d385762001d3862002353565b90600052602060002001549050806008838154811062001d5c5762001d5c62002353565b600091825260208083209091019290925582815260099091526040808220849055858252812055600880548062001d975762001d9762002369565b6001900381819060005260206000200160009055905550505050565b600062001dcb8362001e0460201b62000ec31760201c565b6001600160a01b039093166000908152600660209081526040808320868452825280832085905593825260079052919091209190915550565b60006001600160a01b03821662001e2f5760405162461bcd60e51b81526004016200199d90620023c6565b506001600160a01b031660009081526003602052604090205490565b82805482825590600052602060002090810192821562001e9d579160200282015b8281111562001e9d578251805162001e8c91849160209091019062001fbb565b509160200191906001019062001e6c565b5062001eab92915062002046565b5090565b82805482825590600052602060002090810192821562001e9d579160200282015b8281111562001e9d578251805162001ef091849160209091019062001fbb565b509160200191906001019062001ed0565b82805482825590600052602060002090810192821562001f53579160200282015b8281111562001f53578251805162001f4291849160209091019062001fbb565b509160200191906001019062001f22565b5062001eab92915062002067565b82805482825590600052602060002090810192821562001fad579160200282015b8281111562001fad57825162001f9c908390600762002088565b509160200191906001019062001f82565b5062001eab929150620020da565b82805462001fc990620023ee565b90600052602060002090601f01602090048101928262001fed576000855562002038565b82601f106200200857805160ff191683800117855562002038565b8280016001018555821562002038579182015b82811115620020385782518255916020019190600101906200201b565b5062001eab929150620020fb565b8082111562001eab5760006200205d828262002112565b5060010162002046565b8082111562001eab5760006200207e828262002112565b5060010162002067565b82805482825590600052602060002090810192821562001f53579160200282015b8281111562001f535782518051620020c991849160209091019062001fbb565b5091602001919060010190620020a9565b8082111562001eab576000620020f1828262002151565b50600101620020da565b5b8082111562001eab5760008155600101620020fc565b5080546200212090620023ee565b6000825580601f1062002131575050565b601f0160209004906000526020600020908101906200196d9190620020fb565b50805460008255906000526020600020908101906200196d919062002067565b60208082527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572910190815260005b5060200190565b60208082528101620021b88162002171565b92915050565b634e487b7160e01b600052601160045260246000fd5b60008219821115620021ea57620021ea620021be565b500190565b600781526000602082016604f7665726361760cc1b815291506200219f565b60208082528101620021b881620021ef565b6000600019821415620022375762002237620021be565b5060010190565b60208082527f4552433732313a206d696e7420746f20746865207a65726f2061646472657373910190815260006200219f565b60208082528101620021b8816200223e565b601c81526000602082017f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000815291506200219f565b60208082528101620021b88162002283565b603581526000602082017f455243373231456e756d657261626c653a20636f6e736563757469766520747281527f616e7366657273206e6f7420737570706f727465640000000000000000000000602082015291505b5060400190565b60208082528101620021b881620022ca565b6000828210156200234e576200234e620021be565b500390565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b602981526000602082017f4552433732313a2061646472657373207a65726f206973206e6f7420612076618152683634b21037bbb732b960b91b6020820152915062002320565b60208082528101620021b8816200237f565b634e487b7160e01b600052602260045260246000fd5b6002810460018216806200240357607f821691505b60208210811415620024195762002419620023d8565b50919050565b61379a806200242f6000396000f3fe60806040526004361061025c5760003560e01c8063871fd9cc11610144578063b88d4fde116100b6578063e268e4d31161007a578063e268e4d31461072c578063e489d5101461074c578063e985e9c514610762578063ef87d617146107ab578063f2fde38b146107cb578063fb39b7b2146107eb57600080fd5b8063b88d4fde14610673578063b8df9a7514610693578063c321118c146106b3578063c683630d146106d3578063c87b56dd1461070c57600080fd5b80639da3f8fd116101085780639da3f8fd146105c0578063a035b1fe146105e7578063a22cb465146105fd578063a8ce886e1461061d578063aa66797b1461063d578063b5adce3f1461065357600080fd5b8063871fd9cc146105275780638da5cb5b1461053d57806391b7f5ed1461055b57806395d89b411461057b5780639b19251a1461059057600080fd5b80633d6dc6cf116101dd578063515f765b116101a1578063515f765b1461047f57806351cff8d9146104925780636352211e146104b257806369ba1a75146104d257806370a08231146104f2578063715018a61461051257600080fd5b80633d6dc6cf146103d357806342842e0e1461040957806344aa1ee514610429578063453c2310146104495780634f6ccce71461045f57600080fd5b806318160ddd1161022457806318160ddd1461032857806320fc7eb21461034657806323b872dd146103735780632f745c59146103935780633bef6a93146103b357600080fd5b806301ffc9a71461026157806306fdde0314610297578063081812fc146102b9578063095ea7b3146102e657806311b97a0314610308575b600080fd5b34801561026d57600080fd5b5061028161027c366004612396565b6107fe565b60405161028e91906123c1565b60405180910390f35b3480156102a357600080fd5b506102ac610829565b60405161028e919061242d565b3480156102c557600080fd5b506102d96102d4366004612456565b6108bb565b60405161028e9190612491565b3480156102f257600080fd5b506103066103013660046124b3565b6108e2565b005b34801561031457600080fd5b50610306610323366004612456565b610971565b34801561033457600080fd5b506008545b60405161028e91906124f6565b34801561035257600080fd5b50610339610361366004612504565b60126020526000908152604090205481565b34801561037f57600080fd5b5061030661038e366004612525565b610986565b34801561039f57600080fd5b506103396103ae3660046124b3565b6109b7565b3480156103bf57600080fd5b506102ac6103ce366004612456565b610a09565b3480156103df57600080fd5b506103396103ee366004612504565b6001600160a01b031660009081526012602052604090205490565b34801561041557600080fd5b50610306610424366004612525565b610ba4565b34801561043557600080fd5b506102ac610444366004612456565b610bbf565b34801561045557600080fd5b5061033960115481565b34801561046b57600080fd5b5061033961047a366004612456565b610c6b565b61030661048d366004612456565b610cb9565b34801561049e57600080fd5b506103066104ad366004612504565b610dc7565b3480156104be57600080fd5b506102d96104cd366004612456565b610e50565b3480156104de57600080fd5b506103066104ed366004612456565b610e85565b3480156104fe57600080fd5b5061033961050d366004612504565b610ec3565b34801561051e57600080fd5b50610306610f07565b34801561053357600080fd5b5061033960105481565b34801561054957600080fd5b50600a546001600160a01b03166102d9565b34801561056757600080fd5b50610306610576366004612456565b610f1b565b34801561058757600080fd5b506102ac610f28565b34801561059c57600080fd5b506102816105ab366004612504565b60136020526000908152604090205460ff1681565b3480156105cc57600080fd5b50600f546105da9060ff1681565b60405161028e91906125be565b3480156105f357600080fd5b50610339600e5481565b34801561060957600080fd5b506103066106183660046125df565b610f37565b34801561062957600080fd5b506102ac610638366004612456565b610f46565b34801561064957600080fd5b50610339600d5481565b34801561065f57600080fd5b5061030661066e366004612664565b610f56565b34801561067f57600080fd5b5061030661068e3660046127a3565b610fd5565b34801561069f57600080fd5b506102ac6106ae366004612456565b611007565b3480156106bf57600080fd5b506102ac6106ce366004612456565b611017565b3480156106df57600080fd5b506102816106ee366004612504565b6001600160a01b031660009081526013602052604090205460ff1690565b34801561071857600080fd5b506102ac610727366004612456565b6114da565b34801561073857600080fd5b50610306610747366004612456565b611513565b34801561075857600080fd5b50610339600c5481565b34801561076e57600080fd5b5061028161077d366004612822565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b3480156107b757600080fd5b506102ac6107c6366004612855565b611520565b3480156107d757600080fd5b506103066107e6366004612504565b611564565b6103066107f9366004612456565b61159b565b60006001600160e01b0319821663780e9d6360e01b1480610823575061082382611635565b92915050565b6060600080546108389061288d565b80601f01602080910402602001604051908101604052809291908181526020018280546108649061288d565b80156108b15780601f10610886576101008083540402835291602001916108b1565b820191906000526020600020905b81548152906001019060200180831161089457829003601f168201915b5050505050905090565b60006108c682611685565b506000908152600460205260409020546001600160a01b031690565b60006108ed82610e50565b9050806001600160a01b0316836001600160a01b0316141561092a5760405162461bcd60e51b8152600401610921906128fb565b60405180910390fd5b336001600160a01b03821614806109465750610946813361077d565b6109625760405162461bcd60e51b815260040161092190612965565b61096c83836116b9565b505050565b610979611727565b6109833382611751565b50565b61099033826117ba565b6109ac5760405162461bcd60e51b8152600401610921906129bf565b61096c838383611839565b60006109c283610ec3565b82106109e05760405162461bcd60e51b815260040161092190612a17565b506001600160a01b03919091166000908152600660209081526040808320938352929052205490565b606060008230604051602001610a20929190612a4f565b6040516020818303038152906040528051906020012060001c90506000610a4f8261303960168054905061196e565b90506000610a66836241fbf760148054905061196e565b90506000610a7d846201346a60178054905061196e565b90506000610a918563358eafb3600461196e565b90506000610a9e88611017565b90506000610aab896119b1565b610abe610ab9886001612a8b565b6119b1565b610acc610ab9886001612a8b565b610ada610ab9886001612a8b565b6008891115610b04576040518060400160405280600381526020016252617760e81b815250610b21565b6040518060400160405280600381526020016210dd5d60ea1b8152505b8715610b4a576040518060400160405280600581526020016446616c736560d81b815250610b68565b604051806040016040528060048152602001635472756560e01b8152505b610b7188611a4e565b604051602001610b879796959493929190612bb6565b60408051601f198184030181529190529998505050505050505050565b61096c83838360405180602001604052806000815250610fd5565b60158181548110610bcf57600080fd5b906000526020600020016000915090508054610bea9061288d565b80601f0160208091040260200160405190810160405280929190818152602001828054610c169061288d565b8015610c635780601f10610c3857610100808354040283529160200191610c63565b820191906000526020600020905b815481529060010190602001808311610c4657829003601f168201915b505050505081565b6000610c7660085490565b8210610c945760405162461bcd60e51b815260040161092190612e66565b60088281548110610ca757610ca7612e76565b90600052602060002001549050919050565b610cc1611bb4565b6001600f5460ff166002811115610cda57610cda612575565b14610cf75760405162461bcd60e51b815260040161092190612eb8565b3360009081526013602052604090205460ff16610d265760405162461bcd60e51b815260040161092190612ee5565b60115433600090815260126020526040902054610d44908390612a8b565b1115610d625760405162461bcd60e51b815260040161092190612f21565b600e54610d6f9082612f31565b341015610d8e5760405162461bcd60e51b815260040161092190612f70565b3360009081526012602052604081208054839290610dad908490612a8b565b90915550610dbd90503382611751565b6109836001600b55565b610dcf611727565b60004790506000826001600160a01b031682604051610ded90612f80565b60006040518083038185875af1925050503d8060008114610e2a576040519150601f19603f3d011682016040523d82523d6000602084013e610e2f565b606091505b505090508061096c5760405162461bcd60e51b815260040161092190612fb0565b6000818152600260205260408120546001600160a01b0316806108235760405162461bcd60e51b815260040161092190612ff4565b610e8d611727565b806002811115610e9f57610e9f612575565b600f805460ff19166001836002811115610ebb57610ebb612575565b021790555050565b60006001600160a01b038216610eeb5760405162461bcd60e51b81526004016109219061304a565b506001600160a01b031660009081526003602052604090205490565b610f0f611727565b610f196000611bde565b565b610f23611727565b600e55565b6060600180546108389061288d565b610f42338383611c30565b5050565b60168181548110610bcf57600080fd5b610f5e611727565b60005b82811015610fcf578160136000868685818110610f8057610f80612e76565b9050602002016020810190610f959190612504565b6001600160a01b031681526020810191909152604001600020805460ff191691151591909117905580610fc78161305a565b915050610f61565b50505050565b610fdf33836117ba565b610ffb5760405162461bcd60e51b8152600401610921906129bf565b610fcf84848484611cd3565b60148181548110610bcf57600080fd5b60606000823060405160200161102e929190612a4f565b6040516020818303038152906040528051906020012060001c9050600061105d8261303960168054905061196e565b90506000611074836241fbf760148054905061196e565b9050600061108b846201346a60178054905061196e565b905060006110a2856206a64460158054905061196e565b905060006110b68663358eafb3600461196e565b90506000601686815481106110cd576110cd612e76565b9060005260206000200180546110e29061288d565b80601f016020809104026020016040519081016040528092919081815260200182805461110e9061288d565b801561115b5780601f106111305761010080835404028352916020019161115b565b820191906000526020600020905b81548152906001019060200180831161113e57829003601f168201915b50505050509050806112fe6014878154811061117957611179612e76565b90600052602060002001805461118e9061288d565b80601f01602080910402602001604051908101604052809291908181526020018280546111ba9061288d565b80156112075780601f106111dc57610100808354040283529160200191611207565b820191906000526020600020905b8154815290600101906020018083116111ea57829003601f168201915b50505050506017878154811061121f5761121f612e76565b90600052602060002001805480602002602001604051908101604052809291908181526020016000905b828210156112f55783829060005260206000200180546112689061288d565b80601f01602080910402602001604051908101604052809291908181526020018280546112949061288d565b80156112e15780601f106112b6576101008083540402835291602001916112e1565b820191906000526020600020905b8154815290600101906020018083116112c457829003601f168201915b505050505081526020019060010190611249565b50505050611d06565b831561131957604051806020016040528060008152506114ab565b6114ab6015868154811061132f5761132f612e76565b9060005260206000200180546113449061288d565b80601f01602080910402602001604051908101604052809291908181526020018280546113709061288d565b80156113bd5780601f10611392576101008083540402835291602001916113bd565b820191906000526020600020905b8154815290600101906020018083116113a057829003601f168201915b5050505050601788815481106113d5576113d5612e76565b90600052602060002001805480602002602001604051908101604052809291908181526020016000905b828210156112f557838290600052602060002001805461141e9061288d565b80601f016020809104026020016040519081016040528092919081815260200182805461144a9061288d565b80156114975780601f1061146c57610100808354040283529160200191611497565b820191906000526020600020905b81548152906001019060200180831161147a57829003601f168201915b5050505050815260200190600101906113ff565b6040516020016114bd93929190613075565b604051602081830303815290604052975050505050505050919050565b60606114ed6114e883610a09565b611a4e565b6040516020016114fd91906131b3565b6040516020818303038152906040529050919050565b61151b611727565b601155565b6017828154811061153057600080fd5b90600052602060002001818154811061154857600080fd5b90600052602060002001600091509150508054610bea9061288d565b61156c611727565b6001600160a01b0381166115925760405162461bcd60e51b815260040161092190613228565b61098381611bde565b6115a3611bb4565b600081116115c35760405162461bcd60e51b81526004016109219061325c565b601154336000908152601260205260409020546115e1908390612a8b565b11156115ff5760405162461bcd60e51b815260040161092190612f21565b6002600f5460ff16600281111561161857611618612575565b14610d625760405162461bcd60e51b815260040161092190613290565b60006001600160e01b031982166380ac58cd60e01b148061166657506001600160e01b03198216635b5e139f60e01b145b8061082357506301ffc9a760e01b6001600160e01b0319831614610823565b6000818152600260205260409020546001600160a01b03166109835760405162461bcd60e51b815260040161092190612ff4565b600081815260046020526040902080546001600160a01b0319166001600160a01b03841690811790915581906116ee82610e50565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b600a546001600160a01b03163314610f195760405162461bcd60e51b8152600401610921906132d2565b600c54816010546117629190612a8b565b11156117805760405162461bcd60e51b815260040161092190613300565b60005b8181101561096c576117a88360106000815461179e9061305a565b9182905550611e1f565b806117b28161305a565b915050611783565b6000806117c683610e50565b9050806001600160a01b0316846001600160a01b0316148061180d57506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff165b806118315750836001600160a01b0316611826846108bb565b6001600160a01b0316145b949350505050565b826001600160a01b031661184c82610e50565b6001600160a01b0316146118725760405162461bcd60e51b815260040161092190613352565b6001600160a01b0382166118985760405162461bcd60e51b8152600401610921906133a3565b6118a58383836001611f28565b826001600160a01b03166118b882610e50565b6001600160a01b0316146118de5760405162461bcd60e51b815260040161092190613352565b600081815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0387811680865260038552838620805460001901905590871680865283862080546001019055868652600290945282852080549092168417909155905184937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b60008084846040516020016119849291906133b3565b60408051601f19818403018152919052805160209091012090506119a883826133ef565b95945050505050565b606060006119be8361200e565b600101905060008167ffffffffffffffff8111156119de576119de6126b5565b6040519080825280601f01601f191660200182016040528015611a08576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084611a4157611a46565b611a12565b509392505050565b6060815160001415611a6e57505060408051602081019091526000815290565b60006040518060600160405280604081526020016137256040913990506000600384516002611a9d9190612a8b565b611aa79190613403565b611ab2906004612f31565b90506000611ac1826020612a8b565b67ffffffffffffffff811115611ad957611ad96126b5565b6040519080825280601f01601f191660200182016040528015611b03576020820181803683370190505b509050818152600183018586518101602084015b81831015611b6f576003830192508251603f8160121c168501518253600182019150603f81600c1c168501518253600182019150603f8160061c168501518253600182019150603f8116850151825350600101611b17565b600389510660018114611b895760028114611b9a57611ba6565b613d3d60f01b600119830152611ba6565b603d60f81b6000198301525b509398975050505050505050565b6002600b541415611bd75760405162461bcd60e51b81526004016109219061344b565b6002600b55565b600a80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b816001600160a01b0316836001600160a01b03161415611c625760405162461bcd60e51b81526004016109219061348f565b6001600160a01b0383811660008181526005602090815260408083209487168084529490915290819020805460ff1916851515179055517f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3190611cc69085906123c1565b60405180910390a3505050565b611cde848484611839565b611cea848484846120e6565b610fcf5760405162461bcd60e51b8152600401610921906134ee565b6060806000805b8551811015611e15576000868281518110611d2a57611d2a612e76565b016020015160f81c9050600087611d42846001612a8b565b81518110611d5257611d52612e76565b016020015160f81c90508015611df0576000611d6f6020866133ef565b90506000611d7e602087613403565b90506000898460ff1681518110611d9757611d97612e76565b6020026020010151905087611dae8660ff166119b1565b611dba8560ff166119b1565b611dc68560ff166119b1565b84604051602001611ddb9594939291906134fe565b60405160208183030381529060405297505050505b611dfd60ff831685612a8b565b93505050806002611e0e9190612a8b565b9050611d0d565b5090949350505050565b6001600160a01b038216611e455760405162461bcd60e51b8152600401610921906135d1565b6000818152600260205260409020546001600160a01b031615611e7a5760405162461bcd60e51b815260040161092190613615565b611e88600083836001611f28565b6000818152600260205260409020546001600160a01b031615611ebd5760405162461bcd60e51b815260040161092190613615565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6001811115611f495760405162461bcd60e51b815260040161092190613677565b816001600160a01b038516611fa557611fa081600880546000838152600960205260408120829055600182018355919091527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30155565b611fc8565b836001600160a01b0316856001600160a01b031614611fc857611fc885826121e4565b6001600160a01b038416611fe457611fdf81612281565b612007565b846001600160a01b0316846001600160a01b031614612007576120078482612330565b5050505050565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b831061204d5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310612079576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061209757662386f26fc10000830492506010015b6305f5e10083106120af576305f5e100830492506008015b61271083106120c357612710830492506004015b606483106120d5576064830492506002015b600a83106108235760010192915050565b60006001600160a01b0384163b156121d957604051630a85bd0160e11b81526001600160a01b0385169063150b7a029061212a903390899088908890600401613687565b6020604051808303816000875af1925050508015612165575060408051601f3d908101601f19168201909252612162918101906136d6565b60015b6121bf573d808015612193576040519150601f19603f3d011682016040523d82523d6000602084013e612198565b606091505b5080516121b75760405162461bcd60e51b8152600401610921906134ee565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050611831565b506001949350505050565b600060016121f184610ec3565b6121fb91906136f7565b60008381526007602052604090205490915080821461224e576001600160a01b03841660009081526006602090815260408083208584528252808320548484528184208190558352600790915290208190555b5060009182526007602090815260408084208490556001600160a01b039094168352600681528383209183525290812055565b600854600090612293906001906136f7565b600083815260096020526040812054600880549394509092849081106122bb576122bb612e76565b9060005260206000200154905080600883815481106122dc576122dc612e76565b60009182526020808320909101929092558281526009909152604080822084905585825281205560088054806123145761231461370e565b6001900381819060005260206000200160009055905550505050565b600061233b83610ec3565b6001600160a01b039093166000908152600660209081526040808320868452825280832085905593825260079052919091209190915550565b6001600160e01b031981165b811461098357600080fd5b803561082381612374565b6000602082840312156123ab576123ab600080fd5b6000611831848461238b565b8015155b82525050565b6020810161082382846123b7565b60005b838110156123ea5781810151838201526020016123d2565b83811115610fcf5750506000910152565b6000612405825190565b80845260208401935061241c8185602086016123cf565b601f01601f19169290920192915050565b6020808252810161243e81846123fb565b9392505050565b80612380565b803561082381612445565b60006020828403121561246b5761246b600080fd5b6000611831848461244b565b60006001600160a01b038216610823565b6123bb81612477565b602081016108238284612488565b61238081612477565b80356108238161249f565b600080604083850312156124c9576124c9600080fd5b60006124d585856124a8565b92505060206124e68582860161244b565b9150509250929050565b806123bb565b6020810161082382846124f0565b60006020828403121561251957612519600080fd5b600061183184846124a8565b60008060006060848603121561253d5761253d600080fd5b600061254986866124a8565b935050602061255a868287016124a8565b925050604061256b8682870161244b565b9150509250925092565b634e487b7160e01b600052602160045260246000fd5b6003811061098357610983612575565b806125a58161258b565b919050565b60006108238261259b565b6123bb816125aa565b6020810161082382846125b5565b801515612380565b8035610823816125cc565b600080604083850312156125f5576125f5600080fd5b600061260185856124a8565b92505060206124e6858286016125d4565b60008083601f84011261262757612627600080fd5b50813567ffffffffffffffff81111561264257612642600080fd5b60208301915083602082028301111561265d5761265d600080fd5b9250929050565b60008060006040848603121561267c5761267c600080fd5b833567ffffffffffffffff81111561269657612696600080fd5b6126a286828701612612565b9350935050602061256b868287016125d4565b634e487b7160e01b600052604160045260246000fd5b601f19601f830116810181811067ffffffffffffffff821117156126f1576126f16126b5565b6040525050565b600061270360405190565b90506125a582826126cb565b600067ffffffffffffffff821115612729576127296126b5565b601f19601f83011660200192915050565b82818337506000910152565b60006127596127548461270f565b6126f8565b90508281526020810184848401111561277457612774600080fd5b611a4684828561273a565b600082601f83011261279357612793600080fd5b8135611831848260208601612746565b600080600080608085870312156127bc576127bc600080fd5b60006127c887876124a8565b94505060206127d9878288016124a8565b93505060406127ea8782880161244b565b925050606085013567ffffffffffffffff81111561280a5761280a600080fd5b6128168782880161277f565b91505092959194509250565b6000806040838503121561283857612838600080fd5b600061284485856124a8565b92505060206124e6858286016124a8565b6000806040838503121561286b5761286b600080fd5b60006124d5858561244b565b634e487b7160e01b600052602260045260246000fd5b6002810460018216806128a157607f821691505b602082108114156128b4576128b4612877565b50919050565b602181526000602082017f4552433732313a20617070726f76616c20746f2063757272656e74206f776e658152603960f91b602082015291505b5060400190565b60208082528101610823816128ba565b603d81526000602082017f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f81527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c000000602082015291506128f4565b602080825281016108238161290b565b602d81526000602082017f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6581526c1c881bdc88185c1c1c9bdd9959609a1b602082015291506128f4565b6020808252810161082381612975565b602b81526000602082017f455243373231456e756d657261626c653a206f776e657220696e646578206f7581526a74206f6620626f756e647360a81b602082015291506128f4565b60208082528101610823816129cf565b60006108238260601b90565b600061082382612a27565b6123bb612a4a82612477565b612a33565b6000612a5b82856124f0565b602082019150612a6b8284612a3e565b5060140192915050565b634e487b7160e01b600052601160045260246000fd5b60008219821115612a9e57612a9e612a75565b500190565b6000612aad825190565b612abb8185602086016123cf565b9290920192915050565b61088b60f21b815260005b5060020190565b7f7b2274726169745f74797065223a224261636b67726f756e64222c202276616c8152643ab2911d1160d91b602082015260005b5060250190565b7f227d2c7b2274726169745f74797065223a2250616c65747465222c202276616c8152643ab2911d1160d91b60208201526000612b0b565b7f227d2c7b2274726169745f74797065223a224f6e636861696e222c202276616c8152643ab2911d1160d91b60208201526000612b0b565b635472756560e01b815260005b5060040190565b63089f574b60e21b81526000612b8f565b61227d60f01b81526000612ad0565b6e7b226e616d65223a202247656d202360881b8152600f016000612bda828a612aa3565b9150612be582612ac5565b7f226465736372697074696f6e223a2022313030252066756c6c79206f6e63686181527f696e2067656d73206f66206f70756c656e6365206f6e2048797065726c69717560208201527f69642045564d2e204e6f207574696c6974792c206e6f20726f61646d61702c2060408201527f6a757374206f6f6f68207368696e792067656d732e204372656174656420627960608201527f206461696c6f66726f6720616e6420676f6f70676f6f705f6172742e222c000060808201526d2261747472696275746573223a5b60901b609e82015260ac019150612cc582612ad7565b9150612cd18289612aa3565b7f227d2c7b2274726169745f74797065223a2247656d222c202276616c7565223a8152601160f91b60208201526021019150612d0d8288612aa3565b9150612d1882612b12565b9150612d248287612aa3565b7f227d2c7b2274726169745f74797065223a22526566696e656d656e74222c20228152673b30b63ab2911d1160c11b60208201526028019150612d678286612aa3565b7f227d2c7b2274726169745f74797065223a225368696e79222c202276616c7565815262111d1160e91b60208201526023019150612da58285612aa3565b9150612db082612b4a565b9150612dbb82612b82565b9150612dc682612b96565b7f22696d616765223a2022646174613a696d6167652f7376672b786d6c3b626173815263194d8d0b60e21b60208201526024019150612e058284612aa3565b9150612e1082612ba7565b9998505050505050505050565b602c81526000602082017f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f81526b7574206f6620626f756e647360a01b602082015291506128f4565b6020808252810161082381612e1d565b634e487b7160e01b600052603260045260246000fd5b601281526000602082017115da1a5d195b1a5cdd08191a5cd8589b195960721b815291505b5060200190565b6020808252810161082381612e8c565b6006815260006020820165139bdd0815d360d21b81529150612eb1565b6020808252810161082381612ec8565b601581526000602082017415d85b1b195d081b1a5b5a5d08195e18d959591959605a1b81529150612eb1565b6020808252810161082381612ef5565b6000816000190483118215151615612f4b57612f4b612a75565b500290565b600981526000602082016842616420707269636560b81b81529150612eb1565b6020808252810161082381612f50565b600081610823565b601181526000602082017015d2551211149055d05317d19052531151607a1b81529150612eb1565b6020808252810161082381612f88565b601881526000602082017f4552433732313a20696e76616c696420746f6b656e204944000000000000000081529150612eb1565b6020808252810161082381612fc0565b602981526000602082017f4552433732313a2061646472657373207a65726f206973206e6f7420612076618152683634b21037bbb732b960b91b602082015291506128f4565b6020808252810161082381613004565b600060001982141561306e5761306e612a75565b5060010190565b7f3c7376672076657273696f6e3d22312e302220786d6c6e733d22687474703a2f81527f2f7777772e77332e6f72672f323030302f737667222077696474683d2235313260208201527f22206865696768743d22353132222076696577426f783d22302030203332203360408201527f32222073686170652d72656e646572696e673d2263726973704564676573222060608201527f7072657365727665417370656374526174696f3d22784d6964594d6964206d6560808201527f6574223e203c726563742077696474683d22333222206865696768743d22333260a08201526711103334b6361e9160c11b60c082015260c80160006131768286612aa3565b631110179f60e11b8152600401915061318f8285612aa3565b915061319b8284612aa3565b651e17b9bb339f60d11b815260060195945050505050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c0000008152601d01600061243e8284612aa3565b602681526000602082017f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181526564647265737360d01b602082015291506128f4565b60208082528101610823816131e5565b600d81526000602082016c139bdb8b5e995c9bc81b5a5b9d609a1b81529150612eb1565b6020808252810161082381613238565b600d81526000602082016c135a5b9d08191a5cd8589b1959609a1b81529150612eb1565b602080825281016108238161326c565b60208082527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657291019081526000612eb1565b60208082528101610823816132a0565b600781526000602082016604f7665726361760cc1b81529150612eb1565b60208082528101610823816132e2565b602581526000602082017f4552433732313a207472616e736665722066726f6d20696e636f72726563742081526437bbb732b960d91b602082015291506128f4565b6020808252810161082381613310565b602481526000602082017f4552433732313a207472616e7366657220746f20746865207a65726f206164648152637265737360e01b602082015291506128f4565b6020808252810161082381613362565b60006133bf82856124f0565b6020820191506133cf82846124f0565b5060200192915050565b634e487b7160e01b600052601260045260246000fd5b6000826133fe576133fe6133d9565b500690565b600082613412576134126133d9565b500490565b601f81526000602082017f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0081529150612eb1565b6020808252810161082381613417565b601981526000602082017f4552433732313a20617070726f766520746f2063616c6c65720000000000000081529150612eb1565b602080825281016108238161345b565b603281526000602082017f4552433732313a207472616e7366657220746f206e6f6e20455243373231526581527131b2b4bb32b91034b6b83632b6b2b73a32b960711b602082015291506128f4565b602080825281016108238161349f565b600061350a8288612aa3565b6c1e3932b1ba103bb4b23a341e9160991b8152600d01915061352c8287612aa3565b6f11103432b4b3b43a1e911891103c1e9160811b815260100191506135518286612aa3565b6411103c9e9160d91b8152600501915061356b8285612aa3565b6711103334b6361e9160c11b815260080191506135888284612aa3565b6211179f60e91b8152600301979650505050505050565b60208082527f4552433732313a206d696e7420746f20746865207a65726f206164647265737391019081526000612eb1565b602080825281016108238161359f565b601c81526000602082017f4552433732313a20746f6b656e20616c7265616479206d696e7465640000000081529150612eb1565b60208082528101610823816135e1565b603581526000602082017f455243373231456e756d657261626c653a20636f6e7365637574697665207472815274185b9cd9995c9cc81b9bdd081cdd5c1c1bdc9d1959605a1b602082015291506128f4565b6020808252810161082381613625565b608081016136958287612488565b6136a26020830186612488565b6136af60408301856124f0565b81810360608301526136c181846123fb565b9695505050505050565b805161082381612374565b6000602082840312156136eb576136eb600080fd5b600061183184846136cb565b60008282101561370957613709612a75565b500390565b634e487b7160e01b600052603160045260246000fdfe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2fa2646970667358221220182078e7294249e14e8d3f84d505b3b8ccab4e4fc1c317fb733439f61d55d1f964736f6c634300080c0033ed000601190001010103040401030101170001010104010204040102010501011500010102040102040401020205010113000101030401030404010303050101110001010404010204040103040501010f0001010205090203030104010601010e000101010404050302020401020406010402010d000101010404050302020401020406010402010d000101010404050102040401020406010402010d00010101040405010204040102050602010d000101010603040103060201030304010602010e000101010603050103040601030305010403010f0001010106020501020406010302050104030111000101010601050104040601020105010403011300010101060104040602040301150001010106050403011700080119000601460001021f0001033c0001020103030001030102010001021a0001031f0001023f000102ff00960001025f0001021f0001021f0001031c00020203000103010200023c0001021f000102250001023f0001021e0003021b0003020103030201000102190003021e0001021f0001023f000102ff00b60001023f0001021e000102010301021e000102ff000c000a01150001010a020101130001010102010508040105010301011100010101020105040201050204020201040105010301010f0001010102010504020905010301010e00010103020304040203040202010302010d0001010102010603040206010401020606010202010d000101010201060202020601050204010603040205010202010e00010101030106020201060105010201040505010203010f0001010103010502020105010204060104010203011100010101030104010202050306010401020301130001010103010401020105020601040102030115000101010301040105010601040102030117000101010301040202030119000101020203011b0004011d000201ff00110001011e000101010201011c0001010202010301011a0001010102010401020105010301011800010101020204010202050103010116000101010203040102030501030101140001010102030401050102010501040205010301011200010101020304020501020105020402050103010110000101090205050103010110000101010306050506010403011000010101030205020601050106020501060104030112000101010302050106010501060105010601040301140001010103030502060104030116000101010302050106010403011800010101030105010403011a000101010403011c0003011e000101480001021c000102010001020103010201000102100001020b00010212000102010301021e000102ff00ff002a0001023f0001021b0001020200010201030102010001021c0001021f0001023f0001023c0001025f0001021f0001021f0001031c00010201000102010301021e0001021f0001023f000102c10001021e0001020103010200021e0001027d0001023f0001021c000102010003021e0001021f000102c70001021e000102010301021e000102ff00b20001021e000102010301021e000102ec000101060003011500010101020101030002010202020113000101010201050102030102020204010301011200010101020105010401050102010101030204010201040103020110000101010204040105010201010104020201040105010301010f000101010202040102020402050102010102040205010302010d00010101020104030201040105020601050102030501060105010301010c000101010202040202010401050206010501060105010201010306010302010b00010101020404010506060104010201010306010301010c000101010302040105020602050506010201010206010302010c00010101030105030601050306020202040102010501060105010301010d0001010103020504060202020403050206010302010d0001010103010503060202020401050106020502060105010201010e000101010302060404010506060104010202010e00010101030106030401050306020501060104010203010f0001010103050602050106010501040102030111000101010307050204010202011300010107030202030114000b0116000901f0000601190001010602010117000101010205040202010115000101010202040202020402050103010113000101010202040302020402050103020111000101010203040405010201050206010301011000010101020104010501020104040501020306010302010e000101010201040106010501040405010203060105010302010d00010101020104020601040405010404060105010302010c000101010201040206050501040206010502060105010302010b0001010102080501040206010503060105010302010b00010101020104020501020104020501020206020502060105010203010b0001010102020401020104020501020306010502060105010203010c00010101030304020501020306010502060105010203010d0001010103020403020206010503060105010203010f0001010103090601050102030110000101010303060605010203011200010103030602030114000b0116000901ff000a000f01100001010f0201010f00010102020b040102010602010e000101010201050102090401020105010602010e0001010102020509020205010602010e000101010202040102070501030205010602010e000101010202050102070401030205010602010e00010103040102070501030205010602010e000101010202050102070401030104020502010e0001010102020501020704010301040105010602010e000101010402050102070401030204010502010e00010101040205090301050104010502010e000101010401050103070602050102020502010e00010101040103090602050102010502010e00010101030506010501060605010202010f00110110000f018f0003011c000101030201011a0001010102010401020104010201011800010101020104020201050104010301011600010105020205010401030101140001010102010402020104010203050104010301011200010104030502040301011100010101030505010205060103020110000101010301050304020201060405010302011000010101030105020403020106030501040103020110000101010301050104020201040102010602050204010302011000010101030105020202040102010602050204010302011000010101030105030402020106030501040103020110000101010301050104020201040102010604050103020110000101010301050102030401020106030501040103020110000101010301050404010201060305010401030201100001010103010504040102010604050103020110000101050303020503020111000101010302050206010204060102030112000101010303050102020601040102030114000101010302050102010601040102030116000101010301050102010401020301180001010103020203011a0005011c000301ed0001011e000101010201011c00010101020104010301011a0001010102020401050103010118000101010202040102010501030601130001010102010402020105010303010202020111000101010201040302010501030101020201040102020111000101010204040105010601020304010302011100010101020304020501060104020201050103030110000101010303040206010405050103020201010f000101010303060202010404060305010202010f0001010103010501040102010401060102010401060103030203010f000201010202040105010602020104010305010f0001010202010401050206060403011000010101030104010501060104020201040103010101040105010202011000030101020104010502040105010301010104020202011100010101020204010302050103070111000101020402010203030101000401110009011800030102000301850001021e000102010301021e000102ff00ff00b90001021e000102010301021e00010222000102080001021b000102010001030300010302021200010208000103160001020800010214000202010302021d0001021f0001023f0001023a0001023f0001021d000102010001020100010200023d000102f00001011e000101010201011c000101020202011a00010101020104010204011700010101020204010201010202010301011500010101020304020201060104010302011300010101020204010201040105010201060104010302011200010101020204020202050106020501030201120001010102010501040102030501020104010501030201120001010102050502020104010601020201130001010106020402060204010502060103010112000101010201040102020401050306020501030201110001010103020401020104010502060305010302011200010101030304010501060102020504011300010101030204010601020101010501020401140001010103020601020101010501020201170001010103010601020101020202011800010102030501190006011b0002018b0003011c000101020202010500040111000101020201040102010104000101030202010f00010102020304010201010200010101020204010302010e000101020204040103030102020204010302010d0001010202040401020106010301010103010202040102010302010d000101010204040102010602050103030401020106010302010d0001010102010501040202010603050106010402020306010301010c00010101020206040502040105020603050206010302010a000101010202040106010401050102020501020104010501060105010602050204010301010a000101020203040202030501020405010602040102010302010a00010101030102010402020106060501060204010602020105010301010b0001010103020501060205030401050106030402060305010201010b0001010103030503040102010603040102030601050104010202010b00010101030106010503040102020602020106020502060104010202010c000101010302060104010201060105010602050104010501060205010303010d00010101030106010502040105020601050104010201050206010302010e00010101030206010401020205020601050204010501060104010201010f0001010103010602040305020603050104020202010f0001010103010502040205020602050104020203011000010102030104020501060303020203011200010101030205020401030601140001010102010502040102050116000101040202011a0006011b000501ac000701180001010502010302011400030101020106030401020103020113000101030201030304020201030201120001010202020401060204010202050103020111000101020203040106010401020305030304010d00010101020204010201050106050503060202020301010c00010101020104010203050206030201050606010301010b0001010302020503060304010501060102020401050106010302010a00010101020305010601050106010202040102010501020204010201050106010302010a00010101020203040601020104010201050106020402020106010501030201090001010102010601020204020201060302010602040102020501060105010302010900010102020304010201050206020501060204010502060205010201030101090001010102030401020105020603040a060103010108000101030202050206030401020306020202040106010501060102020107000101010203060105020602040102020501060102030401020106020501020201070001010603010602020205020603040202030601020201080005010202020301060205010602040102030602050102020109000701010301060205020604050103030202010e0002010103050502020203060110000101030302020a0111000a0117000501f2000701130006010602020111000101050201010504010205010d0001010102050401010105010401020104010501030101030202010b00010101020104020203050104010202040205010102040105010302010a000101010202040202020501040102010401050206010501040102010401050103020109000101010202040102020502060104030502060105010201040205010302010800010101020104010203050206030501040206010501040205010601030301070001010102020403050306010501040306020503060103030107000101010201060305010403060205040601040306010303010800010101020106010502040306010401050306010503060105010203010900010101020105050602050406010301050204010203010a0001010103020601040105070601030101030203010b0001010102010602050706010307010c00010102030201030601040105010601020301010003010d0004010206030401050102030113000201010301060405010203011500010103030302030116000901180007012c000102030001031300010206000102010301021600010207000102130001030100020202030102010001031b0001020700010317000102400001031d0001021e000102010301021e000102290001021f0001021d000102030001021d0001029b0001031f0001031b00010301000203010202031d0001033f000103ff00360001033f0001031e000103010201031e0001033f000103ff000f0004011a00020104020201170001010202010303040203010115000101010201030604020301011300010101020103010402020504020301011200010101020104010302020404010501040103020110000101010209040105020401030101100001010102090402050104010302010f0001010102080403050104010302010f00010101020204010504040205010601050104010302011000010101030204040503060104010203011000010101030105010402050406010501040102020112000101010301050204030502040102030113000101020304040202030115000201010303020401170008011a00040147000102060001021e000102010301021700010206000102180001021b0001020100020201030102010001021c0001023f000102da0001023f0001021c00010201000102010302021d0001023f000102c80001023f0001021f0001021e00010201030102010001021c000102230001021e000102010301021e0001023f000102e50007010100050113000101050201030101040201030101120001010102050401030202020401060103010111000101010201040202020501060103010203050106010301011000010101020104020202040105010601040105010402050106010301010f0001010102030401020104020501060105020402050106010301010e000101010203040105020402050106030501040206010301010d000201010201060305020401050206010502040306010301010c000101030202060205010202050102040601050206010301010b0001010102030402060205010202050102020601050104010601020106010301010a0001010102010401020104010501020106030501040106010203060202010601020201090001010102020403050102010603040406020201060104010202010a0001010103030501040506010502060102010601050104020202010b000101010303040202020601050104010202060203030202010c00010101030306010401020206020201060104010306010d0001010103010601040203010203050104020206010e0001010203020201010602020113000d011400040101000701ee0001011e000101010201011c00010101020104010301011a0001010102010401050104010301011800010101020104010201050106010401030101160001010102010402020105010602050103010114000101010202040102010401050206010501030201130001010102040401020206010501030501100001010102030501030102010302050502020110000101010201040102010401020306020502040102020110000101010201050202010501060103010501060205010203011100010101030105010201050106010502060105010203011200010101030105010401050106010501060104010203011400010101030104010501060105010401020301150001010103010401050106010401020301170001010103010501040102030119000101020203011b0004011d000201270001021f0001021a0001020200020201030202020001021a0001021f000102ff00ff00600001021b00010202000102010301021e0001023f000102090001021e000102010301021e000102460001023f0001021e000102010301023e000102ff00ff0054000102210001021e000102010341000102ff000c0005011a0001010402010301011800010101020405010601030101010002011300010101020605010601030101020201011100010101020205020202040205010601020206010301010f00010101020205030202040205010603050106010301010e000101010201050104020201040305010601050202010401050106010301010d00010101020105030402050103010601050202020402050106010301010c0001010102020501040105010601030106010504040105010301050106010302010b0001010103010604050206010502040205010301050206010302010b00010101030206020503060305010602050306010302010b000101010305060105020601050206010502060205010202010c0001010103010502060105010303060205020601030205010202010d0001010103010503060105050601030204010203010e000101010301060305020302060105020401020301100001010403020102030302030112000d011400040102000501ff002c000a01150001010a0201011300010102020904010301011100010101020104010209040103010201010f000101010201040c020104010201010d000101010201040302090401030204010201010c00010101020104030203050104010503040105010301060104010202010b000101010201040102010401020305010401050304010501030206010302010b00010101020104020501020305010401050304010501030206010302010b00010101020104020501020305010401050304010501030206010302010c000101010201040105060205030106010303010d0001010102010401020906020303010f000101020202050104010501040405010303011100010105020503030113000c0115000a01ff00100002011d000101020201011b0001010402010119000101050201040101170001010102020402020205010401011500010101020204040202050104010113000101010202040402010501020205010401011100010107020204010504030101100001010305030204040103030502010f00010103040202040401050103030402010f000101030501020105030402050102030502010f000101030501030102040301020103030502010f00010102050203060602020205020110000101010501030806010201050301110001010a05030113000c0115000a01b400060112000601010001010402010302010c00060101030402010101030106010401020104010302010c000101050201030304010601010106010501020204010302010c00010101020304010601030204010201040106010101040305010202010c0001010102010402020104010602050104010201050106010502040106010202010c000101010201050202010401050106030501040406010203010c00010101020106020501020104020603050104020605010d00020101060405030602040306010301010e000101030201060105010601050104040601050306010301010d0001010102030404060105040601050206010302010c00010101020104020201040a060105010302010c0001010102010501040202010504060203020601050104010302010c00010101030106030501040105010601030301050202010d00010101030106030501020206010309010e0001010103010603050104020601030101010006010f00010101030206010501040306010301011600010101030306010501060105010202011600010101030406010501020201170001010103020601050104010202011800010105020201190007011a0006018d0002011d000101020201011b000101010202050103010119000101010203040105010303011600010101020204010201060103010102030101140001010103020601020106010301010103010401060103010112000101010303060104020602030102010501060102010110000101010201030104010602040105030601050206010202010e000101020202040105010601050106020201050206010203010d000101020202040102010502060102030401050206020301010d000101020201040202010502060304010201050106010201040106010301010d0001010103030501060304020202050106020401050106010201010d0001010203010201060104010501060305030602050106010202010d0001010103020404060102010401050406020202010c0001010103030401050306010202040102020602040106010201010c00010101030104020201050106010402050104020201060204010201050106010201010c00010101030205020602050106020502060104020201050106010202010c00010101030206010301060204050602050206010202010d0001010303020401020105030601030306010203010e0002010103010401020205010602030101030203011000010101030106020502060102070111000101010305060102020101000301130001010103030601020301180001010103020203011a0005011c000301f10003011b000201020202011800020102020204010301011600020102020404010302011400010102020104020202040205020113000101010202040302010403050103010113000101010202040202030502060103020113000101010202040205020602050103020113000101010203050206030501030201130001010102070601030301130001010102010502060202010401060103020115000101010301060202010401050103030115000101010301060204020501020201160001010103010601040205020601020101160001010103010501060105030601040102010116000101010301050206010303040102010115000101010302050103010105020101150001010303080115000a0117000301c8000701190001010602010118000101010204040105010301011700010101020104020202050106010301011600010101020104020203050106010301011500010101020104010501040102030501060103010114000101010201040205010401020104020501060103010114000201020602050104020502060103010112000101010201040202020601050102010503060103010111000101010201040202010502060305030601030101100001010102030401020105030601050306010302010f00010101020205020401020105030601050206010202010f000101010203050204010205060105010202011000010101030206020501040105020601010105010401020201110001010103020602050104010502060101020202011200010101030306020502060501130001010103050601050102040114000101010303060105010401020201170001010303030202011800080119000701450001021600010209000202140001020900010201030d00010203000102010001020103010201000102000208000102130001021f0001023f0001027a0001021b000102020003021e0001023f000102690001025f0001021c0001020100010201030102010001021c0001023f000102e50007011900010104020203010118000101010204040105010301011700010101020404010501060103050112000101010203040102010502060101040201011100010101020304010202050106010101020304010301011000010101020104020205050106020401020105010301011000010101030206050501060104020201050106010301011000010101030306030502060305020601030101100001010103050601050406010502060103010110000101010201050906010502060103010110000101010201050306010402050306010501060105010301011000010101020105020601040105010206060105010301011000010101020206010502020606010501020201100001010103040601050106010501030305010202011100010101030506010501010103030202011200010101030306020501020601130001010303030206011400080119000701ce0005011a000101050201011800010101020504010201011600010101020104030202050104010201011400010101020104030201040305010401020101120001010c0201030101110001010102020501020506010202050103020110000101010202050102050501020205010302011000010101020204010205050102020501030201100001010102020501020504010202050103020110000101010302040102050501020205010302011000010101030205010305040103020501030201100001010103020501030504010302050103020110000101010302050103050401030204010302011000010101030205010305050103020501030201110001010b0303011200010101030506020401020301140001010103030602040102030116000101030302020301180007011a000501

Deployed Bytecode

0x60806040526004361061025c5760003560e01c8063871fd9cc11610144578063b88d4fde116100b6578063e268e4d31161007a578063e268e4d31461072c578063e489d5101461074c578063e985e9c514610762578063ef87d617146107ab578063f2fde38b146107cb578063fb39b7b2146107eb57600080fd5b8063b88d4fde14610673578063b8df9a7514610693578063c321118c146106b3578063c683630d146106d3578063c87b56dd1461070c57600080fd5b80639da3f8fd116101085780639da3f8fd146105c0578063a035b1fe146105e7578063a22cb465146105fd578063a8ce886e1461061d578063aa66797b1461063d578063b5adce3f1461065357600080fd5b8063871fd9cc146105275780638da5cb5b1461053d57806391b7f5ed1461055b57806395d89b411461057b5780639b19251a1461059057600080fd5b80633d6dc6cf116101dd578063515f765b116101a1578063515f765b1461047f57806351cff8d9146104925780636352211e146104b257806369ba1a75146104d257806370a08231146104f2578063715018a61461051257600080fd5b80633d6dc6cf146103d357806342842e0e1461040957806344aa1ee514610429578063453c2310146104495780634f6ccce71461045f57600080fd5b806318160ddd1161022457806318160ddd1461032857806320fc7eb21461034657806323b872dd146103735780632f745c59146103935780633bef6a93146103b357600080fd5b806301ffc9a71461026157806306fdde0314610297578063081812fc146102b9578063095ea7b3146102e657806311b97a0314610308575b600080fd5b34801561026d57600080fd5b5061028161027c366004612396565b6107fe565b60405161028e91906123c1565b60405180910390f35b3480156102a357600080fd5b506102ac610829565b60405161028e919061242d565b3480156102c557600080fd5b506102d96102d4366004612456565b6108bb565b60405161028e9190612491565b3480156102f257600080fd5b506103066103013660046124b3565b6108e2565b005b34801561031457600080fd5b50610306610323366004612456565b610971565b34801561033457600080fd5b506008545b60405161028e91906124f6565b34801561035257600080fd5b50610339610361366004612504565b60126020526000908152604090205481565b34801561037f57600080fd5b5061030661038e366004612525565b610986565b34801561039f57600080fd5b506103396103ae3660046124b3565b6109b7565b3480156103bf57600080fd5b506102ac6103ce366004612456565b610a09565b3480156103df57600080fd5b506103396103ee366004612504565b6001600160a01b031660009081526012602052604090205490565b34801561041557600080fd5b50610306610424366004612525565b610ba4565b34801561043557600080fd5b506102ac610444366004612456565b610bbf565b34801561045557600080fd5b5061033960115481565b34801561046b57600080fd5b5061033961047a366004612456565b610c6b565b61030661048d366004612456565b610cb9565b34801561049e57600080fd5b506103066104ad366004612504565b610dc7565b3480156104be57600080fd5b506102d96104cd366004612456565b610e50565b3480156104de57600080fd5b506103066104ed366004612456565b610e85565b3480156104fe57600080fd5b5061033961050d366004612504565b610ec3565b34801561051e57600080fd5b50610306610f07565b34801561053357600080fd5b5061033960105481565b34801561054957600080fd5b50600a546001600160a01b03166102d9565b34801561056757600080fd5b50610306610576366004612456565b610f1b565b34801561058757600080fd5b506102ac610f28565b34801561059c57600080fd5b506102816105ab366004612504565b60136020526000908152604090205460ff1681565b3480156105cc57600080fd5b50600f546105da9060ff1681565b60405161028e91906125be565b3480156105f357600080fd5b50610339600e5481565b34801561060957600080fd5b506103066106183660046125df565b610f37565b34801561062957600080fd5b506102ac610638366004612456565b610f46565b34801561064957600080fd5b50610339600d5481565b34801561065f57600080fd5b5061030661066e366004612664565b610f56565b34801561067f57600080fd5b5061030661068e3660046127a3565b610fd5565b34801561069f57600080fd5b506102ac6106ae366004612456565b611007565b3480156106bf57600080fd5b506102ac6106ce366004612456565b611017565b3480156106df57600080fd5b506102816106ee366004612504565b6001600160a01b031660009081526013602052604090205460ff1690565b34801561071857600080fd5b506102ac610727366004612456565b6114da565b34801561073857600080fd5b50610306610747366004612456565b611513565b34801561075857600080fd5b50610339600c5481565b34801561076e57600080fd5b5061028161077d366004612822565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b3480156107b757600080fd5b506102ac6107c6366004612855565b611520565b3480156107d757600080fd5b506103066107e6366004612504565b611564565b6103066107f9366004612456565b61159b565b60006001600160e01b0319821663780e9d6360e01b1480610823575061082382611635565b92915050565b6060600080546108389061288d565b80601f01602080910402602001604051908101604052809291908181526020018280546108649061288d565b80156108b15780601f10610886576101008083540402835291602001916108b1565b820191906000526020600020905b81548152906001019060200180831161089457829003601f168201915b5050505050905090565b60006108c682611685565b506000908152600460205260409020546001600160a01b031690565b60006108ed82610e50565b9050806001600160a01b0316836001600160a01b0316141561092a5760405162461bcd60e51b8152600401610921906128fb565b60405180910390fd5b336001600160a01b03821614806109465750610946813361077d565b6109625760405162461bcd60e51b815260040161092190612965565b61096c83836116b9565b505050565b610979611727565b6109833382611751565b50565b61099033826117ba565b6109ac5760405162461bcd60e51b8152600401610921906129bf565b61096c838383611839565b60006109c283610ec3565b82106109e05760405162461bcd60e51b815260040161092190612a17565b506001600160a01b03919091166000908152600660209081526040808320938352929052205490565b606060008230604051602001610a20929190612a4f565b6040516020818303038152906040528051906020012060001c90506000610a4f8261303960168054905061196e565b90506000610a66836241fbf760148054905061196e565b90506000610a7d846201346a60178054905061196e565b90506000610a918563358eafb3600461196e565b90506000610a9e88611017565b90506000610aab896119b1565b610abe610ab9886001612a8b565b6119b1565b610acc610ab9886001612a8b565b610ada610ab9886001612a8b565b6008891115610b04576040518060400160405280600381526020016252617760e81b815250610b21565b6040518060400160405280600381526020016210dd5d60ea1b8152505b8715610b4a576040518060400160405280600581526020016446616c736560d81b815250610b68565b604051806040016040528060048152602001635472756560e01b8152505b610b7188611a4e565b604051602001610b879796959493929190612bb6565b60408051601f198184030181529190529998505050505050505050565b61096c83838360405180602001604052806000815250610fd5565b60158181548110610bcf57600080fd5b906000526020600020016000915090508054610bea9061288d565b80601f0160208091040260200160405190810160405280929190818152602001828054610c169061288d565b8015610c635780601f10610c3857610100808354040283529160200191610c63565b820191906000526020600020905b815481529060010190602001808311610c4657829003601f168201915b505050505081565b6000610c7660085490565b8210610c945760405162461bcd60e51b815260040161092190612e66565b60088281548110610ca757610ca7612e76565b90600052602060002001549050919050565b610cc1611bb4565b6001600f5460ff166002811115610cda57610cda612575565b14610cf75760405162461bcd60e51b815260040161092190612eb8565b3360009081526013602052604090205460ff16610d265760405162461bcd60e51b815260040161092190612ee5565b60115433600090815260126020526040902054610d44908390612a8b565b1115610d625760405162461bcd60e51b815260040161092190612f21565b600e54610d6f9082612f31565b341015610d8e5760405162461bcd60e51b815260040161092190612f70565b3360009081526012602052604081208054839290610dad908490612a8b565b90915550610dbd90503382611751565b6109836001600b55565b610dcf611727565b60004790506000826001600160a01b031682604051610ded90612f80565b60006040518083038185875af1925050503d8060008114610e2a576040519150601f19603f3d011682016040523d82523d6000602084013e610e2f565b606091505b505090508061096c5760405162461bcd60e51b815260040161092190612fb0565b6000818152600260205260408120546001600160a01b0316806108235760405162461bcd60e51b815260040161092190612ff4565b610e8d611727565b806002811115610e9f57610e9f612575565b600f805460ff19166001836002811115610ebb57610ebb612575565b021790555050565b60006001600160a01b038216610eeb5760405162461bcd60e51b81526004016109219061304a565b506001600160a01b031660009081526003602052604090205490565b610f0f611727565b610f196000611bde565b565b610f23611727565b600e55565b6060600180546108389061288d565b610f42338383611c30565b5050565b60168181548110610bcf57600080fd5b610f5e611727565b60005b82811015610fcf578160136000868685818110610f8057610f80612e76565b9050602002016020810190610f959190612504565b6001600160a01b031681526020810191909152604001600020805460ff191691151591909117905580610fc78161305a565b915050610f61565b50505050565b610fdf33836117ba565b610ffb5760405162461bcd60e51b8152600401610921906129bf565b610fcf84848484611cd3565b60148181548110610bcf57600080fd5b60606000823060405160200161102e929190612a4f565b6040516020818303038152906040528051906020012060001c9050600061105d8261303960168054905061196e565b90506000611074836241fbf760148054905061196e565b9050600061108b846201346a60178054905061196e565b905060006110a2856206a64460158054905061196e565b905060006110b68663358eafb3600461196e565b90506000601686815481106110cd576110cd612e76565b9060005260206000200180546110e29061288d565b80601f016020809104026020016040519081016040528092919081815260200182805461110e9061288d565b801561115b5780601f106111305761010080835404028352916020019161115b565b820191906000526020600020905b81548152906001019060200180831161113e57829003601f168201915b50505050509050806112fe6014878154811061117957611179612e76565b90600052602060002001805461118e9061288d565b80601f01602080910402602001604051908101604052809291908181526020018280546111ba9061288d565b80156112075780601f106111dc57610100808354040283529160200191611207565b820191906000526020600020905b8154815290600101906020018083116111ea57829003601f168201915b50505050506017878154811061121f5761121f612e76565b90600052602060002001805480602002602001604051908101604052809291908181526020016000905b828210156112f55783829060005260206000200180546112689061288d565b80601f01602080910402602001604051908101604052809291908181526020018280546112949061288d565b80156112e15780601f106112b6576101008083540402835291602001916112e1565b820191906000526020600020905b8154815290600101906020018083116112c457829003601f168201915b505050505081526020019060010190611249565b50505050611d06565b831561131957604051806020016040528060008152506114ab565b6114ab6015868154811061132f5761132f612e76565b9060005260206000200180546113449061288d565b80601f01602080910402602001604051908101604052809291908181526020018280546113709061288d565b80156113bd5780601f10611392576101008083540402835291602001916113bd565b820191906000526020600020905b8154815290600101906020018083116113a057829003601f168201915b5050505050601788815481106113d5576113d5612e76565b90600052602060002001805480602002602001604051908101604052809291908181526020016000905b828210156112f557838290600052602060002001805461141e9061288d565b80601f016020809104026020016040519081016040528092919081815260200182805461144a9061288d565b80156114975780601f1061146c57610100808354040283529160200191611497565b820191906000526020600020905b81548152906001019060200180831161147a57829003601f168201915b5050505050815260200190600101906113ff565b6040516020016114bd93929190613075565b604051602081830303815290604052975050505050505050919050565b60606114ed6114e883610a09565b611a4e565b6040516020016114fd91906131b3565b6040516020818303038152906040529050919050565b61151b611727565b601155565b6017828154811061153057600080fd5b90600052602060002001818154811061154857600080fd5b90600052602060002001600091509150508054610bea9061288d565b61156c611727565b6001600160a01b0381166115925760405162461bcd60e51b815260040161092190613228565b61098381611bde565b6115a3611bb4565b600081116115c35760405162461bcd60e51b81526004016109219061325c565b601154336000908152601260205260409020546115e1908390612a8b565b11156115ff5760405162461bcd60e51b815260040161092190612f21565b6002600f5460ff16600281111561161857611618612575565b14610d625760405162461bcd60e51b815260040161092190613290565b60006001600160e01b031982166380ac58cd60e01b148061166657506001600160e01b03198216635b5e139f60e01b145b8061082357506301ffc9a760e01b6001600160e01b0319831614610823565b6000818152600260205260409020546001600160a01b03166109835760405162461bcd60e51b815260040161092190612ff4565b600081815260046020526040902080546001600160a01b0319166001600160a01b03841690811790915581906116ee82610e50565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b600a546001600160a01b03163314610f195760405162461bcd60e51b8152600401610921906132d2565b600c54816010546117629190612a8b565b11156117805760405162461bcd60e51b815260040161092190613300565b60005b8181101561096c576117a88360106000815461179e9061305a565b9182905550611e1f565b806117b28161305a565b915050611783565b6000806117c683610e50565b9050806001600160a01b0316846001600160a01b0316148061180d57506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff165b806118315750836001600160a01b0316611826846108bb565b6001600160a01b0316145b949350505050565b826001600160a01b031661184c82610e50565b6001600160a01b0316146118725760405162461bcd60e51b815260040161092190613352565b6001600160a01b0382166118985760405162461bcd60e51b8152600401610921906133a3565b6118a58383836001611f28565b826001600160a01b03166118b882610e50565b6001600160a01b0316146118de5760405162461bcd60e51b815260040161092190613352565b600081815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0387811680865260038552838620805460001901905590871680865283862080546001019055868652600290945282852080549092168417909155905184937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b60008084846040516020016119849291906133b3565b60408051601f19818403018152919052805160209091012090506119a883826133ef565b95945050505050565b606060006119be8361200e565b600101905060008167ffffffffffffffff8111156119de576119de6126b5565b6040519080825280601f01601f191660200182016040528015611a08576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084611a4157611a46565b611a12565b509392505050565b6060815160001415611a6e57505060408051602081019091526000815290565b60006040518060600160405280604081526020016137256040913990506000600384516002611a9d9190612a8b565b611aa79190613403565b611ab2906004612f31565b90506000611ac1826020612a8b565b67ffffffffffffffff811115611ad957611ad96126b5565b6040519080825280601f01601f191660200182016040528015611b03576020820181803683370190505b509050818152600183018586518101602084015b81831015611b6f576003830192508251603f8160121c168501518253600182019150603f81600c1c168501518253600182019150603f8160061c168501518253600182019150603f8116850151825350600101611b17565b600389510660018114611b895760028114611b9a57611ba6565b613d3d60f01b600119830152611ba6565b603d60f81b6000198301525b509398975050505050505050565b6002600b541415611bd75760405162461bcd60e51b81526004016109219061344b565b6002600b55565b600a80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b816001600160a01b0316836001600160a01b03161415611c625760405162461bcd60e51b81526004016109219061348f565b6001600160a01b0383811660008181526005602090815260408083209487168084529490915290819020805460ff1916851515179055517f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3190611cc69085906123c1565b60405180910390a3505050565b611cde848484611839565b611cea848484846120e6565b610fcf5760405162461bcd60e51b8152600401610921906134ee565b6060806000805b8551811015611e15576000868281518110611d2a57611d2a612e76565b016020015160f81c9050600087611d42846001612a8b565b81518110611d5257611d52612e76565b016020015160f81c90508015611df0576000611d6f6020866133ef565b90506000611d7e602087613403565b90506000898460ff1681518110611d9757611d97612e76565b6020026020010151905087611dae8660ff166119b1565b611dba8560ff166119b1565b611dc68560ff166119b1565b84604051602001611ddb9594939291906134fe565b60405160208183030381529060405297505050505b611dfd60ff831685612a8b565b93505050806002611e0e9190612a8b565b9050611d0d565b5090949350505050565b6001600160a01b038216611e455760405162461bcd60e51b8152600401610921906135d1565b6000818152600260205260409020546001600160a01b031615611e7a5760405162461bcd60e51b815260040161092190613615565b611e88600083836001611f28565b6000818152600260205260409020546001600160a01b031615611ebd5760405162461bcd60e51b815260040161092190613615565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6001811115611f495760405162461bcd60e51b815260040161092190613677565b816001600160a01b038516611fa557611fa081600880546000838152600960205260408120829055600182018355919091527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30155565b611fc8565b836001600160a01b0316856001600160a01b031614611fc857611fc885826121e4565b6001600160a01b038416611fe457611fdf81612281565b612007565b846001600160a01b0316846001600160a01b031614612007576120078482612330565b5050505050565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b831061204d5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310612079576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061209757662386f26fc10000830492506010015b6305f5e10083106120af576305f5e100830492506008015b61271083106120c357612710830492506004015b606483106120d5576064830492506002015b600a83106108235760010192915050565b60006001600160a01b0384163b156121d957604051630a85bd0160e11b81526001600160a01b0385169063150b7a029061212a903390899088908890600401613687565b6020604051808303816000875af1925050508015612165575060408051601f3d908101601f19168201909252612162918101906136d6565b60015b6121bf573d808015612193576040519150601f19603f3d011682016040523d82523d6000602084013e612198565b606091505b5080516121b75760405162461bcd60e51b8152600401610921906134ee565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050611831565b506001949350505050565b600060016121f184610ec3565b6121fb91906136f7565b60008381526007602052604090205490915080821461224e576001600160a01b03841660009081526006602090815260408083208584528252808320548484528184208190558352600790915290208190555b5060009182526007602090815260408084208490556001600160a01b039094168352600681528383209183525290812055565b600854600090612293906001906136f7565b600083815260096020526040812054600880549394509092849081106122bb576122bb612e76565b9060005260206000200154905080600883815481106122dc576122dc612e76565b60009182526020808320909101929092558281526009909152604080822084905585825281205560088054806123145761231461370e565b6001900381819060005260206000200160009055905550505050565b600061233b83610ec3565b6001600160a01b039093166000908152600660209081526040808320868452825280832085905593825260079052919091209190915550565b6001600160e01b031981165b811461098357600080fd5b803561082381612374565b6000602082840312156123ab576123ab600080fd5b6000611831848461238b565b8015155b82525050565b6020810161082382846123b7565b60005b838110156123ea5781810151838201526020016123d2565b83811115610fcf5750506000910152565b6000612405825190565b80845260208401935061241c8185602086016123cf565b601f01601f19169290920192915050565b6020808252810161243e81846123fb565b9392505050565b80612380565b803561082381612445565b60006020828403121561246b5761246b600080fd5b6000611831848461244b565b60006001600160a01b038216610823565b6123bb81612477565b602081016108238284612488565b61238081612477565b80356108238161249f565b600080604083850312156124c9576124c9600080fd5b60006124d585856124a8565b92505060206124e68582860161244b565b9150509250929050565b806123bb565b6020810161082382846124f0565b60006020828403121561251957612519600080fd5b600061183184846124a8565b60008060006060848603121561253d5761253d600080fd5b600061254986866124a8565b935050602061255a868287016124a8565b925050604061256b8682870161244b565b9150509250925092565b634e487b7160e01b600052602160045260246000fd5b6003811061098357610983612575565b806125a58161258b565b919050565b60006108238261259b565b6123bb816125aa565b6020810161082382846125b5565b801515612380565b8035610823816125cc565b600080604083850312156125f5576125f5600080fd5b600061260185856124a8565b92505060206124e6858286016125d4565b60008083601f84011261262757612627600080fd5b50813567ffffffffffffffff81111561264257612642600080fd5b60208301915083602082028301111561265d5761265d600080fd5b9250929050565b60008060006040848603121561267c5761267c600080fd5b833567ffffffffffffffff81111561269657612696600080fd5b6126a286828701612612565b9350935050602061256b868287016125d4565b634e487b7160e01b600052604160045260246000fd5b601f19601f830116810181811067ffffffffffffffff821117156126f1576126f16126b5565b6040525050565b600061270360405190565b90506125a582826126cb565b600067ffffffffffffffff821115612729576127296126b5565b601f19601f83011660200192915050565b82818337506000910152565b60006127596127548461270f565b6126f8565b90508281526020810184848401111561277457612774600080fd5b611a4684828561273a565b600082601f83011261279357612793600080fd5b8135611831848260208601612746565b600080600080608085870312156127bc576127bc600080fd5b60006127c887876124a8565b94505060206127d9878288016124a8565b93505060406127ea8782880161244b565b925050606085013567ffffffffffffffff81111561280a5761280a600080fd5b6128168782880161277f565b91505092959194509250565b6000806040838503121561283857612838600080fd5b600061284485856124a8565b92505060206124e6858286016124a8565b6000806040838503121561286b5761286b600080fd5b60006124d5858561244b565b634e487b7160e01b600052602260045260246000fd5b6002810460018216806128a157607f821691505b602082108114156128b4576128b4612877565b50919050565b602181526000602082017f4552433732313a20617070726f76616c20746f2063757272656e74206f776e658152603960f91b602082015291505b5060400190565b60208082528101610823816128ba565b603d81526000602082017f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f81527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c000000602082015291506128f4565b602080825281016108238161290b565b602d81526000602082017f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6581526c1c881bdc88185c1c1c9bdd9959609a1b602082015291506128f4565b6020808252810161082381612975565b602b81526000602082017f455243373231456e756d657261626c653a206f776e657220696e646578206f7581526a74206f6620626f756e647360a81b602082015291506128f4565b60208082528101610823816129cf565b60006108238260601b90565b600061082382612a27565b6123bb612a4a82612477565b612a33565b6000612a5b82856124f0565b602082019150612a6b8284612a3e565b5060140192915050565b634e487b7160e01b600052601160045260246000fd5b60008219821115612a9e57612a9e612a75565b500190565b6000612aad825190565b612abb8185602086016123cf565b9290920192915050565b61088b60f21b815260005b5060020190565b7f7b2274726169745f74797065223a224261636b67726f756e64222c202276616c8152643ab2911d1160d91b602082015260005b5060250190565b7f227d2c7b2274726169745f74797065223a2250616c65747465222c202276616c8152643ab2911d1160d91b60208201526000612b0b565b7f227d2c7b2274726169745f74797065223a224f6e636861696e222c202276616c8152643ab2911d1160d91b60208201526000612b0b565b635472756560e01b815260005b5060040190565b63089f574b60e21b81526000612b8f565b61227d60f01b81526000612ad0565b6e7b226e616d65223a202247656d202360881b8152600f016000612bda828a612aa3565b9150612be582612ac5565b7f226465736372697074696f6e223a2022313030252066756c6c79206f6e63686181527f696e2067656d73206f66206f70756c656e6365206f6e2048797065726c69717560208201527f69642045564d2e204e6f207574696c6974792c206e6f20726f61646d61702c2060408201527f6a757374206f6f6f68207368696e792067656d732e204372656174656420627960608201527f206461696c6f66726f6720616e6420676f6f70676f6f705f6172742e222c000060808201526d2261747472696275746573223a5b60901b609e82015260ac019150612cc582612ad7565b9150612cd18289612aa3565b7f227d2c7b2274726169745f74797065223a2247656d222c202276616c7565223a8152601160f91b60208201526021019150612d0d8288612aa3565b9150612d1882612b12565b9150612d248287612aa3565b7f227d2c7b2274726169745f74797065223a22526566696e656d656e74222c20228152673b30b63ab2911d1160c11b60208201526028019150612d678286612aa3565b7f227d2c7b2274726169745f74797065223a225368696e79222c202276616c7565815262111d1160e91b60208201526023019150612da58285612aa3565b9150612db082612b4a565b9150612dbb82612b82565b9150612dc682612b96565b7f22696d616765223a2022646174613a696d6167652f7376672b786d6c3b626173815263194d8d0b60e21b60208201526024019150612e058284612aa3565b9150612e1082612ba7565b9998505050505050505050565b602c81526000602082017f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f81526b7574206f6620626f756e647360a01b602082015291506128f4565b6020808252810161082381612e1d565b634e487b7160e01b600052603260045260246000fd5b601281526000602082017115da1a5d195b1a5cdd08191a5cd8589b195960721b815291505b5060200190565b6020808252810161082381612e8c565b6006815260006020820165139bdd0815d360d21b81529150612eb1565b6020808252810161082381612ec8565b601581526000602082017415d85b1b195d081b1a5b5a5d08195e18d959591959605a1b81529150612eb1565b6020808252810161082381612ef5565b6000816000190483118215151615612f4b57612f4b612a75565b500290565b600981526000602082016842616420707269636560b81b81529150612eb1565b6020808252810161082381612f50565b600081610823565b601181526000602082017015d2551211149055d05317d19052531151607a1b81529150612eb1565b6020808252810161082381612f88565b601881526000602082017f4552433732313a20696e76616c696420746f6b656e204944000000000000000081529150612eb1565b6020808252810161082381612fc0565b602981526000602082017f4552433732313a2061646472657373207a65726f206973206e6f7420612076618152683634b21037bbb732b960b91b602082015291506128f4565b6020808252810161082381613004565b600060001982141561306e5761306e612a75565b5060010190565b7f3c7376672076657273696f6e3d22312e302220786d6c6e733d22687474703a2f81527f2f7777772e77332e6f72672f323030302f737667222077696474683d2235313260208201527f22206865696768743d22353132222076696577426f783d22302030203332203360408201527f32222073686170652d72656e646572696e673d2263726973704564676573222060608201527f7072657365727665417370656374526174696f3d22784d6964594d6964206d6560808201527f6574223e203c726563742077696474683d22333222206865696768743d22333260a08201526711103334b6361e9160c11b60c082015260c80160006131768286612aa3565b631110179f60e11b8152600401915061318f8285612aa3565b915061319b8284612aa3565b651e17b9bb339f60d11b815260060195945050505050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c0000008152601d01600061243e8284612aa3565b602681526000602082017f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181526564647265737360d01b602082015291506128f4565b60208082528101610823816131e5565b600d81526000602082016c139bdb8b5e995c9bc81b5a5b9d609a1b81529150612eb1565b6020808252810161082381613238565b600d81526000602082016c135a5b9d08191a5cd8589b1959609a1b81529150612eb1565b602080825281016108238161326c565b60208082527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657291019081526000612eb1565b60208082528101610823816132a0565b600781526000602082016604f7665726361760cc1b81529150612eb1565b60208082528101610823816132e2565b602581526000602082017f4552433732313a207472616e736665722066726f6d20696e636f72726563742081526437bbb732b960d91b602082015291506128f4565b6020808252810161082381613310565b602481526000602082017f4552433732313a207472616e7366657220746f20746865207a65726f206164648152637265737360e01b602082015291506128f4565b6020808252810161082381613362565b60006133bf82856124f0565b6020820191506133cf82846124f0565b5060200192915050565b634e487b7160e01b600052601260045260246000fd5b6000826133fe576133fe6133d9565b500690565b600082613412576134126133d9565b500490565b601f81526000602082017f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0081529150612eb1565b6020808252810161082381613417565b601981526000602082017f4552433732313a20617070726f766520746f2063616c6c65720000000000000081529150612eb1565b602080825281016108238161345b565b603281526000602082017f4552433732313a207472616e7366657220746f206e6f6e20455243373231526581527131b2b4bb32b91034b6b83632b6b2b73a32b960711b602082015291506128f4565b602080825281016108238161349f565b600061350a8288612aa3565b6c1e3932b1ba103bb4b23a341e9160991b8152600d01915061352c8287612aa3565b6f11103432b4b3b43a1e911891103c1e9160811b815260100191506135518286612aa3565b6411103c9e9160d91b8152600501915061356b8285612aa3565b6711103334b6361e9160c11b815260080191506135888284612aa3565b6211179f60e91b8152600301979650505050505050565b60208082527f4552433732313a206d696e7420746f20746865207a65726f206164647265737391019081526000612eb1565b602080825281016108238161359f565b601c81526000602082017f4552433732313a20746f6b656e20616c7265616479206d696e7465640000000081529150612eb1565b60208082528101610823816135e1565b603581526000602082017f455243373231456e756d657261626c653a20636f6e7365637574697665207472815274185b9cd9995c9cc81b9bdd081cdd5c1c1bdc9d1959605a1b602082015291506128f4565b6020808252810161082381613625565b608081016136958287612488565b6136a26020830186612488565b6136af60408301856124f0565b81810360608301526136c181846123fb565b9695505050505050565b805161082381612374565b6000602082840312156136eb576136eb600080fd5b600061183184846136cb565b60008282101561370957613709612a75565b500390565b634e487b7160e01b600052603160045260246000fdfe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2fa2646970667358221220182078e7294249e14e8d3f84d505b3b8ccab4e4fc1c317fb733439f61d55d1f964736f6c634300080c0033

[ 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.