ETH Price: $3,913.89 (+0.14%)

Token

Cypher on-chain: EP (BARS)
 

Overview

Max Total Supply

22 BARS

Holders

19

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A
Filtered by Token Holder
j4ck.eth
Balance
1 BARS
0xDFe8beeE223412F316baf2968B17527D6EbA29F1
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information
# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
Cypher

Compiler Version
v0.8.6+commit.11564f7e

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, None license
File 1 of 13 : cypher.sol
pragma solidity 0.8.6;

import "ERC721.sol";
import "Ownable.sol";
import "ReentrancyGuard.sol";
import "Strings.sol";
import "Base64.sol";

/**
       //////////////////   \\\            ///    ///////////\\\    ///         \\\    //////////////   ////////////\\\
       /////////////////     \\\          ///    /////////////\\\   ///          ///   /////////////    /////////////\\\
       ///          ///       \\\        ///     ///          ///   ///          ///   ///              ///          ///
       ///         ///         \\\      ///      ///         ///    ///          ///   ///              ///         ///
       ///        ///           \\\    ///       ///        ///     ///          ///   ///              ///        ///
       ///                       \\\  ///        ///       ///      ///          ///   ///              ///       ///
       ///                        \\v///         ////////////       ////////////////   //////////////   ////////////
       ///                         \///          ///////////        ////////////////   /////////////    ///////////
       ///         \\\             ///           ///                ///          ///   ///              ///      \\\
       ///          \\\           ///            ///                ///          ///   ///              ///       \\\
       ///           \\\         ///             ///                ///          ///   ///         ///  ///        \\\
       ///\\\\\\\\\\\\\\\       ///              ///                ///          ///   //////////////   ///         \\\
       ///\\\\\\\\\\\\\\\\     ///               ///                ///         ///    /////////////    ///          \\\

       "Personal worth is not what a person is worth
       I can give a dollar to every person on Earth"
       - Kanye West, DONDA, Pure Souls

       "So nerdy but the flow wordy
       Brain-freezin' with the flow slurpie"
       - Childish Gambino, Sway in the Morning, Freestyle

       "Don't get offended by this, but that's the market y'all missed
       That's the target I'll hit and that's the heart of my pitch
       I wanna do this whole thing different"
       - Lil Dicky, Professional Rapper, Professional Rapper

       CYPHER ON-CHAIN
       2021
**/

contract Cypher is ERC721, ReentrancyGuard, Ownable {
    uint256 public totalSupply;

    // Track, album, bars length
    uint256 public constant trackLength = 20;
    uint256 public constant albumLength = 10;
    uint256 public constant maxSupply = trackLength*albumLength;
    uint256 private constant barsPerBlock = 4;
    uint256 private immutable maxCharactersPerBar = 40;
    uint256 private immutable minCharactersPerBar = 10;
    
    // Time related constaints
    uint256 public blockStartTime;
    uint256 public albumStartTime;
    uint256 public blockInterval = 5*60;
    uint256 public trackInterval = 1 days + 300;

    // Storage of bars and writers
    mapping(uint256 => string) public tokenIdToBars;
    mapping(uint256 => address) public tokenIdToWriter;

    constructor() public ERC721("Cypher on-chain: EP", "BARS") Ownable() { 
    }

    /******************/
    /*   MINT LOGIC   */
    /******************/
    function mint(string memory user_bars) payable external nonReentrant {
        require(totalSupply < maxSupply, 'Cypher: all blocks minted');
        require(msg.value == 0.01 ether, "Cypher: 0.01 ETH to mint");
        require(balanceOf(msg.sender) <= 2, "Cypher: max 3 per wallet");
        require(block.timestamp >= blockStartTime + blockInterval, "Cypher: next block not yet available");
        require(block.timestamp >= (albumStartTime + (totalSupply / trackLength * trackInterval)), 'Cypher: next track not yet available.');
        
        if(totalSupply == 0){
            require(msg.sender == owner(), "Cypher: only the owner can mint the first block in the first track.");
            albumStartTime = block.timestamp;
        } else {
            require(tokenIdToWriter[totalSupply] != msg.sender, "Cypher: same wallet can't mint twice in a row");
        }

        _cypherValidations(user_bars);
        _mint(msg.sender, ++totalSupply);
        
        tokenIdToBars[totalSupply] = user_bars;
        tokenIdToWriter[totalSupply] = msg.sender;
        blockStartTime = block.timestamp;
    }

    function _cypherValidations(string memory user_bars) internal view {
        bytes memory _bytes = abi.encodePacked(bytes(user_bars), '\n');

        uint256 barCount;
        uint256 lastBarStart;
        uint256 lastLastBarStart;
        uint256 lastBarEnd;
        bool isSpaceOrNewline = false;
        bool prevPrevIsSpaceOrNewLine = true;
        bool prevIsSpaceOrNewline = true;
        bool prevIsComma = false;
        bytes1 char;
        uint8 charInt;

        // To save gas, all validation happens in the same for loop
        for (uint256 i = 0; i < _bytes.length; i++){
            char = _bytes[i];
            charInt = uint8(char);
            isSpaceOrNewline = (charInt == 32 || charInt == 10);

            // Validation: No special characters
            if (! (isSpaceOrNewline || charInt == 44
            || (charInt >= 97 && charInt <= 122) 
            || (charInt >= 65 && charInt <= 90))
                ) {
                require(false, "Cypher: invalid characters");
            }

            // Validation: No adjacent empty characters
            if((isSpaceOrNewline) && (prevIsSpaceOrNewline)){
                require(false, "Cypher: adjacent empty chars");
            }

            if(prevIsComma && !(charInt == 32 && !prevPrevIsSpaceOrNewLine)){
                require(false, "Cypher: comma must be followed by a space and preceded by letters");
            }

            prevIsComma = charInt == 44;

            // Reached new bar: Check per-bar validations
            if (charInt == 10) {
                if (barCount == 0 && totalSupply % trackLength != 0) {
                    require(_rhymeCheckAcrossTokens(totalSupply, _bytes, 0, i-1), "Cypher: first bar must rhyme with prior block's last bar");
                }

                if(barCount == 1 || barCount == 3){
                    require(strictRhymes(_bytes, lastLastBarStart, lastBarEnd-1, _bytes, lastBarStart, i-1), "Cypher: first two bars and last two bars must rhyme");
                }

                barCount = barCount + 1;

                require(i - lastBarStart >= minCharactersPerBar, "Cypher: need >= 10 characters in each bar");
                require(i - lastBarStart <= maxCharactersPerBar, "Cypher: need <= 40 characters in each bar");
                
                lastLastBarStart = lastBarStart;
                lastBarEnd = i;
                lastBarStart = i+1;
            }
            prevPrevIsSpaceOrNewLine = prevIsSpaceOrNewline;
            prevIsSpaceOrNewline = isSpaceOrNewline;
        }

        require(barCount == barsPerBlock, "Cypher: there must be four bars in a block");
    }

    function setBlockInterval(uint256 newInterval) external onlyOwner {
        blockInterval = newInterval;
    }

    function setTrackInterval(uint256 newInterval) external onlyOwner {
        trackInterval = newInterval;
    }

    function withdrawAll() public payable onlyOwner {
        require(payable(_msgSender()).send(address(this).balance));
    }

    function _isVowel(bytes1 char) internal view virtual returns (bool) {
        return (uint8(char) == 97 || uint8(char) == 101 || uint8(char) == 105 || uint8(char) == 111 || uint8(char) == 117 || uint8(char) == 121 || uint8(char) == 65 || uint8(char) == 69 || uint8(char) == 73 || uint8(char) == 79 || uint8(char) == 85 || uint8(char) == 89);
    }

    function lower(bytes1 char) internal view virtual returns (bytes1){
        if(uint8(char) >= 65 && uint8(char) <= 90) {
            return bytes1(uint8(char) + 32);
        } else {
            return char;
        }
    }

    function _rhymeCheckAcrossTokens(uint256 tokenId, bytes memory user_bars, uint256 start, uint256 end) internal view virtual returns (bool) {
        string memory prevBarsString = tokenIdToBars[tokenId];
        bytes memory prev_bars = bytes(prevBarsString);
        uint256 index = prev_bars.length-1;

        while(index >= 0){
            if(prev_bars[index] == '\n'){
                break;
            }
            index -= 1;
        }

        return strictRhymes(prev_bars, index+1, prev_bars.length-1, user_bars, start, end);
    }

    function strictRhymes(bytes memory s1, uint256 s1Start, uint256 s1End, bytes memory s2, uint256 s2Start, uint256 s2End) internal view returns (bool) {
        uint256 s1Ind = s1End;
        uint256 s2Ind = s2End;
        bool vowelSeen = false;
        uint256 consecutive = 0;
        uint256 checked = 0;
        uint256 vowelCt = 10000;
        bool consec = true;

        while(s1Ind >= s1Start && s2Ind >= s2Start){
            bytes1 s1Char = s1[s1Ind];
            bytes1 s2Char = s2[s2Ind];

            if(uint8(s1Char) == 32 || uint8(s2Char) == 32){
                break;
            }

            if(!vowelSeen || vowelSeen && checked < 2) {
                if(lower(s1Char) == lower(s2Char) && consec){
                    consecutive += 1;
                } else {
                    consec = false;
                }
            }

            vowelSeen = vowelSeen || _isVowel(s1Char) || _isVowel(s2Char);

            if(vowelSeen && vowelCt == 10000){
                vowelCt = checked;
            }

            checked += 1;
            
            if(s1Ind == s1Start || s2Ind == s2Start){
                break;
            }
            
            s1Ind -=1;
            s2Ind -=1; 
        }

        if(!vowelSeen || vowelCt == 0){
            return consecutive >= 2 || consecutive >= checked;
        } else {
            return consecutive > vowelCt || consecutive >= checked;
        }
    }

    /*************/
    /* TOKEN URI */
    /*************/
    function tokenURI(uint256 tokenId) public override view returns(string memory) {
        string memory lyric = tokenIdToBars[tokenId];
        string[barsPerBlock] memory bars = splitOnChar(lyric, '\n');
        
        address writer = tokenIdToWriter[tokenId];
        string memory writerAscii = toAsciiString(writer);
        uint256 colorScheme = trackColor(tokenId);

        bytes memory tokenName;
        bytes memory jsonEscapedBars;
        for(uint256 i = 0; i < barsPerBlock; i++){
            tokenName = abi.encodePacked(tokenName, substring(bytes(bars[i]), 0, firstCharIndex(bars[i], ' ')), ' ');
            jsonEscapedBars = abi.encodePacked(jsonEscapedBars, bars[i], i != barsPerBlock - 1 ? '\\n' : '');
        }

        bytes memory jsonSvg = abi.encodePacked(
            '{"name":"',
            '#',
            Strings.toString(tokenId),
            ' - ',
            string(tokenName),
            '", "description":"Cypher on-chain is a smart contract that conducts a rap cypher on Ethereum. Cypher EP is its first collectively written album with 10 tracks. Each track contains 20 blocks, comprised of 4 bars each. A block is an NFT.", ',
            '"bars": "', jsonEscapedBars, '", '
        );

        jsonSvg = abi.encodePacked(jsonSvg, '"attributes": [{',
            '"trait_type": "Track", "value":"',
            Strings.toString(trackNumber(tokenId)),
            '"}, {',
            '"trait_type": "Block", "value":"',
            Strings.toString(trackBlockNumber(tokenId)),
            '"}', 
            ',{',
            '"trait_type": "Writer", "value":"0x',
            writerAscii,
            '"}',
            ']',
            ', "image": "'
            'data:image/svg+xml;base64,',
            Base64.encode(svgImage(tokenId, bars, colorScheme, writer, bytes(writerAscii))),
            '"}'
        );

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

    function svgImage(uint256 tokenId, string[barsPerBlock] memory bars, uint256 colorScheme, address writer, bytes memory writerAscii) internal view returns (bytes memory){
        bytes memory writerAddr = abi.encodePacked(tokenIdToWriter[tokenId]);
        
        return abi.encodePacked(
                '<svg version="1.1" shape-rendering="optimizeSpeed" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"',
                ' x="0px" y="0px" width="300" height="300" viewBox="0 0 10 10" xml:space="preserve">',
                styles(),
                svgGrid(colorScheme, writer),
                svgText(colorScheme, writer, bars),
                abi.encodePacked('<text x="0" y="1" fill="', 
                    string(abi.encodePacked('hsl(', Strings.toString(colorScheme),',95%,40%)')),
                    '">Track: ', Strings.toString(trackNumber(tokenId)), 
                    ' - Block: ', Strings.toString(trackBlockNumber(tokenId)), '</text>'),
                '</svg>'
            );
    }

    function styles() internal view returns (string memory) {   
        bytes memory styles = abi.encodePacked('<style type="text/css">', 
            'rect{width: 1px; height: 1px;}text{font-size: 0.42px; alignment-baseline:text-after-edge}',
            '.c1{fill:#000000;}.writerText{font-size: 0.25px;}</style>');
        return string(styles);
    }

    function trackColor(uint256 tokenId) public view returns (uint256){
        uint16[10] memory colorSchemes = [180, 160, 36, 72, 96, 0, 206, 270, 288, 312];
        uint256 h = trackNumber(tokenId) - 1;
        return colorSchemes[h];
    }

    function trackNumber(uint256 tokenId) public view returns (uint256){
        return (tokenId-1)/(trackLength) + 1;
    }

    function trackBlockNumber(uint256 tokenId) public view returns (uint256){
        return ((tokenId-1) % trackLength) + 1;
    }

    function svgText(uint256 colorScheme, address writer, string[barsPerBlock] memory bars) internal view returns (string memory) {
        bytes memory lyricSvgs;

        for (uint256 i = 0; i < barsPerBlock; i++){
            lyricSvgs = abi.encodePacked(lyricSvgs, '<text x="0" y="', Strings.toString(i+1+1), '" fill="white">', bytes(bars[i]), '</text>');
        }

        lyricSvgs = abi.encodePacked(lyricSvgs, 
            '<text x="0" y="6" fill="', 
            string(abi.encodePacked('hsl(', Strings.toString(colorScheme),',95%,40%)')),
            '" class="writerText">0x', toAsciiString(writer), '</text>');
        return string(lyricSvgs);
    }

    function svgGrid(uint256 colorScheme, address writer) internal view returns (string memory) {
        bytes memory rectString;

        rectString = abi.encodePacked(
            svgLyricCanvasRow(0),
            svgLyricCanvasRow(1),
            svgLyricCanvasRow(2),
            svgLyricCanvasRow(3),
            svgLyricCanvasRow(4),
            svgLyricCanvasRow(5)
        );
        
        for(uint256 i=0; i < barsPerBlock; i++){
            rectString = abi.encodePacked(rectString, svgSignatureRow(abi.encodePacked(writer), 6+i, colorScheme));
        }

        return string(rectString);
    }

    function svgSignatureRow(bytes memory writer, uint256 rowIdx, uint256 colorScheme) internal view returns (string memory) {
        bytes memory rectString;
        uint256 addrInd = 0;
        uint256 stepSize = 2;

        // parts of color band that have less variance nearby
        if(colorScheme == 206 || colorScheme == 312 || colorScheme == 270 || colorScheme == 0 || colorScheme == 144){
            stepSize = 3;
        } else if (colorScheme == 72 || colorScheme == 96) {
            stepSize = 5;
        } else {

        }

        for(uint256 i=0; i<10; i++){
            if (writer.length != 0){
                uint256 addrOffset = rowIdx >= 6 ? (rowIdx-6)*(10/5) : 0;
                uint256 walletInt;

                if (i % 2 == 0){
                    walletInt = uint(uint8(writer[addrInd + addrOffset] >> 4));
                } else {
                    walletInt = uint(uint8(writer[addrInd + addrOffset] & 0x0f));
                    addrInd += 1;
                }
                rectString = abi.encodePacked(rectString, 
                    '<rect x="', Strings.toString(i), '" y="', Strings.toString(rowIdx), 
                    '" fill="',string(abi.encodePacked('hsl(', Strings.toString(colorScheme + walletInt*stepSize),',95%,40%)')) ,'"></rect>');
            }
        }

        return string(rectString);
    }

    function svgLyricCanvasRow(uint256 rowIdx) internal view returns (string memory) {
        bytes memory rectString;

        for(uint256 i=0; i<10; i++){
            rectString = abi.encodePacked(rectString, '<rect x="', Strings.toString(i), '" y="', Strings.toString(rowIdx), '" class="c1 s"/>');
        }
        return string(rectString);
    }

    function firstCharIndex (string memory base, bytes1 char) internal view virtual returns (uint) {
        bytes memory _bytes = bytes(base);
        uint256 i = 0; 

        while (i < _bytes.length){
            if (_bytes[i] == char) {
                return i;
            }
            i += 1;
        }
        return 0;
    }

    function splitOnChar(string memory lyric, bytes1 char) internal view returns (string[barsPerBlock] memory bars) {
        bytes memory b_lyrics = bytes(lyric);
        uint256 splits = 0;
        uint256 start_index = 0;

        for(uint256 i = 0; i < b_lyrics.length; i++){
            if (b_lyrics[i] == char) {
                bars[splits] = string(substring(b_lyrics, start_index, i));
                splits += 1;
                start_index = i+1;
            }
        }
        bars[barsPerBlock-1] = string(substring(b_lyrics, start_index, b_lyrics.length));

        return bars;
    }    

    function substring(bytes memory in_string, uint256 start_index, uint256 end_index) internal view virtual returns (bytes memory) {
        bytes memory new_str = new bytes(end_index-start_index);
        for(uint256 i = 0; i < end_index-start_index; i++) {
            new_str[i] = in_string[start_index+i];
        }
        return new_str;
    }

    function toAsciiString(address x) internal view returns (string memory) {
        bytes memory s = new bytes(40);
        for (uint256 i = 0; i < 20; i++) {
            bytes1 b = bytes1(uint8(uint(uint160(x)) / (2**(8*(19 - i)))));
            bytes1 hi = bytes1(uint8(b) / 16);
            bytes1 lo = bytes1(uint8(b) - 16 * uint8(hi));
            s[2*i] = addressChar(hi);
            s[2*i+1] = addressChar(lo);            
        }
        return string(s);
    }

    function addressChar(bytes1 b) internal view returns (bytes1 c) {
        if (uint8(b) < 10) return bytes1(uint8(b) + 0x30);
        else return bytes1(uint8(b) + 0x57);
    }
}

File 2 of 13 : ERC721.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "IERC721.sol";
import "IERC721Receiver.sol";
import "IERC721Metadata.sol";
import "Address.sol";
import "Context.sol";
import "Strings.sol";
import "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: balance query for the zero address");
        return _balances[owner];
    }

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

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

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

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

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

    /**
     * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
     * token will be the concatenation of the `baseURI` and the `tokenId`. Empty
     * by default, can be overriden 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 owner nor approved for all"
        );

        _approve(to, tokenId);
    }

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

        return _tokenApprovals[tokenId];
    }

    /**
     * @dev See {IERC721-setApprovalForAll}.
     */
    function setApprovalForAll(address operator, bool approved) public virtual override {
        require(operator != _msgSender(), "ERC721: approve to caller");

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

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

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

        _transfer(from, to, tokenId);
    }

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

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

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

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

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

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

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

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

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

        // Clear approvals
        _approve(address(0), tokenId);

        _balances[owner] -= 1;
        delete _owners[tokenId];

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

    /**
     * @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 of token that is not own");
        require(to != address(0), "ERC721: transfer to the zero address");

        _beforeTokenTransfer(from, to, tokenId);

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

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

        emit Transfer(from, to, tokenId);
    }

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

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

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

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

pragma solidity ^0.8.0;

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

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

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

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

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

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

File 4 of 13 : IERC165.sol
// SPDX-License-Identifier: MIT

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

File 5 of 13 : IERC721Receiver.sol
// SPDX-License-Identifier: MIT

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 `IERC721.onERC721Received.selector`.
     */
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}

File 6 of 13 : IERC721Metadata.sol
// SPDX-License-Identifier: MIT

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

File 7 of 13 : Address.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @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
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        assembly {
            size := extcodesize(account)
        }
        return size > 0;
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 8 of 13 : Context.sol
// SPDX-License-Identifier: MIT

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

File 9 of 13 : Strings.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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

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

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

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

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

File 10 of 13 : ERC165.sol
// SPDX-License-Identifier: MIT

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

File 11 of 13 : Ownable.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "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() {
        _setOwner(_msgSender());
    }

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

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _setOwner(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");
        _setOwner(newOwner);
    }

    function _setOwner(address newOwner) private {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

File 12 of 13 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT

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 make it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

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

        _;

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

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

/// @title Base64
/// @author Brecht Devos - <[email protected]>
/// @notice Provides a function for encoding some bytes in base64
pragma solidity ^0.8.0;

library Base64 {
    string internal constant TABLE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';

    function encode(bytes memory data) internal pure returns (string memory) {
        if (data.length == 0) return '';
        
        // load the table into memory
        string memory table = TABLE;

        // 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) {}
            {
               dataPtr := add(dataPtr, 3)
               
               // read 3 bytes
               let input := mload(dataPtr)
               
               // write 4 characters
               mstore(resultPtr, shl(248, mload(add(tablePtr, and(shr(18, input), 0x3F)))))
               resultPtr := add(resultPtr, 1)
               mstore(resultPtr, shl(248, mload(add(tablePtr, and(shr(12, input), 0x3F)))))
               resultPtr := add(resultPtr, 1)
               mstore(resultPtr, shl(248, mload(add(tablePtr, and(shr( 6, input), 0x3F)))))
               resultPtr := add(resultPtr, 1)
               mstore(resultPtr, shl(248, 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;
    }
}

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

Contract Security Audit

Contract ABI

[{"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":"albumLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"albumStartTime","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":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"blockInterval","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"blockStartTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"user_bars","type":"string"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newInterval","type":"uint256"}],"name":"setBlockInterval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newInterval","type":"uint256"}],"name":"setTrackInterval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenIdToBars","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenIdToWriter","outputs":[{"internalType":"address","name":"","type":"address"}],"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":"uint256","name":"tokenId","type":"uint256"}],"name":"trackBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"trackColor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"trackInterval","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"trackLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"trackNumber","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":[],"name":"withdrawAll","outputs":[],"stateMutability":"payable","type":"function"}]

60c06040526028608052600a60a05261012c600b55620152ac600c553480156200002857600080fd5b50604080518082018252601381527f437970686572206f6e2d636861696e3a204550000000000000000000000000006020808301918252835180850190945260048452634241525360e01b9084015281519192916200008a916000916200010b565b508051620000a09060019060208401906200010b565b5050600160065550620000b333620000b9565b620001ee565b600780546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b8280546200011990620001b1565b90600052602060002090601f0160209004810192826200013d576000855562000188565b82601f106200015857805160ff191683800117855562000188565b8280016001018555821562000188579182015b82811115620001885782518255916020019190600101906200016b565b50620001969291506200019a565b5090565b5b808211156200019657600081556001016200019b565b600181811c90821680620001c657607f821691505b60208210811415620001e857634e487b7160e01b600052602260045260246000fd5b50919050565b60805160a05161404b6200021460003960006121ef0152600061227a015261404b6000f3fe6080604052600436106101ed5760003560e01c80637842d6301161010d578063ba6943f6116100a0578063c87b56dd1161006f578063c87b56dd1461054f578063d5abeb011461056f578063d85d3d2714610584578063e985e9c514610597578063f2fde38b146105b757600080fd5b8063ba6943f6146104ee578063c00bd8de1461050e578063c27ef12814610523578063c4c22e981461053957600080fd5b8063a22cb465116100dc578063a22cb46514610478578063afc3ebaa14610498578063b10cf31b146104b8578063b88d4fde146104ce57600080fd5b80637842d6301461041d578063853828b61461043d5780638da5cb5b1461044557806395d89b411461046357600080fd5b806323b872dd1161018557806354e9a6c71161015457806354e9a6c7146103b25780636352211e146103c857806370a08231146103e8578063715018a61461040857600080fd5b806323b872dd1461031c5780633d2716841461033c57806342842e0e146103725780634daf8df81461039257600080fd5b8063095ea7b3116101c1578063095ea7b3146102a457806318160ddd146102c65780631dc8fc0e146102dc57806321c79d9a146102fc57600080fd5b8062b12003146101f257806301ffc9a71461021a57806306fdde031461024a578063081812fc1461026c575b600080fd5b3480156101fe57600080fd5b50610207600a81565b6040519081526020015b60405180910390f35b34801561022657600080fd5b5061023a61023536600461317e565b6105d7565b6040519015158152602001610211565b34801561025657600080fd5b5061025f610629565b6040516102119190613c0e565b34801561027857600080fd5b5061028c610287366004613201565b6106bb565b6040516001600160a01b039091168152602001610211565b3480156102b057600080fd5b506102c46102bf366004613154565b610755565b005b3480156102d257600080fd5b5061020760085481565b3480156102e857600080fd5b5061025f6102f7366004613201565b61086b565b34801561030857600080fd5b50610207610317366004613201565b610905565b34801561032857600080fd5b506102c4610337366004613060565b61099a565b34801561034857600080fd5b5061028c610357366004613201565b600e602052600090815260409020546001600160a01b031681565b34801561037e57600080fd5b506102c461038d366004613060565b6109cb565b34801561039e57600080fd5b506102c46103ad366004613201565b6109e6565b3480156103be57600080fd5b50610207600a5481565b3480156103d457600080fd5b5061028c6103e3366004613201565b610a15565b3480156103f457600080fd5b5061020761040336600461300b565b610a8c565b34801561041457600080fd5b506102c4610b13565b34801561042957600080fd5b50610207610438366004613201565b610b49565b6102c4610b6d565b34801561045157600080fd5b506007546001600160a01b031661028c565b34801561046f57600080fd5b5061025f610bbb565b34801561048457600080fd5b506102c4610493366004613118565b610bca565b3480156104a457600080fd5b506102076104b3366004613201565b610c8f565b3480156104c457600080fd5b50610207600c5481565b3480156104da57600080fd5b506102c46104e936600461309c565b610ca8565b3480156104fa57600080fd5b506102c4610509366004613201565b610ce0565b34801561051a57600080fd5b50610207601481565b34801561052f57600080fd5b5061020760095481565b34801561054557600080fd5b50610207600b5481565b34801561055b57600080fd5b5061025f61056a366004613201565b610d0f565b34801561057b57600080fd5b50610207610fbd565b6102c46105923660046131b8565b610fcc565b3480156105a357600080fd5b5061023a6105b236600461302d565b6113b2565b3480156105c357600080fd5b506102c46105d236600461300b565b6113e0565b60006001600160e01b031982166380ac58cd60e01b148061060857506001600160e01b03198216635b5e139f60e01b145b8061062357506301ffc9a760e01b6001600160e01b03198316145b92915050565b60606000805461063890613efd565b80601f016020809104026020016040519081016040528092919081815260200182805461066490613efd565b80156106b15780601f10610686576101008083540402835291602001916106b1565b820191906000526020600020905b81548152906001019060200180831161069457829003601f168201915b5050505050905090565b6000818152600260205260408120546001600160a01b03166107395760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b60648201526084015b60405180910390fd5b506000908152600460205260409020546001600160a01b031690565b600061076082610a15565b9050806001600160a01b0316836001600160a01b031614156107ce5760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b6064820152608401610730565b336001600160a01b03821614806107ea57506107ea81336113b2565b61085c5760405162461bcd60e51b815260206004820152603860248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f7760448201527f6e6572206e6f7220617070726f76656420666f7220616c6c00000000000000006064820152608401610730565b610866838361147b565b505050565b600d602052600090815260409020805461088490613efd565b80601f01602080910402602001604051908101604052809291908181526020018280546108b090613efd565b80156108fd5780601f106108d2576101008083540402835291602001916108fd565b820191906000526020600020905b8154815290600101906020018083116108e057829003601f168201915b505050505081565b604080516101408101825260b4815260a06020820181905260249282019290925260486060808301919091526080820152600091810182905260ce60c082015261010e60e082015261012061010082018190526101389082015281600161096b85610c8f565b6109759190613e97565b90508181600a811061098957610989613f93565b602002015161ffff16949350505050565b6109a433826114e9565b6109c05760405162461bcd60e51b815260040161073090613ca8565b6108668383836115c0565b61086683838360405180602001604052806000815250610ca8565b6007546001600160a01b03163314610a105760405162461bcd60e51b815260040161073090613c73565b600c55565b6000818152600260205260408120546001600160a01b0316806106235760405162461bcd60e51b815260206004820152602960248201527f4552433732313a206f776e657220717565727920666f72206e6f6e657869737460448201526832b73a103a37b5b2b760b91b6064820152608401610730565b60006001600160a01b038216610af75760405162461bcd60e51b815260206004820152602a60248201527f4552433732313a2062616c616e636520717565727920666f7220746865207a65604482015269726f206164647265737360b01b6064820152608401610730565b506001600160a01b031660009081526003602052604090205490565b6007546001600160a01b03163314610b3d5760405162461bcd60e51b815260040161073090613c73565b610b476000611760565b565b60006014610b58600184613e97565b610b629190613f53565b610623906001613cf9565b6007546001600160a01b03163314610b975760405162461bcd60e51b815260040161073090613c73565b60405133904780156108fc02916000818181858888f19350505050610b4757600080fd5b60606001805461063890613efd565b6001600160a01b038216331415610c235760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610730565b3360008181526005602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b60006014610c9e600184613e97565b610b629190613d36565b610cb233836114e9565b610cce5760405162461bcd60e51b815260040161073090613ca8565b610cda848484846117b2565b50505050565b6007546001600160a01b03163314610d0a5760405162461bcd60e51b815260040161073090613c73565b600b55565b6000818152600d6020526040812080546060929190610d2d90613efd565b80601f0160208091040260200160405190810160405280929190818152602001828054610d5990613efd565b8015610da65780601f10610d7b57610100808354040283529160200191610da6565b820191906000526020600020905b815481529060010190602001808311610d8957829003601f168201915b505050505090506000610dbd82600560f91b6117e5565b6000858152600e60205260408120549192506001600160a01b0390911690610de4826118b5565b90506000610df187610905565b905060608060005b6004811015610efc5782610e48888360048110610e1857610e18613f93565b60200201516000610e438b8660048110610e3457610e34613f93565b6020020151600160fd1b6119fc565b611a62565b604051602001610e59929190613262565b604051602081830303815290604052925081878260048110610e7d57610e7d613f93565b6020020151610e8e60016004613e97565b831415610eaa5760405180602001604052806000815250610ec6565b604051806040016040528060028152602001612e3760f11b8152505b604051602001610ed8939291906132cc565b60405160208183030381529060405291508080610ef490613f38565b915050610df9565b506000610f088a611b33565b8383604051602001610f1c93929190613791565b604051602081830303815290604052905080610f3f610f3a8c610c8f565b611b33565b610f4b610f3a8d610b49565b87610f61610f5c8f8d8b8e8e611c31565b611d1d565b604051602001610f7595949392919061330f565b6040516020818303038152906040529050610f8f81611d1d565b604051602001610f9f9190613979565b60405160208183030381529060405298505050505050505050919050565b610fc9600a6014613e57565b81565b6002600654141561101f5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610730565b6002600655611030600a6014613e57565b600854106110805760405162461bcd60e51b815260206004820152601960248201527f4379706865723a20616c6c20626c6f636b73206d696e746564000000000000006044820152606401610730565b34662386f26fc10000146110d65760405162461bcd60e51b815260206004820152601860248201527f4379706865723a20302e30312045544820746f206d696e7400000000000000006044820152606401610730565b60026110e133610a8c565b111561112f5760405162461bcd60e51b815260206004820152601860248201527f4379706865723a206d61782033207065722077616c6c657400000000000000006044820152606401610730565b600b5460095461113f9190613cf9565b42101561119a5760405162461bcd60e51b8152602060048201526024808201527f4379706865723a206e65787420626c6f636b206e6f742079657420617661696c60448201526361626c6560e01b6064820152608401610730565b600c5460146008546111ac9190613d36565b6111b69190613e57565b600a546111c39190613cf9565b4210156112205760405162461bcd60e51b815260206004820152602560248201527f4379706865723a206e65787420747261636b206e6f742079657420617661696c60448201526430b136329760d91b6064820152608401610730565b6008546112bc576007546001600160a01b031633146112b35760405162461bcd60e51b815260206004820152604360248201527f4379706865723a206f6e6c7920746865206f776e65722063616e206d696e742060448201527f74686520666972737420626c6f636b20696e207468652066697273742074726160648201526231b59760e91b608482015260a401610730565b42600a5561133c565b6008546000908152600e60205260409020546001600160a01b031633141561133c5760405162461bcd60e51b815260206004820152602d60248201527f4379706865723a2073616d652077616c6c65742063616e2774206d696e74207460448201526c7769636520696e206120726f7760981b6064820152608401610730565b61134581611e85565b6113623360086000815461135890613f38565b91829055506123a0565b6008546000908152600d60209081526040909120825161138492840190612ec2565b50506008546000908152600e6020526040902080546001600160a01b03191633179055426009556001600655565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b6007546001600160a01b0316331461140a5760405162461bcd60e51b815260040161073090613c73565b6001600160a01b03811661146f5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610730565b61147881611760565b50565b600081815260046020526040902080546001600160a01b0319166001600160a01b03841690811790915581906114b082610a15565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6000818152600260205260408120546001600160a01b03166115625760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b6064820152608401610730565b600061156d83610a15565b9050806001600160a01b0316846001600160a01b031614806115a85750836001600160a01b031661159d846106bb565b6001600160a01b0316145b806115b857506115b881856113b2565b949350505050565b826001600160a01b03166115d382610a15565b6001600160a01b03161461163b5760405162461bcd60e51b815260206004820152602960248201527f4552433732313a207472616e73666572206f6620746f6b656e2074686174206960448201526839903737ba1037bbb760b91b6064820152608401610730565b6001600160a01b03821661169d5760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608401610730565b6116a860008261147b565b6001600160a01b03831660009081526003602052604081208054600192906116d1908490613e97565b90915550506001600160a01b03821660009081526003602052604081208054600192906116ff908490613cf9565b909155505060008181526002602052604080822080546001600160a01b0319166001600160a01b0386811691821790925591518493918716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b600780546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6117bd8484846115c0565b6117c9848484846124e2565b610cda5760405162461bcd60e51b815260040161073090613c21565b6117ed612f42565b82600080805b835181101561187d57856001600160f81b03191684828151811061181957611819613f93565b01602001516001600160f81b031916141561186b57611839848383611a62565b85846004811061184b5761184b613f93565b602002015261185b600184613cf9565b9250611868816001613cf9565b91505b8061187581613f38565b9150506117f3565b5061188a83828551611a62565b8461189760016004613e97565b600481106118a7576118a7613f93565b602002015250505092915050565b60408051602880825260608281019093526000919060208201818036833701905050905060005b60148110156119f55760006118f2826013613e97565b6118fd906008613e57565b611908906002613daf565b61191b906001600160a01b038716613d36565b60f81b9050600060108260f81c6119329190613d4a565b60f81b905060008160f81c60106119499190613e76565b8360f81c6119579190613eae565b60f81b9050611965826125ef565b85611971866002613e57565b8151811061198157611981613f93565b60200101906001600160f81b031916908160001a9053506119a1816125ef565b856119ad866002613e57565b6119b8906001613cf9565b815181106119c8576119c8613f93565b60200101906001600160f81b031916908160001a90535050505080806119ed90613f38565b9150506118dc565b5092915050565b600082815b8151811015611a5757836001600160f81b031916828281518110611a2757611a27613f93565b01602001516001600160f81b0319161415611a455791506106239050565b611a50600182613cf9565b9050611a01565b506000949350505050565b60606000611a708484613e97565b67ffffffffffffffff811115611a8857611a88613fa9565b6040519080825280601f01601f191660200182016040528015611ab2576020820181803683370190505b50905060005b611ac28585613e97565b811015611b2a5785611ad48287613cf9565b81518110611ae457611ae4613f93565b602001015160f81c60f81b828281518110611b0157611b01613f93565b60200101906001600160f81b031916908160001a90535080611b2281613f38565b915050611ab8565b50949350505050565b606081611b575750506040805180820190915260018152600360fc1b602082015290565b8160005b8115611b815780611b6b81613f38565b9150611b7a9050600a83613d36565b9150611b5b565b60008167ffffffffffffffff811115611b9c57611b9c613fa9565b6040519080825280601f01601f191660200182016040528015611bc6576020820181803683370190505b5090505b84156115b857611bdb600183613e97565b9150611be8600a86613f53565b611bf3906030613cf9565b60f81b818381518110611c0857611c08613f93565b60200101906001600160f81b031916908160001a905350611c2a600a86613d36565b9450611bca565b6000858152600e6020908152604091829020548251606091821b6bffffffffffffffffffffffff191692810192909252825160148184030181526034909201909252611c7b61262a565b611c858686612735565b611c9087878a612829565b611c9988611b33565b604051602001611ca9919061393a565b604051602081830303815290604052611cc4610f3a8c610c8f565b611cd0610f3a8d610b49565b604051602001611ce293929190613b2e565b60408051601f1981840301815290829052611d02949392916020016139be565b60405160208183030381529060405291505095945050505050565b6060815160001415611d3d57505060408051602081019091526000815290565b6000604051806060016040528060408152602001613fd66040913990506000600384516002611d6c9190613cf9565b611d769190613d36565b611d81906004613e57565b90506000611d90826020613cf9565b67ffffffffffffffff811115611da857611da8613fa9565b6040519080825280601f01601f191660200182016040528015611dd2576020820181803683370190505b509050818152600183018586518101602084015b81831015611e405760039283018051603f601282901c811687015160f890811b8552600c83901c8216880151811b6001860152600683901c8216880151811b60028601529116860151901b93820193909352600401611de6565b600389510660018114611e5a5760028114611e6b57611e77565b613d3d60f01b600119830152611e77565b603d60f81b6000198301525b509398975050505050505050565b600081604051602001611e989190613480565b60408051601f198184030181529190529050600080808080600180828080805b8b5181101561232e578b8181518110611ed357611ed3613f93565b016020908101516001600160f81b03198116945060f81c9250821480611efc57508160ff16600a145b96508680611f0d57508160ff16602c145b80611f2b575060618260ff1610158015611f2b5750607a8260ff1611155b80611f49575060418260ff1610158015611f495750605a8260ff1611155b611f955760405162461bcd60e51b815260206004820152601a60248201527f4379706865723a20696e76616c696420636861726163746572730000000000006044820152606401610730565b868015611f9f5750845b15611fec5760405162461bcd60e51b815260206004820152601c60248201527f4379706865723a2061646a6163656e7420656d707479206368617273000000006044820152606401610730565b83801561200757508160ff166020148015612005575085155b155b156120845760405162461bcd60e51b815260206004820152604160248201527f4379706865723a20636f6d6d61206d75737420626520666f6c6c6f776564206260448201527f79206120737061636520616e64207072656365646564206279206c65747465726064820152607360f81b608482015260a401610730565b60ff8216602c81149450600a1415612317578a1580156120b1575060146008546120ae9190613f53565b15155b15612142576008546120d0908d60006120cb600186613e97565b6128fd565b6121425760405162461bcd60e51b815260206004820152603860248201527f4379706865723a20666972737420626172206d757374207268796d652077697460448201527f68207072696f7220626c6f636b2773206c6173742062617200000000000000006064820152608401610730565b8a6001148061215157508a6003145b156121e0576121788c8a61216660018c613e97565b8f8e612173600188613e97565b612a26565b6121e05760405162461bcd60e51b815260206004820152603360248201527f4379706865723a2066697273742074776f206261727320616e64206c6173742060448201527274776f2062617273206d757374207268796d6560681b6064820152608401610730565b6121eb8b6001613cf9565b9a507f00000000000000000000000000000000000000000000000000000000000000006122188b83613e97565b10156122785760405162461bcd60e51b815260206004820152602960248201527f4379706865723a206e656564203e3d203130206368617261637465727320696e6044820152681032b0b1b4103130b960b91b6064820152608401610730565b7f00000000000000000000000000000000000000000000000000000000000000006122a38b83613e97565b11156123035760405162461bcd60e51b815260206004820152602960248201527f4379706865723a206e656564203c3d203430206368617261637465727320696e6044820152681032b0b1b4103130b960b91b6064820152608401610730565b899850965086612314816001613cf9565b99505b93945085938061232681613f38565b915050611eb8565b5060048a146123925760405162461bcd60e51b815260206004820152602a60248201527f4379706865723a207468657265206d75737420626520666f7572206261727320604482015269696e206120626c6f636b60b01b6064820152608401610730565b505050505050505050505050565b6001600160a01b0382166123f65760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610730565b6000818152600260205260409020546001600160a01b03161561245b5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610730565b6001600160a01b0382166000908152600360205260408120805460019290612484908490613cf9565b909155505060008181526002602052604080822080546001600160a01b0319166001600160a01b03861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b60006001600160a01b0384163b156125e457604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290612526903390899088908890600401613bdb565b602060405180830381600087803b15801561254057600080fd5b505af1925050508015612570575060408051601f3d908101601f1916820190925261256d9181019061319b565b60015b6125ca573d80801561259e576040519150601f19603f3d011682016040523d82523d6000602084013e6125a3565b606091505b5080516125c25760405162461bcd60e51b815260040161073090613c21565b805181602001fd5b6001600160e01b031916630a85bd0160e11b1490506115b8565b506001949350505050565b6000600a60f883901c10156126165761260d60f883901c6030613d11565b60f81b92915050565b61260d60f883901c6057613d11565b919050565b6060600060405160200161271f907f3c7374796c6520747970653d22746578742f637373223e00000000000000000081527f726563747b77696474683a203170783b206865696768743a203170783b7d746560178201527f78747b666f6e742d73697a653a20302e343270783b20616c69676e6d656e742d60378201527f626173656c696e653a746578742d61667465722d656467657d0000000000000060578201527f2e63317b66696c6c3a233030303030303b7d2e777269746572546578747b666f60708201527f6e742d73697a653a20302e323570783b7d3c2f7374796c653e00000000000000609082015260a90190565b60408051601f1981840301815291905292915050565b6060806127426000612be1565b61274c6001612be1565b6127566002612be1565b6127606003612be1565b61276a6004612be1565b6127746005612be1565b60405160200161278996959493929190613712565b604051602081830303815290604052905060005b6004811015612821576040516bffffffffffffffffffffffff19606086901b16602082015282906127ec9060340160408051601f198184030181529190526127e6846006613cf9565b88612c39565b6040516020016127fd92919061329d565b6040516020818303038152906040529150808061281990613f38565b91505061279d565b509392505050565b60608060005b600481101561289f5781612852612847836001613cf9565b610f3a906001613cf9565b85836004811061286457612864613f93565b602002015160405160200161287b93929190613550565b6040516020818303038152906040529150808061289790613f38565b91505061282f565b50806128aa86611b33565b6040516020016128ba919061393a565b6040516020818303038152906040526128d2866118b5565b6040516020016128e4939291906134a5565b60408051808303601f1901815291905295945050505050565b6000848152600d60205260408120805482919061291990613efd565b80601f016020809104026020016040519081016040528092919081815260200182805461294590613efd565b80156129925780601f1061296757610100808354040283529160200191612992565b820191906000526020600020905b81548152906001019060200180831161297557829003601f168201915b5050505050905060008190506000600182516129ae9190613e97565b90505b8181815181106129c3576129c3613f93565b6020910101516001600160f81b031916600560f91b14156129e3576129f5565b6129ee600182613e97565b90506129b1565b612a1a82612a04836001613cf9565b60018551612a129190613e97565b8a8a8a612a26565b98975050505050505050565b6000848282808061271060015b8c8710158015612a435750898610155b15612b965760008e8881518110612a5c57612a5c613f93565b602001015160f81c60f81b905060008c8881518110612a7d57612a7d613f93565b016020908101516001600160f81b031916915060f883901c1480612aa55750602060f882901c145b15612ab1575050612b96565b861580612ac65750868015612ac65750600285105b15612b1757612ad481612dde565b6001600160f81b031916612ae783612dde565b6001600160f81b031916148015612afb5750825b15612b1257612b0b600187613cf9565b9550612b17565b600092505b8680612b275750612b2782612e12565b80612b365750612b3681612e12565b9650868015612b46575083612710145b15612b4f578493505b612b5a600186613cf9565b94508e891480612b6957508b88145b15612b75575050612b96565b612b8060018a613e97565b9850612b8d600189613e97565b97505050612a33565b841580612ba1575081155b15612bc457600284101580612bb65750828410155b975050505050505050612bd7565b81841180612bb657505050111593505050505b9695505050505050565b60608060005b600a8110156119f55781612bfa82611b33565b612c0386611b33565b604051602001612c159392919061368a565b60405160208183030381529060405291508080612c3190613f38565b915050612be7565b6060806000600260ce851480612c50575084610138145b80612c5c57508461010e145b80612c65575084155b80612c705750846090145b15612c7d57506003612c95565b8460481480612c8c5750846060145b15612c95575060055b60005b600a811015612dd257875115612dc05760006006881015612cba576000612cd0565b612cc5600689613e97565b612cd0906002613e57565b90506000612cdf600284613f53565b612d1b5760048a612cf08488613cf9565b81518110612d0057612d00613f93565b01602001516001600160f81b031916901c60f81c9050612d52565b89612d268387613cf9565b81518110612d3657612d36613f93565b60209101015160f81c600f169050612d4f600186613cf9565b94505b85612d5c84611b33565b612d658b611b33565b612d7c612d728886613e57565b610f3a908d613cf9565b604051602001612d8c919061393a565b60408051601f1981840301815290829052612dac949392916020016135df565b604051602081830303815290604052955050505b80612dca81613f38565b915050612c98565b50919695505050505050565b6000604160f883901c10801590612dfa5750605a60f883901c11155b15612e0e5761260d60f883901c6020613d11565b5090565b6000606160f883901c1480612e2b5750606560f883901c145b80612e3a5750606960f883901c145b80612e495750606f60f883901c145b80612e585750607560f883901c145b80612e675750607960f883901c145b80612e765750604160f883901c145b80612e855750604560f883901c145b80612e945750604960f883901c145b80612ea35750604f60f883901c145b80612eb25750605560f883901c145b8061062357505060f81c60591490565b828054612ece90613efd565b90600052602060002090601f016020900481019282612ef05760008555612f36565b82601f10612f0957805160ff1916838001178555612f36565b82800160010185558215612f36579182015b82811115612f36578251825591602001919060010190612f1b565b50612e0e929150612f69565b60405180608001604052806004905b6060815260200190600190039081612f515790505090565b5b80821115612e0e5760008155600101612f6a565b600067ffffffffffffffff80841115612f9957612f99613fa9565b604051601f8501601f19908116603f01168101908282118183101715612fc157612fc1613fa9565b81604052809350858152868686011115612fda57600080fd5b858560208301376000602087830101525050509392505050565b80356001600160a01b038116811461262557600080fd5b60006020828403121561301d57600080fd5b61302682612ff4565b9392505050565b6000806040838503121561304057600080fd5b61304983612ff4565b915061305760208401612ff4565b90509250929050565b60008060006060848603121561307557600080fd5b61307e84612ff4565b925061308c60208501612ff4565b9150604084013590509250925092565b600080600080608085870312156130b257600080fd5b6130bb85612ff4565b93506130c960208601612ff4565b925060408501359150606085013567ffffffffffffffff8111156130ec57600080fd5b8501601f810187136130fd57600080fd5b61310c87823560208401612f7e565b91505092959194509250565b6000806040838503121561312b57600080fd5b61313483612ff4565b91506020830135801515811461314957600080fd5b809150509250929050565b6000806040838503121561316757600080fd5b61317083612ff4565b946020939093013593505050565b60006020828403121561319057600080fd5b813561302681613fbf565b6000602082840312156131ad57600080fd5b815161302681613fbf565b6000602082840312156131ca57600080fd5b813567ffffffffffffffff8111156131e157600080fd5b8201601f810184136131f257600080fd5b6115b884823560208401612f7e565b60006020828403121561321357600080fd5b5035919050565b60008151808452613232816020860160208601613ed1565b601f01601f19169290920160200192915050565b60008151613258818560208601613ed1565b9290920192915050565b60008351613274818460208801613ed1565b835190830190613288818360208801613ed1565b600160fd1b9101908152600101949350505050565b600083516132af818460208801613ed1565b8351908301906132c3818360208801613ed1565b01949350505050565b600084516132de818460208901613ed1565b8451908301906132f2818360208901613ed1565b8451910190613305818360208801613ed1565b0195945050505050565b60008651613321818460208b01613ed1565b6f2261747472696275746573223a205b7b60801b9083019081527f2274726169745f74797065223a2022547261636b222c202276616c7565223a2260108201528651613374816030840160208b01613ed1565b64227d2c207b60d81b603092909101918201527f2274726169745f74797065223a2022426c6f636b222c202276616c7565223a22603582015285516133c0816055840160208a01613ed1565b61227d60f01b91016055810191909152612c7b60f01b60578201527f2274726169745f74797065223a2022577269746572222c202276616c7565223a60598201526204460f60eb1b6079820152612a1a61342761347a61344261343583607c87018b613246565b61227d60f01b815260020190565b605d60f81b815260010190565b7f2c2022696d616765223a2022646174613a696d6167652f7376672b786d6c3b62815265185cd94d8d0b60d21b602082015260260190565b86613246565b60008251613492818460208701613ed1565b600560f91b920191825250600101919050565b600084516134b7818460208901613ed1565b7f3c7465787420783d22302220793d2236222066696c6c3d22000000000000000090830190815284516134f1816018840160208901613ed1565b7f2220636c6173733d2277726974657254657874223e307800000000000000000060189290910191820152835161352f81602f840160208801613ed1565b661e17ba32bc3a1f60c91b602f929091019182015260360195945050505050565b60008451613562818460208901613ed1565b6e1e3a32bc3a103c1e911811103c9e9160891b908301908152845161358e81600f840160208901613ed1565b6e11103334b6361e913bb434ba32911f60891b600f929091019182015283516135be81601e840160208801613ed1565b661e17ba32bc3a1f60c91b601e929091019182015260250195945050505050565b600085516135f1818460208a01613ed1565b681e3932b1ba103c1e9160b91b9083019081528551613617816009840160208a01613ed1565b6411103c9e9160d91b60099290910191820152845161363d81600e840160208901613ed1565b6711103334b6361e9160c11b600e92909101918201528351613666816016840160208801613ed1565b68111f1e17b932b1ba1f60b91b60169290910191820152601f019695505050505050565b6000845161369c818460208901613ed1565b681e3932b1ba103c1e9160b91b90830190815284516136c2816009840160208901613ed1565b6411103c9e9160d91b6009929091019182015283516136e881600e840160208801613ed1565b6f111031b630b9b99e913198903991179f60811b600e9290910191820152601e0195945050505050565b6000875160206137258285838d01613ed1565b8851918401916137388184848d01613ed1565b885192019161374a8184848c01613ed1565b875192019161375c8184848b01613ed1565b865192019161376e8184848a01613ed1565b85519201916137808184848901613ed1565b919091019998505050505050505050565b683d913730b6b2911d1160b91b8152602360f81b600982015283516000906137c081600a850160208901613ed1565b6201016960ed1b600a9184019182015284516137e381600d840160208901613ed1565b7f222c20226465736372697074696f6e223a22437970686572206f6e2d636861699101600d8101919091527f6e206973206120736d61727420636f6e7472616374207468617420636f6e6475602d8201527f63747320612072617020637970686572206f6e20457468657265756d2e204379604d8201527f706865722045502069732069747320666972737420636f6c6c6563746976656c606d8201527f79207772697474656e20616c62756d207769746820313020747261636b732e20608d8201527f4561636820747261636b20636f6e7461696e7320323020626c6f636b732c206360ad8201527f6f6d707269736564206f662034206261727320656163682e204120626c6f636b60cd8201526d01034b99030b71027232a171116160951b60ed82015268113130b939911d101160b91b60fb820152612bd761392b610104830161347a565b6201116160ed1b815260030190565b630d0e6d8560e31b815260008251613959816004850160208701613ed1565b682c3935252c3430252960b81b6004939091019283015250600d01919050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c0000008152600082516139b181601d850160208701613ed1565b91909101601d0192915050565b7f3c7376672076657273696f6e3d22312e31222073686170652d72656e6465726981527f6e673d226f7074696d697a6553706565642220786d6c6e733d22687474703a2f60208201527f2f7777772e77332e6f72672f323030302f7376672220786d6c6e733a786c696e60408201527f6b3d22687474703a2f2f7777772e77332e6f72672f313939392f786c696e6b2260608201527f20783d223070782220793d22307078222077696474683d22333030222068656960808201527f6768743d22333030222076696577426f783d223020302031302031302220786d60a082015272361d39b830b1b29e91383932b9b2b93b32911f60691b60c082015260008551613ad08160d3850160208a01613ed1565b855190830190613ae78160d3840160208a01613ed1565b8551910190613afd8160d3840160208901613ed1565b8451910190613b138160d3840160208801613ed1565b612a1a60d382840101651e17b9bb339f60d11b815260060190565b7f3c7465787420783d22302220793d2231222066696c6c3d220000000000000000815260008451613b66816018850160208901613ed1565b680111f2a3930b1b59d160bd1b6018918401918201528451613b8f816021840160208901613ed1565b690101690213637b1b59d160b51b602192909101918201528351613bba81602b840160208801613ed1565b661e17ba32bc3a1f60c91b602b929091019182015260320195945050505050565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090612bd79083018461321a565b602081526000613026602083018461321a565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60208082526031908201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f6040820152701ddb995c881b9bdc88185c1c1c9bdd9959607a1b606082015260800190565b60008219821115613d0c57613d0c613f67565b500190565b600060ff821660ff84168060ff03821115613d2e57613d2e613f67565b019392505050565b600082613d4557613d45613f7d565b500490565b600060ff831680613d5d57613d5d613f7d565b8060ff84160491505092915050565b600181815b80851115613da7578160001904821115613d8d57613d8d613f67565b80851615613d9a57918102915b93841c9390800290613d71565b509250929050565b60006130268383600082613dc557506001610623565b81613dd257506000610623565b8160018114613de85760028114613df257613e0e565b6001915050610623565b60ff841115613e0357613e03613f67565b50506001821b610623565b5060208310610133831016604e8410600b8410161715613e31575081810a610623565b613e3b8383613d6c565b8060001904821115613e4f57613e4f613f67565b029392505050565b6000816000190483118215151615613e7157613e71613f67565b500290565b600060ff821660ff84168160ff0481118215151615613e4f57613e4f613f67565b600082821015613ea957613ea9613f67565b500390565b600060ff821660ff841680821015613ec857613ec8613f67565b90039392505050565b60005b83811015613eec578181015183820152602001613ed4565b83811115610cda5750506000910152565b600181811c90821680613f1157607f821691505b60208210811415613f3257634e487b7160e01b600052602260045260246000fd5b50919050565b6000600019821415613f4c57613f4c613f67565b5060010190565b600082613f6257613f62613f7d565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160e01b03198116811461147857600080fdfe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2fa2646970667358221220b0f169864b81a1c68a6c11e04657c69e14599a5c884ee22b071b0f1a5d54174064736f6c63430008060033

Deployed Bytecode

0x6080604052600436106101ed5760003560e01c80637842d6301161010d578063ba6943f6116100a0578063c87b56dd1161006f578063c87b56dd1461054f578063d5abeb011461056f578063d85d3d2714610584578063e985e9c514610597578063f2fde38b146105b757600080fd5b8063ba6943f6146104ee578063c00bd8de1461050e578063c27ef12814610523578063c4c22e981461053957600080fd5b8063a22cb465116100dc578063a22cb46514610478578063afc3ebaa14610498578063b10cf31b146104b8578063b88d4fde146104ce57600080fd5b80637842d6301461041d578063853828b61461043d5780638da5cb5b1461044557806395d89b411461046357600080fd5b806323b872dd1161018557806354e9a6c71161015457806354e9a6c7146103b25780636352211e146103c857806370a08231146103e8578063715018a61461040857600080fd5b806323b872dd1461031c5780633d2716841461033c57806342842e0e146103725780634daf8df81461039257600080fd5b8063095ea7b3116101c1578063095ea7b3146102a457806318160ddd146102c65780631dc8fc0e146102dc57806321c79d9a146102fc57600080fd5b8062b12003146101f257806301ffc9a71461021a57806306fdde031461024a578063081812fc1461026c575b600080fd5b3480156101fe57600080fd5b50610207600a81565b6040519081526020015b60405180910390f35b34801561022657600080fd5b5061023a61023536600461317e565b6105d7565b6040519015158152602001610211565b34801561025657600080fd5b5061025f610629565b6040516102119190613c0e565b34801561027857600080fd5b5061028c610287366004613201565b6106bb565b6040516001600160a01b039091168152602001610211565b3480156102b057600080fd5b506102c46102bf366004613154565b610755565b005b3480156102d257600080fd5b5061020760085481565b3480156102e857600080fd5b5061025f6102f7366004613201565b61086b565b34801561030857600080fd5b50610207610317366004613201565b610905565b34801561032857600080fd5b506102c4610337366004613060565b61099a565b34801561034857600080fd5b5061028c610357366004613201565b600e602052600090815260409020546001600160a01b031681565b34801561037e57600080fd5b506102c461038d366004613060565b6109cb565b34801561039e57600080fd5b506102c46103ad366004613201565b6109e6565b3480156103be57600080fd5b50610207600a5481565b3480156103d457600080fd5b5061028c6103e3366004613201565b610a15565b3480156103f457600080fd5b5061020761040336600461300b565b610a8c565b34801561041457600080fd5b506102c4610b13565b34801561042957600080fd5b50610207610438366004613201565b610b49565b6102c4610b6d565b34801561045157600080fd5b506007546001600160a01b031661028c565b34801561046f57600080fd5b5061025f610bbb565b34801561048457600080fd5b506102c4610493366004613118565b610bca565b3480156104a457600080fd5b506102076104b3366004613201565b610c8f565b3480156104c457600080fd5b50610207600c5481565b3480156104da57600080fd5b506102c46104e936600461309c565b610ca8565b3480156104fa57600080fd5b506102c4610509366004613201565b610ce0565b34801561051a57600080fd5b50610207601481565b34801561052f57600080fd5b5061020760095481565b34801561054557600080fd5b50610207600b5481565b34801561055b57600080fd5b5061025f61056a366004613201565b610d0f565b34801561057b57600080fd5b50610207610fbd565b6102c46105923660046131b8565b610fcc565b3480156105a357600080fd5b5061023a6105b236600461302d565b6113b2565b3480156105c357600080fd5b506102c46105d236600461300b565b6113e0565b60006001600160e01b031982166380ac58cd60e01b148061060857506001600160e01b03198216635b5e139f60e01b145b8061062357506301ffc9a760e01b6001600160e01b03198316145b92915050565b60606000805461063890613efd565b80601f016020809104026020016040519081016040528092919081815260200182805461066490613efd565b80156106b15780601f10610686576101008083540402835291602001916106b1565b820191906000526020600020905b81548152906001019060200180831161069457829003601f168201915b5050505050905090565b6000818152600260205260408120546001600160a01b03166107395760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b60648201526084015b60405180910390fd5b506000908152600460205260409020546001600160a01b031690565b600061076082610a15565b9050806001600160a01b0316836001600160a01b031614156107ce5760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b6064820152608401610730565b336001600160a01b03821614806107ea57506107ea81336113b2565b61085c5760405162461bcd60e51b815260206004820152603860248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f7760448201527f6e6572206e6f7220617070726f76656420666f7220616c6c00000000000000006064820152608401610730565b610866838361147b565b505050565b600d602052600090815260409020805461088490613efd565b80601f01602080910402602001604051908101604052809291908181526020018280546108b090613efd565b80156108fd5780601f106108d2576101008083540402835291602001916108fd565b820191906000526020600020905b8154815290600101906020018083116108e057829003601f168201915b505050505081565b604080516101408101825260b4815260a06020820181905260249282019290925260486060808301919091526080820152600091810182905260ce60c082015261010e60e082015261012061010082018190526101389082015281600161096b85610c8f565b6109759190613e97565b90508181600a811061098957610989613f93565b602002015161ffff16949350505050565b6109a433826114e9565b6109c05760405162461bcd60e51b815260040161073090613ca8565b6108668383836115c0565b61086683838360405180602001604052806000815250610ca8565b6007546001600160a01b03163314610a105760405162461bcd60e51b815260040161073090613c73565b600c55565b6000818152600260205260408120546001600160a01b0316806106235760405162461bcd60e51b815260206004820152602960248201527f4552433732313a206f776e657220717565727920666f72206e6f6e657869737460448201526832b73a103a37b5b2b760b91b6064820152608401610730565b60006001600160a01b038216610af75760405162461bcd60e51b815260206004820152602a60248201527f4552433732313a2062616c616e636520717565727920666f7220746865207a65604482015269726f206164647265737360b01b6064820152608401610730565b506001600160a01b031660009081526003602052604090205490565b6007546001600160a01b03163314610b3d5760405162461bcd60e51b815260040161073090613c73565b610b476000611760565b565b60006014610b58600184613e97565b610b629190613f53565b610623906001613cf9565b6007546001600160a01b03163314610b975760405162461bcd60e51b815260040161073090613c73565b60405133904780156108fc02916000818181858888f19350505050610b4757600080fd5b60606001805461063890613efd565b6001600160a01b038216331415610c235760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610730565b3360008181526005602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b60006014610c9e600184613e97565b610b629190613d36565b610cb233836114e9565b610cce5760405162461bcd60e51b815260040161073090613ca8565b610cda848484846117b2565b50505050565b6007546001600160a01b03163314610d0a5760405162461bcd60e51b815260040161073090613c73565b600b55565b6000818152600d6020526040812080546060929190610d2d90613efd565b80601f0160208091040260200160405190810160405280929190818152602001828054610d5990613efd565b8015610da65780601f10610d7b57610100808354040283529160200191610da6565b820191906000526020600020905b815481529060010190602001808311610d8957829003601f168201915b505050505090506000610dbd82600560f91b6117e5565b6000858152600e60205260408120549192506001600160a01b0390911690610de4826118b5565b90506000610df187610905565b905060608060005b6004811015610efc5782610e48888360048110610e1857610e18613f93565b60200201516000610e438b8660048110610e3457610e34613f93565b6020020151600160fd1b6119fc565b611a62565b604051602001610e59929190613262565b604051602081830303815290604052925081878260048110610e7d57610e7d613f93565b6020020151610e8e60016004613e97565b831415610eaa5760405180602001604052806000815250610ec6565b604051806040016040528060028152602001612e3760f11b8152505b604051602001610ed8939291906132cc565b60405160208183030381529060405291508080610ef490613f38565b915050610df9565b506000610f088a611b33565b8383604051602001610f1c93929190613791565b604051602081830303815290604052905080610f3f610f3a8c610c8f565b611b33565b610f4b610f3a8d610b49565b87610f61610f5c8f8d8b8e8e611c31565b611d1d565b604051602001610f7595949392919061330f565b6040516020818303038152906040529050610f8f81611d1d565b604051602001610f9f9190613979565b60405160208183030381529060405298505050505050505050919050565b610fc9600a6014613e57565b81565b6002600654141561101f5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610730565b6002600655611030600a6014613e57565b600854106110805760405162461bcd60e51b815260206004820152601960248201527f4379706865723a20616c6c20626c6f636b73206d696e746564000000000000006044820152606401610730565b34662386f26fc10000146110d65760405162461bcd60e51b815260206004820152601860248201527f4379706865723a20302e30312045544820746f206d696e7400000000000000006044820152606401610730565b60026110e133610a8c565b111561112f5760405162461bcd60e51b815260206004820152601860248201527f4379706865723a206d61782033207065722077616c6c657400000000000000006044820152606401610730565b600b5460095461113f9190613cf9565b42101561119a5760405162461bcd60e51b8152602060048201526024808201527f4379706865723a206e65787420626c6f636b206e6f742079657420617661696c60448201526361626c6560e01b6064820152608401610730565b600c5460146008546111ac9190613d36565b6111b69190613e57565b600a546111c39190613cf9565b4210156112205760405162461bcd60e51b815260206004820152602560248201527f4379706865723a206e65787420747261636b206e6f742079657420617661696c60448201526430b136329760d91b6064820152608401610730565b6008546112bc576007546001600160a01b031633146112b35760405162461bcd60e51b815260206004820152604360248201527f4379706865723a206f6e6c7920746865206f776e65722063616e206d696e742060448201527f74686520666972737420626c6f636b20696e207468652066697273742074726160648201526231b59760e91b608482015260a401610730565b42600a5561133c565b6008546000908152600e60205260409020546001600160a01b031633141561133c5760405162461bcd60e51b815260206004820152602d60248201527f4379706865723a2073616d652077616c6c65742063616e2774206d696e74207460448201526c7769636520696e206120726f7760981b6064820152608401610730565b61134581611e85565b6113623360086000815461135890613f38565b91829055506123a0565b6008546000908152600d60209081526040909120825161138492840190612ec2565b50506008546000908152600e6020526040902080546001600160a01b03191633179055426009556001600655565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b6007546001600160a01b0316331461140a5760405162461bcd60e51b815260040161073090613c73565b6001600160a01b03811661146f5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610730565b61147881611760565b50565b600081815260046020526040902080546001600160a01b0319166001600160a01b03841690811790915581906114b082610a15565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6000818152600260205260408120546001600160a01b03166115625760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b6064820152608401610730565b600061156d83610a15565b9050806001600160a01b0316846001600160a01b031614806115a85750836001600160a01b031661159d846106bb565b6001600160a01b0316145b806115b857506115b881856113b2565b949350505050565b826001600160a01b03166115d382610a15565b6001600160a01b03161461163b5760405162461bcd60e51b815260206004820152602960248201527f4552433732313a207472616e73666572206f6620746f6b656e2074686174206960448201526839903737ba1037bbb760b91b6064820152608401610730565b6001600160a01b03821661169d5760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608401610730565b6116a860008261147b565b6001600160a01b03831660009081526003602052604081208054600192906116d1908490613e97565b90915550506001600160a01b03821660009081526003602052604081208054600192906116ff908490613cf9565b909155505060008181526002602052604080822080546001600160a01b0319166001600160a01b0386811691821790925591518493918716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b600780546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6117bd8484846115c0565b6117c9848484846124e2565b610cda5760405162461bcd60e51b815260040161073090613c21565b6117ed612f42565b82600080805b835181101561187d57856001600160f81b03191684828151811061181957611819613f93565b01602001516001600160f81b031916141561186b57611839848383611a62565b85846004811061184b5761184b613f93565b602002015261185b600184613cf9565b9250611868816001613cf9565b91505b8061187581613f38565b9150506117f3565b5061188a83828551611a62565b8461189760016004613e97565b600481106118a7576118a7613f93565b602002015250505092915050565b60408051602880825260608281019093526000919060208201818036833701905050905060005b60148110156119f55760006118f2826013613e97565b6118fd906008613e57565b611908906002613daf565b61191b906001600160a01b038716613d36565b60f81b9050600060108260f81c6119329190613d4a565b60f81b905060008160f81c60106119499190613e76565b8360f81c6119579190613eae565b60f81b9050611965826125ef565b85611971866002613e57565b8151811061198157611981613f93565b60200101906001600160f81b031916908160001a9053506119a1816125ef565b856119ad866002613e57565b6119b8906001613cf9565b815181106119c8576119c8613f93565b60200101906001600160f81b031916908160001a90535050505080806119ed90613f38565b9150506118dc565b5092915050565b600082815b8151811015611a5757836001600160f81b031916828281518110611a2757611a27613f93565b01602001516001600160f81b0319161415611a455791506106239050565b611a50600182613cf9565b9050611a01565b506000949350505050565b60606000611a708484613e97565b67ffffffffffffffff811115611a8857611a88613fa9565b6040519080825280601f01601f191660200182016040528015611ab2576020820181803683370190505b50905060005b611ac28585613e97565b811015611b2a5785611ad48287613cf9565b81518110611ae457611ae4613f93565b602001015160f81c60f81b828281518110611b0157611b01613f93565b60200101906001600160f81b031916908160001a90535080611b2281613f38565b915050611ab8565b50949350505050565b606081611b575750506040805180820190915260018152600360fc1b602082015290565b8160005b8115611b815780611b6b81613f38565b9150611b7a9050600a83613d36565b9150611b5b565b60008167ffffffffffffffff811115611b9c57611b9c613fa9565b6040519080825280601f01601f191660200182016040528015611bc6576020820181803683370190505b5090505b84156115b857611bdb600183613e97565b9150611be8600a86613f53565b611bf3906030613cf9565b60f81b818381518110611c0857611c08613f93565b60200101906001600160f81b031916908160001a905350611c2a600a86613d36565b9450611bca565b6000858152600e6020908152604091829020548251606091821b6bffffffffffffffffffffffff191692810192909252825160148184030181526034909201909252611c7b61262a565b611c858686612735565b611c9087878a612829565b611c9988611b33565b604051602001611ca9919061393a565b604051602081830303815290604052611cc4610f3a8c610c8f565b611cd0610f3a8d610b49565b604051602001611ce293929190613b2e565b60408051601f1981840301815290829052611d02949392916020016139be565b60405160208183030381529060405291505095945050505050565b6060815160001415611d3d57505060408051602081019091526000815290565b6000604051806060016040528060408152602001613fd66040913990506000600384516002611d6c9190613cf9565b611d769190613d36565b611d81906004613e57565b90506000611d90826020613cf9565b67ffffffffffffffff811115611da857611da8613fa9565b6040519080825280601f01601f191660200182016040528015611dd2576020820181803683370190505b509050818152600183018586518101602084015b81831015611e405760039283018051603f601282901c811687015160f890811b8552600c83901c8216880151811b6001860152600683901c8216880151811b60028601529116860151901b93820193909352600401611de6565b600389510660018114611e5a5760028114611e6b57611e77565b613d3d60f01b600119830152611e77565b603d60f81b6000198301525b509398975050505050505050565b600081604051602001611e989190613480565b60408051601f198184030181529190529050600080808080600180828080805b8b5181101561232e578b8181518110611ed357611ed3613f93565b016020908101516001600160f81b03198116945060f81c9250821480611efc57508160ff16600a145b96508680611f0d57508160ff16602c145b80611f2b575060618260ff1610158015611f2b5750607a8260ff1611155b80611f49575060418260ff1610158015611f495750605a8260ff1611155b611f955760405162461bcd60e51b815260206004820152601a60248201527f4379706865723a20696e76616c696420636861726163746572730000000000006044820152606401610730565b868015611f9f5750845b15611fec5760405162461bcd60e51b815260206004820152601c60248201527f4379706865723a2061646a6163656e7420656d707479206368617273000000006044820152606401610730565b83801561200757508160ff166020148015612005575085155b155b156120845760405162461bcd60e51b815260206004820152604160248201527f4379706865723a20636f6d6d61206d75737420626520666f6c6c6f776564206260448201527f79206120737061636520616e64207072656365646564206279206c65747465726064820152607360f81b608482015260a401610730565b60ff8216602c81149450600a1415612317578a1580156120b1575060146008546120ae9190613f53565b15155b15612142576008546120d0908d60006120cb600186613e97565b6128fd565b6121425760405162461bcd60e51b815260206004820152603860248201527f4379706865723a20666972737420626172206d757374207268796d652077697460448201527f68207072696f7220626c6f636b2773206c6173742062617200000000000000006064820152608401610730565b8a6001148061215157508a6003145b156121e0576121788c8a61216660018c613e97565b8f8e612173600188613e97565b612a26565b6121e05760405162461bcd60e51b815260206004820152603360248201527f4379706865723a2066697273742074776f206261727320616e64206c6173742060448201527274776f2062617273206d757374207268796d6560681b6064820152608401610730565b6121eb8b6001613cf9565b9a507f000000000000000000000000000000000000000000000000000000000000000a6122188b83613e97565b10156122785760405162461bcd60e51b815260206004820152602960248201527f4379706865723a206e656564203e3d203130206368617261637465727320696e6044820152681032b0b1b4103130b960b91b6064820152608401610730565b7f00000000000000000000000000000000000000000000000000000000000000286122a38b83613e97565b11156123035760405162461bcd60e51b815260206004820152602960248201527f4379706865723a206e656564203c3d203430206368617261637465727320696e6044820152681032b0b1b4103130b960b91b6064820152608401610730565b899850965086612314816001613cf9565b99505b93945085938061232681613f38565b915050611eb8565b5060048a146123925760405162461bcd60e51b815260206004820152602a60248201527f4379706865723a207468657265206d75737420626520666f7572206261727320604482015269696e206120626c6f636b60b01b6064820152608401610730565b505050505050505050505050565b6001600160a01b0382166123f65760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610730565b6000818152600260205260409020546001600160a01b03161561245b5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610730565b6001600160a01b0382166000908152600360205260408120805460019290612484908490613cf9565b909155505060008181526002602052604080822080546001600160a01b0319166001600160a01b03861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b60006001600160a01b0384163b156125e457604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290612526903390899088908890600401613bdb565b602060405180830381600087803b15801561254057600080fd5b505af1925050508015612570575060408051601f3d908101601f1916820190925261256d9181019061319b565b60015b6125ca573d80801561259e576040519150601f19603f3d011682016040523d82523d6000602084013e6125a3565b606091505b5080516125c25760405162461bcd60e51b815260040161073090613c21565b805181602001fd5b6001600160e01b031916630a85bd0160e11b1490506115b8565b506001949350505050565b6000600a60f883901c10156126165761260d60f883901c6030613d11565b60f81b92915050565b61260d60f883901c6057613d11565b919050565b6060600060405160200161271f907f3c7374796c6520747970653d22746578742f637373223e00000000000000000081527f726563747b77696474683a203170783b206865696768743a203170783b7d746560178201527f78747b666f6e742d73697a653a20302e343270783b20616c69676e6d656e742d60378201527f626173656c696e653a746578742d61667465722d656467657d0000000000000060578201527f2e63317b66696c6c3a233030303030303b7d2e777269746572546578747b666f60708201527f6e742d73697a653a20302e323570783b7d3c2f7374796c653e00000000000000609082015260a90190565b60408051601f1981840301815291905292915050565b6060806127426000612be1565b61274c6001612be1565b6127566002612be1565b6127606003612be1565b61276a6004612be1565b6127746005612be1565b60405160200161278996959493929190613712565b604051602081830303815290604052905060005b6004811015612821576040516bffffffffffffffffffffffff19606086901b16602082015282906127ec9060340160408051601f198184030181529190526127e6846006613cf9565b88612c39565b6040516020016127fd92919061329d565b6040516020818303038152906040529150808061281990613f38565b91505061279d565b509392505050565b60608060005b600481101561289f5781612852612847836001613cf9565b610f3a906001613cf9565b85836004811061286457612864613f93565b602002015160405160200161287b93929190613550565b6040516020818303038152906040529150808061289790613f38565b91505061282f565b50806128aa86611b33565b6040516020016128ba919061393a565b6040516020818303038152906040526128d2866118b5565b6040516020016128e4939291906134a5565b60408051808303601f1901815291905295945050505050565b6000848152600d60205260408120805482919061291990613efd565b80601f016020809104026020016040519081016040528092919081815260200182805461294590613efd565b80156129925780601f1061296757610100808354040283529160200191612992565b820191906000526020600020905b81548152906001019060200180831161297557829003601f168201915b5050505050905060008190506000600182516129ae9190613e97565b90505b8181815181106129c3576129c3613f93565b6020910101516001600160f81b031916600560f91b14156129e3576129f5565b6129ee600182613e97565b90506129b1565b612a1a82612a04836001613cf9565b60018551612a129190613e97565b8a8a8a612a26565b98975050505050505050565b6000848282808061271060015b8c8710158015612a435750898610155b15612b965760008e8881518110612a5c57612a5c613f93565b602001015160f81c60f81b905060008c8881518110612a7d57612a7d613f93565b016020908101516001600160f81b031916915060f883901c1480612aa55750602060f882901c145b15612ab1575050612b96565b861580612ac65750868015612ac65750600285105b15612b1757612ad481612dde565b6001600160f81b031916612ae783612dde565b6001600160f81b031916148015612afb5750825b15612b1257612b0b600187613cf9565b9550612b17565b600092505b8680612b275750612b2782612e12565b80612b365750612b3681612e12565b9650868015612b46575083612710145b15612b4f578493505b612b5a600186613cf9565b94508e891480612b6957508b88145b15612b75575050612b96565b612b8060018a613e97565b9850612b8d600189613e97565b97505050612a33565b841580612ba1575081155b15612bc457600284101580612bb65750828410155b975050505050505050612bd7565b81841180612bb657505050111593505050505b9695505050505050565b60608060005b600a8110156119f55781612bfa82611b33565b612c0386611b33565b604051602001612c159392919061368a565b60405160208183030381529060405291508080612c3190613f38565b915050612be7565b6060806000600260ce851480612c50575084610138145b80612c5c57508461010e145b80612c65575084155b80612c705750846090145b15612c7d57506003612c95565b8460481480612c8c5750846060145b15612c95575060055b60005b600a811015612dd257875115612dc05760006006881015612cba576000612cd0565b612cc5600689613e97565b612cd0906002613e57565b90506000612cdf600284613f53565b612d1b5760048a612cf08488613cf9565b81518110612d0057612d00613f93565b01602001516001600160f81b031916901c60f81c9050612d52565b89612d268387613cf9565b81518110612d3657612d36613f93565b60209101015160f81c600f169050612d4f600186613cf9565b94505b85612d5c84611b33565b612d658b611b33565b612d7c612d728886613e57565b610f3a908d613cf9565b604051602001612d8c919061393a565b60408051601f1981840301815290829052612dac949392916020016135df565b604051602081830303815290604052955050505b80612dca81613f38565b915050612c98565b50919695505050505050565b6000604160f883901c10801590612dfa5750605a60f883901c11155b15612e0e5761260d60f883901c6020613d11565b5090565b6000606160f883901c1480612e2b5750606560f883901c145b80612e3a5750606960f883901c145b80612e495750606f60f883901c145b80612e585750607560f883901c145b80612e675750607960f883901c145b80612e765750604160f883901c145b80612e855750604560f883901c145b80612e945750604960f883901c145b80612ea35750604f60f883901c145b80612eb25750605560f883901c145b8061062357505060f81c60591490565b828054612ece90613efd565b90600052602060002090601f016020900481019282612ef05760008555612f36565b82601f10612f0957805160ff1916838001178555612f36565b82800160010185558215612f36579182015b82811115612f36578251825591602001919060010190612f1b565b50612e0e929150612f69565b60405180608001604052806004905b6060815260200190600190039081612f515790505090565b5b80821115612e0e5760008155600101612f6a565b600067ffffffffffffffff80841115612f9957612f99613fa9565b604051601f8501601f19908116603f01168101908282118183101715612fc157612fc1613fa9565b81604052809350858152868686011115612fda57600080fd5b858560208301376000602087830101525050509392505050565b80356001600160a01b038116811461262557600080fd5b60006020828403121561301d57600080fd5b61302682612ff4565b9392505050565b6000806040838503121561304057600080fd5b61304983612ff4565b915061305760208401612ff4565b90509250929050565b60008060006060848603121561307557600080fd5b61307e84612ff4565b925061308c60208501612ff4565b9150604084013590509250925092565b600080600080608085870312156130b257600080fd5b6130bb85612ff4565b93506130c960208601612ff4565b925060408501359150606085013567ffffffffffffffff8111156130ec57600080fd5b8501601f810187136130fd57600080fd5b61310c87823560208401612f7e565b91505092959194509250565b6000806040838503121561312b57600080fd5b61313483612ff4565b91506020830135801515811461314957600080fd5b809150509250929050565b6000806040838503121561316757600080fd5b61317083612ff4565b946020939093013593505050565b60006020828403121561319057600080fd5b813561302681613fbf565b6000602082840312156131ad57600080fd5b815161302681613fbf565b6000602082840312156131ca57600080fd5b813567ffffffffffffffff8111156131e157600080fd5b8201601f810184136131f257600080fd5b6115b884823560208401612f7e565b60006020828403121561321357600080fd5b5035919050565b60008151808452613232816020860160208601613ed1565b601f01601f19169290920160200192915050565b60008151613258818560208601613ed1565b9290920192915050565b60008351613274818460208801613ed1565b835190830190613288818360208801613ed1565b600160fd1b9101908152600101949350505050565b600083516132af818460208801613ed1565b8351908301906132c3818360208801613ed1565b01949350505050565b600084516132de818460208901613ed1565b8451908301906132f2818360208901613ed1565b8451910190613305818360208801613ed1565b0195945050505050565b60008651613321818460208b01613ed1565b6f2261747472696275746573223a205b7b60801b9083019081527f2274726169745f74797065223a2022547261636b222c202276616c7565223a2260108201528651613374816030840160208b01613ed1565b64227d2c207b60d81b603092909101918201527f2274726169745f74797065223a2022426c6f636b222c202276616c7565223a22603582015285516133c0816055840160208a01613ed1565b61227d60f01b91016055810191909152612c7b60f01b60578201527f2274726169745f74797065223a2022577269746572222c202276616c7565223a60598201526204460f60eb1b6079820152612a1a61342761347a61344261343583607c87018b613246565b61227d60f01b815260020190565b605d60f81b815260010190565b7f2c2022696d616765223a2022646174613a696d6167652f7376672b786d6c3b62815265185cd94d8d0b60d21b602082015260260190565b86613246565b60008251613492818460208701613ed1565b600560f91b920191825250600101919050565b600084516134b7818460208901613ed1565b7f3c7465787420783d22302220793d2236222066696c6c3d22000000000000000090830190815284516134f1816018840160208901613ed1565b7f2220636c6173733d2277726974657254657874223e307800000000000000000060189290910191820152835161352f81602f840160208801613ed1565b661e17ba32bc3a1f60c91b602f929091019182015260360195945050505050565b60008451613562818460208901613ed1565b6e1e3a32bc3a103c1e911811103c9e9160891b908301908152845161358e81600f840160208901613ed1565b6e11103334b6361e913bb434ba32911f60891b600f929091019182015283516135be81601e840160208801613ed1565b661e17ba32bc3a1f60c91b601e929091019182015260250195945050505050565b600085516135f1818460208a01613ed1565b681e3932b1ba103c1e9160b91b9083019081528551613617816009840160208a01613ed1565b6411103c9e9160d91b60099290910191820152845161363d81600e840160208901613ed1565b6711103334b6361e9160c11b600e92909101918201528351613666816016840160208801613ed1565b68111f1e17b932b1ba1f60b91b60169290910191820152601f019695505050505050565b6000845161369c818460208901613ed1565b681e3932b1ba103c1e9160b91b90830190815284516136c2816009840160208901613ed1565b6411103c9e9160d91b6009929091019182015283516136e881600e840160208801613ed1565b6f111031b630b9b99e913198903991179f60811b600e9290910191820152601e0195945050505050565b6000875160206137258285838d01613ed1565b8851918401916137388184848d01613ed1565b885192019161374a8184848c01613ed1565b875192019161375c8184848b01613ed1565b865192019161376e8184848a01613ed1565b85519201916137808184848901613ed1565b919091019998505050505050505050565b683d913730b6b2911d1160b91b8152602360f81b600982015283516000906137c081600a850160208901613ed1565b6201016960ed1b600a9184019182015284516137e381600d840160208901613ed1565b7f222c20226465736372697074696f6e223a22437970686572206f6e2d636861699101600d8101919091527f6e206973206120736d61727420636f6e7472616374207468617420636f6e6475602d8201527f63747320612072617020637970686572206f6e20457468657265756d2e204379604d8201527f706865722045502069732069747320666972737420636f6c6c6563746976656c606d8201527f79207772697474656e20616c62756d207769746820313020747261636b732e20608d8201527f4561636820747261636b20636f6e7461696e7320323020626c6f636b732c206360ad8201527f6f6d707269736564206f662034206261727320656163682e204120626c6f636b60cd8201526d01034b99030b71027232a171116160951b60ed82015268113130b939911d101160b91b60fb820152612bd761392b610104830161347a565b6201116160ed1b815260030190565b630d0e6d8560e31b815260008251613959816004850160208701613ed1565b682c3935252c3430252960b81b6004939091019283015250600d01919050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c0000008152600082516139b181601d850160208701613ed1565b91909101601d0192915050565b7f3c7376672076657273696f6e3d22312e31222073686170652d72656e6465726981527f6e673d226f7074696d697a6553706565642220786d6c6e733d22687474703a2f60208201527f2f7777772e77332e6f72672f323030302f7376672220786d6c6e733a786c696e60408201527f6b3d22687474703a2f2f7777772e77332e6f72672f313939392f786c696e6b2260608201527f20783d223070782220793d22307078222077696474683d22333030222068656960808201527f6768743d22333030222076696577426f783d223020302031302031302220786d60a082015272361d39b830b1b29e91383932b9b2b93b32911f60691b60c082015260008551613ad08160d3850160208a01613ed1565b855190830190613ae78160d3840160208a01613ed1565b8551910190613afd8160d3840160208901613ed1565b8451910190613b138160d3840160208801613ed1565b612a1a60d382840101651e17b9bb339f60d11b815260060190565b7f3c7465787420783d22302220793d2231222066696c6c3d220000000000000000815260008451613b66816018850160208901613ed1565b680111f2a3930b1b59d160bd1b6018918401918201528451613b8f816021840160208901613ed1565b690101690213637b1b59d160b51b602192909101918201528351613bba81602b840160208801613ed1565b661e17ba32bc3a1f60c91b602b929091019182015260320195945050505050565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090612bd79083018461321a565b602081526000613026602083018461321a565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60208082526031908201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f6040820152701ddb995c881b9bdc88185c1c1c9bdd9959607a1b606082015260800190565b60008219821115613d0c57613d0c613f67565b500190565b600060ff821660ff84168060ff03821115613d2e57613d2e613f67565b019392505050565b600082613d4557613d45613f7d565b500490565b600060ff831680613d5d57613d5d613f7d565b8060ff84160491505092915050565b600181815b80851115613da7578160001904821115613d8d57613d8d613f67565b80851615613d9a57918102915b93841c9390800290613d71565b509250929050565b60006130268383600082613dc557506001610623565b81613dd257506000610623565b8160018114613de85760028114613df257613e0e565b6001915050610623565b60ff841115613e0357613e03613f67565b50506001821b610623565b5060208310610133831016604e8410600b8410161715613e31575081810a610623565b613e3b8383613d6c565b8060001904821115613e4f57613e4f613f67565b029392505050565b6000816000190483118215151615613e7157613e71613f67565b500290565b600060ff821660ff84168160ff0481118215151615613e4f57613e4f613f67565b600082821015613ea957613ea9613f67565b500390565b600060ff821660ff841680821015613ec857613ec8613f67565b90039392505050565b60005b83811015613eec578181015183820152602001613ed4565b83811115610cda5750506000910152565b600181811c90821680613f1157607f821691505b60208210811415613f3257634e487b7160e01b600052602260045260246000fd5b50919050565b6000600019821415613f4c57613f4c613f67565b5060010190565b600082613f6257613f62613f7d565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160e01b03198116811461147857600080fdfe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2fa2646970667358221220b0f169864b81a1c68a6c11e04657c69e14599a5c884ee22b071b0f1a5d54174064736f6c63430008060033

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

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