ETH Price: $3,970.69 (+2.77%)

Token

ChainPhallus Arena (8==D~)
 

Overview

Max Total Supply

31 8==D~

Holders

22

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A

Other Info

Filtered by Token Holder
koreanpapi.eth
Balance
2 8==D~
0xfd6aacd2475fcb4797c9beb6bdf909bca2af0408
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:
ChainPhallus

Compiler Version
v0.8.7+commit.e28d00a7

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, GNU GPLv3 license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2023-01-23
*/

// File: contracts/ChainPhallusErrors.sol




pragma solidity 0.8.7;

// Sale
error SaleNotOpen();
error NotPreSaleStage();
error NotMainSaleStage();
error SaleNotComplete();
error MainSaleNotComplete();
error AlreadyClaimed();
error InvalidClaimValue();
error InvalidClaimAmount();
error InvalidProof();
error InvalidMintValue();

// NFT
error NonExistentToken();

// Reveal
error InvalidReveal();
error BalanceNotWithdrawn();
error BalanceAlreadyWithdrawn();

// Arena
error LeavingProhibited();
error ArenaIsActive();
error ArenaNotActive();
error ArenaEntryClosed();
error WienersNotFluffy();
error WienersAreFluffy();
error LastErectWiener();
error GameOver();
error InvalidJoinCount();
error NotYourWiener();
// File: @openzeppelin/[email protected]/utils/cryptography/MerkleProof.sol


// OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/MerkleProof.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// File: @openzeppelin/[email protected]/utils/Strings.sol


// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

// File: contracts/ChainPhallusRenderer.sol



pragma solidity 0.8.7;


contract ChainPhallusRenderer {
    using Strings for uint256;

    // Rendering constants
    string[13] public ballsArray = [unicode"8", unicode"ō", unicode"B", unicode"₿", unicode"β", unicode"З", unicode"$", unicode"𑂈", unicode"𐋀", unicode"Ӡ", unicode"θ", unicode"Ƀ", unicode"Ѯ"];
    string[21] public shaft1Array = [unicode"=", unicode"Ξ", unicode"⇔", unicode"⁐", unicode"÷", unicode"—", unicode"+", unicode"‡", unicode"∺", unicode"ǂ", unicode"―", unicode"–", unicode"∷", unicode"⋍", unicode"⇌", unicode"⎓", unicode"⟾", unicode"⏔", unicode"⏕", unicode"≂", unicode"≃"];
    string[21] public shaft2Array = [unicode"=", unicode"Ξ", unicode"⇔", unicode"⁐", unicode"÷", unicode"—", unicode"+", unicode"‡", unicode"∺", unicode"ǂ", unicode"―", unicode"–", unicode"∷", unicode"⋍", unicode"⇌", unicode"⎓", unicode"⟾", unicode"⏔", unicode"⏕", unicode"≂", unicode"≃"];
    string[19] public headArray = [unicode"D", unicode"Ͽ", unicode"Ͻ", unicode"Đ", unicode"Э", unicode">", unicode"Ӭ", unicode"O", unicode"∋", unicode"Ӛ", unicode"Ә", unicode"»", unicode"Ѳ", unicode"Ӫ", unicode"Θ", unicode"Ɗ", unicode"Ø", unicode"Þ", unicode"⊃"];
    string[11] public jizzArray = [unicode"~", unicode"—", unicode"–", unicode"―", unicode"¬", unicode"⌐", unicode"⁊", unicode"√", unicode"ᜯ", unicode"ᜰ", unicode"∖"];


    uint256[21] rarityArray = [0, 2, 5, 9, 14, 20, 27, 35, 44, 54, 65, 77, 90, 104, 119, 135, 152, 170, 189, 209, 230]; // , 252];

    uint256[10][] ancients;

    // Mapping to determine pulledOut status for the metadata
    mapping(uint256 => bool) public pulledOut;
    // Mapping to determine champion status for the metadata
    mapping(uint256 => bool) public wienerOfWieners;


    constructor() {
        ancients.push([0, 0, 0, 0, 0]);
        ancients.push([1, 1, 1, 1, 1]);
        ancients.push([2, 2, 2, 2, 2]);
        ancients.push([3, 3, 3, 3, 3]);
        ancients.push([4, 4, 4, 4, 4]);
        ancients.push([5, 5, 5, 5, 5]);
        ancients.push([6, 6, 6, 6, 6]);
        ancients.push([7, 7, 7, 7, 7]);
        ancients.push([8, 8, 8, 8, 8]);
        ancients.push([9, 9, 9, 9, 9]);
    }
    // Get ChainPhallus address
    address _chainPhallusAddress;
    function receiveChainPhallusAddress(address chainPhallusAddress) public {
        _chainPhallusAddress = chainPhallusAddress;
    }
    // TODO: modify selectors and symmetry calculation
    function getBalls(uint256 id, uint256 seed) public view returns (string memory) {
        if (id < ancients.length) {
            return ballsArray[ancients[id][0]];
        }

        uint256 raritySelector = seed % 104;

        uint256 charSelector = 0;

        for (uint i = 0; i < 13; i++) {
            if (raritySelector >= rarityArray[i]) {
                charSelector = i;
            }
        }

        return ballsArray[charSelector];
    }

    function getShaft1(uint256 id, uint256 seed) public view returns (string memory) {
        if (id < ancients.length) {
            return shaft1Array[ancients[id][1]];
        }

        uint256 raritySelector = seed % 252;

        uint256 charSelector = 0;

        for (uint i = 0; i < 21; i++) {
            if (raritySelector >= rarityArray[i]) {
                charSelector = i;
            }
        }

        return shaft1Array[charSelector];
    }

    function getShaft2(uint256 id, uint256 seed) public view returns (string memory) {
        if (id < ancients.length) {
            return shaft2Array[ancients[id][2]];
        }

        uint256 raritySelector = uint256(keccak256(abi.encodePacked(seed))) % 252;

        uint256 charSelector = 0;

        for (uint i = 0; i < 21; i++) {
            if (raritySelector >= rarityArray[i]) {
                charSelector = i;
            }
        }

        return shaft2Array[charSelector];
    }

    function getHead(uint256 id, uint256 seed) public view returns (string memory) {
        if (id < ancients.length) {
            return headArray[ancients[id][3]];
        }

        uint256 raritySelector = seed % 209;

        uint256 charSelector = 0;

        for (uint i = 0; i < 19; i++) {
            if (raritySelector >= rarityArray[i]) {
                charSelector = i;
            }
        }

        return headArray[charSelector];
    }

    function getJizz(uint256 id, uint256 seed) public view returns (string memory) {
        if (id < ancients.length) {
            return jizzArray[ancients[id][4]];
        }

        uint256 raritySelector = seed % 77;

        uint256 charSelector = 0;

        for (uint i = 0; i < 11; i++) {
            if (raritySelector >= rarityArray[i]) {
                charSelector = i;
            }
        }

        return jizzArray[charSelector];
    }

    function setPulledOutStatus(uint256 id) external {
        pulledOut[id] = true;
    }
    function setWienerOfWienersStatus(uint256 id) external {
        wienerOfWieners[id] = true;
    }

    function getStatus(uint256 id, address owner) public view returns (string memory) {
        if (owner == _chainPhallusAddress) {
            return "Swingin\'";
        }
        if (pulledOut[id]) {
            return "Pulled out";
        }
        if (wienerOfWieners[id]) {
            return "Wiener";
        }
        return "Virgin";
    }

    function assemblePhallus(bool revealComplete, uint256 id, uint256 seed) public view returns (string memory phallus) {
        if (!revealComplete) {
            return '8==D~';
        }

        return string(abi.encodePacked(
                getBalls(id, seed),
                getShaft1(id, seed),
                getShaft2(id, seed),
                getHead(id, seed),
                getJizz(id, seed)
            ));
    }

    function calculateGolfScore(uint256 id, uint256 seed) public view returns (uint256) {
        if (id < ancients.length) {
            return 0;
        }

        uint256 ballsRarity = seed % 104;
        uint256 shaft1Rarity = seed % 252;
        uint256 shaft2Rarity = uint256(keccak256(abi.encodePacked(seed))) % 252;
        uint256 headRarity = seed % 209;
        uint256 jizzRarity = seed % 77;

        uint256 ballsGolf = 0;
        uint256 shaft1Golf = 0;
        uint256 shaft2Golf = 0;
        uint256 headGolf = 0;
        uint256 jizzGolf = 0;
        uint256 i = 0;

        for (i = 0; i < 13; i++) {
            if (ballsRarity >= rarityArray[i]) {
                ballsGolf = i;
            }
        }
        for (i = 0; i < 21; i++) {
            if (shaft1Rarity >= rarityArray[i]) {
                shaft1Golf = i;
            }
        }
        for (i = 0; i < 21; i++) {
            if (shaft2Rarity >= rarityArray[i]) {
                shaft2Golf = i;
            }
        }
        for (i = 0; i < 19; i++) {
            if (headRarity >= rarityArray[i]) {
                headGolf = i;
            }
        }
        for (i = 0; i < 11; i++) {
            if (jizzRarity >= rarityArray[i]) {
                jizzGolf = i;
            }
        }

        return ballsGolf + shaft1Golf + shaft2Golf + headGolf + jizzGolf;
    }

    function calculateSymmetry(uint256 id, uint256 seed) public view returns (string memory) {

        uint256 symCount = 0;

        if (id < ancients.length) {
            symCount = 1;
        } else {
            uint256 shaft1Rarity = seed % 252;
            uint256 shaft2Rarity = uint256(keccak256(abi.encodePacked(seed))) % 252;

            uint256 shaft1Index = 0;
            uint256 shaft2Index = 0;
            uint256 i = 0;

            for (i = 0; i < 21; i++) {
                if (shaft1Rarity >= rarityArray[i]) {
                    shaft1Index = i;
                }
            }
            for (i = 0; i < 21; i++) {
                if (shaft2Rarity >= rarityArray[i]) {
                    shaft2Index = i;
                }
            }
            if (shaft1Index == shaft2Index) {
                symCount =  1;
            }
        }
        if (symCount == 1) {
            return "Perfect Shaft";
        }
        else {
            return "Crooked Shaft";
        }
    }

    function getTextColor(uint256 id) public view returns (string memory) {
        if (id < ancients.length) {
            return 'RGB(148,256,209)';
        } else {
            return 'RGB(0,0,0)';
        }
    }

    function getBackgroundColor(uint256 id, uint256 seed) public view returns (string memory){
        if (id < ancients.length) {
            return 'RGB(128,128,128)';
        }

        uint256 golf = calculateGolfScore(id, seed);
        uint256 red;
        uint256 green;
        uint256 blue;

        if (golf >= 56) {
            red = 255;
            green = 255;
            blue = 255 - (golf - 56) * 4;
        }
        else {
            red = 255 - (56 - golf) * 4;
            green = 255 - (56 - golf) * 4;
            blue = 255;
        }

        return string(abi.encodePacked("RGB(", red.toString(), ",", green.toString(), ",", blue.toString(), ")"));
    }
    string constant headerText = 'data:application/json;ascii,{"description": "ChainPhallus Arena; where you go sword to sword until you are crowned the wiener.","image":"data:image/svg+xml;base64,';
    string constant attributesText = '","attributes":[{"trait_type":"Golf Score","value":';
    string constant symmetryText = '},{"trait_type":"Shaft","value":"';
    string constant ballsText = '"},{"trait_type":"Balls","value":"';
    string constant shaft1Text = '"},{"trait_type":"Lower Shaft","value":"';
    string constant shaft2Text = '"},{"trait_type":"Upper Shaft","value":"';
    string constant headText = '"},{"trait_type":"Head","value":"';
    string constant jizzText = '"},{"trait_type":"Jizz","value":"';
    string constant statusText = '"},{"trait_type":"Status","value":"';
    string constant arenaDurationText = '"},{"trait_type":"Arena Score","value":';
    string constant ancientText = '},{"trait_type":"Ancient","value":"';
    string constant footerText = '"}]}';

    function renderMetadata(bool revealComplete, uint256 id, uint256 seed, uint256 arenaDuration, address owner) external view returns (string memory) {
        if (!revealComplete) {
            return preRevealMetadata();
        }

        uint256 golfScore = calculateGolfScore(id, seed);

        string memory svg = b64Encode(bytes(renderSvg(true, id, seed, arenaDuration, owner)));

        string memory attributes = string(abi.encodePacked(attributesText, golfScore.toString()));
        attributes = string(abi.encodePacked(attributes, symmetryText, calculateSymmetry(id, seed)));
        attributes = string(abi.encodePacked(attributes, ballsText, getBalls(id, seed)));
        attributes = string(abi.encodePacked(attributes, shaft1Text, getShaft1(id, seed)));
        attributes = string(abi.encodePacked(attributes, shaft2Text, getShaft2(id, seed)));
        attributes = string(abi.encodePacked(attributes, headText, getHead(id, seed)));
        attributes = string(abi.encodePacked(attributes, jizzText, getJizz(id, seed)));
        attributes = string(abi.encodePacked(attributes, statusText, getStatus(id, owner)));
        attributes = string(abi.encodePacked(attributes, arenaDurationText, arenaDuration.toString()));

        if (id < ancients.length) {
            attributes = string(abi.encodePacked(attributes, ancientText, 'Ancient'));
        } else {
            attributes = string(abi.encodePacked(attributes, ancientText, 'Not Ancient'));
        }

        attributes = string(abi.encodePacked(attributes, footerText));

        return string(abi.encodePacked(headerText, svg, attributes));
    }

    string constant svg1 = "<svg xmlns='http://www.w3.org/2000/svg' width='400' height='400' style='background-color:";
    string constant svg2 = "'>  <filter id='noise'> <feTurbulence type='turbulence' baseFrequency='0.0024' numOctaves='8' result='turbulence' /> <feDisplacementMap in='SourceGraphic' scale='42' /> </filter>";
    string constant svg3 = "<text style='filter: url(#noise)' x='50%' y='50%' dominant-baseline='middle' text-anchor='middle' font-size='75px' fill='";
    string constant svg4 = "'>";
    string constant svg5 = "</text></svg>";

    function renderSvg(bool revealComplete, uint256 id, uint256 seed, uint256 arenaDuration, address owner) public view returns (string memory) {
        if (!revealComplete) {
            return preRevealSvg();
        }

        string memory phallus = assemblePhallus(true, id, seed);
        string memory pubes;

        if (arenaDuration > 0) {
            pubes = generatePubes(arenaDuration, seed);
        }

        return string(abi.encodePacked(svg1, getBackgroundColor(id, seed), svg2, pubes, svg3, getTextColor(id), svg4, phallus, svg5));
    }

    string constant pubeSymbol = "<symbol id='pube'><g stroke='RGBA(0,0,0,1)'><text x='40' y='40' dominant-baseline='middle' text-anchor='middle' font-weight='normal' font-size='36px' fill='RGBA(0,0,0,1)'>&#x04A8</text></g></symbol>";
    string constant pubePlacement1 = "<g transform='translate(";
    string constant pubePlacement2 = ") scale(";
    string constant pubePlacement3 = ") rotate(";
    string constant pubePlacement4 = ")'><use href='#pube'/></g>";

    function generatePubes(uint256 arenaDuration, uint256 seed) internal pure returns (string memory) {
        string memory pubes;
        string memory pubesTemp;

        uint256 count = arenaDuration / 10;

        if (count > 500) {
            count = 500;
        }

        for (uint256 i = 0; i < count; i++) {
            string memory pube;

            uint256 pubeSeed = uint256(keccak256(abi.encodePacked(seed, i)));

            uint256 scale1 = pubeSeed % 2;
            uint256 scale2 = pubeSeed % 5;
            if (scale1 == 0) {
                scale2 += 5;
            }
            uint256 xShift = pubeSeed % 332;
            uint256 yShift = pubeSeed % 354;
            int256 rotate = int256(pubeSeed % 91) - 45;

            pube = string(abi.encodePacked(pube, pubePlacement1, xShift.toString(), " ", yShift.toString(), pubePlacement2, scale1.toString(), ".", scale2.toString()));

            if (rotate >= 0) {
                pube = string(abi.encodePacked(pube, pubePlacement3, uint256(rotate).toString(), pubePlacement4));
            } else {
                pube = string(abi.encodePacked(pube, pubePlacement3, "-", uint256(0 - rotate).toString(), pubePlacement4));
            }

            pubesTemp = string(abi.encodePacked(pubesTemp, pube));

            if (i % 10 == 0) {
                pubes = string(abi.encodePacked(pubes, pubesTemp));
                pubesTemp = "";
            }
        }

        return string(abi.encodePacked(pubeSymbol, pubes, pubesTemp));
    }

    function preRevealMetadata() internal pure returns (string memory) {
        string memory JSON;
        string memory svg = preRevealSvg();
        JSON = string(abi.encodePacked('data:application/json;ascii,{"description": "ChainPhallus Arena; where you go sword to sword until you are crowned the wiener.","image":"data:image/svg+xml;base64,', b64Encode(bytes(svg)), '"}'));
        return JSON;
    }

    function preRevealSvg() internal pure returns (string memory) {
        return "<svg xmlns='http://www.w3.org/2000/svg' width='400' height='400' style='background-color:RGB(255,255,255);'><text x='50%' y='50%' dominant-baseline='middle' text-anchor='middle' font-size='75px'>?????</text></svg>";
    }

    string constant private TABLE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';

    function b64Encode(bytes memory _data) internal pure returns (string memory result) {
        if (_data.length == 0) return '';
        string memory _table = TABLE;
        uint256 _encodedLen = 4 * ((_data.length + 2) / 3);
        result = new string(_encodedLen + 32);

        assembly {
            mstore(result, _encodedLen)
            let tablePtr := add(_table, 1)
            let dataPtr := _data
            let endPtr := add(dataPtr, mload(_data))
            let resultPtr := add(result, 32)

            for {} lt(dataPtr, endPtr) {}
            {
                dataPtr := add(dataPtr, 3)
                let input := mload(dataPtr)
                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)
            }
            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;
    }
}
// File: @openzeppelin/[email protected]/utils/Context.sol


// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

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

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

// File: @openzeppelin/[email protected]/access/Ownable.sol


// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)

pragma solidity ^0.8.0;


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

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

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

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

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

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

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

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

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

// File: @openzeppelin/[email protected]/utils/Address.sol


// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)

pragma solidity ^0.8.1;

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

        return account.code.length > 0;
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// File: @openzeppelin/[email protected]/token/ERC721/IERC721Receiver.sol


// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)

pragma solidity ^0.8.0;

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

// File: @openzeppelin/[email protected]/utils/introspection/IERC165.sol


// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

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

// File: @openzeppelin/[email protected]/utils/introspection/ERC165.sol


// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;


/**
 * @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: @openzeppelin/[email protected]/token/ERC721/IERC721.sol


// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.0;


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

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

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

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

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

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

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

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

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

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

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

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

// File: @openzeppelin/[email protected]/token/ERC721/extensions/IERC721Enumerable.sol


// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/IERC721Enumerable.sol)

pragma solidity ^0.8.0;


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

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

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

// File: @openzeppelin/[email protected]/token/ERC721/extensions/IERC721Metadata.sol


// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)

pragma solidity ^0.8.0;


/**
 * @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: @openzeppelin/[email protected]/token/ERC721/ERC721.sol


// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/ERC721.sol)

pragma solidity ^0.8.0;








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

    // Token name
    string private _name;

    // Token symbol
    string private _symbol;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        _approve(to, tokenId);
    }

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

        return _tokenApprovals[tokenId];
    }

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

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

    /**
     * @dev See {IERC721-transferFrom}.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {
        //solhint-disable-next-line max-line-length
        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner 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: caller is not token 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) {
        address owner = ERC721.ownerOf(tokenId);
        return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender);
    }

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

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

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

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

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

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

        _afterTokenTransfer(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);

        _afterTokenTransfer(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 from incorrect owner");
        require(to != address(0), "ERC721: transfer to the zero address");

        _beforeTokenTransfer(from, to, tokenId);

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

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

        emit Transfer(from, to, tokenId);

        _afterTokenTransfer(from, to, tokenId);
    }

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

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

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

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

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

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

// File: @openzeppelin/[email protected]/token/ERC721/extensions/ERC721Enumerable.sol


// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/ERC721Enumerable.sol)

pragma solidity ^0.8.0;



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

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

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

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

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

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

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

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

    /**
     * @dev 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` cannot be the zero address.
     * - `to` cannot be the zero address.
     *
     * 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 override {
        super._beforeTokenTransfer(from, to, tokenId);

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

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

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

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

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

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

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

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

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

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

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

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

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

// File: contracts/ChainPhallus.sol



pragma solidity 0.8.7;







contract ChainPhallus is ERC721, ERC721Enumerable, Ownable {

    /*************************
     COMMON
     *************************/

    // Sale stage enum
    enum Stage {
        STAGE_COMPLETE,  // 0
        STAGE_PRESALE,  // 1
        STAGE_MAIN_SALE // 2
    }

    bool balanceNotWithdrawn;

    constructor(uint256 _secretCommit, address _renderer, bytes32 _merkleRoot) ERC721("ChainPhallus Arena", unicode"8==D~")  {
        // tokenLimit = _tokenLimit;
        secret = _secretCommit;
        merkleRoot = _merkleRoot;
        balanceNotWithdrawn = true;

        // Start in presale stage
        stage = Stage.STAGE_PRESALE;

        renderer = ChainPhallusRenderer(_renderer);

        // Send address to renderer
        renderer.receiveChainPhallusAddress(address(this));

        // Mint ancients
        for (uint256 i = 0; i < 10;) {
            _createPhallus();
            unchecked{ i++; }
        }
    }

    fallback() external payable {}

    /*************************
     TOKEN SALE
     *************************/

    Stage public               stage;
    uint256 public             saleEnds;

    // Merkle distributor values
    bytes32 immutable merkleRoot;
    mapping(uint256 => uint256) private claimedBitMap;
    uint256 public constant saleLength = 69 hours;
    uint256 public constant salePrice = 0.025 ether;

    uint256 secret;             // Entropy supplied by owner (commit/reveal style)
    uint256 userSecret;         // Pseudorandom entropy provided by minters

    // -- MODIFIERS --

    modifier onlyMainSaleOpen() {
        if (stage != Stage.STAGE_MAIN_SALE || mainSaleComplete()) {
            revert SaleNotOpen();
        }
        _;
    }

    modifier onlyPreSale() {
        if (stage != Stage.STAGE_PRESALE) {
            revert NotPreSaleStage();
        }
        _;
    }

    modifier onlyMainSale() {
        if (stage != Stage.STAGE_MAIN_SALE) {
            revert NotMainSaleStage();
        }
        _;
    }

    modifier onlySaleComplete() {
        if (stage != Stage.STAGE_COMPLETE) {
            revert SaleNotComplete();
        }
        _;
    }

    // -- VIEW METHODS --

    function mainSaleComplete() public view returns (bool) {
        return block.timestamp >= saleEnds;  // || totalSupply() == tokenLimit;
    }

    function isClaimed(uint256 index) public view returns (bool) {
        uint256 claimedWordIndex = index / 256;
        uint256 claimedBitIndex = index % 256;
        uint256 claimedWord = claimedBitMap[claimedWordIndex];
        uint256 mask = (1 << claimedBitIndex);
        return claimedWord & mask == mask;
    }

    // -- OWNER METHODS --

    // Reveal the wieners
    function theGreatReveal(uint256 _secretReveal) external onlyOwner onlyMainSale {
        if (!mainSaleComplete()) {
            revert MainSaleNotComplete();
        }

        if (uint256(keccak256(abi.encodePacked(_secretReveal))) != secret) {
            revert InvalidReveal();
        }

        // Final secret is XOR between the pre-committed secret and the pseudo-random user contributed salt
        secret = _secretReveal ^ userSecret;

        // Won't be needing this anymore
        delete userSecret;

        stage = Stage.STAGE_COMPLETE;
    }

    // Start main sale
    function startMainSale() external onlyOwner onlyPreSale {
        stage = Stage.STAGE_MAIN_SALE;
        saleEnds = block.timestamp + saleLength;
    }

    // Withdraw sale proceeds
    function withdraw() external onlyOwner {
        // Owner can't reneg on bounty
        if (arenaActive()) {
            revert ArenaIsActive();
        }
        // Can only withdraw once, and only a fixed percentage
        if (!balanceNotWithdrawn) {
            revert BalanceAlreadyWithdrawn();
        }
        balanceNotWithdrawn = false;
        owner().call{value : address(this).balance * 3058 / 10000}("");
    }

    // -- USER METHODS --

    function claim(uint256 _index, uint256 _ogAmount, uint256 _wlAmount, bytes32[] calldata _merkleProof, uint256 _amount) external payable onlyPreSale {
        // Ensure not already claimed
        if (isClaimed(_index)) {
            revert AlreadyClaimed();
        }

        // Prevent accidental claim of 0
        if (_amount == 0) {
            revert InvalidClaimAmount();
        }

        // Check claim amount
        uint256 total = _ogAmount + _wlAmount;
        if (_amount > total) {
            revert InvalidClaimAmount();
        }

        // Check claim value
        uint256 paidClaims = 0;
        if (_amount > _ogAmount) {
            paidClaims = _amount - _ogAmount;
        }
        if (msg.value < paidClaims * salePrice) {
            revert InvalidClaimValue();
        }

        // Verify the merkle proof
        bytes32 node = keccak256(abi.encodePacked(_index, msg.sender, _ogAmount, _wlAmount));
        if (!MerkleProof.verify(_merkleProof, merkleRoot, node)) {
            revert InvalidProof();
        }

        // Mark it claimed and mint
        _setClaimed(_index);

        for (uint256 i = 0; i < _amount; i++) {
            _createPhallus();
        }

        _mix();
    }

    // Mint wieners
    function createPhallus() external payable onlyMainSaleOpen {
        uint256 count = msg.value / salePrice;

        if (count == 0) {
            revert InvalidMintValue();
        } else if (count > 20) {
            count = 20;
        }

        // Mint 'em
        for (uint256 i = 0; i < count;) {
            _createPhallus();
            unchecked{ i++; }
        }

        _mix();

        // Send any excess ETH back to the caller
        uint256 excess = msg.value - (salePrice * count);
        if (excess > 0) {
            (bool success,) = msg.sender.call{value : excess}("");
            require(success);
        }
    }

    // -- INTERNAL METHODS --

    function _setClaimed(uint256 index) internal {
        uint256 claimedWordIndex = index / 256;
        uint256 claimedBitIndex = index % 256;
        claimedBitMap[claimedWordIndex] = claimedBitMap[claimedWordIndex] | (1 << claimedBitIndex);
    }

    function _createPhallus() internal {
        uint256 tokenId = totalSupply();
        _mint(msg.sender, tokenId);
    }

    function _mix() internal {
        // Add some pseudorandom value which will be mixed with the pre-committed secret
        unchecked {
            userSecret += uint256(blockhash(block.number - 1));
        }
    }

    /*************************
     NFT
     *************************/

    modifier onlyTokenExists(uint256 _id) {
        if (!_exists(_id)) {
            revert NonExistentToken();
        }
        _;
    }

    ChainPhallusRenderer public renderer;

    // -- VIEW METHODS --

    function assemblePhallus(uint256 _id) external view onlyTokenExists(_id) returns (string memory) {
        return renderer.assemblePhallus(stage == Stage.STAGE_COMPLETE, _id, getFinalizedSeed(_id));
    }

    function tokenURI(uint256 _id) public view override onlyTokenExists(_id) returns (string memory) {
        return renderer.renderMetadata(stage == Stage.STAGE_COMPLETE, _id, getFinalizedSeed(_id), roundsSurvived[_id], ownerOf(_id));
    }

    function renderSvg(uint256 _id) external view onlyTokenExists(_id) returns (string memory) {
        uint256 rounds;

        // If wiener is still in the arena, show them with correct amount of scars
        if (ownerOf(_id) == address(this)) {
            rounds = currentRound;
        } else {
            rounds = roundsSurvived[_id];
        }

        return renderer.renderSvg(stage == Stage.STAGE_COMPLETE, _id, getFinalizedSeed(_id), rounds, ownerOf(_id));
    }

    // -- INTERNAL METHODS --

    function getFinalizedSeed(uint256 _tokenId) internal view returns (uint256) {
        return uint256(keccak256(abi.encodePacked(secret, _tokenId)));
    }

    /*************************
     ARENA
     *************************/

    uint256     arenaOpenedBlock;
    uint256     wienersLastBust;
    uint256     champion;

    uint256 public currentRound = 0;
    uint256 public bustedNut = 0;
    uint256 public pulledOut = 0;
    uint256 public swingin = 0;

    uint256 public constant arenaWaitBlocks = 12600;
    uint256 public constant blocksPerRound = 42;

    mapping(uint256 => address) public wienerDepositor;
    mapping(uint256 => uint256) public roundsSurvived;

    // -- MODIFIERS --

    modifier onlyOpenArena() {
        if (!entryOpen()) {
            revert ArenaEntryClosed();
        }
        _;
    }

    // -- VIEW METHODS --

    struct ArenaInfo {
        uint256 busted;
        uint256 swingin;
        uint256 pulledOut;
        uint256 currentRound;
        uint256 bounty;
        uint256 hardness;
        uint256 nextBust;
        uint256 champion;
        uint256 entryClosedBlock;
        bool horny;
        bool open;
        bool active;
        bool gameOver;
    }

    function arenaInfo() external view returns (ArenaInfo memory info) {
        info.busted = bustedNut;
        info.swingin = swingin;
        info.pulledOut = pulledOut;
        info.currentRound = currentRound;
        info.bounty = address(this).balance;
        info.hardness = howHornyAreTheWieners();
        info.champion = champion;
        info.entryClosedBlock = entryClosedBlock();

        if (!theWienersAreFluffy()) {
            info.nextBust = wienersLastBust + blocksPerRound - block.number;
        }

        info.horny = theWienersAreFluffy();
        info.open = entryOpen();
        info.active = arenaActive();
        info.gameOver = block.number > info.entryClosedBlock && info.swingin <= 1;
    }

    // Return array of msg.senders remaining wieners
    function myWieners() external view returns (uint256[] memory) {
        return ownerWieners(msg.sender);
    }

    // Return array of owner's remaining wieners
    function ownerWieners(address _owner) public view returns (uint256[] memory) {
        address holdingAddress;
        holdingAddress = address(this);

        uint256 total = balanceOf(holdingAddress);
        uint256[] memory wieners = new uint256[](total);

        uint256 index = 0;

        for (uint256 i = 0; i < total; i++) {
            uint256 id = tokenOfOwnerByIndex(holdingAddress, i);

            if (wienerDepositor[id] == _owner) {
                wieners[index++] = id;
            }
        }

        assembly {
            mstore(wieners, index)
        }

        return wieners;
    }

    function arenaActive() public view returns (bool) {
        return arenaOpenedBlock > 0;
    }

    function entryOpen() public view returns (bool) {
        return arenaActive() && block.number < entryClosedBlock();
    }

    function entryClosedBlock() public view returns (uint256) {
        return arenaOpenedBlock + arenaWaitBlocks;
    }

    function howHornyAreTheWieners() public view returns (uint256) {

        if (swingin == 0) {
            return 0;
        }

        uint256 hardness = 1;

        // Calculate how many wieners busted (0.2% of wieners > 1000)
        if (swingin >= 2000) {
            uint256 excess = swingin - 1000;
            hardness = excess / 500;
        }

        // The last wiener standing never busts
        if (hardness >= swingin) {
            hardness = swingin - 1;
        }

        // Generous upper bound to prevent gas overflow
        if (hardness > 50) {
            hardness = 50;
        }

        return hardness;
    }

    function theWienersAreFluffy() public view returns (bool) {
        return block.number >= wienersLastBust + blocksPerRound;
    }

    // -- OWNER METHODS --

    function openArena() external payable onlyOwner onlySaleComplete {
        if (arenaActive()) {
            revert ArenaIsActive();
        }
        if (balanceNotWithdrawn) {
            revert BalanceNotWithdrawn();
        }

        // Open the arena
        arenaOpenedBlock = block.number;
        wienersLastBust = block.number + arenaWaitBlocks;
    }

    // -- USER METHODS --

    // Can be called every `blocksPerRound` blocks to kill off some eager wieners
    function timeToBust() external {
        if (!arenaActive()) {
            revert ArenaNotActive();
        }
        if (!theWienersAreFluffy()) {
            revert WienersNotFluffy();
        }

        if (swingin == 1) {
            revert LastErectWiener();
        }
        if (swingin == 0) {
            revert GameOver();
        }

        // The blockhash of every `blocksPerRound` block is used to determine who busts
        uint256 entropyBlock;
        if (block.number - (wienersLastBust + blocksPerRound) > 255) {
            // If this method isn't called within 255 blocks of the period end, this is a fallback so we can still progress
            entropyBlock = (block.number / blocksPerRound) * blocksPerRound - 1;
        } else {
            // Use blockhash of every 42nd block
            entropyBlock = (wienersLastBust + blocksPerRound) - 1;
        }
        uint256 entropy = uint256(blockhash(entropyBlock));
        assert(entropy != 0);

        // Update state
        wienersLastBust = block.number;
        currentRound++;

        // Kill off a percentage of wieners
        uint256 killCounter = howHornyAreTheWieners();
        bytes memory buffer = new bytes(32);
        // i starts at 1 to prevent infinite loop
        for (uint256 i = 1; i <= killCounter;) {
            // Entropy must increase even if the kill doesn't count
            unchecked { entropy = entropy + i; }
            // Gas saving trick to avoid abi.encodePacked
            assembly { mstore(add(buffer, 32), entropy) }
            // Balance of contract in case tokens were transferred without joining
            uint256 whoDied = uint256(keccak256(buffer)) % balanceOf(address(this));
            // Go to your happy place, loser
            uint256 wienerToBust = tokenOfOwnerByIndex(address(this), whoDied);
            _burn(wienerToBust);
            // Check to ensure that busted wiener was participating in the arena
            if (wienerDepositor[wienerToBust] == address(0)) {
                // If not participating, kill doesn't count
                unchecked{ --i; }
            }
            else {
                // If participating, update counts
                // Clear state
                delete wienerDepositor[wienerToBust];
                bustedNut++;
                swingin--;
            }
            unchecked{ i++; }
        }

        // Record the champion
        if (swingin == 1) {
            // Check all tokens in contract until champion is found
            uint256 wienerToCheck;
            for (uint256 i = 0; i < balanceOf(address(this));) {
                wienerToCheck = tokenOfOwnerByIndex(address(this), i);
                if (wienerDepositor[wienerToCheck] != address(0)) {
                    // If token was participating in arena it must the the champion
                    champion = wienerToCheck;
                    break;
                }
                unchecked{ i++; }
            }
            // Record the champion's achievement
            roundsSurvived[champion] = currentRound;
            // Set status
            renderer.setWienerOfWienersStatus(champion);
            // Pay the champion's owner and return wiener
            payable(wienerDepositor[champion]).transfer(address(this).balance);
            _transfer(address(this), wienerDepositor[champion], champion);
        }
    }

    function joinArena(uint256 _tokenId) external onlyOpenArena {
        _joinArena(_tokenId);
    }

    function multiJoinArena(uint256[] memory _tokenIds) external onlyOpenArena {
        if (_tokenIds.length > 20) {
            revert InvalidJoinCount();
        }

        for (uint256 i; i < _tokenIds.length;) {
            _joinArena(_tokenIds[i]);
            unchecked{ i++; }
        }
    }

    function claimBounty(uint256 _tokenId) external {
        if (wienerDepositor[_tokenId] != msg.sender) {
            revert NotYourWiener();
        }

        // Can't leave arena if wieners are horny (unless it's the champ and the game is over)
        if (swingin != 1 && theWienersAreFluffy()) {
            revert WienersAreFluffy();
        }

        // Can't leave before a single round has passed
        uint256 round = currentRound;
        if (currentRound == 0) {
            revert LeavingProhibited();
        }

        // Record the wiener's achievement
        roundsSurvived[_tokenId] = round;

        // Clear state
        delete wienerDepositor[_tokenId];

        // Must burn NFT to claim bounty
        uint256 battleBounty = address(this).balance / swingin;
        _burn(_tokenId);
        bustedNut++;
        swingin--;
        payable(msg.sender).transfer(battleBounty);

        // If this was the second last wiener to leave, the last one left is the champ
        if (swingin == 1) {
            // Check all tokens in contract until champion is found
            uint256 wienerToCheck;
            for (uint256 i = 0; i < balanceOf(address(this));) {
                wienerToCheck = tokenOfOwnerByIndex(address(this), i);
                if (wienerDepositor[wienerToCheck] != address(0)) {
                    // If token was participating in arena it must the the champion
                    champion = wienerToCheck;
                    break;
                }
                unchecked{ i++; }
            }
            // Record the champion's achievement
            roundsSurvived[champion] = round;
            // Set status
            renderer.setWienerOfWienersStatus(champion);
            // Pay the champion's owner and return wiener
            payable(wienerDepositor[champion]).transfer(address(this).balance);
            _transfer(address(this), wienerDepositor[champion], champion);
        }
    }

    function leaveArena(uint256 _tokenId) external {
        if (wienerDepositor[_tokenId] != msg.sender) {
            revert NotYourWiener();
        }

        // Can't leave arena if wieners are horny (unless it's the champ and the game is over)
        if (swingin != 1 && theWienersAreFluffy()) {
            revert WienersAreFluffy();
        }

        // Can't leave before a single round has passed
        uint256 round = currentRound;
        if (currentRound == 0) {
            revert LeavingProhibited();
        }

        // Record the wiener's achievement
        roundsSurvived[_tokenId] = round;

        // Set status
        renderer.setPulledOutStatus(_tokenId);
        // Clear state
        delete wienerDepositor[_tokenId];

        // Return wiener
         _transfer(address(this), msg.sender, _tokenId);
        pulledOut++;
        swingin--;

        // If this was the second last wiener to leave, the last one left is the champ
        if (swingin == 1) {
            // Check all tokens in contract until champion is found
            uint256 wienerToCheck;
            for (uint256 i = 0; i < balanceOf(address(this));) {
                wienerToCheck = tokenOfOwnerByIndex(address(this), i);
                if (wienerDepositor[wienerToCheck] != address(0)) {
                    // If token was participating in arena it must the the champion
                    champion = wienerToCheck;
                    break;
                }
                unchecked{ i++; }
            }
            // Record the champion's achievement
            roundsSurvived[champion] = round;
            // Set status
            renderer.setWienerOfWienersStatus(champion);
            // Pay the champion's owner and return wiener
            payable(wienerDepositor[champion]).transfer(address(this).balance);
            _transfer(address(this), wienerDepositor[champion], champion);
        }
    }
    // -- INTERNAL METHODS --

    function _joinArena(uint256 _tokenId) internal {
        // Send wiener to the arena
        transferFrom(msg.sender, address(this), _tokenId);
        wienerDepositor[_tokenId] = msg.sender;
        swingin++;
    }

    /*************************
     MISC
     *************************/

    function onERC721Received(address, address, uint256, bytes memory) external pure returns (bytes4) {
        return this.onERC721Received.selector;
    }

    function _beforeTokenTransfer(address _from, address _to, uint256 _tokenId) internal override(ERC721, ERC721Enumerable) {
        super._beforeTokenTransfer(_from, _to, _tokenId);
    }

    function supportsInterface(bytes4 _interfaceId) public view virtual override(ERC721, ERC721Enumerable) returns (bool) {
        return super.supportsInterface(_interfaceId);
    }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"uint256","name":"_secretCommit","type":"uint256"},{"internalType":"address","name":"_renderer","type":"address"},{"internalType":"bytes32","name":"_merkleRoot","type":"bytes32"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyClaimed","type":"error"},{"inputs":[],"name":"ArenaEntryClosed","type":"error"},{"inputs":[],"name":"ArenaIsActive","type":"error"},{"inputs":[],"name":"ArenaNotActive","type":"error"},{"inputs":[],"name":"BalanceAlreadyWithdrawn","type":"error"},{"inputs":[],"name":"BalanceNotWithdrawn","type":"error"},{"inputs":[],"name":"GameOver","type":"error"},{"inputs":[],"name":"InvalidClaimAmount","type":"error"},{"inputs":[],"name":"InvalidClaimValue","type":"error"},{"inputs":[],"name":"InvalidJoinCount","type":"error"},{"inputs":[],"name":"InvalidMintValue","type":"error"},{"inputs":[],"name":"InvalidProof","type":"error"},{"inputs":[],"name":"InvalidReveal","type":"error"},{"inputs":[],"name":"LastErectWiener","type":"error"},{"inputs":[],"name":"LeavingProhibited","type":"error"},{"inputs":[],"name":"MainSaleNotComplete","type":"error"},{"inputs":[],"name":"NonExistentToken","type":"error"},{"inputs":[],"name":"NotMainSaleStage","type":"error"},{"inputs":[],"name":"NotPreSaleStage","type":"error"},{"inputs":[],"name":"NotYourWiener","type":"error"},{"inputs":[],"name":"SaleNotComplete","type":"error"},{"inputs":[],"name":"SaleNotOpen","type":"error"},{"inputs":[],"name":"WienersAreFluffy","type":"error"},{"inputs":[],"name":"WienersNotFluffy","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"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"},{"stateMutability":"payable","type":"fallback"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"arenaActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"arenaInfo","outputs":[{"components":[{"internalType":"uint256","name":"busted","type":"uint256"},{"internalType":"uint256","name":"swingin","type":"uint256"},{"internalType":"uint256","name":"pulledOut","type":"uint256"},{"internalType":"uint256","name":"currentRound","type":"uint256"},{"internalType":"uint256","name":"bounty","type":"uint256"},{"internalType":"uint256","name":"hardness","type":"uint256"},{"internalType":"uint256","name":"nextBust","type":"uint256"},{"internalType":"uint256","name":"champion","type":"uint256"},{"internalType":"uint256","name":"entryClosedBlock","type":"uint256"},{"internalType":"bool","name":"horny","type":"bool"},{"internalType":"bool","name":"open","type":"bool"},{"internalType":"bool","name":"active","type":"bool"},{"internalType":"bool","name":"gameOver","type":"bool"}],"internalType":"struct ChainPhallus.ArenaInfo","name":"info","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"arenaWaitBlocks","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"assemblePhallus","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"blocksPerRound","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bustedNut","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"},{"internalType":"uint256","name":"_ogAmount","type":"uint256"},{"internalType":"uint256","name":"_wlAmount","type":"uint256"},{"internalType":"bytes32[]","name":"_merkleProof","type":"bytes32[]"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"claim","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"claimBounty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"createPhallus","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"currentRound","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"entryClosedBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"entryOpen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"howHornyAreTheWieners","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"isClaimed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"joinArena","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"leaveArena","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mainSaleComplete","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"}],"name":"multiJoinArena","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"myWieners","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"openArena","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"ownerWieners","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pulledOut","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"renderSvg","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renderer","outputs":[{"internalType":"contract ChainPhallusRenderer","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"roundsSurvived","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":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"saleEnds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"saleLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"salePrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stage","outputs":[{"internalType":"enum ChainPhallus.Stage","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"startMainSale","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":"swingin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_secretReveal","type":"uint256"}],"name":"theGreatReveal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"theWienersAreFluffy","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"timeToBust","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"wienerDepositor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60a060405260006013556000601455600060155560006016553480156200002557600080fd5b50604051620040ab380380620040ab833981016040819052620000489162000738565b6040805180820182526012815271436861696e5068616c6c7573204172656e6160701b6020808301918252835180850190945260058452641c1e9ea23f60d91b9084015281519192916200009f9160009162000692565b508051620000b590600190602084019062000692565b505050620000d2620000cc6200018c60201b60201c565b62000190565b600d8390556080819052600a805461010160a01b61ffff60a01b19909116179055600f80546001600160a01b0384166001600160a01b03199091168117909155604051631b45075f60e01b8152306004820152631b45075f90602401600060405180830381600087803b1580156200014957600080fd5b505af11580156200015e573d6000803e3d6000fd5b5050505060005b600a811015620001825762000179620001e2565b60010162000165565b5050505062000834565b3390565b600a80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000620001ee60085490565b9050620001fc3382620001ff565b50565b6001600160a01b0382166200025b5760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f206164647265737360448201526064015b60405180910390fd5b6000818152600260205260409020546001600160a01b031615620002c25760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604482015260640162000252565b620002d06000838362000359565b6001600160a01b0382166000908152600360205260408120805460019290620002fb90849062000780565b909155505060008181526002602052604080822080546001600160a01b0319166001600160a01b03861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b620003718383836200037660201b620024561760201c565b505050565b6200038e8383836200037160201b62000bbd1760201c565b6001600160a01b038316620003ec57620003e681600880546000838152600960205260408120829055600182018355919091527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30155565b62000412565b816001600160a01b0316836001600160a01b031614620004125762000412838262000452565b6001600160a01b0382166200042c576200037181620004ff565b826001600160a01b0316826001600160a01b0316146200037157620003718282620005b9565b600060016200046c846200060a60201b620015b21760201c565b6200047891906200079b565b600083815260076020526040902054909150808214620004cc576001600160a01b03841660009081526006602090815260408083208584528252808320548484528184208190558352600790915290208190555b5060009182526007602090815260408084208490556001600160a01b039094168352600681528383209183525290812055565b60085460009062000513906001906200079b565b600083815260096020526040812054600880549394509092849081106200053e576200053e6200081e565b9060005260206000200154905080600883815481106200056257620005626200081e565b60009182526020808320909101929092558281526009909152604080822084905585825281205560088054806200059d576200059d62000808565b6001900381819060005260206000200160009055905550505050565b6000620005d1836200060a60201b620015b21760201c565b6001600160a01b039093166000908152600660209081526040808320868452825280832085905593825260079052919091209190915550565b60006001600160a01b038216620006765760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b606482015260840162000252565b506001600160a01b031660009081526003602052604090205490565b828054620006a090620007b5565b90600052602060002090601f016020900481019282620006c457600085556200070f565b82601f10620006df57805160ff19168380011785556200070f565b828001600101855582156200070f579182015b828111156200070f578251825591602001919060010190620006f2565b506200071d92915062000721565b5090565b5b808211156200071d576000815560010162000722565b6000806000606084860312156200074e57600080fd5b835160208501519093506001600160a01b03811681146200076e57600080fd5b80925050604084015190509250925092565b60008219821115620007965762000796620007f2565b500190565b600082821015620007b057620007b0620007f2565b500390565b600181811c90821680620007ca57607f821691505b60208210811415620007ec57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60805161385b620008506000396000611c48015261385b6000f3fe60806040526004361061033e5760003560e01c80638a19c8bc116101ae578063ccb9fe1d116100eb578063e97deabf1161008f578063f2fde38b1161006c578063f2fde38b14610962578063f51f96dd14610982578063f6b3a00a1461099d578063fd5ad319146109bd57005b8063e97deabf146108c1578063e985e9c5146108f7578063f2e45a4f1461094057005b8063dba7fd4a116100c8578063dba7fd4a1461086a578063dcafd0bc14610880578063e13cbe3814610895578063e23666de146108ac57005b8063ccb9fe1d14610807578063d0f9e2be14610827578063d660a7bd1461085457005b8063acedb5b411610152578063c040e6b81161012f578063c040e6b814610791578063c57540b9146107bf578063c87b56dd146107d4578063cb0274d5146107f457005b8063acedb5b41461073c578063b88d4fde1461075c578063bd978e8d1461077c57005b806395d89b411161018b57806395d89b41146106c75780639671219b146106dc5780639e34070f146106fc578063a22cb4651461071c57005b80638a19c8bc146106735780638ada6b0f146106895780638da5cb5b146106a957005b80633ccfd60b1161027c578063580e77d41161022057806370a08231116101fd57806370a0823114610620578063715018a61461064057806376c242461461065557806378aafea21461066b57005b8063580e77d4146105d65780636352211e146105eb5780636e4ed7961461060b57005b806346feb24a1161025957806346feb24a1461056b578063473e3ea41461058b5780634f6ccce7146105a05780635533f19a146105c057005b80633ccfd60b1461051657806342842e0e1461052b57806344021ad71461054b57005b8063150b7a02116102e35780632ae07c33116102c05780632ae07c33146104b85780632f745c59146104ce5780633364b0d2146104ee57806339af9afe146104f657005b8063150b7a021461044057806318160ddd1461047957806323b872dd1461049857005b8063095ea7b31161031c578063095ea7b3146103cf5780630a212469146103ef5780630bc634d914610407578063130eb2f61461042957005b806301ffc9a71461034057806306fdde0314610375578063081812fc14610397575b005b34801561034c57600080fd5b5061036061035b366004613283565b6109dd565b60405190151581526020015b60405180910390f35b34801561038157600080fd5b5061038a6109ee565b60405161036c91906134bd565b3480156103a357600080fd5b506103b76103b2366004613334565b610a80565b6040516001600160a01b03909116815260200161036c565b3480156103db57600080fd5b5061033e6103ea3660046131ac565b610aa7565b3480156103fb57600080fd5b50600b54421015610360565b34801561041357600080fd5b5061041c610bc2565b60405161036c9190613451565b34801561043557600080fd5b506010541515610360565b34801561044c57600080fd5b5061046061045b3660046130c5565b610bd2565b6040516001600160e01b0319909116815260200161036c565b34801561048557600080fd5b506008545b60405190815260200161036c565b3480156104a457600080fd5b5061033e6104b3366004613089565b610be3565b3480156104c457600080fd5b5061048a61313881565b3480156104da57600080fd5b5061048a6104e93660046131ac565b610c14565b61033e610caa565b34801561050257600080fd5b5061033e6105113660046131d6565b610de3565b34801561052257600080fd5b5061033e610e61565b34801561053757600080fd5b5061033e610546366004613089565b610f21565b34801561055757600080fd5b5061033e610566366004613334565b610f3c565b34801561057757600080fd5b5061033e610586366004613334565b6111ae565b34801561059757600080fd5b5061048a611442565b3480156105ac57600080fd5b5061048a6105bb366004613334565b611454565b3480156105cc57600080fd5b5061048a600b5481565b3480156105e257600080fd5b5061033e6114e7565b3480156105f757600080fd5b506103b7610606366004613334565b611552565b34801561061757600080fd5b5061048a602a81565b34801561062c57600080fd5b5061048a61063b36600461303b565b6115b2565b34801561064c57600080fd5b5061033e611638565b34801561066157600080fd5b5061048a60155481565b61033e61164c565b34801561067f57600080fd5b5061048a60135481565b34801561069557600080fd5b50600f546103b7906001600160a01b031681565b3480156106b557600080fd5b50600a546001600160a01b03166103b7565b3480156106d357600080fd5b5061038a6116f6565b3480156106e857600080fd5b5061038a6106f7366004613334565b611705565b34801561070857600080fd5b50610360610717366004613334565b61180c565b34801561072857600080fd5b5061033e610737366004613170565b61184d565b34801561074857600080fd5b5061033e610757366004613334565b611858565b34801561076857600080fd5b5061033e6107773660046130c5565b611925565b34801561078857600080fd5b5061048a611957565b34801561079d57600080fd5b50600a546107b290600160a81b900460ff1681565b60405161036c9190613495565b3480156107cb57600080fd5b506103606119c9565b3480156107e057600080fd5b5061038a6107ef366004613334565b6119ec565b61033e61080236600461334d565b611ac8565b34801561081357600080fd5b5061041c61082236600461303b565b611cdc565b34801561083357600080fd5b5061048a610842366004613334565b60186020526000908152604090205481565b34801561086057600080fd5b5061048a60145481565b34801561087657600080fd5b5061048a60165481565b34801561088c57600080fd5b5061033e611db9565b3480156108a157600080fd5b5061048a6203ca5081565b3480156108b857600080fd5b50610360612110565b3480156108cd57600080fd5b506103b76108dc366004613334565b6017602052600090815260409020546001600160a01b031681565b34801561090357600080fd5b50610360610912366004613056565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b34801561094c57600080fd5b50610955612129565b60405161036c9190613570565b34801561096e57600080fd5b5061033e61097d36600461303b565b61225d565b34801561098e57600080fd5b5061048a6658d15e1762800081565b3480156109a957600080fd5b5061033e6109b8366004613334565b6122d6565b3480156109c957600080fd5b5061038a6109d8366004613334565b612304565b60006109e88261250e565b92915050565b6060600080546109fd90613711565b80601f0160208091040260200160405190810160405280929190818152602001828054610a2990613711565b8015610a765780601f10610a4b57610100808354040283529160200191610a76565b820191906000526020600020905b815481529060010190602001808311610a5957829003601f168201915b5050505050905090565b6000610a8b82612533565b506000908152600460205260409020546001600160a01b031690565b6000610ab282611552565b9050806001600160a01b0316836001600160a01b03161415610b255760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b60648201526084015b60405180910390fd5b336001600160a01b0382161480610b415750610b418133610912565b610bb35760405162461bcd60e51b815260206004820152603e60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206e6f7220617070726f76656420666f7220616c6c00006064820152608401610b1c565b610bbd8383612592565b505050565b6060610bcd33611cdc565b905090565b630a85bd0160e11b5b949350505050565b610bed3382612600565b610c095760405162461bcd60e51b8152600401610b1c90613522565b610bbd83838361267e565b6000610c1f836115b2565b8210610c815760405162461bcd60e51b815260206004820152602b60248201527f455243373231456e756d657261626c653a206f776e657220696e646578206f7560448201526a74206f6620626f756e647360a81b6064820152608401610b1c565b506001600160a01b03919091166000908152600660209081526040808320938352929052205490565b6002600a54600160a81b900460ff166002811115610cca57610cca6137b7565b141580610cd95750600b544210155b15610cf757604051631117739360e21b815260040160405180910390fd5b6000610d0a6658d15e1762800034613684565b905080610d2a5760405163c755930f60e01b815260040160405180910390fd5b6014811115610d37575060145b60005b81811015610d5257610d4a612825565b600101610d3a565b50610d65600e8054600019430140019055565b6000610d78826658d15e17628000613698565b610d8290346136b7565b90508015610ddf57604051600090339083908381818185875af1925050503d8060008114610dcc576040519150601f19603f3d011682016040523d82523d6000602084013e610dd1565b606091505b5050905080610bbd57600080fd5b5050565b610deb6119c9565b610e085760405163fd270db760e01b815260040160405180910390fd5b601481511115610e2b576040516359a363c360e01b815260040160405180910390fd5b60005b8151811015610ddf57610e59828281518110610e4c57610e4c6137e3565b602002602001015161283c565b600101610e2e565b610e6961287b565b60105415610e8a57604051631f0f458560e31b815260040160405180910390fd5b600a54600160a01b900460ff16610eb457604051633b9aea6160e01b815260040160405180910390fd5b600a805460ff60a01b1981169091556001600160a01b0316612710610edb47610bf2613698565b610ee59190613684565b604051600081818185875af1925050503d8060008114610bbd576040519150601f19603f3d011682016040523d82523d6000602084013e505050565b610bbd83838360405180602001604052806000815250611925565b6000818152601760205260409020546001600160a01b03163314610f735760405163c625044360e01b815260040160405180910390fd5b601654600114158015610f895750610f89612110565b15610fa75760405163b1be465b60e01b815260040160405180910390fd5b60135480610fc8576040516329dfd3af60e21b815260040160405180910390fd5b60008281526018602090815260408083208490556017909152812080546001600160a01b0319169055601654610ffe9047613684565b9050611009836128d5565b6014805490600061101983613746565b90915550506016805490600061102e836136fa565b9091555050604051339082156108fc029083906000818181858888f19350505050158015611060573d6000803e3d6000fd5b5060165460011415610bbd576000805b611079306115b2565b8110156110bc5761108a3082610c14565b6000818152601760205260409020549092506001600160a01b0316156110b45760128290556110bc565b600101611070565b506012805460009081526018602052604090819020859055600f5491549051638967562360e01b81526001600160a01b03909216916389675623916111079160040190815260200190565b600060405180830381600087803b15801561112157600080fd5b505af1158015611135573d6000803e3d6000fd5b50506012546000908152601760205260408082205490516001600160a01b0390911693504780156108fc02935091818181858888f19350505050158015611180573d6000803e3d6000fd5b506012546000818152601760205260409020546111a89130916001600160a01b03169061267e565b50505050565b6000818152601760205260409020546001600160a01b031633146111e55760405163c625044360e01b815260040160405180910390fd5b6016546001141580156111fb57506111fb612110565b156112195760405163b1be465b60e01b815260040160405180910390fd5b6013548061123a576040516329dfd3af60e21b815260040160405180910390fd5b60008281526018602052604090819020829055600f54905163907d870160e01b8152600481018490526001600160a01b039091169063907d870190602401600060405180830381600087803b15801561129257600080fd5b505af11580156112a6573d6000803e3d6000fd5b505050600083815260176020526040902080546001600160a01b0319169055506112d130338461267e565b601580549060006112e183613746565b9091555050601680549060006112f6836136fa565b919050555060165460011415610ddf576000805b611313306115b2565b811015611356576113243082610c14565b6000818152601760205260409020549092506001600160a01b03161561134e576012829055611356565b60010161130a565b506012805460009081526018602052604090819020849055600f5491549051638967562360e01b81526001600160a01b03909216916389675623916113a19160040190815260200190565b600060405180830381600087803b1580156113bb57600080fd5b505af11580156113cf573d6000803e3d6000fd5b50506012546000908152601760205260408082205490516001600160a01b0390911693504780156108fc02935091818181858888f1935050505015801561141a573d6000803e3d6000fd5b50601254600081815260176020526040902054610bbd9130916001600160a01b03169061267e565b6000613138601054610bcd919061366c565b600061145f60085490565b82106114c25760405162461bcd60e51b815260206004820152602c60248201527f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f60448201526b7574206f6620626f756e647360a01b6064820152608401610b1c565b600882815481106114d5576114d56137e3565b90600052602060002001549050919050565b6114ef61287b565b6001600a54600160a81b900460ff16600281111561150f5761150f6137b7565b1461152d576040516334e6c21f60e01b815260040160405180910390fd5b600a805460ff60a81b1916600160a91b17905561154d6203ca504261366c565b600b55565b6000818152600260205260408120546001600160a01b0316806109e85760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b6044820152606401610b1c565b60006001600160a01b03821661161c5760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b6064820152608401610b1c565b506001600160a01b031660009081526003602052604090205490565b61164061287b565b61164a600061297c565b565b61165461287b565b6000600a54600160a81b900460ff166002811115611674576116746137b7565b1461169257604051630da27c1960e11b815260040160405180910390fd5b601054156116b357604051631f0f458560e31b815260040160405180910390fd5b600a54600160a01b900460ff16156116de5760405163061865db60e41b815260040160405180910390fd5b4360108190556116f1906131389061366c565b601155565b6060600180546109fd90613711565b606081611729816000908152600260205260409020546001600160a01b0316151590565b61174657604051634a1850bf60e11b815260040160405180910390fd5b600f546001600160a01b0316636cfbaa746000600a54600160a81b900460ff166002811115611777576117776137b7565b1485611782876129ce565b6040516001600160e01b031960e086901b1681529215156004840152602483019190915260448201526064015b60006040518083038186803b1580156117c757600080fd5b505afa1580156117db573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261180391908101906132bd565b91505b50919050565b60008061181b61010084613684565b9050600061182b61010085613761565b6000928352600c602052604090922054600190921b9182169091149392505050565b610ddf338383612a0c565b61186061287b565b6002600a54600160a81b900460ff166002811115611880576118806137b7565b1461189e5760405163634a054360e11b815260040160405180910390fd5b600b544210156118c15760405163f1da374560e01b815260040160405180910390fd5b600d546040805160208101849052016040516020818303038152906040528051906020012060001c1461190757604051639ea6d12760e01b815260040160405180910390fd5b600e805491909118600d5560009055600a805460ff60a81b19169055565b61192f3383612600565b61194b5760405162461bcd60e51b8152600401610b1c90613522565b6111a884848484612adb565b60006016546000141561196a5750600090565b6016546001906107d01161199c5760006103e860165461198a91906136b7565b90506119986101f482613684565b9150505b60165481106119b75760016016546119b491906136b7565b90505b60328111156119c4575060325b919050565b60006119d6601054151590565b8015610bcd57506119e5611442565b4310905090565b606081611a10816000908152600260205260409020546001600160a01b0316151590565b611a2d57604051634a1850bf60e11b815260040160405180910390fd5b600f546001600160a01b031663f7db218c6000600a54600160a81b900460ff166002811115611a5e57611a5e6137b7565b1485611a69876129ce565b600088815260186020526040902054611a8189611552565b6040516001600160e01b031960e088901b16815294151560048601526024850193909352604484019190915260648301526001600160a01b0316608482015260a4016117af565b6001600a54600160a81b900460ff166002811115611ae857611ae86137b7565b14611b06576040516334e6c21f60e01b815260040160405180910390fd5b611b0f8661180c565b15611b2d57604051630c8d9eab60e31b815260040160405180910390fd5b80611b4b5760405163843ce46b60e01b815260040160405180910390fd5b6000611b57858761366c565b905080821115611b7a5760405163843ce46b60e01b815260040160405180910390fd5b600086831115611b9157611b8e87846136b7565b90505b611ba26658d15e1762800082613698565b341015611bc25760405163611f16b160e11b815260040160405180910390fd5b60408051602081018a90526bffffffffffffffffffffffff193360601b16918101919091526054810188905260748101879052600090609401604051602081830303815290604052805190602001209050611c738686808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152507f00000000000000000000000000000000000000000000000000000000000000009250859150612b0e9050565b611c90576040516309bde33960e01b815260040160405180910390fd5b611c9989612b24565b60005b84811015611cbe57611cac612825565b80611cb681613746565b915050611c9c565b50611cd1600e8054600019430140019055565b505050505050505050565b6060306000611cea826115b2565b905060008167ffffffffffffffff811115611d0757611d076137f9565b604051908082528060200260200182016040528015611d30578160200160208202803683370190505b5090506000805b83811015611dae576000611d4b8683610c14565b6000818152601760205260409020549091506001600160a01b0389811691161415611d9b57808484611d7c81613746565b955081518110611d8e57611d8e6137e3565b6020026020010181815250505b5080611da681613746565b915050611d37565b508152949350505050565b601054611dd95760405163237ce2fd60e21b815260040160405180910390fd5b611de1612110565b611dfe576040516357be4ad560e01b815260040160405180910390fd5b60165460011415611e2257604051631dd4f54560e11b815260040160405180910390fd5b601654611e425760405163df469ccb60e01b815260040160405180910390fd5b600060ff602a601154611e55919061366c565b611e5f90436136b7565b1115611e8e576001602a611e738143613684565b611e7d9190613698565b611e8791906136b7565b9050611eac565b6001602a601154611e9f919061366c565b611ea991906136b7565b90505b804080611ebb57611ebb613775565b4360115560138054906000611ecf83613746565b91905055506000611ede611957565b6040805160208082528183019092529192506000919060208201818036833701905050905060015b828111611fc45780840193508360208301526000611f23306115b2565b83516020850120611f349190613761565b90506000611f423083610c14565b9050611f4d816128d5565b6000818152601760205260409020546001600160a01b0316611f755760001990920191611fba565b600081815260176020526040812080546001600160a01b03191690556014805491611f9f83613746565b909155505060168054906000611fb4836136fa565b91905055505b5050600101611f06565b50601654600114156111a8576000805b611fdd306115b2565b81101561202057611fee3082610c14565b6000818152601760205260409020549092506001600160a01b031615612018576012829055612020565b600101611fd4565b50601354601280546000908152601860205260409081902092909255600f5490549151638967562360e01b815260048101929092526001600160a01b031690638967562390602401600060405180830381600087803b15801561208257600080fd5b505af1158015612096573d6000803e3d6000fd5b50506012546000908152601760205260408082205490516001600160a01b0390911693504780156108fc02935091818181858888f193505050501580156120e1573d6000803e3d6000fd5b506012546000818152601760205260409020546121099130916001600160a01b03169061267e565b5050505050565b6000602a601154612121919061366c565b431015905090565b61219c604051806101a001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000151581526020016000151581526020016000151581526020016000151581525090565b60145481526016546020820152601554604082015260135460608201524760808201526121c7611957565b60a082015260125460e08201526121dc611442565b6101008201526121ea612110565b61220e5743602a6011546121fe919061366c565b61220891906136b7565b60c08201525b612216612110565b15156101208201526122266119c9565b151561014082015260105415156101608201526101008101514311801561225257506001816020015111155b151561018082015290565b61226561287b565b6001600160a01b0381166122ca5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610b1c565b6122d38161297c565b50565b6122de6119c9565b6122fb5760405163fd270db760e01b815260040160405180910390fd5b6122d38161283c565b606081612328816000908152600260205260409020546001600160a01b0316151590565b61234557604051634a1850bf60e11b815260040160405180910390fd5b60003061235185611552565b6001600160a01b03161415612369575060135461237a565b506000838152601860205260409020545b600f546001600160a01b031663a98edced6000600a54600160a81b900460ff1660028111156123ab576123ab6137b7565b14866123b6886129ce565b856123c08a611552565b6040516001600160e01b031960e088901b16815294151560048601526024850193909352604484019190915260648301526001600160a01b0316608482015260a40160006040518083038186803b15801561241a57600080fd5b505afa15801561242e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610bdb91908101906132bd565b6001600160a01b0383166124b1576124ac81600880546000838152600960205260408120829055600182018355919091527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30155565b6124d4565b816001600160a01b0316836001600160a01b0316146124d4576124d48382612b62565b6001600160a01b0382166124eb57610bbd81612bff565b826001600160a01b0316826001600160a01b031614610bbd57610bbd8282612cae565b60006001600160e01b0319821663780e9d6360e01b14806109e857506109e882612cf2565b6000818152600260205260409020546001600160a01b03166122d35760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b6044820152606401610b1c565b600081815260046020526040902080546001600160a01b0319166001600160a01b03841690811790915581906125c782611552565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b60008061260c83611552565b9050806001600160a01b0316846001600160a01b0316148061265357506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff165b80610bdb5750836001600160a01b031661266c84610a80565b6001600160a01b031614949350505050565b826001600160a01b031661269182611552565b6001600160a01b0316146126f55760405162461bcd60e51b815260206004820152602560248201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060448201526437bbb732b960d91b6064820152608401610b1c565b6001600160a01b0382166127575760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608401610b1c565b612762838383612d42565b61276d600082612592565b6001600160a01b03831660009081526003602052604081208054600192906127969084906136b7565b90915550506001600160a01b03821660009081526003602052604081208054600192906127c490849061366c565b909155505060008181526002602052604080822080546001600160a01b0319166001600160a01b0386811691821790925591518493918716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b600061283060085490565b90506122d33382612d4d565b612847333083610be3565b600081815260176020526040812080546001600160a01b03191633179055601680549161287383613746565b919050555050565b600a546001600160a01b0316331461164a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b1c565b60006128e082611552565b90506128ee81600084612d42565b6128f9600083612592565b6001600160a01b03811660009081526003602052604081208054600192906129229084906136b7565b909155505060008281526002602052604080822080546001600160a01b0319169055518391906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b600a80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000600d54826040516020016129ee929190918252602082015260400190565b60408051601f19818403018152919052805160209091012092915050565b816001600160a01b0316836001600160a01b03161415612a6e5760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610b1c565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b612ae684848461267e565b612af284848484612e9b565b6111a85760405162461bcd60e51b8152600401610b1c906134d0565b600082612b1b8584612fa5565b14949350505050565b6000612b3261010083613684565b90506000612b4261010084613761565b6000928352600c60205260409092208054600190931b9092179091555050565b60006001612b6f846115b2565b612b7991906136b7565b600083815260076020526040902054909150808214612bcc576001600160a01b03841660009081526006602090815260408083208584528252808320548484528184208190558352600790915290208190555b5060009182526007602090815260408084208490556001600160a01b039094168352600681528383209183525290812055565b600854600090612c11906001906136b7565b60008381526009602052604081205460088054939450909284908110612c3957612c396137e3565b906000526020600020015490508060088381548110612c5a57612c5a6137e3565b6000918252602080832090910192909255828152600990915260408082208490558582528120556008805480612c9257612c926137cd565b6001900381819060005260206000200160009055905550505050565b6000612cb9836115b2565b6001600160a01b039093166000908152600660209081526040808320868452825280832085905593825260079052919091209190915550565b60006001600160e01b031982166380ac58cd60e01b1480612d2357506001600160e01b03198216635b5e139f60e01b145b806109e857506301ffc9a760e01b6001600160e01b03198316146109e8565b610bbd838383612456565b6001600160a01b038216612da35760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610b1c565b6000818152600260205260409020546001600160a01b031615612e085760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610b1c565b612e1460008383612d42565b6001600160a01b0382166000908152600360205260408120805460019290612e3d90849061366c565b909155505060008181526002602052604080822080546001600160a01b0319166001600160a01b03861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b60006001600160a01b0384163b15612f9d57604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290612edf903390899088908890600401613414565b602060405180830381600087803b158015612ef957600080fd5b505af1925050508015612f29575060408051601f3d908101601f19168201909252612f26918101906132a0565b60015b612f83573d808015612f57576040519150601f19603f3d011682016040523d82523d6000602084013e612f5c565b606091505b508051612f7b5760405162461bcd60e51b8152600401610b1c906134d0565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050610bdb565b506001610bdb565b600081815b8451811015612fea57612fd682868381518110612fc957612fc96137e3565b6020026020010151612ff2565b915080612fe281613746565b915050612faa565b509392505050565b600081831061300e57600082815260208490526040902061301d565b60008381526020839052604090205b9392505050565b80356001600160a01b03811681146119c457600080fd5b60006020828403121561304d57600080fd5b61301d82613024565b6000806040838503121561306957600080fd5b61307283613024565b915061308060208401613024565b90509250929050565b60008060006060848603121561309e57600080fd5b6130a784613024565b92506130b560208501613024565b9150604084013590509250925092565b600080600080608085870312156130db57600080fd5b6130e485613024565b93506130f260208601613024565b925060408501359150606085013567ffffffffffffffff81111561311557600080fd5b8501601f8101871361312657600080fd5b803561313961313482613644565b613613565b81815288602083850101111561314e57600080fd5b8160208401602083013760006020838301015280935050505092959194509250565b6000806040838503121561318357600080fd5b61318c83613024565b9150602083013580151581146131a157600080fd5b809150509250929050565b600080604083850312156131bf57600080fd5b6131c883613024565b946020939093013593505050565b600060208083850312156131e957600080fd5b823567ffffffffffffffff8082111561320157600080fd5b818501915085601f83011261321557600080fd5b813581811115613227576132276137f9565b8060051b9150613238848301613613565b8181528481019084860184860187018a101561325357600080fd5b600095505b83861015613276578035835260019590950194918601918601613258565b5098975050505050505050565b60006020828403121561329557600080fd5b813561301d8161380f565b6000602082840312156132b257600080fd5b815161301d8161380f565b6000602082840312156132cf57600080fd5b815167ffffffffffffffff8111156132e657600080fd5b8201601f810184136132f757600080fd5b805161330561313482613644565b81815285602083850101111561331a57600080fd5b61332b8260208301602086016136ce565b95945050505050565b60006020828403121561334657600080fd5b5035919050565b60008060008060008060a0878903121561336657600080fd5b863595506020870135945060408701359350606087013567ffffffffffffffff8082111561339357600080fd5b818901915089601f8301126133a757600080fd5b8135818111156133b657600080fd5b8a60208260051b85010111156133cb57600080fd5b602083019550809450505050608087013590509295509295509295565b600081518084526134008160208601602086016136ce565b601f01601f19169290920160200192915050565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090613447908301846133e8565b9695505050505050565b6020808252825182820181905260009190848201906040850190845b818110156134895783518352928401929184019160010161346d565b50909695505050505050565b60208101600383106134b757634e487b7160e01b600052602160045260246000fd5b91905290565b60208152600061301d60208301846133e8565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b6020808252602e908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526d1c881b9bdc88185c1c1c9bdd995960921b606082015260800190565b60006101a082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e0830152610100808401518184015250610120808401516135e38285018215159052565b50506101408381015115159083015261016080840151151590830152610180928301511515929091019190915290565b604051601f8201601f1916810167ffffffffffffffff8111828210171561363c5761363c6137f9565b604052919050565b600067ffffffffffffffff82111561365e5761365e6137f9565b50601f01601f191660200190565b6000821982111561367f5761367f61378b565b500190565b600082613693576136936137a1565b500490565b60008160001904831182151516156136b2576136b261378b565b500290565b6000828210156136c9576136c961378b565b500390565b60005b838110156136e95781810151838201526020016136d1565b838111156111a85750506000910152565b6000816137095761370961378b565b506000190190565b600181811c9082168061372557607f821691505b6020821081141561180657634e487b7160e01b600052602260045260246000fd5b600060001982141561375a5761375a61378b565b5060010190565b600082613770576137706137a1565b500690565b634e487b7160e01b600052600160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160e01b0319811681146122d357600080fdfea2646970667358221220dae9601cc6aa1fba524034cb8a7b4712794491d5df82b16c3aaddf921884c1fd64736f6c63430008070033bdd3ef7aa3fe0f5e1ca451a428919fed839d046e4397767d9d8d98271dac4a7f000000000000000000000000b60d7d1d5f63f8f720526919b770ff3985e183e4799a04ec1676eb17f6792c74bbd3482bb9063e1274a084903d0bef83c5414231

Deployed Bytecode

0x60806040526004361061033e5760003560e01c80638a19c8bc116101ae578063ccb9fe1d116100eb578063e97deabf1161008f578063f2fde38b1161006c578063f2fde38b14610962578063f51f96dd14610982578063f6b3a00a1461099d578063fd5ad319146109bd57005b8063e97deabf146108c1578063e985e9c5146108f7578063f2e45a4f1461094057005b8063dba7fd4a116100c8578063dba7fd4a1461086a578063dcafd0bc14610880578063e13cbe3814610895578063e23666de146108ac57005b8063ccb9fe1d14610807578063d0f9e2be14610827578063d660a7bd1461085457005b8063acedb5b411610152578063c040e6b81161012f578063c040e6b814610791578063c57540b9146107bf578063c87b56dd146107d4578063cb0274d5146107f457005b8063acedb5b41461073c578063b88d4fde1461075c578063bd978e8d1461077c57005b806395d89b411161018b57806395d89b41146106c75780639671219b146106dc5780639e34070f146106fc578063a22cb4651461071c57005b80638a19c8bc146106735780638ada6b0f146106895780638da5cb5b146106a957005b80633ccfd60b1161027c578063580e77d41161022057806370a08231116101fd57806370a0823114610620578063715018a61461064057806376c242461461065557806378aafea21461066b57005b8063580e77d4146105d65780636352211e146105eb5780636e4ed7961461060b57005b806346feb24a1161025957806346feb24a1461056b578063473e3ea41461058b5780634f6ccce7146105a05780635533f19a146105c057005b80633ccfd60b1461051657806342842e0e1461052b57806344021ad71461054b57005b8063150b7a02116102e35780632ae07c33116102c05780632ae07c33146104b85780632f745c59146104ce5780633364b0d2146104ee57806339af9afe146104f657005b8063150b7a021461044057806318160ddd1461047957806323b872dd1461049857005b8063095ea7b31161031c578063095ea7b3146103cf5780630a212469146103ef5780630bc634d914610407578063130eb2f61461042957005b806301ffc9a71461034057806306fdde0314610375578063081812fc14610397575b005b34801561034c57600080fd5b5061036061035b366004613283565b6109dd565b60405190151581526020015b60405180910390f35b34801561038157600080fd5b5061038a6109ee565b60405161036c91906134bd565b3480156103a357600080fd5b506103b76103b2366004613334565b610a80565b6040516001600160a01b03909116815260200161036c565b3480156103db57600080fd5b5061033e6103ea3660046131ac565b610aa7565b3480156103fb57600080fd5b50600b54421015610360565b34801561041357600080fd5b5061041c610bc2565b60405161036c9190613451565b34801561043557600080fd5b506010541515610360565b34801561044c57600080fd5b5061046061045b3660046130c5565b610bd2565b6040516001600160e01b0319909116815260200161036c565b34801561048557600080fd5b506008545b60405190815260200161036c565b3480156104a457600080fd5b5061033e6104b3366004613089565b610be3565b3480156104c457600080fd5b5061048a61313881565b3480156104da57600080fd5b5061048a6104e93660046131ac565b610c14565b61033e610caa565b34801561050257600080fd5b5061033e6105113660046131d6565b610de3565b34801561052257600080fd5b5061033e610e61565b34801561053757600080fd5b5061033e610546366004613089565b610f21565b34801561055757600080fd5b5061033e610566366004613334565b610f3c565b34801561057757600080fd5b5061033e610586366004613334565b6111ae565b34801561059757600080fd5b5061048a611442565b3480156105ac57600080fd5b5061048a6105bb366004613334565b611454565b3480156105cc57600080fd5b5061048a600b5481565b3480156105e257600080fd5b5061033e6114e7565b3480156105f757600080fd5b506103b7610606366004613334565b611552565b34801561061757600080fd5b5061048a602a81565b34801561062c57600080fd5b5061048a61063b36600461303b565b6115b2565b34801561064c57600080fd5b5061033e611638565b34801561066157600080fd5b5061048a60155481565b61033e61164c565b34801561067f57600080fd5b5061048a60135481565b34801561069557600080fd5b50600f546103b7906001600160a01b031681565b3480156106b557600080fd5b50600a546001600160a01b03166103b7565b3480156106d357600080fd5b5061038a6116f6565b3480156106e857600080fd5b5061038a6106f7366004613334565b611705565b34801561070857600080fd5b50610360610717366004613334565b61180c565b34801561072857600080fd5b5061033e610737366004613170565b61184d565b34801561074857600080fd5b5061033e610757366004613334565b611858565b34801561076857600080fd5b5061033e6107773660046130c5565b611925565b34801561078857600080fd5b5061048a611957565b34801561079d57600080fd5b50600a546107b290600160a81b900460ff1681565b60405161036c9190613495565b3480156107cb57600080fd5b506103606119c9565b3480156107e057600080fd5b5061038a6107ef366004613334565b6119ec565b61033e61080236600461334d565b611ac8565b34801561081357600080fd5b5061041c61082236600461303b565b611cdc565b34801561083357600080fd5b5061048a610842366004613334565b60186020526000908152604090205481565b34801561086057600080fd5b5061048a60145481565b34801561087657600080fd5b5061048a60165481565b34801561088c57600080fd5b5061033e611db9565b3480156108a157600080fd5b5061048a6203ca5081565b3480156108b857600080fd5b50610360612110565b3480156108cd57600080fd5b506103b76108dc366004613334565b6017602052600090815260409020546001600160a01b031681565b34801561090357600080fd5b50610360610912366004613056565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b34801561094c57600080fd5b50610955612129565b60405161036c9190613570565b34801561096e57600080fd5b5061033e61097d36600461303b565b61225d565b34801561098e57600080fd5b5061048a6658d15e1762800081565b3480156109a957600080fd5b5061033e6109b8366004613334565b6122d6565b3480156109c957600080fd5b5061038a6109d8366004613334565b612304565b60006109e88261250e565b92915050565b6060600080546109fd90613711565b80601f0160208091040260200160405190810160405280929190818152602001828054610a2990613711565b8015610a765780601f10610a4b57610100808354040283529160200191610a76565b820191906000526020600020905b815481529060010190602001808311610a5957829003601f168201915b5050505050905090565b6000610a8b82612533565b506000908152600460205260409020546001600160a01b031690565b6000610ab282611552565b9050806001600160a01b0316836001600160a01b03161415610b255760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b60648201526084015b60405180910390fd5b336001600160a01b0382161480610b415750610b418133610912565b610bb35760405162461bcd60e51b815260206004820152603e60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206e6f7220617070726f76656420666f7220616c6c00006064820152608401610b1c565b610bbd8383612592565b505050565b6060610bcd33611cdc565b905090565b630a85bd0160e11b5b949350505050565b610bed3382612600565b610c095760405162461bcd60e51b8152600401610b1c90613522565b610bbd83838361267e565b6000610c1f836115b2565b8210610c815760405162461bcd60e51b815260206004820152602b60248201527f455243373231456e756d657261626c653a206f776e657220696e646578206f7560448201526a74206f6620626f756e647360a81b6064820152608401610b1c565b506001600160a01b03919091166000908152600660209081526040808320938352929052205490565b6002600a54600160a81b900460ff166002811115610cca57610cca6137b7565b141580610cd95750600b544210155b15610cf757604051631117739360e21b815260040160405180910390fd5b6000610d0a6658d15e1762800034613684565b905080610d2a5760405163c755930f60e01b815260040160405180910390fd5b6014811115610d37575060145b60005b81811015610d5257610d4a612825565b600101610d3a565b50610d65600e8054600019430140019055565b6000610d78826658d15e17628000613698565b610d8290346136b7565b90508015610ddf57604051600090339083908381818185875af1925050503d8060008114610dcc576040519150601f19603f3d011682016040523d82523d6000602084013e610dd1565b606091505b5050905080610bbd57600080fd5b5050565b610deb6119c9565b610e085760405163fd270db760e01b815260040160405180910390fd5b601481511115610e2b576040516359a363c360e01b815260040160405180910390fd5b60005b8151811015610ddf57610e59828281518110610e4c57610e4c6137e3565b602002602001015161283c565b600101610e2e565b610e6961287b565b60105415610e8a57604051631f0f458560e31b815260040160405180910390fd5b600a54600160a01b900460ff16610eb457604051633b9aea6160e01b815260040160405180910390fd5b600a805460ff60a01b1981169091556001600160a01b0316612710610edb47610bf2613698565b610ee59190613684565b604051600081818185875af1925050503d8060008114610bbd576040519150601f19603f3d011682016040523d82523d6000602084013e505050565b610bbd83838360405180602001604052806000815250611925565b6000818152601760205260409020546001600160a01b03163314610f735760405163c625044360e01b815260040160405180910390fd5b601654600114158015610f895750610f89612110565b15610fa75760405163b1be465b60e01b815260040160405180910390fd5b60135480610fc8576040516329dfd3af60e21b815260040160405180910390fd5b60008281526018602090815260408083208490556017909152812080546001600160a01b0319169055601654610ffe9047613684565b9050611009836128d5565b6014805490600061101983613746565b90915550506016805490600061102e836136fa565b9091555050604051339082156108fc029083906000818181858888f19350505050158015611060573d6000803e3d6000fd5b5060165460011415610bbd576000805b611079306115b2565b8110156110bc5761108a3082610c14565b6000818152601760205260409020549092506001600160a01b0316156110b45760128290556110bc565b600101611070565b506012805460009081526018602052604090819020859055600f5491549051638967562360e01b81526001600160a01b03909216916389675623916111079160040190815260200190565b600060405180830381600087803b15801561112157600080fd5b505af1158015611135573d6000803e3d6000fd5b50506012546000908152601760205260408082205490516001600160a01b0390911693504780156108fc02935091818181858888f19350505050158015611180573d6000803e3d6000fd5b506012546000818152601760205260409020546111a89130916001600160a01b03169061267e565b50505050565b6000818152601760205260409020546001600160a01b031633146111e55760405163c625044360e01b815260040160405180910390fd5b6016546001141580156111fb57506111fb612110565b156112195760405163b1be465b60e01b815260040160405180910390fd5b6013548061123a576040516329dfd3af60e21b815260040160405180910390fd5b60008281526018602052604090819020829055600f54905163907d870160e01b8152600481018490526001600160a01b039091169063907d870190602401600060405180830381600087803b15801561129257600080fd5b505af11580156112a6573d6000803e3d6000fd5b505050600083815260176020526040902080546001600160a01b0319169055506112d130338461267e565b601580549060006112e183613746565b9091555050601680549060006112f6836136fa565b919050555060165460011415610ddf576000805b611313306115b2565b811015611356576113243082610c14565b6000818152601760205260409020549092506001600160a01b03161561134e576012829055611356565b60010161130a565b506012805460009081526018602052604090819020849055600f5491549051638967562360e01b81526001600160a01b03909216916389675623916113a19160040190815260200190565b600060405180830381600087803b1580156113bb57600080fd5b505af11580156113cf573d6000803e3d6000fd5b50506012546000908152601760205260408082205490516001600160a01b0390911693504780156108fc02935091818181858888f1935050505015801561141a573d6000803e3d6000fd5b50601254600081815260176020526040902054610bbd9130916001600160a01b03169061267e565b6000613138601054610bcd919061366c565b600061145f60085490565b82106114c25760405162461bcd60e51b815260206004820152602c60248201527f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f60448201526b7574206f6620626f756e647360a01b6064820152608401610b1c565b600882815481106114d5576114d56137e3565b90600052602060002001549050919050565b6114ef61287b565b6001600a54600160a81b900460ff16600281111561150f5761150f6137b7565b1461152d576040516334e6c21f60e01b815260040160405180910390fd5b600a805460ff60a81b1916600160a91b17905561154d6203ca504261366c565b600b55565b6000818152600260205260408120546001600160a01b0316806109e85760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b6044820152606401610b1c565b60006001600160a01b03821661161c5760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b6064820152608401610b1c565b506001600160a01b031660009081526003602052604090205490565b61164061287b565b61164a600061297c565b565b61165461287b565b6000600a54600160a81b900460ff166002811115611674576116746137b7565b1461169257604051630da27c1960e11b815260040160405180910390fd5b601054156116b357604051631f0f458560e31b815260040160405180910390fd5b600a54600160a01b900460ff16156116de5760405163061865db60e41b815260040160405180910390fd5b4360108190556116f1906131389061366c565b601155565b6060600180546109fd90613711565b606081611729816000908152600260205260409020546001600160a01b0316151590565b61174657604051634a1850bf60e11b815260040160405180910390fd5b600f546001600160a01b0316636cfbaa746000600a54600160a81b900460ff166002811115611777576117776137b7565b1485611782876129ce565b6040516001600160e01b031960e086901b1681529215156004840152602483019190915260448201526064015b60006040518083038186803b1580156117c757600080fd5b505afa1580156117db573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261180391908101906132bd565b91505b50919050565b60008061181b61010084613684565b9050600061182b61010085613761565b6000928352600c602052604090922054600190921b9182169091149392505050565b610ddf338383612a0c565b61186061287b565b6002600a54600160a81b900460ff166002811115611880576118806137b7565b1461189e5760405163634a054360e11b815260040160405180910390fd5b600b544210156118c15760405163f1da374560e01b815260040160405180910390fd5b600d546040805160208101849052016040516020818303038152906040528051906020012060001c1461190757604051639ea6d12760e01b815260040160405180910390fd5b600e805491909118600d5560009055600a805460ff60a81b19169055565b61192f3383612600565b61194b5760405162461bcd60e51b8152600401610b1c90613522565b6111a884848484612adb565b60006016546000141561196a5750600090565b6016546001906107d01161199c5760006103e860165461198a91906136b7565b90506119986101f482613684565b9150505b60165481106119b75760016016546119b491906136b7565b90505b60328111156119c4575060325b919050565b60006119d6601054151590565b8015610bcd57506119e5611442565b4310905090565b606081611a10816000908152600260205260409020546001600160a01b0316151590565b611a2d57604051634a1850bf60e11b815260040160405180910390fd5b600f546001600160a01b031663f7db218c6000600a54600160a81b900460ff166002811115611a5e57611a5e6137b7565b1485611a69876129ce565b600088815260186020526040902054611a8189611552565b6040516001600160e01b031960e088901b16815294151560048601526024850193909352604484019190915260648301526001600160a01b0316608482015260a4016117af565b6001600a54600160a81b900460ff166002811115611ae857611ae86137b7565b14611b06576040516334e6c21f60e01b815260040160405180910390fd5b611b0f8661180c565b15611b2d57604051630c8d9eab60e31b815260040160405180910390fd5b80611b4b5760405163843ce46b60e01b815260040160405180910390fd5b6000611b57858761366c565b905080821115611b7a5760405163843ce46b60e01b815260040160405180910390fd5b600086831115611b9157611b8e87846136b7565b90505b611ba26658d15e1762800082613698565b341015611bc25760405163611f16b160e11b815260040160405180910390fd5b60408051602081018a90526bffffffffffffffffffffffff193360601b16918101919091526054810188905260748101879052600090609401604051602081830303815290604052805190602001209050611c738686808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152507f799a04ec1676eb17f6792c74bbd3482bb9063e1274a084903d0bef83c54142319250859150612b0e9050565b611c90576040516309bde33960e01b815260040160405180910390fd5b611c9989612b24565b60005b84811015611cbe57611cac612825565b80611cb681613746565b915050611c9c565b50611cd1600e8054600019430140019055565b505050505050505050565b6060306000611cea826115b2565b905060008167ffffffffffffffff811115611d0757611d076137f9565b604051908082528060200260200182016040528015611d30578160200160208202803683370190505b5090506000805b83811015611dae576000611d4b8683610c14565b6000818152601760205260409020549091506001600160a01b0389811691161415611d9b57808484611d7c81613746565b955081518110611d8e57611d8e6137e3565b6020026020010181815250505b5080611da681613746565b915050611d37565b508152949350505050565b601054611dd95760405163237ce2fd60e21b815260040160405180910390fd5b611de1612110565b611dfe576040516357be4ad560e01b815260040160405180910390fd5b60165460011415611e2257604051631dd4f54560e11b815260040160405180910390fd5b601654611e425760405163df469ccb60e01b815260040160405180910390fd5b600060ff602a601154611e55919061366c565b611e5f90436136b7565b1115611e8e576001602a611e738143613684565b611e7d9190613698565b611e8791906136b7565b9050611eac565b6001602a601154611e9f919061366c565b611ea991906136b7565b90505b804080611ebb57611ebb613775565b4360115560138054906000611ecf83613746565b91905055506000611ede611957565b6040805160208082528183019092529192506000919060208201818036833701905050905060015b828111611fc45780840193508360208301526000611f23306115b2565b83516020850120611f349190613761565b90506000611f423083610c14565b9050611f4d816128d5565b6000818152601760205260409020546001600160a01b0316611f755760001990920191611fba565b600081815260176020526040812080546001600160a01b03191690556014805491611f9f83613746565b909155505060168054906000611fb4836136fa565b91905055505b5050600101611f06565b50601654600114156111a8576000805b611fdd306115b2565b81101561202057611fee3082610c14565b6000818152601760205260409020549092506001600160a01b031615612018576012829055612020565b600101611fd4565b50601354601280546000908152601860205260409081902092909255600f5490549151638967562360e01b815260048101929092526001600160a01b031690638967562390602401600060405180830381600087803b15801561208257600080fd5b505af1158015612096573d6000803e3d6000fd5b50506012546000908152601760205260408082205490516001600160a01b0390911693504780156108fc02935091818181858888f193505050501580156120e1573d6000803e3d6000fd5b506012546000818152601760205260409020546121099130916001600160a01b03169061267e565b5050505050565b6000602a601154612121919061366c565b431015905090565b61219c604051806101a001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000151581526020016000151581526020016000151581526020016000151581525090565b60145481526016546020820152601554604082015260135460608201524760808201526121c7611957565b60a082015260125460e08201526121dc611442565b6101008201526121ea612110565b61220e5743602a6011546121fe919061366c565b61220891906136b7565b60c08201525b612216612110565b15156101208201526122266119c9565b151561014082015260105415156101608201526101008101514311801561225257506001816020015111155b151561018082015290565b61226561287b565b6001600160a01b0381166122ca5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610b1c565b6122d38161297c565b50565b6122de6119c9565b6122fb5760405163fd270db760e01b815260040160405180910390fd5b6122d38161283c565b606081612328816000908152600260205260409020546001600160a01b0316151590565b61234557604051634a1850bf60e11b815260040160405180910390fd5b60003061235185611552565b6001600160a01b03161415612369575060135461237a565b506000838152601860205260409020545b600f546001600160a01b031663a98edced6000600a54600160a81b900460ff1660028111156123ab576123ab6137b7565b14866123b6886129ce565b856123c08a611552565b6040516001600160e01b031960e088901b16815294151560048601526024850193909352604484019190915260648301526001600160a01b0316608482015260a40160006040518083038186803b15801561241a57600080fd5b505afa15801561242e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610bdb91908101906132bd565b6001600160a01b0383166124b1576124ac81600880546000838152600960205260408120829055600182018355919091527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30155565b6124d4565b816001600160a01b0316836001600160a01b0316146124d4576124d48382612b62565b6001600160a01b0382166124eb57610bbd81612bff565b826001600160a01b0316826001600160a01b031614610bbd57610bbd8282612cae565b60006001600160e01b0319821663780e9d6360e01b14806109e857506109e882612cf2565b6000818152600260205260409020546001600160a01b03166122d35760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b6044820152606401610b1c565b600081815260046020526040902080546001600160a01b0319166001600160a01b03841690811790915581906125c782611552565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b60008061260c83611552565b9050806001600160a01b0316846001600160a01b0316148061265357506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff165b80610bdb5750836001600160a01b031661266c84610a80565b6001600160a01b031614949350505050565b826001600160a01b031661269182611552565b6001600160a01b0316146126f55760405162461bcd60e51b815260206004820152602560248201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060448201526437bbb732b960d91b6064820152608401610b1c565b6001600160a01b0382166127575760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608401610b1c565b612762838383612d42565b61276d600082612592565b6001600160a01b03831660009081526003602052604081208054600192906127969084906136b7565b90915550506001600160a01b03821660009081526003602052604081208054600192906127c490849061366c565b909155505060008181526002602052604080822080546001600160a01b0319166001600160a01b0386811691821790925591518493918716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b600061283060085490565b90506122d33382612d4d565b612847333083610be3565b600081815260176020526040812080546001600160a01b03191633179055601680549161287383613746565b919050555050565b600a546001600160a01b0316331461164a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b1c565b60006128e082611552565b90506128ee81600084612d42565b6128f9600083612592565b6001600160a01b03811660009081526003602052604081208054600192906129229084906136b7565b909155505060008281526002602052604080822080546001600160a01b0319169055518391906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b600a80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000600d54826040516020016129ee929190918252602082015260400190565b60408051601f19818403018152919052805160209091012092915050565b816001600160a01b0316836001600160a01b03161415612a6e5760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610b1c565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b612ae684848461267e565b612af284848484612e9b565b6111a85760405162461bcd60e51b8152600401610b1c906134d0565b600082612b1b8584612fa5565b14949350505050565b6000612b3261010083613684565b90506000612b4261010084613761565b6000928352600c60205260409092208054600190931b9092179091555050565b60006001612b6f846115b2565b612b7991906136b7565b600083815260076020526040902054909150808214612bcc576001600160a01b03841660009081526006602090815260408083208584528252808320548484528184208190558352600790915290208190555b5060009182526007602090815260408084208490556001600160a01b039094168352600681528383209183525290812055565b600854600090612c11906001906136b7565b60008381526009602052604081205460088054939450909284908110612c3957612c396137e3565b906000526020600020015490508060088381548110612c5a57612c5a6137e3565b6000918252602080832090910192909255828152600990915260408082208490558582528120556008805480612c9257612c926137cd565b6001900381819060005260206000200160009055905550505050565b6000612cb9836115b2565b6001600160a01b039093166000908152600660209081526040808320868452825280832085905593825260079052919091209190915550565b60006001600160e01b031982166380ac58cd60e01b1480612d2357506001600160e01b03198216635b5e139f60e01b145b806109e857506301ffc9a760e01b6001600160e01b03198316146109e8565b610bbd838383612456565b6001600160a01b038216612da35760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610b1c565b6000818152600260205260409020546001600160a01b031615612e085760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610b1c565b612e1460008383612d42565b6001600160a01b0382166000908152600360205260408120805460019290612e3d90849061366c565b909155505060008181526002602052604080822080546001600160a01b0319166001600160a01b03861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b60006001600160a01b0384163b15612f9d57604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290612edf903390899088908890600401613414565b602060405180830381600087803b158015612ef957600080fd5b505af1925050508015612f29575060408051601f3d908101601f19168201909252612f26918101906132a0565b60015b612f83573d808015612f57576040519150601f19603f3d011682016040523d82523d6000602084013e612f5c565b606091505b508051612f7b5760405162461bcd60e51b8152600401610b1c906134d0565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050610bdb565b506001610bdb565b600081815b8451811015612fea57612fd682868381518110612fc957612fc96137e3565b6020026020010151612ff2565b915080612fe281613746565b915050612faa565b509392505050565b600081831061300e57600082815260208490526040902061301d565b60008381526020839052604090205b9392505050565b80356001600160a01b03811681146119c457600080fd5b60006020828403121561304d57600080fd5b61301d82613024565b6000806040838503121561306957600080fd5b61307283613024565b915061308060208401613024565b90509250929050565b60008060006060848603121561309e57600080fd5b6130a784613024565b92506130b560208501613024565b9150604084013590509250925092565b600080600080608085870312156130db57600080fd5b6130e485613024565b93506130f260208601613024565b925060408501359150606085013567ffffffffffffffff81111561311557600080fd5b8501601f8101871361312657600080fd5b803561313961313482613644565b613613565b81815288602083850101111561314e57600080fd5b8160208401602083013760006020838301015280935050505092959194509250565b6000806040838503121561318357600080fd5b61318c83613024565b9150602083013580151581146131a157600080fd5b809150509250929050565b600080604083850312156131bf57600080fd5b6131c883613024565b946020939093013593505050565b600060208083850312156131e957600080fd5b823567ffffffffffffffff8082111561320157600080fd5b818501915085601f83011261321557600080fd5b813581811115613227576132276137f9565b8060051b9150613238848301613613565b8181528481019084860184860187018a101561325357600080fd5b600095505b83861015613276578035835260019590950194918601918601613258565b5098975050505050505050565b60006020828403121561329557600080fd5b813561301d8161380f565b6000602082840312156132b257600080fd5b815161301d8161380f565b6000602082840312156132cf57600080fd5b815167ffffffffffffffff8111156132e657600080fd5b8201601f810184136132f757600080fd5b805161330561313482613644565b81815285602083850101111561331a57600080fd5b61332b8260208301602086016136ce565b95945050505050565b60006020828403121561334657600080fd5b5035919050565b60008060008060008060a0878903121561336657600080fd5b863595506020870135945060408701359350606087013567ffffffffffffffff8082111561339357600080fd5b818901915089601f8301126133a757600080fd5b8135818111156133b657600080fd5b8a60208260051b85010111156133cb57600080fd5b602083019550809450505050608087013590509295509295509295565b600081518084526134008160208601602086016136ce565b601f01601f19169290920160200192915050565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090613447908301846133e8565b9695505050505050565b6020808252825182820181905260009190848201906040850190845b818110156134895783518352928401929184019160010161346d565b50909695505050505050565b60208101600383106134b757634e487b7160e01b600052602160045260246000fd5b91905290565b60208152600061301d60208301846133e8565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b6020808252602e908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526d1c881b9bdc88185c1c1c9bdd995960921b606082015260800190565b60006101a082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e0830152610100808401518184015250610120808401516135e38285018215159052565b50506101408381015115159083015261016080840151151590830152610180928301511515929091019190915290565b604051601f8201601f1916810167ffffffffffffffff8111828210171561363c5761363c6137f9565b604052919050565b600067ffffffffffffffff82111561365e5761365e6137f9565b50601f01601f191660200190565b6000821982111561367f5761367f61378b565b500190565b600082613693576136936137a1565b500490565b60008160001904831182151516156136b2576136b261378b565b500290565b6000828210156136c9576136c961378b565b500390565b60005b838110156136e95781810151838201526020016136d1565b838111156111a85750506000910152565b6000816137095761370961378b565b506000190190565b600181811c9082168061372557607f821691505b6020821081141561180657634e487b7160e01b600052602260045260246000fd5b600060001982141561375a5761375a61378b565b5060010190565b600082613770576137706137a1565b500690565b634e487b7160e01b600052600160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160e01b0319811681146122d357600080fdfea2646970667358221220dae9601cc6aa1fba524034cb8a7b4712794491d5df82b16c3aaddf921884c1fd64736f6c63430008070033

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

bdd3ef7aa3fe0f5e1ca451a428919fed839d046e4397767d9d8d98271dac4a7f000000000000000000000000b60d7d1d5f63f8f720526919b770ff3985e183e4799a04ec1676eb17f6792c74bbd3482bb9063e1274a084903d0bef83c5414231

-----Decoded View---------------
Arg [0] : _secretCommit (uint256): 85861585936666380609408835558486275043416692853044039650146259634895094303359
Arg [1] : _renderer (address): 0xb60d7D1D5F63f8F720526919b770FF3985e183e4
Arg [2] : _merkleRoot (bytes32): 0x799a04ec1676eb17f6792c74bbd3482bb9063e1274a084903d0bef83c5414231

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : bdd3ef7aa3fe0f5e1ca451a428919fed839d046e4397767d9d8d98271dac4a7f
Arg [1] : 000000000000000000000000b60d7d1d5f63f8f720526919b770ff3985e183e4
Arg [2] : 799a04ec1676eb17f6792c74bbd3482bb9063e1274a084903d0bef83c5414231


Deployed Bytecode Sourcemap

73373:21280:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;94469:181;;;;;;;;;;-1:-1:-1;94469:181:0;;;;;:::i;:::-;;:::i;:::-;;;8610:14:1;;8603:22;8585:41;;8573:2;8558:18;94469:181:0;;;;;;;;53872:100;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;55385:171::-;;;;;;;;;;-1:-1:-1;55385:171:0;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;7271:32:1;;;7253:51;;7241:2;7226:18;55385:171:0;7107:203:1;54902:417:0;;;;;;;;;;-1:-1:-1;54902:417:0;;;;;:::i;:::-;;:::i;75622:144::-;;;;;;;;;;-1:-1:-1;75714:8:0;;75695:15;:27;;75622:144;;83391:112;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;84199:96::-;;;;;;;;;;-1:-1:-1;84267:16:0;;:20;;84199:96;;94112:154;;;;;;;;;;-1:-1:-1;94112:154:0;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;;9637:33:1;;;9619:52;;9607:2;9592:18;94112:154:0;9475:202:1;67784:113:0;;;;;;;;;;-1:-1:-1;67872:10:0;:17;67784:113;;;17855:25:1;;;17843:2;17828:18;67784:113:0;17709:177:1;56085:336:0;;;;;;;;;;-1:-1:-1;56085:336:0;;;;;:::i;:::-;;:::i;81810:47::-;;;;;;;;;;;;81852:5;81810:47;;67452:256;;;;;;;;;;-1:-1:-1;67452:256:0;;;;;:::i;:::-;;:::i;78723:661::-;;;:::i;89469:305::-;;;;;;;;;;-1:-1:-1;89469:305:0;;;;;:::i;:::-;;:::i;76961:435::-;;;;;;;;;;;;;:::i;56492:185::-;;;;;;;;;;-1:-1:-1;56492:185:0;;;;;:::i;:::-;;:::i;89782:2004::-;;;;;;;;;;-1:-1:-1;89782:2004:0;;;;;:::i;:::-;;:::i;91794:1972::-;;;;;;;;;;-1:-1:-1;91794:1972:0;;;;;:::i;:::-;;:::i;84435:118::-;;;;;;;;;;;;;:::i;67974:233::-;;;;;;;;;;-1:-1:-1;67974:233:0;;;;;:::i;:::-;;:::i;74508:35::-;;;;;;;;;;;;;;;;76768:154;;;;;;;;;;;;;:::i;53583:222::-;;;;;;;;;;-1:-1:-1;53583:222:0;;;;;:::i;:::-;;:::i;81864:43::-;;;;;;;;;;;;81905:2;81864:43;;53314:207;;;;;;;;;;-1:-1:-1;53314:207:0;;;;;:::i;:::-;;:::i;32353:103::-;;;;;;;;;;;;;:::i;81740:28::-;;;;;;;;;;;;;;;;85399:371;;;:::i;81667:31::-;;;;;;;;;;;;;;;;80266:36;;;;;;;;;;-1:-1:-1;80266:36:0;;;;-1:-1:-1;;;;;80266:36:0;;;31705:87;;;;;;;;;;-1:-1:-1;31778:6:0;;-1:-1:-1;;;;;31778:6:0;31705:87;;54041:104;;;;;;;;;;;;;:::i;80340:206::-;;;;;;;;;;-1:-1:-1;80340:206:0;;;;;:::i;:::-;;:::i;75774:322::-;;;;;;;;;;-1:-1:-1;75774:322:0;;;;;:::i;:::-;;:::i;55628:155::-;;;;;;;;;;-1:-1:-1;55628:155:0;;;;;:::i;:::-;;:::i;76161:575::-;;;;;;;;;;-1:-1:-1;76161:575:0;;;;;:::i;:::-;;:::i;56748:323::-;;;;;;;;;;-1:-1:-1;56748:323:0;;;;;:::i;:::-;;:::i;84561:660::-;;;;;;;;;;;;;:::i;74469:32::-;;;;;;;;;;-1:-1:-1;74469:32:0;;;;-1:-1:-1;;;74469:32:0;;;;;;;;;;;;;:::i;84303:124::-;;;;;;;;;;;;;:::i;80554:240::-;;;;;;;;;;-1:-1:-1;80554:240:0;;;;;:::i;:::-;;:::i;77433:1261::-;;;;;;:::i;:::-;;:::i;83561:630::-;;;;;;;;;;-1:-1:-1;83561:630:0;;;;;:::i;:::-;;:::i;81973:49::-;;;;;;;;;;-1:-1:-1;81973:49:0;;;;;:::i;:::-;;;;;;;;;;;;;;81705:28;;;;;;;;;;;;;;;;81775:26;;;;;;;;;;;;;;;;85890:3464;;;;;;;;;;;;;:::i;74677:45::-;;;;;;;;;;;;74714:8;74677:45;;85229:132;;;;;;;;;;;;;:::i;81916:50::-;;;;;;;;;;-1:-1:-1;81916:50:0;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;;;81916:50:0;;;55854:164;;;;;;;;;;-1:-1:-1;55854:164:0;;;;;:::i;:::-;-1:-1:-1;;;;;55975:25:0;;;55951:4;55975:25;;;:18;:25;;;;;;;;:35;;;;;;;;;;;;;;;55854:164;82590:739;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;32611:201::-;;;;;;;;;;-1:-1:-1;32611:201:0;;;;;:::i;:::-;;:::i;74729:47::-;;;;;;;;;;;;74765:11;74729:47;;89362:99;;;;;;;;;;-1:-1:-1;89362:99:0;;;;;:::i;:::-;;:::i;80802:483::-;;;;;;;;;;-1:-1:-1;80802:483:0;;;;;:::i;:::-;;:::i;94469:181::-;94581:4;94605:37;94629:12;94605:23;:37::i;:::-;94598:44;94469:181;-1:-1:-1;;94469:181:0:o;53872:100::-;53926:13;53959:5;53952:12;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;53872:100;:::o;55385:171::-;55461:7;55481:23;55496:7;55481:14;:23::i;:::-;-1:-1:-1;55524:24:0;;;;:15;:24;;;;;;-1:-1:-1;;;;;55524:24:0;;55385:171::o;54902:417::-;54983:13;54999:23;55014:7;54999:14;:23::i;:::-;54983:39;;55047:5;-1:-1:-1;;;;;55041:11:0;:2;-1:-1:-1;;;;;55041:11:0;;;55033:57;;;;-1:-1:-1;;;55033:57:0;;15364:2:1;55033:57:0;;;15346:21:1;15403:2;15383:18;;;15376:30;15442:34;15422:18;;;15415:62;-1:-1:-1;;;15493:18:1;;;15486:31;15534:19;;55033:57:0;;;;;;;;;30330:10;-1:-1:-1;;;;;55125:21:0;;;;:62;;-1:-1:-1;55150:37:0;55167:5;30330:10;55854:164;:::i;55150:37::-;55103:174;;;;-1:-1:-1;;;55103:174:0;;13858:2:1;55103:174:0;;;13840:21:1;13897:2;13877:18;;;13870:30;13936:34;13916:18;;;13909:62;14007:32;13987:18;;;13980:60;14057:19;;55103:174:0;13656:426:1;55103:174:0;55290:21;55299:2;55303:7;55290:8;:21::i;:::-;54972:347;54902:417;;:::o;83391:112::-;83435:16;83471:24;83484:10;83471:12;:24::i;:::-;83464:31;;83391:112;:::o;94112:154::-;-1:-1:-1;;;94112:154:0;;;;;;;:::o;56085:336::-;56280:41;30330:10;56313:7;56280:18;:41::i;:::-;56272:100;;;;-1:-1:-1;;;56272:100:0;;;;;;;:::i;:::-;56385:28;56395:4;56401:2;56405:7;56385:9;:28::i;67452:256::-;67549:7;67585:23;67602:5;67585:16;:23::i;:::-;67577:5;:31;67569:87;;;;-1:-1:-1;;;67569:87:0;;10688:2:1;67569:87:0;;;10670:21:1;10727:2;10707:18;;;10700:30;10766:34;10746:18;;;10739:62;-1:-1:-1;;;10817:18:1;;;10810:41;10868:19;;67569:87:0;10486:407:1;67569:87:0;-1:-1:-1;;;;;;67674:19:0;;;;;;;;:12;:19;;;;;;;;:26;;;;;;;;;67452:256::o;78723:661::-;75026:21;75017:5;;-1:-1:-1;;;75017:5:0;;;;:30;;;;;;;;:::i;:::-;;;:52;;;-1:-1:-1;75714:8:0;;75695:15;:27;;75051:18;75013:105;;;75093:13;;-1:-1:-1;;;75093:13:0;;;;;;;;;;;75013:105;78793:13:::1;78809:21;74765:11;78809:9;:21;:::i;:::-;78793:37:::0;-1:-1:-1;78847:10:0;78843:127:::1;;78881:18;;-1:-1:-1::0;;;78881:18:0::1;;;;;;;;;;;78843:127;78929:2;78921:5;:10;78917:53;;;-1:-1:-1::0;78956:2:0::1;78917:53;79008:9;79003:106;79027:5;79023:1;:9;79003:106;;;79050:16;:14;:16::i;:::-;79092:3;;79003:106;;;;79121:6;79965:10:::0;:50;;-1:-1:-1;;79997:12:0;:16;79987:27;79965:50;;;79814:220;79121:6:::1;79191:14;79221:17;79233:5:::0;74765:11:::1;79221:17;:::i;:::-;79208:31;::::0;:9:::1;:31;:::i;:::-;79191:48:::0;-1:-1:-1;79254:10:0;;79250:127:::1;;79299:35;::::0;79282:12:::1;::::0;79299:10:::1;::::0;79323:6;;79282:12;79299:35;79282:12;79299:35;79323:6;79299:10;:35:::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;79281:53;;;79357:7;79349:16;;;::::0;::::1;79250:127;78782:602;;78723:661::o:0;89469:305::-;82098:11;:9;:11::i;:::-;82093:70;;82133:18;;-1:-1:-1;;;82133:18:0;;;;;;;;;;;82093:70;89578:2:::1;89559:9;:16;:21;89555:79;;;89604:18;;-1:-1:-1::0;;;89604:18:0::1;;;;;;;;;;;89555:79;89651:9;89646:121;89666:9;:16;89662:1;:20;89646:121;;;89700:24;89711:9;89721:1;89711:12;;;;;;;;:::i;:::-;;;;;;;89700:10;:24::i;:::-;89750:3;;89646:121;;76961:435:::0;31591:13;:11;:13::i;:::-;84267:16;;:20;77051:68:::1;;77092:15;;-1:-1:-1::0;;;77092:15:0::1;;;;;;;;;;;77051:68;77198:19;::::0;-1:-1:-1;;;77198:19:0;::::1;;;77193:85;;77241:25;;-1:-1:-1::0;;;77241:25:0::1;;;;;;;;;;;77193:85;77288:19;:27:::0;;-1:-1:-1;;;;77288:27:0;::::1;::::0;;;-1:-1:-1;;;;;31778:6:0;77378:5:::1;77347:28;:21;77371:4;77347:28;:::i;:::-;:36;;;;:::i;:::-;77326:62;::::0;::::1;::::0;;;;;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;54972:347:::0;54902:417;;:::o;56492:185::-;56630:39;56647:4;56653:2;56657:7;56630:39;;;;;;;;;;;;:16;:39::i;89782:2004::-;89845:25;;;;:15;:25;;;;;;-1:-1:-1;;;;;89845:25:0;89874:10;89845:39;89841:94;;89908:15;;-1:-1:-1;;;89908:15:0;;;;;;;;;;;89841:94;90047:7;;90058:1;90047:12;;:37;;;;;90063:21;:19;:21::i;:::-;90043:95;;;90108:18;;-1:-1:-1;;;90108:18:0;;;;;;;;;;;90043:95;90223:12;;90250:17;90246:76;;90291:19;;-1:-1:-1;;;90291:19:0;;;;;;;;;;;90246:76;90378:24;;;;:14;:24;;;;;;;;:32;;;90454:15;:25;;;;;90447:32;;-1:-1:-1;;;;;;90447:32:0;;;90581:7;;90557:31;;:21;:31;:::i;:::-;90534:54;;90599:15;90605:8;90599:5;:15::i;:::-;90625:9;:11;;;:9;:11;;;:::i;:::-;;;;-1:-1:-1;;90647:7:0;:9;;;:7;:9;;;:::i;:::-;;;;-1:-1:-1;;90667:42:0;;90675:10;;90667:42;;;;;90696:12;;90667:42;;;;90696:12;90675:10;90667:42;;;;;;;;;;;;;;;;;;;;;90814:7;;90825:1;90814:12;90810:969;;;90912:21;;90948:422;90972:24;90990:4;90972:9;:24::i;:::-;90968:1;:28;90948:422;;;91034:37;91062:4;91069:1;91034:19;:37::i;:::-;91136:1;91094:30;;;:15;:30;;;;;;91018:53;;-1:-1:-1;;;;;;91094:30:0;:44;91090:230;;91248:8;:24;;;91295:5;;91090:230;91349:3;;90948:422;;;-1:-1:-1;91449:8:0;;;91434:24;;;;:14;:24;;;;;;;:32;;;91508:8;;91542;;91508:43;;-1:-1:-1;;;91508:43:0;;-1:-1:-1;;;;;91508:8:0;;;;:33;;:43;;;;17855:25:1;;;17843:2;17828:18;;17709:177;91508:43:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;91649:8:0;;91633:25;;;;:15;:25;;;;;;;91625:66;;-1:-1:-1;;;;;91633:25:0;;;;-1:-1:-1;91669:21:0;91625:66;;;;;-1:-1:-1;91669:21:0;91625:66;91633:25;91625:66;91669:21;91633:25;91625:66;;;;;;;;;;;;;;;;;;;;-1:-1:-1;91747:8:0;;91731:25;;;;:15;:25;;;;;;91706:61;;91724:4;;-1:-1:-1;;;;;91731:25:0;;91706:9;:61::i;:::-;90828:951;89830:1956;;89782:2004;:::o;91794:1972::-;91856:25;;;;:15;:25;;;;;;-1:-1:-1;;;;;91856:25:0;91885:10;91856:39;91852:94;;91919:15;;-1:-1:-1;;;91919:15:0;;;;;;;;;;;91852:94;92058:7;;92069:1;92058:12;;:37;;;;;92074:21;:19;:21::i;:::-;92054:95;;;92119:18;;-1:-1:-1;;;92119:18:0;;;;;;;;;;;92054:95;92234:12;;92261:17;92257:76;;92302:19;;-1:-1:-1;;;92302:19:0;;;;;;;;;;;92257:76;92389:24;;;;:14;:24;;;;;;;:32;;;92457:8;;:37;;-1:-1:-1;;;92457:37:0;;;;;17855:25:1;;;-1:-1:-1;;;;;92457:8:0;;;;:27;;17828:18:1;;92457:37:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;92536:25:0;;;;:15;:25;;;;;92529:32;;-1:-1:-1;;;;;;92529:32:0;;;-1:-1:-1;92601:46:0;92619:4;92626:10;92552:8;92601:9;:46::i;:::-;92658:9;:11;;;:9;:11;;;:::i;:::-;;;;-1:-1:-1;;92680:7:0;:9;;;:7;:9;;;:::i;:::-;;;;;;92794:7;;92805:1;92794:12;92790:969;;;92892:21;;92928:422;92952:24;92970:4;92952:9;:24::i;:::-;92948:1;:28;92928:422;;;93014:37;93042:4;93049:1;93014:19;:37::i;:::-;93116:1;93074:30;;;:15;:30;;;;;;92998:53;;-1:-1:-1;;;;;;93074:30:0;:44;93070:230;;93228:8;:24;;;93275:5;;93070:230;93329:3;;92928:422;;;-1:-1:-1;93429:8:0;;;93414:24;;;;:14;:24;;;;;;;:32;;;93488:8;;93522;;93488:43;;-1:-1:-1;;;93488:43:0;;-1:-1:-1;;;;;93488:8:0;;;;:33;;:43;;;;17855:25:1;;;17843:2;17828:18;;17709:177;93488:43:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;93629:8:0;;93613:25;;;;:15;:25;;;;;;;93605:66;;-1:-1:-1;;;;;93613:25:0;;;;-1:-1:-1;93649:21:0;93605:66;;;;;-1:-1:-1;93649:21:0;93605:66;93613:25;93605:66;93649:21;93613:25;93605:66;;;;;;;;;;;;;;;;;;;;-1:-1:-1;93727:8:0;;93711:25;;;;:15;:25;;;;;;93686:61;;93704:4;;-1:-1:-1;;;;;93711:25:0;;93686:9;:61::i;84435:118::-;84484:7;81852:5;84511:16;;:34;;;;:::i;67974:233::-;68049:7;68085:30;67872:10;:17;;67784:113;68085:30;68077:5;:38;68069:95;;;;-1:-1:-1;;;68069:95:0;;15766:2:1;68069:95:0;;;15748:21:1;15805:2;15785:18;;;15778:30;15844:34;15824:18;;;15817:62;-1:-1:-1;;;15895:18:1;;;15888:42;15947:19;;68069:95:0;15564:408:1;68069:95:0;68182:10;68193:5;68182:17;;;;;;;;:::i;:::-;;;;;;;;;68175:24;;67974:233;;;:::o;76768:154::-;31591:13;:11;:13::i;:::-;75192:19:::1;75183:5;::::0;-1:-1:-1;;;75183:5:0;::::1;;;:28;::::0;::::1;;;;;;:::i;:::-;;75179:85;;75235:17;;-1:-1:-1::0;;;75235:17:0::1;;;;;;;;;;;75179:85;76835:5:::2;:29:::0;;-1:-1:-1;;;;76835:29:0::2;-1:-1:-1::0;;;76835:29:0::2;::::0;;76886:28:::2;74714:8;76886:15;:28;:::i;:::-;76875:8;:39:::0;76768:154::o;53583:222::-;53655:7;53691:16;;;:7;:16;;;;;;-1:-1:-1;;;;;53691:16:0;53726:19;53718:56;;;;-1:-1:-1;;;53718:56:0;;15011:2:1;53718:56:0;;;14993:21:1;15050:2;15030:18;;;15023:30;-1:-1:-1;;;15069:18:1;;;15062:54;15133:18;;53718:56:0;14809:348:1;53314:207:0;53386:7;-1:-1:-1;;;;;53414:19:0;;53406:73;;;;-1:-1:-1;;;53406:73:0;;13448:2:1;53406:73:0;;;13430:21:1;13487:2;13467:18;;;13460:30;13526:34;13506:18;;;13499:62;-1:-1:-1;;;13577:18:1;;;13570:39;13626:19;;53406:73:0;13246:405:1;53406:73:0;-1:-1:-1;;;;;;53497:16:0;;;;;:9;:16;;;;;;;53314:207::o;32353:103::-;31591:13;:11;:13::i;:::-;32418:30:::1;32445:1;32418:18;:30::i;:::-;32353:103::o:0;85399:371::-;31591:13;:11;:13::i;:::-;75493:20:::1;75484:5;::::0;-1:-1:-1;;;75484:5:0;::::1;;;:29;::::0;::::1;;;;;;:::i;:::-;;75480:86;;75537:17;;-1:-1:-1::0;;;75537:17:0::1;;;;;;;;;;;75480:86;84267:16:::0;;:20;85475:68:::2;;85516:15;;-1:-1:-1::0;;;85516:15:0::2;;;;;;;;;;;85475:68;85557:19;::::0;-1:-1:-1;;;85557:19:0;::::2;;;85553:80;;;85600:21;;-1:-1:-1::0;;;85600:21:0::2;;;;;;;;;;;85553:80;85691:12;85672:16;:31:::0;;;85732:30:::2;::::0;81852:5:::2;::::0;85732:30:::2;:::i;:::-;85714:15;:48:::0;85399:371::o;54041:104::-;54097:13;54130:7;54123:14;;;;;:::i;80340:206::-;80422:13;80408:3;80173:12;80181:3;58643:4;58667:16;;;:7;:16;;;;;;-1:-1:-1;;;;;58667:16:0;:30;;;58578:127;80173:12;80168:71;;80209:18;;-1:-1:-1;;;80209:18:0;;;;;;;;;;;80168:71;80455:8:::1;::::0;-1:-1:-1;;;;;80455:8:0::1;:24;:8;80480:5;::::0;-1:-1:-1;;;80480:5:0;::::1;;;:29;::::0;::::1;;;;;;:::i;:::-;;80511:3;80516:21;80533:3;80516:16;:21::i;:::-;80455:83;::::0;-1:-1:-1;;;;;;80455:83:0::1;::::0;;;;;;8858:14:1;;8851:22;80455:83:0::1;::::0;::::1;8833:41:1::0;8890:18;;;8883:34;;;;8933:18;;;8926:34;8806:18;;80455:83:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;::::0;;::::1;-1:-1:-1::0;;80455:83:0::1;::::0;::::1;;::::0;::::1;::::0;;;::::1;::::0;::::1;:::i;:::-;80448:90;;80249:1;80340:206:::0;;;;:::o;75774:322::-;75829:4;;75873:11;75881:3;75873:5;:11;:::i;:::-;75846:38;-1:-1:-1;75895:23:0;75921:11;75929:3;75921:5;:11;:::i;:::-;75943:19;75965:31;;;:13;:31;;;;;;;76023:1;:20;;;76062:18;;;:26;;;;75774:322;-1:-1:-1;;;75774:322:0:o;55628:155::-;55723:52;30330:10;55756:8;55766;55723:18;:52::i;76161:575::-;31591:13;:11;:13::i;:::-;75339:21:::1;75330:5;::::0;-1:-1:-1;;;75330:5:0;::::1;;;:30;::::0;::::1;;;;;;:::i;:::-;;75326:88;;75384:18;;-1:-1:-1::0;;;75384:18:0::1;;;;;;;;;;;75326:88;75714:8:::0;;75695:15;:27;;76251:80:::2;;76298:21;;-1:-1:-1::0;;;76298:21:0::2;;;;;;;;;;;76251:80;76402:6;::::0;76365:31:::2;::::0;;::::2;::::0;::::2;6367:19:1::0;;;6402:12;76365:31:0::2;;;;;;;;;;;;76355:42;;;;;;76347:51;;:61;76343:116;;76432:15;;-1:-1:-1::0;;;76432:15:0::2;;;;;;;;;;;76343:116;76605:10;::::0;;76589:26;;;::::2;76580:6;:35:::0;-1:-1:-1;76670:17:0;;76700:5:::2;:28:::0;;-1:-1:-1;;;;76700:28:0::2;::::0;;76161:575::o;56748:323::-;56922:41;30330:10;56955:7;56922:18;:41::i;:::-;56914:100;;;;-1:-1:-1;;;56914:100:0;;;;;;;:::i;:::-;57025:38;57039:4;57045:2;57049:7;57058:4;57025:13;:38::i;84561:660::-;84615:7;84641;;84652:1;84641:12;84637:53;;;-1:-1:-1;84677:1:0;;84561:660::o;84637:53::-;84810:7;;84721:1;;84821:4;-1:-1:-1;84806:117:0;;84842:14;84869:4;84859:7;;:14;;;;:::i;:::-;84842:31;-1:-1:-1;84899:12:0;84908:3;84842:31;84899:12;:::i;:::-;84888:23;;84827:96;84806:117;85000:7;;84988:8;:19;84984:74;;85045:1;85035:7;;:11;;;;:::i;:::-;85024:22;;84984:74;85142:2;85131:8;:13;85127:59;;;-1:-1:-1;85172:2:0;85127:59;85205:8;84561:660;-1:-1:-1;84561:660:0:o;84303:124::-;84345:4;84369:13;84267:16;;:20;;;84199:96;84369:13;:50;;;;;84401:18;:16;:18::i;:::-;84386:12;:33;84362:57;;84303:124;:::o;80554:240::-;80636:13;80622:3;80173:12;80181:3;58643:4;58667:16;;;:7;:16;;;;;;-1:-1:-1;;;;;58667:16:0;:30;;;58578:127;80173:12;80168:71;;80209:18;;-1:-1:-1;;;80209:18:0;;;;;;;;;;;80168:71;80669:8:::1;::::0;-1:-1:-1;;;;;80669:8:0::1;:23;:8;80693:5;::::0;-1:-1:-1;;;80693:5:0;::::1;;;:29;::::0;::::1;;;;;;:::i;:::-;;80724:3;80729:21;80746:3;80729:16;:21::i;:::-;80752:19;::::0;;;:14:::1;:19;::::0;;;;;80773:12:::1;80767:3:::0;80773:7:::1;:12::i;:::-;80669:117;::::0;-1:-1:-1;;;;;;80669:117:0::1;::::0;;;;;;9249:14:1;;9242:22;80669:117:0::1;::::0;::::1;9224:41:1::0;9281:18;;;9274:34;;;;9324:18;;;9317:34;;;;9367:18;;;9360:34;-1:-1:-1;;;;;9431:32:1;9410:19;;;9403:61;9196:19;;80669:117:0::1;8971:499:1::0;77433:1261:0;75192:19;75183:5;;-1:-1:-1;;;75183:5:0;;;;:28;;;;;;;;:::i;:::-;;75179:85;;75235:17;;-1:-1:-1;;;75235:17:0;;;;;;;;;;;75179:85;77635:17:::1;77645:6;77635:9;:17::i;:::-;77631:73;;;77676:16;;-1:-1:-1::0;;;77676:16:0::1;;;;;;;;;;;77631:73;77762:12:::0;77758:72:::1;;77798:20;;-1:-1:-1::0;;;77798:20:0::1;;;;;;;;;;;77758:72;77873:13;77889:21;77901:9:::0;77889;:21:::1;:::i;:::-;77873:37;;77935:5;77925:7;:15;77921:75;;;77964:20;;-1:-1:-1::0;;;77964:20:0::1;;;;;;;;;;;77921:75;78038:18;78085:9;78075:7;:19;78071:84;;;78124:19;78134:9:::0;78124:7;:19:::1;:::i;:::-;78111:32;;78071:84;78181:22;74765:11;78181:10:::0;:22:::1;:::i;:::-;78169:9;:34;78165:93;;;78227:19;;-1:-1:-1::0;;;78227:19:0::1;;;;;;;;;;;78165:93;78331:58;::::0;;::::1;::::0;::::1;6638:19:1::0;;;-1:-1:-1;;78356:10:0::1;6695:2:1::0;6691:15;6687:53;6673:12;;;6666:75;;;;6757:12;;;6750:28;;;6794:12;;;6787:28;;;78306:12:0::1;::::0;6831:13:1;;78331:58:0::1;;;;;;;;;;;;78321:69;;;;;;78306:84;;78406:50;78425:12;;78406:50;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;;;;-1:-1:-1;78439:10:0::1;::::0;-1:-1:-1;78451:4:0;;-1:-1:-1;78406:18:0::1;::::0;-1:-1:-1;78406:50:0:i:1;:::-;78401:105;;78480:14;;-1:-1:-1::0;;;78480:14:0::1;;;;;;;;;;;78401:105;78555:19;78567:6;78555:11;:19::i;:::-;78592:9;78587:81;78611:7;78607:1;:11;78587:81;;;78640:16;:14;:16::i;:::-;78620:3:::0;::::1;::::0;::::1;:::i;:::-;;;;78587:81;;;;78680:6;79965:10:::0;:50;;-1:-1:-1;;79997:12:0;:16;79987:27;79965:50;;;79814:220;78680:6:::1;77581:1113;;;77433:1261:::0;;;;;;:::o;83561:630::-;83620:16;83707:4;83649:22;83741:25;83707:4;83741:9;:25::i;:::-;83725:41;;83777:24;83818:5;83804:20;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;83804:20:0;;83777:47;;83837:13;83872:9;83867:221;83891:5;83887:1;:9;83867:221;;;83918:10;83931:38;83951:14;83967:1;83931:19;:38::i;:::-;83990:19;;;;:15;:19;;;;;;;;-1:-1:-1;;;;;;83990:29:0;;;:19;;:29;83986:91;;;84059:2;84040:7;84048;;;;:::i;:::-;;;84040:16;;;;;;;;:::i;:::-;;;;;;:21;;;;;83986:91;-1:-1:-1;83898:3:0;;;;:::i;:::-;;;;83867:221;;;-1:-1:-1;84124:22:0;;84131:7;83561:630;-1:-1:-1;;;;83561:630:0:o;85890:3464::-;84267:16;;85932:70;;85974:16;;-1:-1:-1;;;85974:16:0;;;;;;;;;;;85932:70;86017:21;:19;:21::i;:::-;86012:80;;86062:18;;-1:-1:-1;;;86062:18:0;;;;;;;;;;;86012:80;86108:7;;86119:1;86108:12;86104:69;;;86144:17;;-1:-1:-1;;;86144:17:0;;;;;;;;;;;86104:69;86187:7;;86183:62;;86223:10;;-1:-1:-1;;;86223:10:0;;;;;;;;;;;86183:62;86346:20;86433:3;81905:2;86397:15;;:32;;;;:::i;:::-;86381:49;;:12;:49;:::i;:::-;:55;86377:416;;;86644:1;81905:2;86594:29;81905:2;86594:12;:29;:::i;:::-;86593:48;;;;:::i;:::-;:52;;;;:::i;:::-;86578:67;;86377:416;;;86780:1;81905:2;86744:15;;:32;;;;:::i;:::-;86743:38;;;;:::i;:::-;86728:53;;86377:416;86829:23;;86871:12;86864:20;;;;:::i;:::-;86940:12;86922:15;:30;86963:12;:14;;;:12;:14;;;:::i;:::-;;;;;;87035:19;87057:23;:21;:23::i;:::-;87113:13;;;87123:2;87113:13;;;;;;;;;87035:45;;-1:-1:-1;87091:19:0;;87113:13;;;;;;;;;;;-1:-1:-1;;87091:35:0;-1:-1:-1;87205:1:0;87188:1139;87213:11;87208:1;:16;87188:1139;;87343:1;87333:7;:11;87323:21;;87455:7;87450:2;87442:6;87438:15;87431:32;87563:15;87610:24;87628:4;87610:9;:24::i;:::-;87589:17;;;;;;87581:53;;;;:::i;:::-;87563:71;;87695:20;87718:43;87746:4;87753:7;87718:19;:43::i;:::-;87695:66;;87776:19;87782:12;87776:5;:19::i;:::-;87937:1;87896:29;;;:15;:29;;;;;;-1:-1:-1;;;;;87896:29:0;87892:393;;-1:-1:-1;;88032:3:0;;;;87892:393;;;88182:29;;;;:15;:29;;;;;88175:36;;-1:-1:-1;;;;;;88175:36:0;;;88230:9;:11;;;;;;:::i;:::-;;;;-1:-1:-1;;88260:7:0;:9;;;:7;:9;;;:::i;:::-;;;;;;87892:393;-1:-1:-1;;88310:3:0;;87188:1139;;;;88375:7;;88386:1;88375:12;88371:976;;;88473:21;;88509:422;88533:24;88551:4;88533:9;:24::i;:::-;88529:1;:28;88509:422;;;88595:37;88623:4;88630:1;88595:19;:37::i;:::-;88697:1;88655:30;;;:15;:30;;;;;;88579:53;;-1:-1:-1;;;;;;88655:30:0;:44;88651:230;;88809:8;:24;;;88856:5;;88651:230;88910:3;;88509:422;;;-1:-1:-1;89022:12:0;;89010:8;;;88995:24;;;;:14;:24;;;;;;;:39;;;;89076:8;;89110;;89076:43;;-1:-1:-1;;;89076:43:0;;;;;17855:25:1;;;;-1:-1:-1;;;;;89076:8:0;;:33;;17828:18:1;;89076:43:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;89217:8:0;;89201:25;;;;:15;:25;;;;;;;89193:66;;-1:-1:-1;;;;;89201:25:0;;;;-1:-1:-1;89237:21:0;89193:66;;;;;-1:-1:-1;89237:21:0;89193:66;89201:25;89193:66;89237:21;89201:25;89193:66;;;;;;;;;;;;;;;;;;;;-1:-1:-1;89315:8:0;;89299:25;;;;:15;:25;;;;;;89274:61;;89292:4;;-1:-1:-1;;;;;89299:25:0;;89274:9;:61::i;:::-;88389:958;85921:3433;;;;85890:3464::o;85229:132::-;85281:4;81905:2;85321:15;;:32;;;;:::i;:::-;85305:12;:48;;85298:55;;85229:132;:::o;82590:739::-;82634:21;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;82634:21:0;82682:9;;82668:23;;82717:7;;82702:12;;;:22;82752:9;;82735:14;;;:26;82792:12;;82772:17;;;:32;82829:21;82815:11;;;:35;82877:23;:21;:23::i;:::-;82861:13;;;:39;82927:8;;82911:13;;;:24;82970:18;:16;:18::i;:::-;82946:21;;;:42;83006:21;:19;:21::i;:::-;83001:118;;83095:12;81905:2;83060:15;;:32;;;;:::i;:::-;:47;;;;:::i;:::-;83044:13;;;:63;83001:118;83144:21;:19;:21::i;:::-;83131:34;;:10;;;:34;83188:11;:9;:11::i;:::-;83176:23;;:9;;;:23;84267:16;;:20;;83210:11;;;:27;83279:21;;;;83264:12;:36;:57;;;;;83320:1;83304:4;:12;;;:17;;83264:57;83248:73;;:13;;;:73;:4;82590:739::o;32611:201::-;31591:13;:11;:13::i;:::-;-1:-1:-1;;;;;32700:22:0;::::1;32692:73;;;::::0;-1:-1:-1;;;32692:73:0;;11519:2:1;32692:73:0::1;::::0;::::1;11501:21:1::0;11558:2;11538:18;;;11531:30;11597:34;11577:18;;;11570:62;-1:-1:-1;;;11648:18:1;;;11641:36;11694:19;;32692:73:0::1;11317:402:1::0;32692:73:0::1;32776:28;32795:8;32776:18;:28::i;:::-;32611:201:::0;:::o;89362:99::-;82098:11;:9;:11::i;:::-;82093:70;;82133:18;;-1:-1:-1;;;82133:18:0;;;;;;;;;;;82093:70;89433:20:::1;89444:8;89433:10;:20::i;80802:483::-:0;80878:13;80864:3;80173:12;80181:3;58643:4;58667:16;;;:7;:16;;;;;;-1:-1:-1;;;;;58667:16:0;:30;;;58578:127;80173:12;80168:71;;80209:18;;-1:-1:-1;;;80209:18:0;;;;;;;;;;;80168:71;80904:14:::1;81043:4;81019:12;81027:3:::0;81019:7:::1;:12::i;:::-;-1:-1:-1::0;;;;;81019:29:0::1;;81015:144;;;-1:-1:-1::0;81074:12:0::1;::::0;81015:144:::1;;;-1:-1:-1::0;81128:19:0::1;::::0;;;:14:::1;:19;::::0;;;;;81015:144:::1;81178:8;::::0;-1:-1:-1;;;;;81178:8:0::1;:18;:8;81197:5;::::0;-1:-1:-1;;;81197:5:0;::::1;;;:29;::::0;::::1;;;;;;:::i;:::-;;81228:3;81233:21;81250:3;81233:16;:21::i;:::-;81256:6;81264:12;81272:3;81264:7;:12::i;:::-;81178:99;::::0;-1:-1:-1;;;;;;81178:99:0::1;::::0;;;;;;9249:14:1;;9242:22;81178:99:0::1;::::0;::::1;9224:41:1::0;9281:18;;;9274:34;;;;9324:18;;;9317:34;;;;9367:18;;;9360:34;-1:-1:-1;;;;;9431:32:1;9410:19;;;9403:61;9196:19;;81178:99:0::1;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;::::0;;::::1;-1:-1:-1::0;;81178:99:0::1;::::0;::::1;;::::0;::::1;::::0;;;::::1;::::0;::::1;:::i;68820:589::-:0;-1:-1:-1;;;;;69026:18:0;;69022:187;;69061:40;69093:7;70236:10;:17;;70209:24;;;;:15;:24;;;;;:44;;;70264:24;;;;;;;;;;;;70132:164;69061:40;69022:187;;;69131:2;-1:-1:-1;;;;;69123:10:0;:4;-1:-1:-1;;;;;69123:10:0;;69119:90;;69150:47;69183:4;69189:7;69150:32;:47::i;:::-;-1:-1:-1;;;;;69223:16:0;;69219:183;;69256:45;69293:7;69256:36;:45::i;69219:183::-;69329:4;-1:-1:-1;;;;;69323:10:0;:2;-1:-1:-1;;;;;69323:10:0;;69319:83;;69350:40;69378:2;69382:7;69350:27;:40::i;67144:224::-;67246:4;-1:-1:-1;;;;;;67270:50:0;;-1:-1:-1;;;67270:50:0;;:90;;;67324:36;67348:11;67324:23;:36::i;63360:135::-;58643:4;58667:16;;;:7;:16;;;;;;-1:-1:-1;;;;;58667:16:0;63434:53;;;;-1:-1:-1;;;63434:53:0;;15011:2:1;63434:53:0;;;14993:21:1;15050:2;15030:18;;;15023:30;-1:-1:-1;;;15069:18:1;;;15062:54;15133:18;;63434:53:0;14809:348:1;62639:174:0;62714:24;;;;:15;:24;;;;;:29;;-1:-1:-1;;;;;;62714:29:0;-1:-1:-1;;;;;62714:29:0;;;;;;;;:24;;62768:23;62714:24;62768:14;:23::i;:::-;-1:-1:-1;;;;;62759:46:0;;;;;;;;;;;62639:174;;:::o;58872:264::-;58965:4;58982:13;58998:23;59013:7;58998:14;:23::i;:::-;58982:39;;59051:5;-1:-1:-1;;;;;59040:16:0;:7;-1:-1:-1;;;;;59040:16:0;;:52;;;-1:-1:-1;;;;;;55975:25:0;;;55951:4;55975:25;;;:18;:25;;;;;;;;:35;;;;;;;;;;;;59060:32;59040:87;;;;59120:7;-1:-1:-1;;;;;59096:31:0;:20;59108:7;59096:11;:20::i;:::-;-1:-1:-1;;;;;59096:31:0;;59032:96;58872:264;-1:-1:-1;;;;58872:264:0:o;61895:625::-;62054:4;-1:-1:-1;;;;;62027:31:0;:23;62042:7;62027:14;:23::i;:::-;-1:-1:-1;;;;;62027:31:0;;62019:81;;;;-1:-1:-1;;;62019:81:0;;11926:2:1;62019:81:0;;;11908:21:1;11965:2;11945:18;;;11938:30;12004:34;11984:18;;;11977:62;-1:-1:-1;;;12055:18:1;;;12048:35;12100:19;;62019:81:0;11724:401:1;62019:81:0;-1:-1:-1;;;;;62119:16:0;;62111:65;;;;-1:-1:-1;;;62111:65:0;;12689:2:1;62111:65:0;;;12671:21:1;12728:2;12708:18;;;12701:30;12767:34;12747:18;;;12740:62;-1:-1:-1;;;12818:18:1;;;12811:34;12862:19;;62111:65:0;12487:400:1;62111:65:0;62189:39;62210:4;62216:2;62220:7;62189:20;:39::i;:::-;62293:29;62310:1;62314:7;62293:8;:29::i;:::-;-1:-1:-1;;;;;62335:15:0;;;;;;:9;:15;;;;;:20;;62354:1;;62335:15;:20;;62354:1;;62335:20;:::i;:::-;;;;-1:-1:-1;;;;;;;62366:13:0;;;;;;:9;:13;;;;;:18;;62383:1;;62366:13;:18;;62383:1;;62366:18;:::i;:::-;;;;-1:-1:-1;;62395:16:0;;;;:7;:16;;;;;;:21;;-1:-1:-1;;;;;;62395:21:0;-1:-1:-1;;;;;62395:21:0;;;;;;;;;62434:27;;62395:16;;62434:27;;;;;;;54972:347;54902:417;;:::o;79684:122::-;79730:15;79748:13;67872:10;:17;;67784:113;79748:13;79730:31;;79772:26;79778:10;79790:7;79772:5;:26::i;93805:221::-;93900:49;93913:10;93933:4;93940:8;93900:12;:49::i;:::-;93960:25;;;;:15;:25;;;;;:38;;-1:-1:-1;;;;;;93960:38:0;93988:10;93960:38;;;94009:7;:9;;;;;;:::i;:::-;;;;;;93805:221;:::o;31870:132::-;31778:6;;-1:-1:-1;;;;;31778:6:0;30330:10;31934:23;31926:68;;;;-1:-1:-1;;;31926:68:0;;14650:2:1;31926:68:0;;;14632:21:1;;;14669:18;;;14662:30;14728:34;14708:18;;;14701:62;14780:18;;31926:68:0;14448:356:1;61138:420:0;61198:13;61214:23;61229:7;61214:14;:23::i;:::-;61198:39;;61250:48;61271:5;61286:1;61290:7;61250:20;:48::i;:::-;61339:29;61356:1;61360:7;61339:8;:29::i;:::-;-1:-1:-1;;;;;61381:16:0;;;;;;:9;:16;;;;;:21;;61401:1;;61381:16;:21;;61401:1;;61381:21;:::i;:::-;;;;-1:-1:-1;;61420:16:0;;;;:7;:16;;;;;;61413:23;;-1:-1:-1;;;;;;61413:23:0;;;61454:36;61428:7;;61420:16;-1:-1:-1;;;;;61454:36:0;;;;;61420:16;;61454:36;78782:602:::1;;78723:661::o:0;32972:191::-;33065:6;;;-1:-1:-1;;;;;33082:17:0;;;-1:-1:-1;;;;;;33082:17:0;;;;;;;33115:40;;33065:6;;;33082:17;33065:6;;33115:40;;33046:16;;33115:40;33035:128;32972:191;:::o;81326:156::-;81393:7;81455:6;;81463:8;81438:34;;;;;;;;7012:19:1;;;7056:2;7047:12;;7040:28;7093:2;7084:12;;6855:247;81438:34:0;;;;-1:-1:-1;;81438:34:0;;;;;;;;;81428:45;;81438:34;81428:45;;;;;81326:156;-1:-1:-1;;81326:156:0:o;62956:315::-;63111:8;-1:-1:-1;;;;;63102:17:0;:5;-1:-1:-1;;;;;63102:17:0;;;63094:55;;;;-1:-1:-1;;;63094:55:0;;13094:2:1;63094:55:0;;;13076:21:1;13133:2;13113:18;;;13106:30;13172:27;13152:18;;;13145:55;13217:18;;63094:55:0;12892:349:1;63094:55:0;-1:-1:-1;;;;;63160:25:0;;;;;;;:18;:25;;;;;;;;:35;;;;;;;;;;;;;:46;;-1:-1:-1;;63160:46:0;;;;;;;;;;63222:41;;8585::1;;;63222::0;;8558:18:1;63222:41:0;;;;;;;62956:315;;;:::o;57952:313::-;58108:28;58118:4;58124:2;58128:7;58108:9;:28::i;:::-;58155:47;58178:4;58184:2;58188:7;58197:4;58155:22;:47::i;:::-;58147:110;;;;-1:-1:-1;;;58147:110:0;;;;;;;:::i;1978:190::-;2103:4;2156;2127:25;2140:5;2147:4;2127:12;:25::i;:::-;:33;;1978:190;-1:-1:-1;;;;1978:190:0:o;79425:251::-;79481:24;79508:11;79516:3;79508:5;:11;:::i;:::-;79481:38;-1:-1:-1;79530:23:0;79556:11;79564:3;79556:5;:11;:::i;:::-;79612:31;;;;:13;:31;;;;;;;;79647:1;:20;;;79612:56;;;79578:90;;;-1:-1:-1;;79425:251:0:o;70923:988::-;71189:22;71239:1;71214:22;71231:4;71214:16;:22::i;:::-;:26;;;;:::i;:::-;71251:18;71272:26;;;:17;:26;;;;;;71189:51;;-1:-1:-1;71405:28:0;;;71401:328;;-1:-1:-1;;;;;71472:18:0;;71450:19;71472:18;;;:12;:18;;;;;;;;:34;;;;;;;;;71523:30;;;;;;:44;;;71640:30;;:17;:30;;;;;:43;;;71401:328;-1:-1:-1;71825:26:0;;;;:17;:26;;;;;;;;71818:33;;;-1:-1:-1;;;;;71869:18:0;;;;;:12;:18;;;;;:34;;;;;;;71862:41;70923:988::o;72206:1079::-;72484:10;:17;72459:22;;72484:21;;72504:1;;72484:21;:::i;:::-;72516:18;72537:24;;;:15;:24;;;;;;72910:10;:26;;72459:46;;-1:-1:-1;72537:24:0;;72459:46;;72910:26;;;;;;:::i;:::-;;;;;;;;;72888:48;;72974:11;72949:10;72960;72949:22;;;;;;;;:::i;:::-;;;;;;;;;;;;:36;;;;73054:28;;;:15;:28;;;;;;;:41;;;73226:24;;;;;73219:31;73261:10;:16;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;72277:1008;;;72206:1079;:::o;69710:221::-;69795:14;69812:20;69829:2;69812:16;:20::i;:::-;-1:-1:-1;;;;;69843:16:0;;;;;;;:12;:16;;;;;;;;:24;;;;;;;;:34;;;69888:26;;;:17;:26;;;;;;:35;;;;-1:-1:-1;69710:221:0:o;52945:305::-;53047:4;-1:-1:-1;;;;;;53084:40:0;;-1:-1:-1;;;53084:40:0;;:105;;-1:-1:-1;;;;;;;53141:48:0;;-1:-1:-1;;;53141:48:0;53084:105;:158;;;-1:-1:-1;;;;;;;;;;44692:40:0;;;53206:36;44583:157;94274:187;94405:48;94432:5;94439:3;94444:8;94405:26;:48::i;60470:439::-;-1:-1:-1;;;;;60550:16:0;;60542:61;;;;-1:-1:-1;;;60542:61:0;;14289:2:1;60542:61:0;;;14271:21:1;;;14308:18;;;14301:30;14367:34;14347:18;;;14340:62;14419:18;;60542:61:0;14087:356:1;60542:61:0;58643:4;58667:16;;;:7;:16;;;;;;-1:-1:-1;;;;;58667:16:0;:30;60614:58;;;;-1:-1:-1;;;60614:58:0;;12332:2:1;60614:58:0;;;12314:21:1;12371:2;12351:18;;;12344:30;12410;12390:18;;;12383:58;12458:18;;60614:58:0;12130:352:1;60614:58:0;60685:45;60714:1;60718:2;60722:7;60685:20;:45::i;:::-;-1:-1:-1;;;;;60743:13:0;;;;;;:9;:13;;;;;:18;;60760:1;;60743:13;:18;;60760:1;;60743:18;:::i;:::-;;;;-1:-1:-1;;60772:16:0;;;;:7;:16;;;;;;:21;;-1:-1:-1;;;;;;60772:21:0;-1:-1:-1;;;;;60772:21:0;;;;;;;;60811:33;;60772:16;;;60811:33;;60772:16;;60811:33;78782:602:::1;;78723:661::o:0;64059:853::-;64213:4;-1:-1:-1;;;;;64234:13:0;;34704:19;:23;64230:675;;64270:71;;-1:-1:-1;;;64270:71:0;;-1:-1:-1;;;;;64270:36:0;;;;;:71;;30330:10;;64321:4;;64327:7;;64336:4;;64270:71;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;64270:71:0;;;;;;;;-1:-1:-1;;64270:71:0;;;;;;;;;;;;:::i;:::-;;;64266:584;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;64511:13:0;;64507:328;;64554:60;;-1:-1:-1;;;64554:60:0;;;;;;;:::i;64507:328::-;64785:6;64779:13;64770:6;64766:2;64762:15;64755:38;64266:584;-1:-1:-1;;;;;;64392:51:0;-1:-1:-1;;;64392:51:0;;-1:-1:-1;64385:58:0;;64230:675;-1:-1:-1;64889:4:0;64882:11;;2845:296;2928:7;2971:4;2928:7;2986:118;3010:5;:12;3006:1;:16;2986:118;;;3059:33;3069:12;3083:5;3089:1;3083:8;;;;;;;;:::i;:::-;;;;;;;3059:9;:33::i;:::-;3044:48;-1:-1:-1;3024:3:0;;;;:::i;:::-;;;;2986:118;;;-1:-1:-1;3121:12:0;2845:296;-1:-1:-1;;;2845:296:0:o;9052:149::-;9115:7;9146:1;9142;:5;:51;;9277:13;9371:15;;;9407:4;9400:15;;;9454:4;9438:21;;9142:51;;;9277:13;9371:15;;;9407:4;9400:15;;;9454:4;9438:21;;9150:20;9135:58;9052:149;-1:-1:-1;;;9052:149:0:o;14:173:1:-;82:20;;-1:-1:-1;;;;;131:31:1;;121:42;;111:70;;177:1;174;167:12;192:186;251:6;304:2;292:9;283:7;279:23;275:32;272:52;;;320:1;317;310:12;272:52;343:29;362:9;343:29;:::i;383:260::-;451:6;459;512:2;500:9;491:7;487:23;483:32;480:52;;;528:1;525;518:12;480:52;551:29;570:9;551:29;:::i;:::-;541:39;;599:38;633:2;622:9;618:18;599:38;:::i;:::-;589:48;;383:260;;;;;:::o;648:328::-;725:6;733;741;794:2;782:9;773:7;769:23;765:32;762:52;;;810:1;807;800:12;762:52;833:29;852:9;833:29;:::i;:::-;823:39;;881:38;915:2;904:9;900:18;881:38;:::i;:::-;871:48;;966:2;955:9;951:18;938:32;928:42;;648:328;;;;;:::o;981:888::-;1076:6;1084;1092;1100;1153:3;1141:9;1132:7;1128:23;1124:33;1121:53;;;1170:1;1167;1160:12;1121:53;1193:29;1212:9;1193:29;:::i;:::-;1183:39;;1241:38;1275:2;1264:9;1260:18;1241:38;:::i;:::-;1231:48;;1326:2;1315:9;1311:18;1298:32;1288:42;;1381:2;1370:9;1366:18;1353:32;1408:18;1400:6;1397:30;1394:50;;;1440:1;1437;1430:12;1394:50;1463:22;;1516:4;1508:13;;1504:27;-1:-1:-1;1494:55:1;;1545:1;1542;1535:12;1494:55;1581:2;1568:16;1606:48;1622:31;1650:2;1622:31;:::i;:::-;1606:48;:::i;:::-;1677:2;1670:5;1663:17;1717:7;1712:2;1707;1703;1699:11;1695:20;1692:33;1689:53;;;1738:1;1735;1728:12;1689:53;1793:2;1788;1784;1780:11;1775:2;1768:5;1764:14;1751:45;1837:1;1832:2;1827;1820:5;1816:14;1812:23;1805:34;1858:5;1848:15;;;;;981:888;;;;;;;:::o;1874:347::-;1939:6;1947;2000:2;1988:9;1979:7;1975:23;1971:32;1968:52;;;2016:1;2013;2006:12;1968:52;2039:29;2058:9;2039:29;:::i;:::-;2029:39;;2118:2;2107:9;2103:18;2090:32;2165:5;2158:13;2151:21;2144:5;2141:32;2131:60;;2187:1;2184;2177:12;2131:60;2210:5;2200:15;;;1874:347;;;;;:::o;2226:254::-;2294:6;2302;2355:2;2343:9;2334:7;2330:23;2326:32;2323:52;;;2371:1;2368;2361:12;2323:52;2394:29;2413:9;2394:29;:::i;:::-;2384:39;2470:2;2455:18;;;;2442:32;;-1:-1:-1;;;2226:254:1:o;2485:957::-;2569:6;2600:2;2643;2631:9;2622:7;2618:23;2614:32;2611:52;;;2659:1;2656;2649:12;2611:52;2699:9;2686:23;2728:18;2769:2;2761:6;2758:14;2755:34;;;2785:1;2782;2775:12;2755:34;2823:6;2812:9;2808:22;2798:32;;2868:7;2861:4;2857:2;2853:13;2849:27;2839:55;;2890:1;2887;2880:12;2839:55;2926:2;2913:16;2948:2;2944;2941:10;2938:36;;;2954:18;;:::i;:::-;3000:2;2997:1;2993:10;2983:20;;3023:28;3047:2;3043;3039:11;3023:28;:::i;:::-;3085:15;;;3116:12;;;;3148:11;;;3178;;;3174:20;;3171:33;-1:-1:-1;3168:53:1;;;3217:1;3214;3207:12;3168:53;3239:1;3230:10;;3249:163;3263:2;3260:1;3257:9;3249:163;;;3320:17;;3308:30;;3281:1;3274:9;;;;;3358:12;;;;3390;;3249:163;;;-1:-1:-1;3431:5:1;2485:957;-1:-1:-1;;;;;;;;2485:957:1:o;3447:245::-;3505:6;3558:2;3546:9;3537:7;3533:23;3529:32;3526:52;;;3574:1;3571;3564:12;3526:52;3613:9;3600:23;3632:30;3656:5;3632:30;:::i;3697:249::-;3766:6;3819:2;3807:9;3798:7;3794:23;3790:32;3787:52;;;3835:1;3832;3825:12;3787:52;3867:9;3861:16;3886:30;3910:5;3886:30;:::i;3951:635::-;4031:6;4084:2;4072:9;4063:7;4059:23;4055:32;4052:52;;;4100:1;4097;4090:12;4052:52;4133:9;4127:16;4166:18;4158:6;4155:30;4152:50;;;4198:1;4195;4188:12;4152:50;4221:22;;4274:4;4266:13;;4262:27;-1:-1:-1;4252:55:1;;4303:1;4300;4293:12;4252:55;4332:2;4326:9;4357:48;4373:31;4401:2;4373:31;:::i;4357:48::-;4428:2;4421:5;4414:17;4468:7;4463:2;4458;4454;4450:11;4446:20;4443:33;4440:53;;;4489:1;4486;4479:12;4440:53;4502:54;4553:2;4548;4541:5;4537:14;4532:2;4528;4524:11;4502:54;:::i;:::-;4575:5;3951:635;-1:-1:-1;;;;;3951:635:1:o;4591:180::-;4650:6;4703:2;4691:9;4682:7;4678:23;4674:32;4671:52;;;4719:1;4716;4709:12;4671:52;-1:-1:-1;4742:23:1;;4591:180;-1:-1:-1;4591:180:1:o;4776:889::-;4898:6;4906;4914;4922;4930;4938;4991:3;4979:9;4970:7;4966:23;4962:33;4959:53;;;5008:1;5005;4998:12;4959:53;5044:9;5031:23;5021:33;;5101:2;5090:9;5086:18;5073:32;5063:42;;5152:2;5141:9;5137:18;5124:32;5114:42;;5207:2;5196:9;5192:18;5179:32;5230:18;5271:2;5263:6;5260:14;5257:34;;;5287:1;5284;5277:12;5257:34;5325:6;5314:9;5310:22;5300:32;;5370:7;5363:4;5359:2;5355:13;5351:27;5341:55;;5392:1;5389;5382:12;5341:55;5432:2;5419:16;5458:2;5450:6;5447:14;5444:34;;;5474:1;5471;5464:12;5444:34;5527:7;5522:2;5512:6;5509:1;5505:14;5501:2;5497:23;5493:32;5490:45;5487:65;;;5548:1;5545;5538:12;5487:65;5579:2;5575;5571:11;5561:21;;5601:6;5591:16;;;;;5654:3;5643:9;5639:19;5626:33;5616:43;;4776:889;;;;;;;;:::o;5766:257::-;5807:3;5845:5;5839:12;5872:6;5867:3;5860:19;5888:63;5944:6;5937:4;5932:3;5928:14;5921:4;5914:5;5910:16;5888:63;:::i;:::-;6005:2;5984:15;-1:-1:-1;;5980:29:1;5971:39;;;;6012:4;5967:50;;5766:257;-1:-1:-1;;5766:257:1:o;7315:488::-;-1:-1:-1;;;;;7584:15:1;;;7566:34;;7636:15;;7631:2;7616:18;;7609:43;7683:2;7668:18;;7661:34;;;7731:3;7726:2;7711:18;;7704:31;;;7509:4;;7752:45;;7777:19;;7769:6;7752:45;:::i;:::-;7744:53;7315:488;-1:-1:-1;;;;;;7315:488:1:o;7808:632::-;7979:2;8031:21;;;8101:13;;8004:18;;;8123:22;;;7950:4;;7979:2;8202:15;;;;8176:2;8161:18;;;7950:4;8245:169;8259:6;8256:1;8253:13;8245:169;;;8320:13;;8308:26;;8389:15;;;;8354:12;;;;8281:1;8274:9;8245:169;;;-1:-1:-1;8431:3:1;;7808:632;-1:-1:-1;;;;;;7808:632:1:o;9919:338::-;10061:2;10046:18;;10094:1;10083:13;;10073:144;;10139:10;10134:3;10130:20;10127:1;10120:31;10174:4;10171:1;10164:15;10202:4;10199:1;10192:15;10073:144;10226:25;;;9919:338;:::o;10262:219::-;10411:2;10400:9;10393:21;10374:4;10431:44;10471:2;10460:9;10456:18;10448:6;10431:44;:::i;10898:414::-;11100:2;11082:21;;;11139:2;11119:18;;;11112:30;11178:34;11173:2;11158:18;;11151:62;-1:-1:-1;;;11244:2:1;11229:18;;11222:48;11302:3;11287:19;;10898:414::o;15977:410::-;16179:2;16161:21;;;16218:2;16198:18;;;16191:30;16257:34;16252:2;16237:18;;16230:62;-1:-1:-1;;;16323:2:1;16308:18;;16301:44;16377:3;16362:19;;15977:410::o;16392:1312::-;16538:4;16580:3;16569:9;16565:19;16557:27;;16617:6;16611:13;16600:9;16593:32;16681:4;16673:6;16669:17;16663:24;16656:4;16645:9;16641:20;16634:54;16744:4;16736:6;16732:17;16726:24;16719:4;16708:9;16704:20;16697:54;16807:4;16799:6;16795:17;16789:24;16782:4;16771:9;16767:20;16760:54;16870:4;16862:6;16858:17;16852:24;16845:4;16834:9;16830:20;16823:54;16933:4;16925:6;16921:17;16915:24;16908:4;16897:9;16893:20;16886:54;16996:4;16988:6;16984:17;16978:24;16971:4;16960:9;16956:20;16949:54;17059:4;17051:6;17047:17;17041:24;17034:4;17023:9;17019:20;17012:54;17085:6;17145:2;17137:6;17133:15;17127:22;17122:2;17111:9;17107:18;17100:50;;17169:6;17222:2;17214:6;17210:15;17204:22;17235:49;17280:2;17269:9;17265:18;17251:12;5740:13;5733:21;5721:34;;5670:91;17235:49;-1:-1:-1;;17303:6:1;17346:15;;;17340:22;5740:13;5733:21;17403:18;;;5721:34;17441:6;17484:15;;;17478:22;5740:13;5733:21;17541:18;;;5721:34;17579:6;17622:15;;;17616:22;5740:13;5733:21;17679:18;;;;5721:34;;;;16392:1312;:::o;17891:275::-;17962:2;17956:9;18027:2;18008:13;;-1:-1:-1;;18004:27:1;17992:40;;18062:18;18047:34;;18083:22;;;18044:62;18041:88;;;18109:18;;:::i;:::-;18145:2;18138:22;17891:275;;-1:-1:-1;17891:275:1:o;18171:186::-;18219:4;18252:18;18244:6;18241:30;18238:56;;;18274:18;;:::i;:::-;-1:-1:-1;18340:2:1;18319:15;-1:-1:-1;;18315:29:1;18346:4;18311:40;;18171:186::o;18362:128::-;18402:3;18433:1;18429:6;18426:1;18423:13;18420:39;;;18439:18;;:::i;:::-;-1:-1:-1;18475:9:1;;18362:128::o;18495:120::-;18535:1;18561;18551:35;;18566:18;;:::i;:::-;-1:-1:-1;18600:9:1;;18495:120::o;18620:168::-;18660:7;18726:1;18722;18718:6;18714:14;18711:1;18708:21;18703:1;18696:9;18689:17;18685:45;18682:71;;;18733:18;;:::i;:::-;-1:-1:-1;18773:9:1;;18620:168::o;18793:125::-;18833:4;18861:1;18858;18855:8;18852:34;;;18866:18;;:::i;:::-;-1:-1:-1;18903:9:1;;18793:125::o;18923:258::-;18995:1;19005:113;19019:6;19016:1;19013:13;19005:113;;;19095:11;;;19089:18;19076:11;;;19069:39;19041:2;19034:10;19005:113;;;19136:6;19133:1;19130:13;19127:48;;;-1:-1:-1;;19171:1:1;19153:16;;19146:27;18923:258::o;19186:136::-;19225:3;19253:5;19243:39;;19262:18;;:::i;:::-;-1:-1:-1;;;19298:18:1;;19186:136::o;19327:380::-;19406:1;19402:12;;;;19449;;;19470:61;;19524:4;19516:6;19512:17;19502:27;;19470:61;19577:2;19569:6;19566:14;19546:18;19543:38;19540:161;;;19623:10;19618:3;19614:20;19611:1;19604:31;19658:4;19655:1;19648:15;19686:4;19683:1;19676:15;19712:135;19751:3;-1:-1:-1;;19772:17:1;;19769:43;;;19792:18;;:::i;:::-;-1:-1:-1;19839:1:1;19828:13;;19712:135::o;19852:112::-;19884:1;19910;19900:35;;19915:18;;:::i;:::-;-1:-1:-1;19949:9:1;;19852:112::o;19969:127::-;20030:10;20025:3;20021:20;20018:1;20011:31;20061:4;20058:1;20051:15;20085:4;20082:1;20075:15;20101:127;20162:10;20157:3;20153:20;20150:1;20143:31;20193:4;20190:1;20183:15;20217:4;20214:1;20207:15;20233:127;20294:10;20289:3;20285:20;20282:1;20275:31;20325:4;20322:1;20315:15;20349:4;20346:1;20339:15;20365:127;20426:10;20421:3;20417:20;20414:1;20407:31;20457:4;20454:1;20447:15;20481:4;20478:1;20471:15;20497:127;20558:10;20553:3;20549:20;20546:1;20539:31;20589:4;20586:1;20579:15;20613:4;20610:1;20603:15;20629:127;20690:10;20685:3;20681:20;20678:1;20671:31;20721:4;20718:1;20711:15;20745:4;20742:1;20735:15;20761:127;20822:10;20817:3;20813:20;20810:1;20803:31;20853:4;20850:1;20843:15;20877:4;20874:1;20867:15;20893:131;-1:-1:-1;;;;;;20967:32:1;;20957:43;;20947:71;;21014:1;21011;21004:12

Swarm Source

ipfs://dae9601cc6aa1fba524034cb8a7b4712794491d5df82b16c3aaddf921884c1fd
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.